MCP Offensive Playbooks¶
These playbooks cover MCP over HTTP/WebSocket and local stdio.
Tool-Call Argument Rewrite¶
Threat model: a planner calls a tool with safe-looking arguments, but an in-path proxy changes the account, object id, or action argument before the tool server receives it.
seam rules explain --rules rules/mcp_tool_call_argument_rewrite.yaml \
--rule mcp_tool_call_argument_rewrite
Expected touched path:
decoded.json.params.arguments.account
Tool-Call Argument Merge¶
Threat model: the operator needs to preserve the original call structure while adding nested authority, scope, or policy fields.
seam rules test \
--rules rules/mcp_tool_call_argument_merge.yaml \
--fixture examples/mcp-tool-call.json \
--expect-rule mcp_tool_call_argument_merge \
--json
Expected touched path:
decoded.json.params.arguments
The payload comes from examples/payloads/mcp-argument-merge.yaml.
Tool-Result Injection¶
Threat model: a planner trusts tool output that can be rewritten in path.
seam rules explain --rules rules/mcp_tool_result_string_injection.yaml \
--rule mcp_tool_result_string_injection
seam rules explain --rules rules/mcp_tool_result_content_insert.yaml \
--rule mcp_tool_result_content_insert
Expected touched paths:
decoded.json.result.content.0.text
decoded.json.result.content
Lab L6 tool_result_injection is the proof-oriented scenario for this pattern.
Local stdio Wrapping¶
Use stdio mode when the target launches a local MCP server command.
printf '{"jsonrpc":"2.0","id":"call-1","method":"tools/call","params":{"name":"echo","arguments":{"account":"ORIGINAL"}}}\n' \
| seam stdio proxy --command python3 \
--rules rules/mcp_stdio_argument_spoof.yaml \
--transcript stdio.json \
--schema schemas/transcript.schema.json \
-- examples/mcp-stdio-fixture.py
Seam decodes stdout lines as MCP traffic. Child stderr is forwarded as logs and is not decoded or mutated.
For object merge instead of scalar overwrite:
printf '{"jsonrpc":"2.0","id":"call-1","method":"tools/call","params":{"name":"echo","arguments":{"account":"ORIGINAL"}}}\n' \
| seam stdio proxy --command python3 \
--rules rules/mcp_stdio_argument_merge.yaml \
--transcript stdio-merge.json \
--schema schemas/transcript.schema.json \
-- examples/mcp-stdio-fixture.py
Correlation¶
MCP JSON-RPC ids are tracked under decoded.correlation. Use that when rules need to target a specific interleaved request/response pair.