Metadata-Version: 2.4
Name: unplug-mcp
Version: 0.1.6
Summary: MCP server for Unplug — LLM defense layer for Claude Code, Cursor, and more
Project-URL: Homepage, https://unplug-ai.org
Project-URL: Repository, https://github.com/UnplugAI/unplug-mcp
Project-URL: Issues, https://github.com/UnplugAI/unplug-mcp/issues
Project-URL: Documentation, https://github.com/UnplugAI/unplug-mcp#readme
Project-URL: Changelog, https://github.com/UnplugAI/unplug-mcp/blob/main/CHANGELOG.md
Author: Chirag Gupta
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ai-safety,claude,cursor,guardrails,llm,mcp,prompt-injection
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Security
Requires-Python: >=3.11
Requires-Dist: mcp<2,>=1.0
Requires-Dist: unplug-ai<0.7,>=0.5.2
Provides-Extra: agent
Requires-Dist: httpx>=0.27; extra == 'agent'
Requires-Dist: unplug-ai[ml]; extra == 'agent'
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: unplug-ai[ml]; extra == 'dev'
Provides-Extra: ml
Requires-Dist: unplug-ai[ml]; extra == 'ml'
Description-Content-Type: text/markdown

# Unplug MCP

[![CI](https://github.com/UnplugAI/unplug-mcp/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/UnplugAI/unplug-mcp/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/unplug-mcp)](https://pypi.org/project/unplug-mcp/)
[![License](https://img.shields.io/badge/License-Apache_2.0-9ca3af)](LICENSE)

Model Context Protocol server for [Unplug](https://github.com/UnplugAI/Unplug) — LLM defense layer.

Integrates with Claude Code, Cursor, Windsurf, and any MCP-compatible client.

## Installation

```bash
pip install unplug-mcp
```

Optional ML span scanner:

```bash
pip install "unplug-mcp[ml]"
```

Run without a prior install (recommended for MCP clients):

```bash
uvx unplug-mcp
```

See [`examples/mcp.json`](examples/mcp.json) for copy-paste client configs.

## Usage

### Local mode (default)

Add to your MCP client configuration:

**Cursor** — `.cursor/mcp.json` or Settings → MCP:

```json
{
  "mcpServers": {
    "unplug": {
      "command": "unplug-mcp",
      "args": []
    }
  }
}
```

**With uvx** (no pip install):

```json
{
  "mcpServers": {
    "unplug": {
      "command": "uvx",
      "args": ["unplug-mcp"]
    }
  }
}
```

**Claude Desktop** — `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "unplug": {
      "command": "unplug-mcp",
      "args": []
    }
  }
}
```

### Hosted server mode

Point at your Unplug API (same wire format as `Guard(mode="server")`):

```json
{
  "mcpServers": {
    "unplug": {
      "command": "unplug-mcp",
      "env": {
        "UNPLUG_MODE": "server",
        "UNPLUG_SERVER_URL": "https://api.unplug-ai.org/v1",
        "UNPLUG_API_KEY": "up_live_xxx"
      }
    }
  }
}
```

### Configuration

| Variable | Default | Purpose |
|----------|---------|---------|
| `UNPLUG_MODE` | `local` | `local` or `server` |
| `UNPLUG_CONFIG` | — | Path to Unplug TOML config |
| `UNPLUG_SERVER_URL` | — | Hosted API base URL (server mode) |
| `UNPLUG_API_KEY` | — | API key (server mode) |
| `UNPLUG_ACTIVE_MODEL` | — | ML model name override |
| `UNPLUG_MODEL_PATH` | — | Local ML checkpoint path |

## Tools

| Tool | Purpose |
|------|---------|
| `scan_text` | Scan text for injection/leakage (default `source=retrieved`, session-tainting) |
| `scan_tool_result` | Scan tool output before the agent reads it |
| `check_destructive` | Gate side-effect tool calls |
| `wrap_untrusted_content` | Boundary markers + scan for RAG/web content |
| `session_status` | Session taint state for agent hardening |
| `notify_taint_source` | Record an untrusted content source in session state |
| `notify_trusted_user_turn` | Host-only: clear session taint after a real user message |

### `scan_text` source parameter

`scan_text` defaults to **`source="retrieved"`** so scans participate in session taint and
`check_destructive` can require human review after untrusted input (fail-closed for agent hosts).

| `source` | Session taint | When to use |
|----------|---------------|-------------|
| `retrieved` (default) | Yes | RAG chunks, docs, or any content when provenance is unclear |
| `user`, `system` | No (clean session only) | Host-attested direct user or system messages only |
| `web_fetch`, `email`, `file`, `external`, … | Yes | Mapped to retrieved; prefer `wrap_untrusted_content` for web/RAG |

Once the session is tainted, later `scan_text` calls cannot downgrade gates by claiming
`source="user"`. Only the host may clear taint via `notify_trusted_user_turn` (see below).

### Session taint reset (host-only)

`notify_trusted_user_turn` replaces the old `reset_session_taint` tool. It requires
`confirm_trusted_user_turn=true`; without it the session **stays tainted** (fail-closed).

**Threat model:** Prompt injection in untrusted content may instruct an agent to call
taint-reset tools. Agents must **never** call `notify_trusted_user_turn` after reading
retrieved, web, email, or tool output. MCP hosts (Cursor, Claude Desktop) should:

1. Wire `notify_trusted_user_turn(confirm_trusted_user_turn=true)` to **user-turn hooks**
   (when a new human message arrives), not to agent tool lists.
2. Omit this tool from configs where the agent can invoke every registered MCP tool.

Naive calls without confirmation leave destructive tools gated at `review`.

All tools **fail closed**: scan failures return `safe=false` and `action=block` so agents never proceed on errors. `session_status` and taint helpers conservatively mark the session tainted when they cannot read state.

## CI

- `ci.yml` — lint + pytest against PyPI `unplug-ai`
- `pr-scan.yml` — regex Guard scan on changed agent/MCP config files (via `UnplugAI/unplug-scan-action@v1`)
- `publish-pypi.yml` — PyPI release on GitHub Release or manual dispatch

## Development

```bash
uv sync --extra dev
uv run pytest -q
uv run unplug-mcp
```

Local SDK path override (monorepo): `tool.uv.sources` in `pyproject.toml`.

## Distribution

See [`MARKETPLACE.md`](MARKETPLACE.md) for MCP registry listing steps and [`PUBLISH.md`](PUBLISH.md) for PyPI release workflow.

## Related

- [unplug-ai](https://pypi.org/project/unplug-ai/) — Python SDK
- [unplug-scan-action](https://github.com/UnplugAI/unplug-scan-action) — GitHub Actions agent scan
- [unplug-server](https://github.com/UnplugAI/unplug-server) — hosted scan API

## License

Apache-2.0 — see [LICENSE](LICENSE).
