Skip to content
Conduit

mcp server

pluto-aguard

Security scanner and launch gate for AI agents & MCP apps — config scanning, policy coverage, risk modeling, drift detection, CI/SARIF, and launch-readiness evidence

arshan846/pluto-aguardcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "pluto-aguard": {
      "command": "uvx",
      "args": [
        "pluto-aguard"
      ]
    }
  }
}

same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12

Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs

README

synced Oct 17, 2026

🛡️ Pluto AgentGuard

Your Claude Desktop / Cursor / VS Code MCP config may already let an AI agent call tools with no authentication, or ship a hardcoded API key. Check in 30 seconds.

CI License: Apache-2.0 Python 3.10+ PyPI

30-Second Scan

pip install pluto-aguard

# macOS Claude Desktop:
aguard scan ~/Library/Application\ Support/Claude/

# Windows Claude Desktop:
aguard scan %APPDATA%\Claude\

# Cursor / any project with a local mcp.json:
aguard scan .

Real output from scanning a realistic (but fictional) claude_desktop_config.json built entirely from real MCP fields — no invented schema, see examples/claude_desktop_config.json:

🔍 Scanning ...

  🟠 HIGH: Hardcoded secret in env var 'GITHUB_PERSONAL_ACCESS_TOKEN' on server 'github' (MCP01:2025)
  🟠 HIGH: Insecure HTTP transport on MCP server 'internal-metrics' (MCP07:2025)
  🟠 HIGH: No authentication configured for remote MCP server 'internal-metrics' (MCP07:2025)
  🟠 HIGH: Hardcoded GitHub Token detected (MCP01:2025)

  📊 Risk Score: 44.8/100 ██████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  📋 Findings: 4 high

No cloud accounts, no API keys, nothing leaves your machine — it's static analysis of the config file, not a live connection to your MCP servers. False positive? See docs/suppressions.md.

There's More Than a Scanner

Once you've found a problem, the harder question is "did my fix actually help, and can I prove it to whoever signs off on shipping this agent?" That's what the rest of AgentGuard is for — the two commands below are the part no other MCP scanner does:

git clone https://github.com/arshan846/pluto-aguard.git && cd pluto-aguard

# See the risk score drop *before* you apply a fix
aguard whatif --config ./examples/insecure-agent-config.yaml

# Generate a launch-approval packet: findings + policy coverage + sign-off checklist
aguard evidence ./examples/ --config ./examples/insecure-agent-config.yaml \
  --policy ./examples/agent-policy.yaml

Plus policy coverage linting (test), an OWASP-inspired control report (owasp), and drift detection (baseline) — see Commands below, or the interactive demo for all 7 in action.

CapabilityScannersAgentGuard
Detect secrets & misconfigs statically (no server execution)🟡 Varies✅ aguard scan
Policy coverage linting (22 named attack scenarios)❌✅ aguard test
"What-if" risk impact before applying changes❌✅ aguard whatif
OWASP-inspired control coverage (20 controls)❌✅ aguard owasp
Launch readiness evidence packets❌✅ aguard evidence
Baseline drift detection❌✅ aguard baseline
Behavioral trace audit with approval model❌✅ aguard monitor

MCP security scanners are multiplying fast (Snyk agent-scan, Invariant guardrails, AgentSeal) and mostly stop at config detection or runtime analysis. AgentGuard's differentiator is the pair above — quantified risk delta before you change anything, and a packet to hand whoever approves the launch — not the scanning itself, which is table stakes.

Real-World Validation: 1,200 GitHub Configs

We scanned 1,200 real MCP configs from public GitHub repos (1,159 unique projects) using AgentGuard:

MetricResult
Configs scanned1,200
Total findings2,891
🔴 CRITICAL0
🟠 HIGH189
🟡 MEDIUM169
ℹ️ INFO2,533
Repos with HIGH findings156 (13%)

What we actually found:

  • 189 remote MCP endpoints with no authentication configured
  • 169 unencrypted HTTP on non-localhost transport
  • Hardcoded secrets in a subset of configs
  • 2,533 informational items (capability inventory — shell access, browser automation, etc.)

Important context: Capability-related findings (e.g., a server having shell tools) are reported as INFO for awareness only. Per the MCP specification, human-in-the-loop enforcement is strictly a client/host responsibility, not the server's. See full methodology and results.

GitHub Action

- name: Agent Security Gate
  uses: arshan846/pluto-aguard@v0.9.5
  with:
    path: '.'
    max-risk: '50'
    fail-on: 'high'
    policy: 'agent-policy.yaml'
    attack-pack: 'all'
    sarif-output: 'results.sarif'

- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: results.sarif

See docs/github-action-usage.md for full options.


