agent tooling / MCP security
MCP Security Preflight
Before an agent gets tools, tokens, local files, or write access, run the boring check. This tiny app scores an MCP server against the traps builders keep tripping over: token passthrough, confused deputy flows, SSRF during discovery, and local command execution.
applicable controls
Toggle what actually exists
Must-fix list
- Token passthrough is blockedIf the server calls upstream APIs, it obtains its own upstream token instead of forwarding the client token.
- Per-client consent is stored before OAuth forwardingProxy-style servers record approved client IDs, scopes, and redirect URIs per user.
- OAuth discovery blocks SSRF targetsDiscovery rejects non-HTTPS URLs, private IP ranges, metadata endpoints, and DNS rebinding tricks.
Policy brief to paste into a PR
MCP Security Preflight Transport: http Auth model: oauth Exposure: team Calls upstream APIs: yes Destructive tools: yes Local file access: no Score: 51/100 — do not connect Missing controls: - Token passthrough is blocked: If the server calls upstream APIs, it obtains its own upstream token instead of forwarding the client token. - Per-client consent is stored before OAuth forwarding: Proxy-style servers record approved client IDs, scopes, and redirect URIs per user. - OAuth discovery blocks SSRF targets: Discovery rejects non-HTTPS URLs, private IP ranges, metadata endpoints, and DNS rebinding tricks. Next test: - Send a token with the wrong audience and confirm the server returns 401, not a successful tool result.
minimum proof
Five tests before connecting a real agent
- Wrong-audience token returns
401; insufficient scope returns403. - OAuth discovery rejects private IPs, cloud metadata hosts, redirects to
file:, and non-loopback HTTP. - Proxy consent screen names the requesting client, requested scopes, and exact redirect URI.
- Local stdio setup shows the full command before execution and runs with the smallest useful permissions.
- Destructive tools require explicit confirmation and leave safe audit logs. No tokens in query strings. Ever.