About a2a-auditor
a2a-auditor is an MCP server that scans TypeScript and Python code implementing the A2A protocol for selected security anti-patterns. It checks webhook SSRF, missing authentication, and credentials in Agent Card metadata, with SARIF output for CI/CD use.
Key features
- 01Scan TypeScript and Python A2A code
- 02Detect webhook SSRF patterns
- 03Find missing authentication
- 04Flag credentials in Agent Card metadata
- 05Output findings as SARIF
Use cases
- 01Review A2A agent code for security issues
- 02Scan a file or directory in CI/CD
- 03Inspect supported detection patterns
MCP support
The MCP server provides tools to scan code snippets, files, and directories, and to list supported patterns. Findings cover the listed A2A security anti-patterns.
Configuration
Local server config is the same for every client. Copy it into your client’s MCP config file.
Tools
4Saved tool list · updated 2w ago
| Parameter | Type | Required | Description |
|---|---|---|---|
| label | string | No | Optional label shown in findings (e.g. filename) |
| content | string | Yes | The code content to scan |
Details
From the project README@guardbee/mcp-a2a-auditor
🇬🇧 English | 🇹🇷 Türkçe | 🇨🇳 中文 | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇧🇷 Português | 🇪🇸 Español | 🇩🇪 Deutsch
An MCP (Model Context Protocol) server that scans an agent's own Agent2Agent (A2A) protocol implementation for anti-patterns — not invented from the spec text, but read directly out of the reference SDKs (@a2a-js/sdk, a2a-sdk) and their own official sample code.
A2A doesn't have an MCP-style "Security Considerations" section yet to quote. So instead of guessing, this package's patterns come from three things found in the reference SDK source itself: the official push-notification sender fetches a client-supplied webhook URL with no host check at all, the official sample agent ships with an empty security scheme and a literal noAuthentication request handler, and the Python SDK's AgentCard(...) constructor treats its two security kwargs as fully optional — silently meaning "no auth" if you don't pass them.
Telemetry is off by default. With
GUARDBEE_TELEMETRY=1it sends the server, tool, success, duration and short parameter values such as a file path; longer strings and fields likecontent,tokenorpasswordare replaced with a placeholder. See@guardbee/mcp-telemetry.
Claude ──► a2a-auditor ──► Your A2A agent's source
│
├─ webhook-ssrf (push-notification webhook URL fetched with no allowlist)
├─ missing-authentication (Agent Card / request handler requires no auth at all)
└─ credential-exposure (literal credential inside publicly-served Agent Card metadata)
Why these three specifically
Webhook SSRF because the reference DefaultPushNotificationSender does exactly const url = pushConfig.url; ... fetch(url, ...) — pushConfig.url is set by whichever client subscribed to task updates, and the SDK fetches it with zero host validation. A caller can point a server running this code at an internal service, a cloud metadata endpoint, or anything else reachable from the server's network.
Missing authentication because the SDK's own sample agent (src/samples/agents/movie-agent) ships with securitySchemes: {}, securityRequirements: [], and userBuilder: UserBuilder.noAuthentication — a copy-paste-friendly shape that looks like a placeholder but is, functionally, "accept every request from anyone." The Python SDK has the same failure mode via absence rather than an explicit empty value: AgentCard(...) never requires security_schemes/security_requirements, so a real agent built by following the reference examples can end up with no authentication and no error telling you so.
Credential exposure because an Agent Card is served publicly — anyone who can reach /.well-known/agent-card.json (or the equivalent discovery response) can read it, no authentication required to fetch the card itself. A literal API key sitting in that JSON is effectively public.
Features
- 3 categories: webhook-ssrf, missing-authentication, credential-exposure
- Both TypeScript and Python A2A code — the SDKs use different idioms for the same failure (empty object vs. absent kwargs), so this checks both, not just one language
- Two of the six checks track data flow across a few lines instead of matching a single call site: the webhook check follows a
urlvariable back to apushConfig.url-shaped assignment before flagging thefetch()that uses it, and the credential check extracts the full Agent Card object span (brace-matched) before searching inside it for a literal secret — so it doesn't just flag anyapiKey:anywhere in the file - SARIF 2.1.0 output — CI/CD integration (GitHub Code Scanning, etc.)
- Config file support via
guardbee.yml - 18 unit tests — a positive and a negative (false-positive) scenario for every pattern, including a regression test for a real bug found during development (
\bAgentCarddoesn't match insidemovieAgentCard— no word boundary between a lowercase and uppercase letter — fixed to match the class name as a suffix instead). End-to-end verified against fixtures with all patterns deliberately planted in both TypeScript and Python (caught all of them), and against the entire guardbee-mcp monorepo (461 files — zero findings in any real code; the only matches were this package's own test fixtures, pattern-definition source, and manifest description text)
Quick Start
Claude Desktop / MCP Client
{
"mcpServers": {
"guardbee-a2a-auditor": {
"command": "npx",
"args": ["-y", "@guardbee/mcp-a2a-auditor"]
}
}
}
CLI (CI/CD)
npx @guardbee/mcp-a2a-auditor scan ./src --fail-on=high --format=sarif > results.sarif
MCP Tools
| Tool | Description |
|---|---|
scan_text | Scans a code snippet |
scan_file | Scans a single file |
scan_directory | Recursively scans a directory |
list_patterns | Lists all supported patterns by category |
Detected Patterns
| Category | Pattern | Severity |
|---|---|---|
| webhook-ssrf | webhook_url_direct_fetch_no_allowlist | critical |
| webhook-ssrf | webhook_url_indirect_fetch_no_allowlist | critical |
| missing-authentication | no_authentication_user_builder | critical |
| missing-authentication | empty_agent_card_security | high |
| missing-authentication | python_agent_card_no_auth | high |
| credential-exposure | agent_card_credential_in_metadata | high |
Configuration (guardbee.yml)
a2a-auditor:
fail-on: high # any | critical | high | medium | none
max-files: 5000
exclude:
- ".test.ts"
Limitations (by design)
- Heuristic, not a full A2A conformance test. This finds specific anti-patterns taken from the reference SDK's own source, not a live protocol conformance check against a running agent. A2A is a young, fast-moving spec — new failure modes will show up over time that aren't covered here yet.
- The data-flow checks (indirect webhook fetch, Agent Card credential span) use a bounded text window and bracket-matching, not a real parser — a
urlvariable assigned through a more indirect chain (e.g. passed through a helper function) won't be traced correctly, and neither will an Agent Card object spread across multipleObject.assign()-style merges instead of one literal. - Naming-convention dependent. The checks look for identifiers shaped like
pushConfig.url,*AgentCard,UserBuilder.noAuthentication— code that renames these away from the SDK's own conventions won't be recognized, the same limitation every pattern-based scanner in this family has.
Development
npm run build
npm test # 18 unit tests
License
MIT — GuardBee
Feedback
Questions, ideas, or a false positive? Start a thread in GitHub Discussions or open an issue. If GuardBee is useful to you, a ⭐ on the repository helps others find it.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.