CiscoCiscoDefenseClaw
Setup

Setup MCP scanner

Behavioural scan of every Model Context Protocol server an agent might call. DefenseClaw wraps cisco-ai-mcp-scanner to surface hidden tool intents and shadow capabilities, and writes verdicts into the same mcp_actions admission policy as the watcher.

The Model Context Protocol (MCP) is becoming the default way for agents to acquire new tools. Each MCP server exposes a set of tools; the agent picks them up at startup and calls them as needed.

That tool list is also a perfect place to hide a "shadow capability" — a tool whose description claims to read calendar events but whose implementation actually exfiltrates files, or a safe_lookup tool that quietly modifies a database. Static metadata isn't enough; you need to look at what the server will say it can do, and what its implementations imply.

DefenseClaw integrates Cisco's open-source cisco-ai-mcp-scanner for exactly that. Verdicts feed the mcp_actions admission policy by severity bucket — same shape as skill_actions.

What it scans

The wrapper at cli/defenseclaw/scanner/mcp.py accepts two target shapes — both as a positional TARGET argument (there is no --server or --remote flag — the scanner figures out which from the target's shape):

  • Local stdio server name — described by a JSON file with a top-level mcpServers block (the format used by Claude Desktop, Cursor, OpenClaw, Gemini, Codex, and Copilot). DefenseClaw spins each server up in a sandbox, lists its tools, and records every advertised description, parameter schema, and example.
  • Remote HTTP server URL — passed as the positional target. The scanner calls scan_remote_server_tools directly without spawning a subprocess.

For every tool the scanner produces:

  1. A static signature (name, schema, description hash).
  2. An optional LLM-assisted intent analysis — the description vs. the implied side effects.
  3. A consolidated finding with severity and reasoning.

Where DefenseClaw finds your servers

The CLI auto-discovers MCP server lists from the connectors you've set up, so you usually don't pass paths:

defenseclaw mcp scan --all

The default sources include:

  • ~/.openclaw/openclaw.jsonmcp.servers
  • ~/Library/Application Support/Claude/claude_desktop_config.jsonmcpServers
  • ~/.cursor/mcp.jsonmcpServers
  • ~/.codeium/windsurf/mcp_config.jsonmcpServers
  • Connector-specific paths registered by defenseclaw setup guardrail.

Each server is scanned independently and findings are tagged with the connector that discovered them.

One-shot scans

defenseclaw mcp scan --all --json | jq -s '[.[].findings[]]'

CI-friendly. Walks every server discovered in openclaw.json and emits one JSON object per server as a stream of top-level values (NDJSON-shaped, not wrapped in an array). jq -s slurps the stream into an array so a single pipeline can iterate findings across servers; for line-oriented tools use --json | jq -c '.findings[]' instead.

defenseclaw mcp scan filesystem

Scans just the named server entry from the discovered configs. The name is the positional target, not a --server flag.

defenseclaw mcp scan https://mcp.example.com/sse

Pass the URL as the positional target — the scanner detects it's an HTTP target and uses scan_remote_server_tools. No subprocess spawn. The remote server is not added to any connector — this is purely a pre-flight check.

defenseclaw mcp scan filesystem --scan-prompts --scan-resources --scan-instructions

Extends the scan beyond the tool list to also evaluate the server's prompts, resources, and instructions surfaces. Use when you suspect a server is hiding intent in its prompt templates.

Other real flags: --analyzers <list> to constrain which analyzer plugins run, --json for machine output.

Continuous protection

Just like skills, MCP scanning is most valuable as part of an admission pipeline. defenseclaw setup guardrail configures the watcher to:

Block — when a new entry appears in any tracked mcpServers file, hold the agent off until the scan resolves.

Allow — release the server back to the agent if the result severity maps to runtime: enable for the active rule pack.

Scan — run the wrapper against the new entry and emit the findings to the audit pipeline.

If you only want one-shot scans (no watcher), keep setup guardrail's admission off and run defenseclaw mcp scan --all from CI or a daily cron. The findings still flow to the same audit sinks.

Configure the action mapping

The scanner produces a severity. What that severity does lives in the active OPA policy file under mcp_actions — the schema is per-severity buckets, identical in shape to skill_actions:

policies/default.yaml (excerpt)
admission:
  scan_on_install: true
  allow_list_bypass_scan: true

mcp_actions:
  critical:
    file:    quarantine
    runtime: disable
    install: block
  high:
    file:    quarantine
    runtime: disable
    install: block
  medium:
    file:    none
    runtime: enable
    install: none
  low:
    file:    none
    runtime: enable
    install: none
  info:
    file:    none
    runtime: enable
    install: none

# Optional per-asset overrides (in scanner_overrides), e.g. tighten medium for the mcp class:
scanner_overrides:
  mcp:
    medium:
      file: quarantine
      runtime: disable
      install: block

To switch profiles for the entire mcp_actions table:

defenseclaw policy activate strict       # see Defaults page for the diff vs default
defenseclaw policy activate default
defenseclaw policy activate permissive

Block / allow individual servers

The watcher's verdict is the default. Operators always have manual override (block / allow act on the whole server, not on individual tools — the CLI doesn't take a --tool flag):

defenseclaw mcp list                                         # what is configured + state
defenseclaw mcp block untrusted-fs --reason "exfil tool found"
defenseclaw mcp allow cisco-internal --reason "first-party"

Every action is audited (block-mcp, etc.) so the trail is intact even when the manual override contradicts the watcher.

Using the unified LLM key

Behavioural intent analysis depends on the LLM judge being able to reason about each tool's description vs. its parameter schema. Set the unified key once:

defenseclaw keys set DEFENSECLAW_LLM_KEY

DefenseClaw injects it into the scanner subprocess via inject_llm_env, alongside any Cisco AI Defense API key for content classification. See Setup → Unified LLM key for the resolution order and Bifrost provider catalog.

The MCP scanner runs each stdio server inside a subprocess sandbox with a wall-clock timeout. Servers that hang are killed; servers that try to spawn networked side processes are flagged as findings, not just terminated silently.

Install if missing

cisco-ai-mcp-scanner is a hard dependency of defenseclaw (Python ≥3.11) and is pulled in automatically by pip install defenseclaw. If your environment somehow lost it, reinstall it directly:

pip install --upgrade cisco-ai-mcp-scanner

defenseclaw mcp exits cleanly with a one-line install hint if the SDK isn't present — it never crashes the gateway.

See also