MCP & A2A security proxy with real-time threat detection
Project description
Crossfire
MCP & A2A Security Proxy with Real-Time Threat Detection
Crossfire is a transparent man-in-the-middle proxy that sits between your IDE and MCP servers, detecting credential theft, prompt injection, data exfiltration, and 7 other attack patterns in real time. It also intercepts A2A (Agent-to-Agent) protocol traffic over HTTP.
Virtual environment (recommended)
Crossfire does not require a venv, but you should use one so pip install -e . does not mix with system or other projects’ packages (especially if you install the gemini extra).
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[gemini]" # or: pip install -e .
.venv/ is listed in .gitignore. In Cursor, select Python: Select Interpreter → ./.venv/bin/python for this workspace.
Quick Start (pip — recommended)
You do not need Node or npm for the MCP proxy: pip install adds both crossfire and crossfire-proxy next to your Python (same venv). Run crossfire install from that environment so mcp.json gets the absolute path to crossfire-proxy (works even when Cursor has a minimal PATH).
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install Crossfire (core detectors + dashboard API; no Gemini SDK)
pip install -e .
# When published to PyPI: pip install crossfire-mcp
# Optional: Gemini enrichment (GOOGLE_API_KEY or CROSSFIRE_GEMINI_KEY)
# pip install -e ".[gemini]"
# Build the React dashboard once (needed for the full UI on :9999; or use Vite dev on :5173 only)
cd dashboard && npm install && npm run build && cd ..
# Rewrite MCP configs to use crossfire-proxy, then start the dashboard
crossfire install
crossfire dashboard
# Open http://localhost:9999
# crossfire ping # smoke-test event without MCP
# crossfire ping --threat # + sample critical threat
# Demo (poisoned MCP server): bash demo/run-demo.sh
PyPI wheels: Before python -m build / publishing, copy the built UI into the package so the wheel ships static assets:
cd dashboard && npm ci && npm run build && cd ..
python3 scripts/sync_dashboard_dist.py
python -m build
(server/web_dist/ is gitignored; editable installs still use dashboard/dist from the repo.)
MCP config & what Crossfire sees
Crossfire’s stdio proxy only applies to MCP servers defined with a command (and optional args). The installer rewrites those so traffic flows through crossfire-proxy (the pip console script, or the optional Node shim) before your real server.
- URL-only MCP (
urlset, nocommand): the IDE talks to a remote endpoint directly.crossfire installskips these — Crossfire cannot sit in the middle without a local process. Use stdio-based servers if you need inspection. - Config locations (all are scanned; the same file on disk is only processed once):
- Cursor:
~/.cursor/mcp.jsonand project.cursor/mcp.json(relative to cwd when you runcrossfire install) - VS Code:
~/.vscode/mcp.jsonand project.vscode/mcp.json - Windsurf (Codeium):
~/.codeium/windsurf/mcp_config.json - Google Antigravity:
~/.gemini/antigravity/mcp_config.json - Claude Desktop: OS-specific paths under Application Support /
.config(seeproxy/installer.py)
- Cursor:
Diagnostics: crossfire doctor prints each known config path (if present), classifies each server (proxied / stdio not proxied / URL-only), and checks the dashboard (/health, /api/guardian). Run the dashboard first (crossfire dashboard) for a full green check.
If MCP servers won’t start or configs don’t look proxied
- Use the same Python/venv where you ran
pip install -e .: activate it, thencrossfire install. The installer preferscrossfire-proxynext tosys.executable, somcp.jsonstores a full path that Cursor can run without relying on shellPATH. - If you still see warnings, ensure
crossfire-proxyexists (e.g.ls "$(dirname $(which python3))/crossfire-proxy"). crossfire startrestores MCP configs on exit (Ctrl+C). For a persistent setup, usecrossfire installandcrossfire dashboardinstead of the one-shot flow.
npm / npx (thin shim — installs Python from PyPI)
The npm package crossfire-mcp ships only bin/ scripts plus a postinstall hook. On install it runs pipx install crossfire-mcp (preferred) or pip install --user crossfire-mcp, so the real crossfire and crossfire-proxy CLIs come from PyPI (bundled dashboard in the wheel). You do not need a git clone for the published npm package.
npx crossfire-mcp dashboard
# or: npm install -g crossfire-mcp && crossfire dashboard
From a git clone: if pyproject.toml is present next to package.json, postinstall uses pip install -e . into .venv/ (development layout).
Publishing the wheel first: npx users need the crossfire-mcp Python package on PyPI (same name as the npm package). Build the UI, sync, and upload the wheel (see PyPI wheels above) before npm publish.
Seeing traffic (dashboard)
| Step | What to do |
|---|---|
| Smoke test (no MCP) | Start crossfire dashboard, then run crossfire ping. The Traffic Log should show one event (server: ping). Use crossfire ping --threat to also post a sample critical threat (demo). The UI loads past events on connect (GET /api/events); POST /api/events accepts one JSON object per request (not a JSON array). |
| Real MCP traffic | Add stdio MCP servers (command + args), run crossfire install, restart the IDE, then use a chat that invokes tools (not just text). URL-only MCP is not proxied. |
| Dashboard URL | If the proxy and UI are not on http://localhost:9999, set CROSSFIRE_DASHBOARD_URL (or dashboard.url in crossfire.yaml) and restart the IDE. |
| Config not found | The IDE often runs MCP with a cwd that is not your repo root, so crossfire.yaml is skipped. Fix: set CROSSFIRE_CONFIG to the full path of your crossfire.yaml, or set CROSSFIRE_DASHBOARD_URL in the MCP server env block. The proxy also checks the repo root next to the installed proxy package (after cwd and before ~/.crossfire.yaml). |
Active vulnerability scan (no IDE)
Runs initialize → tools/list → synthetic tools/call probes and applies the same detectors as the live proxy (description poisoning, rules, response secret patterns, cross-call chains).
crossfire scan --cmd "python3 demo/poisoned_weather.py"
crossfire scan --server myserver # resolve command from MCP configs
crossfire scan --all # every stdio server in configs
crossfire scan --cmd "python3 demo/poisoned_weather.py" --json
With crossfire dashboard running, trigger a scan via POST /api/scan with {"server_name":"..."} or {"command":["python3","demo/poisoned_weather.py"]}. Progress appears on WebSocket /ws as scan_progress and scan_complete; GET /api/scan/results returns recent reports. (A dashboard “Scan” button can call the same API.)
Figma design URLs: Crossfire records MCP JSON-RPC (e.g. tools/call with fileKey / node id in arguments). Opening a file in the browser at https://www.figma.com/design/... does not go through the MCP proxy; you will see the design when you invoke a Figma MCP tool that references that file (check the Traffic Log / raw params).
Architecture
IDE (Cursor, VS Code, Windsurf, Antigravity, Claude, …)
│ stdin/stdout (JSON-RPC)
▼
┌─────────────────────┐
│ CROSSFIRE PROXY │──── POST /api/events ────▶ Dashboard Server (:9999)
│ (stdio MITM) │ │
│ • 10 rule detectors│ ▼
│ • Gemini AI agent │ React Dashboard (:5173)
│ • Chain tracker │ • React Flow graph
└─────────────────────┘ • Traffic log
│ stdin/stdout • Threat detail
▼ • Guardian toggle
MCP Server
Threat Detection (10 Patterns)
| Pattern | Severity | Detection |
|---|---|---|
| CRED-THEFT | critical | Sensitive file path matching (.ssh, .env, tokens) |
| SHELL-INJECT | critical | Shell command pattern matching (curl, nc, base64) |
| EXFIL-NET | high | Large payloads to reporting/telemetry tools |
| TOOL-SHADOW | medium | Unknown tool not in server's registry |
| PROMPT-RELAY | critical | Prompt injection → privileged tool calls |
| MEM-POISON | high | Suspicious writes to memory tools |
| PRIV-ESCAPE | critical | File write → shell execution chain |
| RUG-PULL | critical | SHA-256 hash diff on tool descriptions |
| TYPOSQUAT | high | Levenshtein distance to known server names |
| A2A-HIJACK | critical | A2A-specific impersonation/exfil/injection |
Environment variables
| Variable | Purpose |
|---|---|
CROSSFIRE_DASHBOARD_URL |
Override dashboard base URL for the proxy / A2A forwarder (default: http://localhost:9999 or dashboard.url in config). |
CROSSFIRE_CONFIG |
Path to crossfire.yaml or a directory containing it; highest priority when set (useful when the MCP process cwd is not the repo). |
GOOGLE_API_KEY / CROSSFIRE_GEMINI_KEY |
Optional Gemini enrichment (install pip install -e ".[gemini]" first). |
VITE_WS_URL |
(Dashboard dev/build) Override WebSocket URL; otherwise the UI uses ws(s)://<current-host>/ws. |
Gemini: Core Crossfire works without any Google packages. Install the gemini extra and set an API key only if you want AI-assisted explanations on top of rules.
Config-as-Code
Create crossfire.yaml or .crossfire.yaml:
version: 1
mode: monitor # or "block" (also toggle Guardian in the dashboard)
dashboard:
url: "http://localhost:9999"
rules:
sensitive_paths:
enabled: true
block: ["~/.ssh/*", "**/.env"]
shell_injection:
enabled: true
blocked_patterns: ["curl *", "| bash"]
typosquat:
enabled: true
max_distance: 2
rug_pull:
enabled: true
Project Structure
crossfire/
├── proxy/ # Python MCP proxy + detectors
│ ├── __main__.py # CLI entry point
│ ├── protocol.py # MCP wire format handler
│ ├── proxy.py # Bidirectional stdio proxy
│ ├── a2a_proxy.py # A2A HTTP reverse proxy
│ ├── config.py # YAML config loader
│ ├── installer.py # Auto-detect & rewrite MCP configs
│ ├── scanner.py # Active MCP vuln scan (CLI + /api/scan)
│ └── detectors/ # 10 threat detectors + Gemini AI
├── server/ # FastAPI dashboard backend
├── dashboard/ # React + React Flow frontend
├── shared/ # Event schema contract (Python + TypeScript)
├── demo/ # Poisoned weather server + sandbox
├── bin/ # Node.js CLI wrappers for npm
└── crossfire.yaml # Default configuration
Tech Stack
- Proxy: Python 3.10+, asyncio, aiohttp
- Detectors: regex, python-Levenshtein, SHA-256 hashing
- AI Analysis: Google ADK + Gemini 2.5 Flash
- A2A Proxy: FastAPI + httpx (HTTP reverse proxy)
- Dashboard Backend: FastAPI + WebSockets + uvicorn
- Dashboard Frontend: React 19, React Flow v12, Tailwind v4
- Config: YAML with deep merge + hot reload
- Distribution: pip + npm (npx crossfire install)
Team
- Yugandhar - Python backend (proxy, server, detectors)
- Ruthvik - React dashboard (components, flow graph, UI)
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crossfire_mcp-0.1.0.tar.gz.
File metadata
- Download URL: crossfire_mcp-0.1.0.tar.gz
- Upload date:
- Size: 274.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18b37b12d6147106c7f50ffad124cc3bb4102bda9a8b96145c12416f9411a74f
|
|
| MD5 |
c0a06003363e03376d31cf48f9f422f1
|
|
| BLAKE2b-256 |
04c3b37412440661ceb2f8244378c25d119f93429d0001922b76c81a1e0a1943
|
File details
Details for the file crossfire_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: crossfire_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 284.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1a67c20cd4b585025017ee2bc2564fbb9a87bbe95353f7063de3d5a81dd4ded
|
|
| MD5 |
219c5c9212d3e3e7d60153f28deb7556
|
|
| BLAKE2b-256 |
986f775bb53220f1e742cd0987d5a2cd3408ff7a2a201072b789a751d23ab9b0
|