MCP server (egmcp)

tools/mcp/egmcp.py is a Model Context Protocol server (stdio transport) that lets AI agents operate the whole platform as tools: phishlets, token-gated lures, captured sessions, upstream proxy, the Google relay — including opening a captured session in a real Chrome window on the operator machine.


Install

pip install -r tools/mcp/requirements.txt     # mcp SDK
pip install playwright                        # only for relay_open_session

Configuration

Reuses the console node list tools/my-servers.json:

[
  {
    "name": "vps-node-1",
    "host": "<node-ip>", "port": 9443, "base": "/api-XXXXXXXXXXXX",
    "ca": "api-certs-vps/ca.crt", "cert": "api-certs-vps/client.crt",
    "key": "api-certs-vps/client.key",
    "relay": { "host": "127.0.0.1", "port": 9445, "op_key": "<RELAY_OP_KEY>" }
  }
]

The MCP API key

Two transports, one key rule:

Getting / rotating the key (from egconsole)

eg> mcpkey           # show the key + ready-made agent config snippets
eg> mcpkey new       # generate a NEW key (rotates tools/mcp/mcp.key)

The key lives in tools/mcp/mcp.key (gitignored, 0600); EG_MCP_API_KEY env overrides the file. Rotating invalidates every agent config still holding the old key — update them (the mcpkey output gives you copy-paste snippets with the key already filled in).

Env for the HTTP transport: EG_MCP_HOST (bind — default loopback; set only behind a tunnel/firewall), EG_MCP_PORT (default 8306).

Registering with agents

Claude Desktop / Claude Code (stdio, local)

claude_desktop_config.json (Desktop) or .mcp.json (Code):

{ "mcpServers": { "RedPhish": {
    "command": "python",
    "args": ["C:/path/to/RedPhish/tools/mcp/egmcp.py"],
    "env": { "EG_MCP_DEFAULT_SERVER": "vps-node-1" } } } }

Claude Code also accepts it straight on the command line: claude mcp add RedPhish -- python <REPO>/tools/mcp/egmcp.py. Verify from the chat: “list my evilginx servers” (calls servers_list).

Cursor (.cursor/mcp.json)

stdio on the same machine:

{ "mcpServers": { "RedPhish": {
    "command": "python",
    "args": ["<REPO>/tools/mcp/egmcp.py"] } } }

or streamable-http from another machine (serve --http first):

{ "mcpServers": { "RedPhish": {
    "url": "http://<egmcp-host>:8306/mcp",
    "headers": { "X-API-Key": "<key from: egconsole mcpkey>" } } } }

ZCode

Same two shapes in the ZCode MCP config — stdio (command/args) for a local server, or the streamable-http entry (url + headers: {"X-API-Key": …}) for the networked one. EG_MCP_DEFAULT_SERVER in the server’s env selects the node.

ChatGPT (Connectors / MCP)

ChatGPT only reaches remote MCP servers over public HTTPS — stdio and plain-HTTP LAN endpoints won’t work. Expose the HTTP transport through an authenticated tunnel (cloudflared / ngrok / an SSH reverse tunnel with TLS) and register the resulting https://…/mcp URL as a connector, using the API key as the connector’s auth token. Keep the tunnel scoped to the campaign and tear it down afterwards — this is an internet-reachable path to your node controls.

Tools

Node & phishlets

Tool Args Effect
servers_list — configured nodes, default marker, relay availability
status — node heartbeat + session count
phishlets_list — names + enabled/disabled
phishlet_enable / phishlet_disable name hot switch (no restart)
phishlets_reload — re-read YAMLs from disk
phishlet_hostname name, hostname change base hostname

Lures

Tool Args Effect
lures_list phishlet? lures (path, redirect, relay, token)
lure_create phishlet, redirect_url?, relay? new lure with auto gate token
lure_url lure_id, params? campaign URL + the ?t=<token> reminder appended
lure_edit lure_id, fields_json partial edit (JSON object)
lure_delete lure_id delete

Sessions & browser-open

Tool Args Effect
sessions_list / session_detail / session_delete — captured sessions CRUD
session_cookies session_id import-ready cookies + gotchas (expires/secure/__Host-)
session_export session_id, file? Cookie-Editor JSON file
open_session session_id, url?, chrome?, headless? opens a real Chrome window on this machine signed in as the victim (evilginx-captured session; detached process, window survives the call)

Upstream proxy

proxy_status · proxy_set(address, port, type, username, password, routes, enabled) (partial — omitted fields keep values; masked password echoed back clobbers it) · proxy_route_add/del(suffix) · proxy_on / proxy_off.

Google relay

Tool Args Effect
relay_sessions — live relay victim sessions (needs tunnel + relay block)
relay_capture capture_id full capture: {email, password, cookies[], ua, ts}
relay_open_session capture_id, url? opens Chrome signed in with the relay capture (default: the victim’s Gmail inbox)

All node tools take an optional server argument for multi-node fleets.

Example session (what the agent actually does)

Operator: “Open the Gmail inbox for the newest session.”

Agent: relay_sessions → picks the newest capture → relay_open_session <id> → “Chrome opened, signed in as boyhoang37@gmail.com (Inbox (52)).”

Operator: “Create a new google lure pointing at mail.google.com and give me the URL.”

Agent: lure_create phishlet=google redirect_url=https://mail.google.com → lure_url <id> → returns https://<host>/<path> plus a reminder to append the ?t= token (which the agent fetches from the lure record — and must not log it).

Security notes