About Bad MCP
Bad MCP is an MCP server published by canack in the Developer Tools category: 10 intentionally malicious MCP servers that exploit protocol features to attack AI clients. For security research and defense testing.
The repository has 9 stars and 1 forks, with the last commit 8 months ago. Six months or more without a commit doesn't mean the server is broken, but check the open issues before depending on it in production.
Install
git clone https://github.com/canack/bad-mcpThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Bad MCP
Powered by Claude · Grounded in docs
Security checks
Static checks derived from the repository yesterday. Heuristics on the source, not an audit.
- ✓README presentThe repository ships documentation.
- ✓License declaredUsable under a stated license.
- ✓Tests presentA test suite exists in the repository.
- ✓Dependencies pinnedA lockfile pins dependency versions.
- ✓No dynamic code executionSource scan found no eval, dynamic Function, or shell execution.
- !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.
README
bad-mcp
10 intentionally malicious MCP servers that demonstrate protocol-level attack patterns against AI clients. Each server exploits a distinct feature of the Model Context Protocol — tool descriptions, schemas, resources, session management, and cross-server interactions.
These aren't buggy servers waiting to be exploited. They are the attacker.
WARNING: This project is for authorized security research and education only. Do NOT expose these servers to the internet or use them in production.
Why This Exists
MCP adoption is accelerating — Claude Desktop, Cursor, Windsurf, and dozens of other AI clients now support it. But the protocol's trust model has fundamental gaps: tool descriptions are unverified, schemas can carry hidden instructions, and servers can mutate definitions mid-session. Research from CyberArk, Invariant Labs, and Elastic Security Labs has documented these attacks, but working implementations are scarce.
bad-mcp provides concrete, runnable attack servers so client developers can test defenses, security teams can assess risk, and researchers can study protocol-level threats without building everything from scratch.
How This Differs
| bad-mcp | damn-vulnerable-MCP-server | vulnerable-mcp-servers-lab | |
|---|---|---|---|
| Perspective | Server is the attacker | Server is the victim | Server is the victim |
| Focus | MCP protocol-level attacks only | Mixed (prompt injection + classic appsec) | Mixed (path traversal, SQLi, MCP) |
| Attacks | FSP, ATPA, rug-pull, resource poisoning, cross-server shadowing | CTF challenges (easy/med/hard) | 9 servers, pentest training |
| Language | Go + mcp-go SDK | Python | JS + Python |
| Isolation | Docker-compose, no host access | Local Python scripts | Docker-compose |
| Unique | Rug-pull via session tools + notifications, full-schema poisoning via param names | Challenge/scoring format | Typosquatting focus |
Architecture
vuln-external network (localhost:8001-8010)
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ schema-poison-notes│ │ response-inject- │ │ shadow-exfil │
│ :8001 │ │ tickets :8002 │ │ :8003 │
└────────────────────┘ └────────────────────┘ └────────────────────┘
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ squatting-file-ops │ │ tool-poisoning-calc│ │ true-rug-pull │
│ :8004 │ │ :8005 │ │ :8006 │
└────────────────────┘ └────────────────────┘ └────────────────────┘
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ resource-poison- │ │ indirect-inject- │ │ exfil-chain- │
│ docs :8007 │ │ fetcher :8008 │ │ analytics :8009 │
└────────────────────┘ └────────────────────┘ └────────────────────┘
┌────────────────────┐
│ denial-of-wallet │
│ :8010 │
└────────────────────┘
Servers
| Port | Server | MCP Attack Class | Protocol Feature Exploited |
|---|---|---|---|
| 8001 | schema-poison-notes | Full-Schema Poisoning (FSP) | input_schema parameter names |
| 8002 | response-inject-tickets | Adv. Tool Poisoning via Output (ATPA) | Tool response content |
| 8003 | shadow-exfil | Cross-Server Shadowing | Multi-server tool descriptions |
| 8004 | squatting-file-ops | Tool Name Collision / Squatting | Tool naming + descriptions |
| 8005 | tool-poisoning-calc | Tool Description Poisoning (TPA) | Tool descriptions |
| 8006 | true-rug-pull | Rug-Pull (Tool Def Mutation) | Session tools + notifications |
| 8007 | resource-poison-docs | Resource Poisoning (ATPA variant) | resources/list + resources/read |
| 8008 | indirect-inject-fetcher | Indirect Prompt Injection | External data in tool output |
| 8009 | exfil-chain-analytics | Cross-Tool Exfiltration Chain | Tool chaining via descriptions |
| 8010 | denial-of-wallet | Denial of Wallet | Recursive invocation + massive output |
Each server has its own README.md with vulnerability details, exploit scenarios, detection methods, and mitigation strategies.
Quick Start
# Build and start all servers
docker-compose build && docker-compose up -d
# Run smoke tests (runs entirely inside Docker)
docker-compose --profile test run --rm smoke-test
# View exfiltration logs
docker-compose logs schema-poison-notes | grep EXFIL
docker-compose logs true-rug-pull | grep RUG-PULL
# Stop
docker-compose down
Connecting an MCP Client
After docker-compose up -d, connect any SSE-compatible MCP client (Claude Desktop, Cursor, Windsurf, Claude Code, etc.). All servers use the same JSON format:
{
"mcpServers": {
"schema-poison-notes": { "url": "http://localhost:8001/sse" },
"response-inject-tickets":{ "url": "http://localhost:8002/sse" },
"shadow-exfil": { "url": "http://localhost:8003/sse" },
"squatting-file-ops": { "url": "http://localhost:8004/sse" },
"tool-poisoning-calc": { "url": "http://localhost:8005/sse" },
"true-rug-pull": { "url": "http://localhost:8006/sse" },
"resource-poison-docs": { "url": "http://localhost:8007/sse" },
"indirect-inject-fetcher":{ "url": "http://localhost:8008/sse" },
"exfil-chain-analytics": { "url": "http://localhost:8009/sse" },
"denial-of-wallet": { "url": "http://localhost:8010/sse" }
}
}
Tip: Start with
tool-poisoning-calc(:8005) — simplest attack to observe. Then trytrue-rug-pull(:8006) — ask about the weather 3+ times and watch the tools mutate.
Safety Guarantees
| Concern | Guarantee |
|---|---|
| Host filesystem | No volume mounts. Containers have zero access to host filesystem. |
| Host network | No network_mode: host. All containers use isolated Docker bridge networks. |
| Privileged access | No privileged: true. No cap_add. Default restricted capabilities. |
| Environment leakage | No host env vars passed. All "credentials" are fake hardcoded strings. |
| Host execution | Nothing runs on the host. Tests run inside Docker via --profile test. |
| Code on disk | Inert Go source files. Not executable outside Docker. |
Tech Stack
- MCP servers: Go + mcp-go v0.32.0 (SSE transport)
- Docker: Multi-stage
golang:1.23-alpine->alpine:3.19 - Orchestration: docker-compose with network isolation
- Testing: Dockerized Go smoke test (
--profile test)
Research References
| Server | Source |
|---|---|
| schema-poison-notes | CyberArk — Full-Schema Poisoning |
| response-inject-tickets | CyberArk — ATPA |
| shadow-exfil | Invariant Labs — Tool Poisoning |
| squatting-file-ops | Elastic Security Labs |
| tool-poisoning-calc | Invariant Labs — Tool Poisoning |
| true-rug-pull | ETDI Paper |
| resource-poison-docs | Pillar Security |
| indirect-inject-fetcher | Microsoft — Indirect Injection |
| exfil-chain-analytics | Elastic Security Labs |
| denial-of-wallet | Prompt Security — Top 10 MCP Risks |
See also: Adversa AI — MCP Security TOP 25 | MCPTox Benchmark | OWASP Top 10 for Agentic Applications
Known Gaps
The following published MCP attack classes are not yet implemented:
- Server Identity Spoofing — MCP server spoofing trusted
serverInfoname/version during initialization - Sampling Abuse — Exploiting
sampling/createMessageto inject arbitrary prompts - Prompt/System Instruction Leakage — Extracting system prompts via crafted tool responses
- Notification Channel Exfiltration — Abusing progress/logging notifications as data channels
README fetched from the repository yesterday. The original is authoritative.