Configuration¶
mcp-posture.toml¶
Read from the current directory (or --config PATH). CLI flags override the file; relative
paths resolve from the file's directory.
[scan]
targets = ["https://mcp.example.com/mcp"]
targets_file = "mcp-servers.txt" # one URL per line, # comments
client_configs = ["auto"] # or paths to .mcp.json / claude_desktop_config.json / ...
fail_on = "high" # info | low | medium | high | critical
spec = "auto" # or 2025-03-26 | 2025-06-18 | 2025-11-25 | 2026-07-28
enable = [] # check IDs or families, e.g. ["PRM", "ASM04"]
disable = ["ASM08"]
timeout = 10 # seconds per request
target_timeout = 300 # seconds for everything about one target
retries = 2 # idempotent requests only, exponential backoff
backoff = 0.5
max_bytes = 1048576 # response body cap
concurrency = 4 # targets scanned in parallel
proxy = "http://proxy.internal:3128"
ca_bundle = "certs/internal-ca.pem"
user_agent = "mcp-posture (security team)"
allow_private = false # loopback / RFC 1918 / link-local targets
tls_probe = true # extra TLS handshakes (legacy versions, certificate)
baseline = "mcp-posture.lock.json"
ignore_file = ".mcp-posture-ignore"
sarif_anchor = "mcp-posture.toml" # repo file SARIF results point to by default
[login] # `login` and `scan --login`; never secrets
client_id = "mcp-posture-local" # pre-registered client (or client_metadata_url)
scope = "notes:read"
port = 0 # loopback redirect port, 0 = ephemeral
register = false # allow Dynamic Client Registration without asking
Suppressions: .mcp-posture-ignore¶
[[ignore]]
check = "MCPP-ASM09" # or the short form "ASM09"
target = "https://mcp.example.com/*" # glob, default "*"
location = "*" # glob on the finding location
justification = "Open DCR is intended: public client registry" # required, 10+ chars
expires = 2026-12-31 # optional; expired suppressions resurface the finding
Suppressed findings stay in JSON and SARIF (with the justification) but do not count towards the exit code.
Rug-pull baseline¶
mcp-posture pin https://mcp.example.com/mcp -o mcp-posture.lock.json # review, then commit it
mcp-posture scan https://mcp.example.com/mcp --baseline mcp-posture.lock.json
The lock stores a canonical hash and the security-relevant fields (name, title, description,
schemas, annotations, URIs) of every tool, prompt, resource and template. Unicode is not
normalized on purpose, so an invisible character added to a description is a change.
MCPP-PIN03 reports a unified diff with hidden characters made visible.
Client configs¶
--from-client-config auto reads, when present: .mcp.json, .vscode/mcp.json,
.cursor/mcp.json in the current directory; ~/.claude.json (including per-project servers),
~/.cursor/mcp.json, Windsurf, Claude Desktop and VS Code user configs. Only remote entries
(url / serverUrl, or mcp-remote bridges) are scanned. Headers and environment values from
these files are never read into the scan or the report.