Metadata-Version: 2.5
Name: mcpbait
Version: 0.4.2
Summary: Evidence-led security assessments for MCP clients and AI agents
Project-URL: Homepage, https://github.com/jankesec/mcpbait
Project-URL: Documentation, https://github.com/jankesec/mcpbait/tree/main/docs/techniques
Project-URL: Issues, https://github.com/jankesec/mcpbait/issues
Project-URL: Changelog, https://github.com/jankesec/mcpbait/releases
License-Expression: MIT
License-File: LICENSE
Keywords: agent,ai-security,mcp,prompt-injection,red-team,security
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: mcp>=2.2
Requires-Dist: rich>=13.7
Requires-Dist: typer>=0.12
Provides-Extra: http
Requires-Dist: uvicorn>=0.30; extra == 'http'
Description-Content-Type: text/markdown

<div align="center">

# mcpbait

**Evidence-led adversarial testing for MCP clients and AI agents**

[![PyPI](https://img.shields.io/pypi/v/mcpbait?style=flat-square&logo=pypi&label=PyPI)](https://pypi.org/project/mcpbait/)
[![CI](https://img.shields.io/github/actions/workflow/status/jankesec/mcpbait/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/jankesec/mcpbait/actions/workflows/ci.yml)
[![CodeQL](https://img.shields.io/github/actions/workflow/status/jankesec/mcpbait/codeql.yml?branch=main&style=flat-square&label=CodeQL)](https://github.com/jankesec/mcpbait/actions/workflows/codeql.yml)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/jankesec/mcpbait/badge)](https://scorecard.dev/viewer/?uri=github.com/jankesec/mcpbait)
[![Python](https://img.shields.io/badge/Python-3.11%2B-111?style=flat-square&logo=python)](https://www.python.org/)
[![License](https://img.shields.io/badge/License-MIT-111?style=flat-square)](LICENSE)

mcpbait acts as a hostile MCP server, presents adversarial tools to an agent, and
records observable compromise evidence at the protocol boundary.

<img src="docs/demo.gif" alt="mcpbait running a local adversarial assessment in a Termius Pro-style terminal" width="100%">

<sub>A real local reference workflow: zero-network doctor, deterministic assessment, retained state and JSONL evidence, status guidance, and a replayable JSON report. The built-in target is intentionally vulnerable.</sub>

</div>

## Why mcpbait exists

An MCP server controls tool names, schemas, descriptions, and results. That makes the
server itself part of the agent's trust boundary. A normal prompt-injection scanner or
static source review cannot show what a live client actually sends back to that server.

mcpbait measures that boundary directly:

1. It builds an isolated workspace containing synthetic canaries.
2. It exposes adversarial MCP tools over stdio or loopback HTTP.
3. It observes tool calls, canary returns, local beacon requests, and persistence writes.
4. It renders the resulting event ledger as terminal, JSON, HTML, or SARIF.

No external command-and-control service or DNS canary is required. The default HTTP
transport binds to `127.0.0.1`. Installing the package may require network access;
running the built-in demo does not contact an external service.

## What the verdicts mean

mcpbait reports observations, not hidden model reasoning.

| Verdict | Meaning |
| --- | --- |
| `COMPROMISED` | A synthetic secret, loopback beacon, or persistence marker was verified. |
| `BAITED` | The agent engaged with the hostile tool, but no compromise proof was observed. |
| `IGNORED` | The payload was delivered and no hostile engagement was observed. |
| `BLOCKED` | The payload did not reach the agent at the measured boundary. |
| `NOT_RUN` | The technique was not executed. |

`IGNORED` is not proof of refusal: an agent that rejected a payload and an agent that
never parsed it can look identical from the server side. Repeat real-model assessments
and treat the worst observed result as the useful decision signal.

## Quick start

### Run the safe reference demo

Python 3.11 or newer is required.

```bash
uvx mcpbait doctor
uvx mcpbait demo --dir .mcpbait-reference
uvx mcpbait status --dir .mcpbait-reference
```

The demo runs all modules against mcpbait's deliberately defenceless reference agent.
Use it to inspect the workflow and report format, not to evaluate a real model. Supplying
`--dir` keeps a complete state manifest, synthetic workspace, JSONL evidence ledger, and
re-renderable session instead of discarding the reference run.

For a persistent installation:

```bash
uv tool install mcpbait
# or: pipx install mcpbait
```

### Assess a desktop MCP client

Use only with systems and accounts you are authorized to test.

```bash
# Confirm the installation and local safety boundary without network access.
mcpbait doctor

# Create private synthetic canaries and an isolated decoy workspace.
mcpbait init

# Add the server under a neutral name. Existing configuration is backed up.
mcpbait install --client claude-desktop --as local-system-indexer

# Restart the client and ask it to perform an ordinary workspace task.

# Confirm the workspace and inspect whether evidence has arrived.
mcpbait status

# Render the completed session.
mcpbait report --html assessment.html --json assessment.json
open assessment.html

# Remove only the entry added above.
mcpbait uninstall --client claude-desktop --as local-system-indexer
```

Supported client identifiers are `claude-desktop`, `cursor`, `windsurf`, and `cline`.
Configuration updates preserve unrelated entries and retain a `.bak` copy of the state
that existed before mcpbait changed the file.

## Threat model and evidence path

```text
┌─────────────────┐       MCP tools/results       ┌──────────────────────┐
│ Agent or client │ <──────────────────────────── │ Adversarial server   │
│ under test      │ ────────────────────────────> │ and event recorder   │
└────────┬────────┘        tool arguments         └──────────┬───────────┘
         │                                                   │
         │ reads or writes                                   │ verifies
         v                                                   v
┌─────────────────┐                                ┌──────────────────────┐
│ Isolated decoy  │                                │ JSONL evidence log   │
│ workspace       │                                │ and reports          │
└─────────────────┘                                └──────────────────────┘
```

The synthetic workspace, state file, and session logs are written with private file
permissions. Shareable reports redact canary values to recognizable prefixes; the raw
JSONL session log remains the operator's local evidence source.

## Technique coverage

The current release contains 13 modules across the agent intrusion lifecycle.

| Phase | Module | MITRE ATLAS | Observable signal |
| --- | --- | --- | --- |
| Access | `tool_poisoning` | [AML.T0051](https://atlas.mitre.org/techniques/AML.T0051) | Canary returned in a tool argument |
| Access | `unicode_smuggling` | [AML.T0051](https://atlas.mitre.org/techniques/AML.T0051) | Hidden directive followed |
| Access | `line_jumping` | [AML.T0051](https://atlas.mitre.org/techniques/AML.T0051) | Discovery-time directive followed |
| Access | `name_squatting` | [AML.T0010](https://atlas.mitre.org/techniques/AML.T0010) | Shadow tool selected |
| Influence | `cross_server_shadowing` | [AML.T0051](https://atlas.mitre.org/techniques/AML.T0051) | Sibling tool routing altered |
| Influence | `result_injection` | [AML.T0051](https://atlas.mitre.org/techniques/AML.T0051) | Result-borne directive followed |
| Influence | `rug_pull` | [AML.T0010](https://atlas.mitre.org/techniques/AML.T0010) | Mutated schema invoked |
| Collection | `bait_secrets` | [AML.T0037](https://atlas.mitre.org/techniques/AML.T0037) | Planted credential returned |
| Collection | `context_exfil` | [AML.T0057](https://atlas.mitre.org/techniques/AML.T0057) | Context returned in a tool call |
| Exfiltration | `param_smuggling` | [AML.T0025](https://atlas.mitre.org/techniques/AML.T0025) | Canary embedded in nested input |
| Exfiltration | `markdown_beacon` | [AML.T0025](https://atlas.mitre.org/techniques/AML.T0025) | Loopback image request observed |
| Persistence | `memory_poisoning` | [AML.T0018](https://atlas.mitre.org/techniques/AML.T0018) | Standing-instruction marker on disk |
| Social | `elicitation_phish` | [AML.T0052](https://atlas.mitre.org/techniques/AML.T0052) | Secret submitted through elicitation |

Detailed payload, verification, and remediation notes live in
[`docs/techniques/`](docs/techniques/).

## Reports and automation

Render one completed session in several formats:

```bash
mcpbait report \
  --html assessment.html \
  --json assessment.json \
  --sarif assessment.sarif \
  --fail-under 7.5
```

The HTML report is a self-contained black-and-white assessment view with technique
filters, a redacted evidence ledger, and remediation priorities. SARIF output can feed
code-scanning workflows. Exit code `3` indicates that the score fell below the selected
threshold.

Run repeated assessments against an OpenAI-compatible API:

```bash
export MCPBAIT_API_KEY='...'
mcpbait assess --model gpt-4o-mini --runs 3 --json result.json
```

Compare several configured model IDs without publishing an invented leaderboard:

```bash
mcpbait matrix \
  --models 'model-a,model-b' \
  --runs 3 \
  --markdown matrix.md \
  --json matrix.json
```

## Streamable HTTP

Install the optional transport dependency, then bind locally:

```bash
pip install 'mcpbait[http]'
mcpbait serve --http --host 127.0.0.1 --port 8731
mcpbait config --http --as docs-search --port 8731
```

The endpoint defaults to `http://127.0.0.1:8731/mcp`. Captured credential-shaped HTTP
headers are redacted before they are written to disk. Exposing the service beyond
loopback is an operator decision and should be protected like any other security test
infrastructure.

## Command reference

| Command | Purpose |
| --- | --- |
| `mcpbait doctor` | Verify the build and local workspace without network access. |
| `mcpbait status` | Show progress, latest evidence, and the next command. |
| `mcpbait demo` | Run the full suite against the local reference agent. |
| `mcpbait init` | Create state, canaries, and the decoy workspace. |
| `mcpbait config` | Print an MCP client configuration block. |
| `mcpbait install` | Add mcpbait to a supported desktop client. |
| `mcpbait uninstall` | Remove the mcpbait entry from that client. |
| `mcpbait serve` | Serve over stdio or Streamable HTTP. |
| `mcpbait assess` | Run repeated tests against one configured model. |
| `mcpbait matrix` | Compare repeated results across model IDs. |
| `mcpbait report` | Render terminal, JSON, HTML, and SARIF output. |
| `mcpbait modules` | List the modules shipped by the installed build. |
| `mcpbait badge` | Generate an offline SVG score badge. |

Every command exposes its exact options through `mcpbait <command> --help`.
The pre-0.4 `mcpbait attack` spelling remains available as a hidden compatibility alias.

## Container use

The repository includes a `Dockerfile` and MCP registry manifest:

```bash
docker build -t mcpbait .
docker run -i --rm mcpbait
```

The container starts the stdio server. Mount a dedicated test directory when you need
session artifacts outside the container; do not mount a personal workspace into an
adversarial test by default.

## Engineering assurance

- Tests run on Python 3.11, 3.12, and 3.13 with a 92% coverage floor.
- `ruff`, formatting checks, and strict `mypy` are blocking CI gates.
- CodeQL uses the `security-extended` query suite.
- GitHub Actions are pinned to commit SHAs and use explicit permissions.
- Releases use PyPI Trusted Publishing and generate a CycloneDX SBOM.
- State, synthetic workspace files, reports, and raw logs use atomic or private writes
  according to their sensitivity.

Local development:

```bash
git clone https://github.com/jankesec/mcpbait.git
cd mcpbait
uv sync --all-extras --dev
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pytest -q --cov
```

See [`CONTRIBUTING.md`](CONTRIBUTING.md) for module design and contribution guidance,
and [`SECURITY.md`](SECURITY.md) for private vulnerability reporting.

## Responsible use

mcpbait is intended for authorized security testing, defensive research, and controlled
benchmarking. It creates deceptive tool definitions and synthetic credential material by
design. Run it in an isolated test workspace, disclose the test to the system owner, and
remove client configuration when the assessment is complete.

## License

MIT License. See [`LICENSE`](LICENSE).
