P4ST4S/mcp-audit
GitHub: P4ST4S/mcp-audit
mcp-audit 是一个透明的 Go 代理,用于在不修改客户端和服务器的前提下拦截、签名记录和审计 MCP 工具调用流量。
Stars: 7 | Forks: 8
# mcp-audit

[](https://github.com/P4ST4S/mcp-audit/actions/workflows/ci.yml)
[](https://codecov.io/gh/P4ST4S/mcp-audit)
[](https://glama.ai/mcp/servers/P4ST4S/mcp-audit)


[](https://github.com/P4ST4S/mcp-audit/discussions)
一个用于 MCP server 的即插即用型安全与可观测性代理。`mcp-audit` 位于 MCP client 和任何上游 MCP server 之间,用于生成签名的审计跟踪、脱敏敏感 payload、执行允许/拒绝策略和基于工具的速率限制,并公开本地只读 dashboard。
有关面向贡献者的 runtime、package 边界、并发模型和设计不变量说明,请参阅 [ARCHITECTURE.md](ARCHITECTURE.md)。
## 为什么选择 mcp-audit?
[MCP 2026 路线图](https://modelcontextprotocol.io/development/roadmap) 提出了在审计跟踪、网关模式和运维可见性方面的企业需求。`mcp-audit` 作为可部署的 sidecar 或本地封装填补了这一空白:它位于任何 MCP client 和 server 之间,保留协议流量,并为 tool 调用、资源读取、prompt 请求以及所有其他 JSON-RPC 方法记录签名的审计条目。
```
+-------------+ JSON-RPC / MCP +-----------+ JSON-RPC / MCP +-------------+
| MCP client | <-------------------> | mcp-audit | <---------------------> | MCP server |
+-------------+ +-----------+ +-------------+
|
v
JSONL or SQLite audit log
|
v
Read-only dashboard
```
## 它是什么 / 不是什么
`mcp-audit` 不是特定领域的 MCP server。它是一个透明的安全与可观测性代理,封装了任何 MCP server 并审计流经它的 JSON-RPC 流量。
目录可能会显示上游 server 暴露的工具,而不是 `mcp-audit` 自身实现的工具。
## 支持的 Transport
- `stdio` 用于本地 MCP client(例如 Claude Desktop)
- `http` 用于通过 HTTP 暴露的 MCP server
HTTP 上游可以使用自定义 CA bundle、TLS server 名称覆盖和可选的 mTLS client 证书。上游重试默认关闭,仅在启用时应用于保守的、幂等的 JSON-RPC 方法;不会对 `tools/call` 进行重试。
## 使用场景
- 审计受监管环境中 AI agent 进行的 tool 调用
- 检测意外或危险的 MCP tool 使用情况
- 保留签名的 JSONL 或 SQLite 日志以供事件审查
- 在存储请求和响应之前脱敏敏感字段
- 阻止不允许的工具并应用基于工具的速率限制,而无需修改上游 MCP server
## 演示

## 安装
有关详细的特定平台说明和故障排除,请参阅
[INSTALL.md](INSTALL.md)。
下载最新的预编译二进制文件并运行:
```
# Linux/macOS:解析最新版本、下载、验证其启动
version=$(curl -fsSL https://api.github.com/repos/P4ST4S/mcp-audit/releases/latest \
| grep '"tag_name"' | head -n1 | cut -d'"' -f4 | sed 's/^v//')
os=$(uname | tr '[:upper:]' '[:lower:]')
arch=$(uname -m); [ "$arch" = "x86_64" ] && arch=amd64 || arch=arm64
base="https://github.com/P4ST4S/mcp-audit/releases/download/v${version}"
archive="mcp-audit_${version}_${os}_${arch}.tar.gz"
curl -L -o "${archive}" "${base}/${archive}"
tar -xzf "${archive}"
./mcp-audit --version
```
使用 Docker 运行:
```
docker run --rm ghcr.io/p4st4s/mcp-audit:latest --version
```
使用 Go 从源码安装:
```
go install github.com/P4ST4S/mcp-audit/cmd/mcp-audit@latest
```
要固定特定的发布版本以实现可重现安装,请参阅
[INSTALL.md](INSTALL.md#choosing-a-version)。
## 快速开始
在 stdio 模式下运行:
```
AUDIT_SECRET="$(openssl rand -hex 32)" \
mcp-audit --transport stdio --upstream "npx @modelcontextprotocol/server-filesystem /tmp"
```
在 Windows PowerShell 上,生成密钥并将其设置为环境变量:
```
$env:AUDIT_SECRET = -join ((1..32) | ForEach-Object { '{0:x2}' -f (Get-Random -Max 256) })
.\mcp-audit.exe --transport stdio --upstream "npx @modelcontextprotocol/server-filesystem C:\Temp"
```
在 HTTP 模式下运行:
```
mcp-audit --transport http --upstream http://localhost:8080 --port 4422
```
使用 Docker Compose 运行:
```
docker compose up --build
```
默认情况下,dashboard 可在 `http://127.0.0.1:9090` 访问。
默认情况下,Prometheus 指标可在 `http://localhost:9091/metrics` 访问。
## 示例
- [Cursor stdio 配置](examples/cursor/README.md)
- [Continue stdio 配置](examples/continue/README.md)
- [VS Code stdio 配置](examples/vscode/README.md)
- [Claude Desktop stdio 配置](examples/claude-desktop/README.md)
## 配置
`mcp-audit` 默认从当前目录加载 `config.yaml`。CLI 标志会覆盖配置值,而 `AUDIT_SECRET` 会覆盖 `audit.secret`。
| Key | Default | Description |
| --- | --- | --- |
| `proxy.transport` | `stdio` | 代理 transport:`stdio` 或 `http`。 |
| `proxy.upstream` | 必需 | Stdio 命令或 HTTP 上游 URL。 |
| `proxy.port` | `4422` | HTTP 监听端口。 |
| `proxy.upstream_timeout_ms` | `30000` | HTTP 上游请求超时时间(以毫秒为单位)。 |
| `proxy.forward_headers` | 空 | 允许绕过默认上游剥离列表的请求 header。仅在上游 MCP HTTP server 需要 bearer-token 认证时使用 `["Authorization"]`。 |
| `proxy.tls.ca_file` | 空 | 可选的 CA bundle,用于验证 HTTPS 上游 MCP server。 |
| `proxy.tls.server_name` | 空 | 上游 MCP server 的可选 TLS server 名称覆盖。 |
| `proxy.tls.insecure_skip_verify` | `false` | 跳过上游 TLS 证书验证。仅用于本地测试。 |
| `proxy.tls.client_cert_file` | 空 | 用于上游 mTLS 的可选 client 证书。必须与 `proxy.tls.client_key_file` 一起配置。 |
| `proxy.tls.client_key_file` | 空 | 用于上游 mTLS 的可选 client 密钥。必须与 `proxy.tls.client_cert_file` 一起配置。 |
| `proxy.retry.max_retries` | `0` | 安全 HTTP 上游请求的最大保守重试次数。默认关闭。 |
| `proxy.retry.initial_interval_ms` | `200` | 初始上游重试退避时间。 |
| `proxy.retry.max_interval_ms` | `2000` | 最大上游重试退避时间。 |
| `proxy.client_id` | `claude-desktop` | 写入审计条目的 client 标识符。 |
| `proxy.server_id` | `filesystem` | 写入审计条目的 server 标识符。 |
| `audit.storage` | `jsonl` | 存储后端:`jsonl` 或 `sqlite`。 |
| `audit.path` | `./audit.jsonl` | JSONL 审计日志路径。 |
| `audit.sqlite_path` | `./audit.db` | SQLite 数据库路径。 |
| `audit.sign` | `true` | 设置密钥时启用 HMAC-SHA256 签名。 |
| `audit.secret` | 空 | HMAC 密钥。首选 `AUDIT_SECRET`。 |
| `audit.async.enabled` | `false` | 通过有界环形缓冲区启用异步批处理审计写入。 |
| `audit.async.queue_size` | `4096` | 在反压阻塞写入器之前排队的最大审计条目数。 |
| `audit.async.batch_size` | `128` | 每个存储批次写入的最大条目数。 |
| `audit.async.flush_interval_ms` | `1000` | 刷新部分批次前的最长时间。 |
| `audit.rotation.max_size_bytes` | `0` | 归档轮转前的最大活动 JSONL 文件大小。`0` 禁用内置轮转。 |
| `audit.rotation.max_files` | `0` | 要保留的最大已轮转 JSONL 归档数量。`0` 禁用保留。 |
| `audit.rotation.interval` | 空 | 可选的基于时间的 JSONL 轮转间隔:`hourly` 或 `daily`。为空则禁用基于时间的轮转。 |
| `audit.rotation.max_age_days` | `0` | 删除文件名轮转时间戳早于指定天数的 JSONL 归档。`0` 禁用年龄保留。 |
| `middleware.rate_limit.enabled` | `true` | 启用基于 client、基于 tool 的 token bucket。 |
| `middleware.rate_limit.requests_per_minute` | `60` | 每个 `(client_id, tool_name)` 每分钟允许的请求数。 |
| `middleware.redact.enabled` | `true` | 启用基于 JSON 键的 PII 脱敏。 |
| `middleware.redact.patterns` | 敏感键 | 用于脱敏的区分大小写的键片段。 |
| `policy.enabled` | `false` | 对 `tools/call` 启用同步允许/拒绝策略检查。 |
| `policy.default_action` | `allow` | 没有策略规则匹配时的后备操作:`allow` 或 `deny`。 |
| `policy.rules` | 空 | 用于 tool 调用的有序首个匹配允许/拒绝规则。 |
| `dashboard.enabled` | `true` | 提供 dashboard 服务。 |
| `dashboard.bind_address` | `127.0.0.1` | Dashboard 监听地址。仅在 dashboard 受网络控制或 auth 保护时,才显式设置(例如设置为 `0.0.0.0`)。 |
| `dashboard.port` | `9090` | Dashboard 监听端口。 |
| `dashboard.auth.token` | 空 | 访问 dashboard HTML 和 API 请求所需的可选 bearer token,格式为 `Authorization: Bearer `。 |
| `metrics.enabled` | `true` | 在单独的 HTTP endpoint 上提供 Prometheus 指标服务。 |
| `metrics.port` | `9091` | 指标监听端口。 |
| `metrics.path` | `/metrics` | 指标 HTTP 路径。 |
| `metrics.include_go_metrics` | `true` | 包含 Go runtime 指标。 |
| `metrics.include_process_metrics` | `true` | 包含进程指标。 |
| `metrics.tool_labels` | `true` | 包含用于工具级别指标的 `tool_name` 和 `client_id` 标签。禁用以最小化标签基数。 |
| `otel.enabled` | `false` | 将 `tools/call` 审计条目导出为 OTLP/HTTP JSON span。 |
| `otel.endpoint` | `http://localhost:4318` | OTLP HTTP endpoint 基础 URL。自动追加 `/v1/traces`。 |
| `otel.service_name` | `mcp-audit` | OpenTelemetry `service.name` 资源属性。 |
| `otel.headers` | 空 | 附加的 OTLP HTTP header,例如 `Authorization` 或 API 密钥 header。 |
| `otel.tls.ca_file` | 空 | 用于验证 OTLP endpoint 的可选 CA bundle。 |
| `otel.tls.server_name` | 空 | 可选的 TLS server 名称覆盖。 |
| `otel.tls.insecure_skip_verify` | `false` | 跳过 OTLP TLS 证书验证。仅用于本地测试。 |
| `otel.retry.max_retries` | `3` | 导出请求失败后的最大 OTLP 重试次数。 |
| `otel.retry.initial_interval_ms` | `200` | 初始 OTLP 重试退避时间。 |
| `otel.retry.max_interval_ms` | `2000` | 最大 OTLP 重试退避时间。 |
| `otel.queue_size` | `1024` | 丢弃 trace 导出前排队的最大审计条目数。 |
| `otel.batch_size` | `64` | 每个 OTLP 导出请求的最大 span 数。 |
| `otel.flush_interval_ms` | `1000` | 导出部分 OTLP 批次前的最长时间。 |
| `otel.timeout_ms` | `5000` | OTLP HTTP 请求超时时间。 |
默认情况下,`mcp-audit` 在将 HTTP 请求转发给上游之前,会剥离逐跳(hop-by-hop)请求 header 和 `Authorization`。要将 bearer token 传递给受信任的已认证上游,请显式选择启用:
```
proxy:
forward_headers:
- Authorization
```
安全提示:转发的 header(包括 bearer token 等机密信息)将原封不动地传输到上游 server。仅在您控制或信任上游 MCP server 时才启用此功能。`Authorization` 是唯一可以选择启用转发的敏感 header,因为某些 MCP HTTP server 需要它进行上游认证。`Cookie`、`Set-Cookie` 和 `Proxy-Authorization` 始终会被拒绝:它们代表 destined for 其他组件(例如浏览器会话或代理链)的状态,在 MCP 请求转发中没有合法用途。如果现有部署依赖于隐式的 `Authorization` 转发,请添加上述配置。
JSONL 轮转默认禁用,并支持基于大小和基于 UTC 时间的触发器。轮转后的归档文件使用 UTC 时间戳,例如 `audit.jsonl.20260610T214605Z`;如果同一秒内发生多次轮转,则会添加数字后缀。归档时间戳反映的是轮转事件的挂钟时间,而不是跨越的截止时间。基于时间的轮转是由 append 驱动的:`mcp-audit` 不会启动后台计时器,因此如果几天都没有发生写入,则活动文件在越过截止后的下一次 append 之前不会轮转。错过的截止时间不会被追赶;下一次 append 最多创建一个归档。
```
audit:
storage: jsonl
rotation:
max_size_bytes: 104857600
interval: daily
max_files: 10
max_age_days: 30
```
`max_age_days` 使用归档文件名中编码的轮转时间戳。这意味着自轮转以来的年龄,而不是归档内最旧条目的年龄。年龄保留在 `max_files` 保留之前运行。压缩和 SQLite 归档不属于此版本的一部分。
CLI 标志:
```
--transport stdio | http
--upstream upstream server command or URL
--port proxy port for http mode
--upstream-timeout upstream HTTP request timeout in milliseconds
--config path to config.yaml
--storage jsonl | sqlite
--no-dashboard disable the web dashboard
--no-metrics disable Prometheus metrics
--version print version and exit
--log-level debug | info | warn | error
```
## Claude Desktop
将 Claude Desktop 配置为启动 `mcp-audit` 而不是上游 MCP server:
```
{
"mcpServers": {
"filesystem-audited": {
"command": "mcp-audit",
"args": [
"--transport",
"stdio",
"--upstream",
"npx @modelcontextprotocol/server-filesystem /tmp"
],
"env": {
"AUDIT_SECRET": "replace-with-a-long-random-secret"
}
}
}
}
```
## 仪表板
Dashboard 显示最近的条目、过滤器、可展开的请求/结果 JSON、热门工具、今日调用和错误率。它每五秒刷新一次。
默认情况下,dashboard 仅在 `127.0.0.1:9090` 上监听。要在其他接口上公开它,请显式配置 `dashboard.bind_address`,并启用身份验证或将其置于受信任的访问代理之后。
```
dashboard:
enabled: true
bind_address: 127.0.0.1
port: 9090
auth:
token: "replace-with-a-long-random-token"
```
配置 `dashboard.auth.token` 后,对 `/`、`/api/entries` 和 `/api/stats` 的请求必须包含:
```
Authorization: Bearer replace-with-a-long-random-token
```
缺失或无效的凭证将返回 `401 Unauthorized` 以及 `WWW-Authenticate: Bearer realm="mcp-audit-dashboard"`。来自同一远程地址的重复失败身份验证尝试将受到 `429 Too Many Requests` 的限制。
Dashboard JSON API 响应包含 `Cache-Control: no-store`,因此中介和浏览器不会保留审计 payload。
## Prometheus 指标
`mcp-audit` 在单独的 endpoint 上公开 Prometheus 指标,以便平台团队可以在不公开 dashboard 的情况下抓取操作数据。
```
scrape_configs:
- job_name: mcp-audit
static_configs:
- targets: ["localhost:9091"]
```
应用程序指标使用 `mcp_audit_` 前缀,并避免无界的标签。可以通过 `metrics.tool_labels: false` 禁用工具级别标签,以进行更严格的基数控制。策略决策以 `mcp_audit_policy_decisions_total{action="allow|deny"}` 的形式公开。
有关现成的 Prometheus + Grafana 技术栈,请参阅 [examples/docker-compose-observability](examples/docker-compose-observability/README.md)。
## 策略引擎
`mcp-audit` 可以在 `tools/call` 到达上游 MCP server 之前强制执行同步允许/拒绝规则。被拒绝的调用将返回 JSON-RPC 错误,并且仍会写入审计日志。
```
policy:
enabled: true
default_action: allow
rules:
- action: deny
client_id: claude-desktop
server_id: filesystem
tool_name: delete_file
reason: "Destructive filesystem operations are blocked"
```
规则按顺序评估。空字段和 `*` 匹配任何值,因此 `default_action: deny` 可以与显式的允许规则结合使用,以实现更严格的部署。
## OpenTelemetry
`mcp-audit` 可以将 `tools/call` 审计条目作为 OTLP/HTTP JSON span 导出到 Jaeger、Tempo、Honeycomb 或任何兼容 OTLP 的 collector。
```
otel:
enabled: true
endpoint: "http://localhost:4318"
service_name: "mcp-audit"
headers:
Authorization: "Bearer your-token"
timeout_ms: 5000
retry:
max_retries: 3
initial_interval_ms: 200
max_interval_ms: 2000
```
导出器在可能的情况下使用当前的 OpenTelemetry MCP 和 GenAI 语义约定,包括 `mcp.method.name`、`jsonrpc.request.id`、`gen_ai.operation.name`、`gen_ai.tool.name`、`network.transport`、`network.protocol.name`、`rpc.response.status_code` 和 `error.type`。项目特定的属性保持面向链接,例如 `mcp_audit.entry_id`、`mcp_audit.direction`、`mcp_audit.client_id`、`mcp_audit.server_id`、`mcp_audit.storage` 和 `mcp_audit.signature.present`。
默认情况下,请求参数和工具结果不会导出到 span。签名的 JSONL 或 SQLite 审计行保留为证据工件;OTLP 提供相关性、延迟和运维可见性。
导出器健康状况可以通过 `mcp_audit_otel_` 前缀下的 Prometheus 指标查看,包括导出请求、span 结果、丢弃的 span、队列深度和队列容量。临时 OTLP 故障将通过有限的指数退避进行重试;对于可重试的响应,最多可遵从 `Retry-After`,直至达到 `otel.retry.max_interval_ms`。
## 审计条目
每个存储的条目都包含一个 ULID、时间戳、方向、transport、JSON-RPC 方法(如果存在)、脱敏的参数/结果、JSON-RPC 错误(如果存在)、持续时间、client/server 标识符以及可选的 HMAC-SHA256 签名。
JSONL 条目示例:
```
{
"id": "01HY8G6Y8S6W9K6ZD7VJ4Q8X4R",
"timestamp": "2026-05-25T12:34:56Z",
"direction": "client_to_server",
"transport": "stdio",
"method": "tools/call",
"tool_name": "read_file",
"params": {
"name": "read_file",
"arguments": {
"path": "/tmp/example.txt",
"token": "[REDACTED]"
}
},
"duration_ms": 18,
"client_id": "claude-desktop",
"server_id": "filesystem",
"signature": "hmac-sha256:..."
}
```
签名涵盖:
```
id + timestamp + method + tool_name + raw_params
```
## 路线图
- SIEM 友好的导出
- OTLP 压缩和 trace context 传播
## 社区
- [讨论](https://github.com/P4ST4S/mcp-audit/discussions):问题、想法和设计对话
- [问题](https://github.com/P4ST4S/mcp-audit/issues):bug 报告和具体的功能请求
- 安全:有关私有漏洞报告流程,请参阅 [SECURITY.md](SECURITY.md)
## 许可证
Apache-2.0。请参阅 [LICENSE](LICENSE)。
标签:EVTX分析, 日志审计, 用户代理, 自定义请求头, 请求拦截