Commands

CommandWhat It DoesMaturity
aguard scanStatic analysis — secrets, misconfigs, unsafe AI code patterns✅ Stable
aguard testPolicy coverage linting — 22 named attack scenarios across 6 packs✅ Stable
aguard owaspOWASP-inspired control coverage report (20 controls)✅ Stable
aguard whatifPolicy impact simulation — risk delta before applying changes✅ Stable
aguard evidenceLaunch readiness packet with approval checklist🔶 Beta
aguard baselineSecurity snapshot + drift comparison over time🔶 Beta
aguard monitorBehavioral trace audit — replays tool calls against policy🔶 Beta

aguard scan

Finds real issues in any AI project — no MCP configs needed. Detects eval/exec on LLM output, hardcoded secrets (18+ patterns), missing authentication on remote endpoints, Dockerfile misconfigs, unpinned AI deps, LangChain unsafe settings, system prompt leaks, and more.

$ aguard scan ./my-project/

  🔴 CRITICAL: Unsafe execution of LLM output: eval() (MCP05:2025)
  🟠 HIGH: Hardcoded OpenAI Key detected (MCP01:2025)
  🟠 HIGH: .env file not in .gitignore (MCP01:2025)
  🟡 MEDIUM: Unpinned AI dependencies (MCP04:2025)

  📊 Risk Score: 100/100 ██████████████████████████████████████████████████
  📋 Findings: 1 critical · 14 high · 3 medium

CI flags: --max-risk 50 / --fail-on high / --format sarif

False positive? Suppress it via a .aguard.yaml file or an inline # aguard-ignore comment — see docs/suppressions.md. Use --no-suppress to see every finding regardless of suppression rules.

Not every check applies to every config: transport/auth/secrets checks work on any real claude_desktop_config.json, but the permission-wildcard and tool-poisoning checks look for metadata (permissions, tools[].description) that only exists in AgentGuard's own extended schema or in gateway configs that add it themselves — see docs/config-schema.md for exactly what's standard vs. extended, and examples/claude_desktop_config.json for a scan of a real, unmodified config.

aguard test

Policy coverage linting, not adversarial testing: for each of 22 named attack scenarios, checks whether the tool it would invoke is in your policy's denied_tools or require_human_approval list. Reports what gets caught vs. what gets through. No LLM needed — nothing is executed and no prompt text is evaluated. A scenario's attack_prompt is documentation of the threat it represents, not an input this command interprets; two scenarios that name the same tool (e.g. execute) get the identical verdict regardless of how different the underlying attack is.

⚠️ This tests whether your policy document would block each attack — not whether your actual LLM agent would resist it. Real agent resistance requires runtime testing against a live agent (planned for v1.2).

6 attack packs: prompt-injection, data-exfiltration, permission-escalation, approval-bypass, tool-poisoning, context-manipulation.

$ aguard test --policy agent-policy.yaml --attack-pack all

  ✅ PASS  PI-001  Direct instruction override        execute       Blocked
  ✅ PASS  DE-001  File export of sensitive data      file_write    Blocked
  ❌ FAIL  DE-004  SQL data dump                      sql_query     NOT caught

  📊 Results: 21 blocked · 1 missed · 22 total

  Recommended fixes:
    → Add sql_query to require_human_approval

CI flag: --fail-on-miss exits with code 1 if any attacks succeed.

aguard owasp

Evaluates 20 controls mapped to an OWASP-inspired control framework. Control IDs use a project-defined MCP01–MCP10 taxonomy that draws on OWASP LLM Top 10 and the emerging OWASP Agentic AI initiative, with MCP-specific extensions the existing standards don't yet cover.

$ aguard owasp ./my-project/

  ❌ MCP01:2025 Token Mismanagement: 3 failed, 1 passed
    ✗ AGC-MCP01-001: No hardcoded secrets
    ✓ AGC-MCP01-002: No static long-lived tokens
  ✅ MCP07:2025 AuthN/AuthZ: 2 passed
    ✓ AGC-MCP07-001: Remote servers have auth
    ✓ AGC-MCP07-002: HTTPS transport

  📊 Control Coverage: 9/10 risks
     Controls: 8 passed · 6 failed · 6 not tested · 20 total

aguard whatif

Simulates policy changes and shows risk score impact before applying them. Output below is the real, reproducible result of running aguard whatif --config examples/insecure-agent-config.yaml:

