关于 mcpprobe
mcpprobe 是面向开发者和安全团队的本地只读 MCP 服务扫描器。默认不会调用工具,而是检查协议与元数据风险,并生成带证据的 JSON、SARIF 和终端报告。
主要功能
- 01身份验证与传输检查
- 02工具元数据投毒检查
- 03映射 OWASP 风险项
- 04生成 JSON、SARIF 和终端报告
- 05通过 SHA-256 基线检测变更
- 06本地运行且不发送遥测数据
适用场景
- 01发布前检查 MCP 服务
- 02在 CI 中运行安全检查
- 03将工具元数据与批准基线对比
- 04查看授权服务的发现项与检查覆盖范围
MCP 相关
可扫描远程 HTTP 和本地 stdio MCP 服务。默认被动模式不会调用工具;主动检查须通过授权与所有权验证。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://mcpprobe.tech/mcpclaude mcp add --transport http tech-mcpprobe-scanner https://mcpprobe.tech/mcp{"mcpServers":{"tech-mcpprobe-scanner":{"type":"http","url":"https://mcpprobe.tech/mcp"}}}在 Cursor 中打开{"servers":{"tech-mcpprobe-scanner":{"type":"http","url":"https://mcpprobe.tech/mcp"}}}在 VS Code 中打开{"mcpServers":{"tech-mcpprobe-scanner":{"type":"http","url":"https://mcpprobe.tech/mcp"}}}{"mcpServers":{"tech-mcpprobe-scanner":{"serverUrl":"https://mcpprobe.tech/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
mcpprobe
Model Context Protocol 服务安全扫描器。 它会检查身份验证、OAuth 元数据、传输合规性、工具描述投毒、突发式变更、元数据中的机密、详细错误和基本资源限制, 将每项发现映射到 OWASP MCP、Agentic 和 LLM Top 10 列表,并生成 JSON、 SARIF 2.1.0 和易读的终端摘要。
它在本地运行,不发送遥测数据,且在默认模式下绝不会调用工具。
只能扫描你拥有或已获明确授权进行测试的服务。 请参阅所有权规则。
60 秒快速入门
$ pipx run --spec mcpprobe-scanner mcpprobe https://your-server.example/mcp
或安装:
$ pipx install mcpprobe-scanner # or: pip install mcpprobe-scanner; the command is `mcpprobe`
$ mcpprobe https://your-server.example/mcp --sarif mcpprobe.sarif --json mcpprobe.json
你自行运行的本地 stdio 服务:
$ mcpprobe --stdio "npx -y @your-scope/[email protected]"
传入你拥有的 bearer token(用于检查需要身份验证的服务):
$ mcpprobe https://your-server.example/mcp --header "Authorization: Bearer $MCP_TEST_TOKEN"
摘要会列出每项发现的严重程度、检查 ID、置信度、OWASP 映射、证据摘录和通俗易懂的修复建议,随后附上覆盖范围表,展示运行了哪些检查、跳过了哪些检查及原因。mcpprobe checks 会列出所有检查;CHECKS.md 对它们进行了完整说明。
检查内容
| 区域 | 检查项 | 示例 |
|---|---|---|
| 身份验证 | AUTH-01..06 | 端点无需凭据即可响应;缺少 RFC 9728 受保护资源元数据;未使用 PKCE S256;接受受众错误的自签 JWT;在查询字符串中接受令牌;2026-07-28:授权服务器未公布 RFC 9207 iss;使用已弃用的动态客户端注册,且未使用客户端 ID 元数据文档 |
| 传输 | TRANS-01..09 | 未验证 Origin(DNS 重绑定);接受伪造的 MCP-Protocol-Version;Mcp-Session-Id 薄弱或可伪造;仍提供已弃用的 HTTP+SSE;纯 HTTP、TLS 薄弱、缺少标头;2026-07-28:server/discover 结果不完整;接受服务器未公布的版本(降级);未通过 -32020 拒绝 Mcp-Method 标头与正文不匹配;缺少或无效的 ttlMs/cacheScope |
| 工具元数据 | META-01..07 | 针对模型的指令(“始终先调用此工具”“不要告诉用户”);要求发送对话、系统提示词或机密;跨工具冒名;凭据路径、URL、base64、HTML 注释、零宽字符/双向控制字符/同形异义 Unicode;与已存储 SHA-256 基线进行突发式变更对比;声明可执行任意命令或访问文件(严重;未经过身份验证时为危急);架构规范性;描述或 stdio 环境变量中的机密;缺少工具注释或注释与工具不一致(readOnlyHint、destructiveHint、idempotentHint、openWorldHint、title);同一服务中同时存在私有数据、不可信内容和出站通道的“致命三要素” |
| 健壮性 | ERR-01、DOS-01 | 错误中包含堆栈跟踪和版本信息;一个超大参数、一次 64 层嵌套探测和 20 次限速的 tools/list 调用,仅此而已 |
| 主动检查(门控占位项) | INJ-01..05、SUPPLY-01/02、SANDBOX-01 | 已注册,并在此版本中报告为 not_implemented |
| 治理 | GOV-01..05 | 列为仅供证明的项目:无法通过扫描评估,绝不会标记为通过 |
24 项被动检查(另有 8 项门控主动检查占位项和 5 项仅供证明的治理项目);
mcpprobe checks 会列出这些项目。
协议修订版本:扫描器会先尝试 server/discover(2026-07-28),再使用 2025-11-25 和 2025-06-18 调用
initialize,然后尝试已弃用的 2024-11-05 HTTP+SSE
传输,并记录哪个版本作出了响应。对于使用较早版本的服务,仅存在于
2026-07-28 版本规则的检查会报告为不适用,并以协商的修订版本作为原因。
目录就绪情况
每份 JSON 报告都包含一个 readiness 列表,用于将扫描结果对应到 Anthropic、OpenAI 和 HubSpot MCP 目录的收录要求(OAuth 2.0、完整准确的工具注释、无隐藏指令、无未解决的严重/高危发现、低数据泄露和投毒风险、HTTPS)。每项状态为 met、not_met 或 not_assessable,注明其来源并列出所依据的检查;结果仅根据实际运行的检查得出。对于扫描无法判定的事项(例如端点所有权证明),状态为 not_assessable,并说明原因。参见
docs/report-schema.md。
目标上的速率限制
遇到 HTTP 429 时会遵守限制:根据 Retry-After 指定的时间后重试(若未提供,则等待 1 秒),且整个扫描的总等待时间不超过预算(默认 30 秒,可通过 --rate-limit-wait 设置)。
预算用尽后,对于请求被限流的检查,将报告为不适用,而不会根据被限流的响应得出结论。DOS-01 的突发请求是例外:它要查找的证据正是 429。
被动模式与主动模式
被动模式(默认)只发送普通 MCP 客户端会发送的内容(协商、*/list 方法、well-known 元数据文档),以及少量无害的格式错误请求(错误的 Origin、伪造的版本标头、伪造的会话 ID、自行签发且受众错误的 JWT、截断的 JSON、一条超大请求和一条深度嵌套请求)。它绝不会调用工具。
主动模式(--active)用于执行会通过非破坏性 canary 调用工具的检查。在 0.1.0 中,这些检查还是存根,但准入门槛真实有效,并在代码中强制执行。除非同时传入以下所有参数,否则会拒绝启用主动模式:
--authorised-by "<who approved this, e.g. name/role/ticket>"--scope "<what is in scope>"--verify dns-txt(HTTP 目标)或--verify local(由你自行运行的 stdio 服务)
对于 dns-txt,请生成令牌并发布:
$ mcpprobe token your-server.example
Publish this DNS TXT record, then run with --active --verify dns-txt:
_mcpprobe.your-server.example. TXT "mcpprobe-verification=<token>"
$ mcpprobe https://your-server.example/mcp --active --verify dns-txt \
--authorised-by "platform security, CHG-1234" --scope "https://your-server.example/mcp" \
--json scan.json
每次主动扫描都会生成一份授权记录(scan.authorisation.json,与报告保存在同一目录):包括授权人、范围、验证证明、速率上限和排除的工具。对于绝不能调用的工具,请使用 --exclude-tool NAME。
所有权规则
仅扫描你拥有、运营或已获得明确书面测试许可的 MCP 服务。这一规则同样适用于被动模式:如果系统不属于你,即使请求无害,也属于未经授权的访问。mcpprobe 会在每个请求中标明自身身份,并遵守退出扫描请求(见下文),但这些只是礼貌性机制,并不代表获得了许可。
扫描器标识、退出扫描请求和速率限制
- User-Agent:
mcpprobe/<version> (+https://mcpprobe.tech/scanning-policy)。 - 退出扫描请求会在发送任何 MCP 请求前检查,且无法绕过:
_mcpprobe.<host>(或父域名)上的 DNS TXT 记录mcpprobe-opt-out=all,会在任何数据包到达主机前检查;/.well-known/mcpprobe-opt-out返回 HTTP200。
- 速率:默认每秒 5 个请求(
--rate),硬性上限为 10。
退出代码
| 代码 | 含义 |
|---|---|
0 | 没有达到或超过 --fail-on(默认 high)级别的发现 |
1 | 至少有一项发现达到或超过 --fail-on 级别 |
2 | 错误:目标不可达、参数错误、所有权验证失败、授权被拒绝,或目标已退出扫描 |
3 | 目标有响应,但不是 MCP 服务(例如普通网站);所有检查均报告为不适用,且没有任何检查通过 |
SARIF 和 GitHub 代码扫描
作为 GitHub Action 使用(Docker 容器 Action,无需配置 Python):
name: MCP security
on: [push, pull_request]
permissions:
contents: read
security-events: write
jobs:
mcpprobe:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mcpprobe-dev/[email protected]
id: scan
with:
target: https://staging.your-server.example/mcp
fail-on: high
sarif-output: mcpprobe.sarif
sarif-location: src/server.py # optional: anchor alerts to a repo file
# Upload only when the scan ran (exit 0 or 1). Exit 2 (error) and 3 (not an MCP
# server) produce SARIF with no results, which would close every open alert.
- uses: github/codeql-action/upload-sarif@v3
if: ${{ !cancelled() && (steps.scan.outputs.exit-code == '0' || steps.scan.outputs.exit-code == '1') }}
with:
sarif_file: mcpprobe.sarif
category: mcpprobe
输入、输出、退出代码和手动调度示例见 docs/github-action.md。
也可以通过 CLI 在任何 CI 中运行:
$ pipx run --spec mcpprobe-scanner mcpprobe https://staging.your-server.example/mcp --sarif mcpprobe.sarif --fail-on high
结果中,严重/高危使用 error,中危使用 warning,低危/信息使用 note;每条规则都带有 GitHub 的 security-severity,并将 OWASP ID 作为标签。由于被扫描的端点不是文件,结果会指向目标 URL,除非你传入 --sarif-location。
Rug-pull 检测
$ mcpprobe https://your-server.example/mcp --baseline .mcpprobe/baseline.json
首次运行会存储每个工具、提示词、资源和服务器指令的规范 SHA-256 哈希值。之后的运行会报告所有新增、移除或更改的内容(批准后更改描述是典型的 rug-pull),并更新文件;使用 --no-write-baseline 可进行比较而不更新。
报告和证据
--json FILE:完整报告,包括每组请求/响应(时间戳、方法、状态、所有标头,以及不超过 64 KiB 的正文)。凭据标头和可识别的机密模式会被编辑。每条发现都包含一个根据解析数据生成的proof摘录、一条可运行的verify命令,以及在置信度不高时提供的confidence_reason。缺少前置条件的检查会以not_applicable状态报告并附上原因,绝不会计为通过。架构见 docs/report-schema.md。--sarif FILE:SARIF 2.1.0。-v:在终端中显示描述和扫描备注;-q:不输出终端信息。
服务器提供的文本会将控制字符显示出来,且绝不会被解释为终端标记。
META-01 的可选分类器
$ pip install 'mcpprobe-scanner[hf]' # transformers, torch, safetensors
$ mcpprobe https://your-server.example/mcp --judge hf:/path/to/local/model
$ mcpprobe https://your-server.example/mcp --judge hf:<hub-model-id> --judge-download
默认关闭。本地提示词注入分类器会对 META-01 给出第二种判断;若它标记了某条描述,则会添加一个中严重性指示项。只会加载 .safetensors 权重,不会执行模型代码,且只有在传入 --judge-download 时才会下载内容。模型许可各不相同;请先阅读 docs/judges.md。启发式检测数据见 docs/benchmark.md。
Python API 和 LLM 裁判钩子
import asyncio
from mcpprobe.checks import JudgeVerdict, ScanOptions
from mcpprobe.scanner import ScanConfig, run_scan
def judge(text: str, task: str) -> JudgeVerdict | None:
return None # plug in your own model here; mcpprobe makes no LLM calls
report, evidence = asyncio.run(
run_scan(ScanConfig(target="https://your-server.example/mcp", options=ScanOptions(judge=judge)))
)
print(report.counts())
开发
$ pip install -e ".[dev]"
$ ruff check . && ruff format --check . && mypy && pytest
$ python -m tests.fake_server --preset vulnerable --port 8765 # deliberately vulnerable local server
$ mcpprobe http://127.0.0.1:8765/mcp
安全问题:请参阅 SECURITY.md。许可:从 0.2.0 版本起采用 Apache-2.0(参见 NOTICE);0.1.0 版本以 MIT 许可发布。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。