$ aguard whatif --config examples/insecure-agent-config.yaml

  Current Risk Score: 100/100

  ✅ Restrict SQL tool to SELECT-only queries               → 56  (↓ 44%)
  ✅ Add human-in-the-loop for file operations              → 97  (↓ 3%)
  ✅ Rotate API keys to ephemeral tokens                    → 82  (↓ 18%)
  ✅ Add rate limits (100 calls/minute) and timeout (5 min) → 57  (↓ 43%)
  ✅ Restrict outbound network access to allowlisted domains → 82  (↓ 18%)
  ✅ Convert from implicit-allow to explicit tool allowlist → 82  (↓ 18%)
  ✅ Run agent in sandboxed execution environment           → 82  (↓ 18%)

  💡 Apply all 7 → Risk drops to 5 (↓95%)

aguard evidence

Generates a launch readiness packet — risk summary, findings, tool permissions, policy coverage, required mitigations, and sign-off checklist. See examples/sample-launch-readiness.md.

aguard baseline

Save a security snapshot, compare later to detect drift.

aguard baseline create .               # Save current state
aguard baseline compare .              # What changed?
aguard baseline compare . --fail-on-drift  # CI: fail if new findings

aguard monitor

Replays agent action traces against a declared policy. Detects denied tool calls, unauthorized access, permission escalation, and missing/expired approvals.

aguard monitor --trace-file traces.jsonl --policy policy.yaml

Accepts real OTel GenAI semantic-convention traces (gen_ai.tool.name, gen_ai.operation.name — what OpenLIT and OTel-native LangChain instrumentation actually emit), this project's own OTel-shaped format, or a flat simple {"tool_name": "X", "tool_args": {}} format. See docs/trace-ingestion.md and examples/otel-genai-traces.jsonl.

Approvals are single-use — one approval authorizes exactly one matching call, not every future call to that tool — and, when both sides carry a timestamp, an approval recorded after the action it's supposed to cover is flagged as a DRIFT-BACKDATED-APPROVAL. See docs/approval-semantics.md.


How It Fits

┌─────────────────────────────────────────────────────┐
│  LAYER 1: Content Guardrails (existing)             │
│  Azure Content Safety · NeMo · Guardrails AI        │
│  → Protects what LLMs SAY                           │
├─────────────────────────────────────────────────────┤
│  LAYER 2: Agent Security (Pluto AgentGuard)         │
│  scan · test · owasp · whatif · evidence · baseline  │
│  → Watches what agents DO                           │
└─────────────────────────────────────────────────────┘

Risk Scoring

See docs/risk-scoring.md for the full scoring methodology — formula, weights, examples, CI threshold guidance, and limitations.

OWASP-Inspired Control Matrix

See docs/owasp-control-matrix.md for the complete mapping of 20 controls. Control IDs draw on OWASP LLM Top 10 (LLM01–LLM10) and introduce MCP-specific extensions (MCP01–MCP10) for risks the existing standards don't yet cover.

Roadmap

  • v0.1–v0.5 — Scanner, monitor, whatif, evidence, baseline, CI gates, SARIF, HTML reports
  • v0.8 — Policy coverage testing (17 scenarios, 5 attack packs)
  • v0.9 — OWASP-inspired control framework (20 controls, coverage reports)
  • v0.9.1 — Context manipulation pack (context stuffing, multi-turn confusion, indirect injection, RAG poisoning), supply-chain manifest poisoning scenario
  • v1.0 — Runtime proxy / tool-call firewall (observability on live tool calls without full red-team harness)
  • v1.1 — Multi-framework adapters (LangChain, CrewAI, AutoGen). aguard monitor already ingests real OTel GenAI semantic-convention traces (see docs/trace-ingestion.md) — a framework-specific setup adapter is what remains.
  • v1.2 — Live agent testing (send adversarial inputs to running agents)

Project Structure

pluto-aguard/
├── src/pluto_aguard/
│   ├── cli.py                  # 7 CLI commands
│   ├── models.py               # Finding, RiskScore, ControlResult, etc.
│   ├── scanners/               # MCP + AI config + permission scanners
│   ├── testing/                # 22 attack scenarios across 6 packs
│   ├── controls/               # 20 OWASP-aligned control definitions
│   ├── evidence/               # Launch readiness packet generator
│   ├── baseline/               # Snapshot + drift comparison
│   ├── monitor/                # Behavioral trace audit
│   ├── simulator/              # What-If policy simulation
│   ├── suppressions.py         # .aguard.yaml + inline finding suppression
│   └── reports/                # HTML + SARIF output
├── examples/                   # Demo project + configs + traces
├── docs/                       # Risk scoring, OWASP matrix, suppressions, GitHub Action docs
├── tests/                      # 174 tests
├── action.yml                  # GitHub Action
└── SECURITY.md

Contributing

See CONTRIBUTING.md for setup and guidelines.

License

Apache License 2.0 — see LICENSE.

↑↓ navigate openesc close