Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

#### Flight recorder
- `[recorder]` config section and per-session JSONL recordings written by
`mcp-guard serve`: every client request, every response, every guard
decision, with a SHA-256 hash chain (`prev`/`hash`) and optional HMAC signing
via `signing_key_env`.
- Payload redaction before hashing (built-in patterns for private keys, cloud
and SaaS API keys, JWTs, bearer tokens, credentials in URLs, plus the user's
`[audit] redaction_rules`), truncation of large payloads with the hash of the
original kept.
- `mcp-guard replay`: timeline of a session (`--list`, `--denied`, `--tool`,
`--json`), with the chain status.
- `mcp-guard verify`: recompute the chain, report the first bad record, exit 1
on tampering. Checks HMAC signatures when the key is present.
- `mcp-guard wrap` enables the recorder for wrapped servers; `doctor` reports
`RECORDER_DISABLED`.

#### Argument-level policy and shadow mode
- `[[policy.rules]]`: rules on tool arguments (`when` conditions with
`starts_with`, `not_in`, `glob`, `regex`, numeric and existence operators),
Expand Down
15 changes: 10 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# CLAUDE.md - MCP Guard Project Context

> **Last Updated:** 2026-10-22
> **Project Status:** v1.0.0 shipped (gateway). Local mode (wrap/doctor/pin/serve) and argument-level policy with shadow mode landed; roadmap below is the plan from here.
> **Project Status:** v1.0.0 shipped (gateway). Local mode, argument-level policy with shadow mode, and the flight recorder landed; roadmap below is the plan from here.

---

Expand Down Expand Up @@ -34,6 +34,7 @@ mcp-guard/ Cargo workspace, version 1.0.0, AGPL-3.0
│ │ ├── src/clients.rs MCP client config discovery, wrap/unwrap/doctor logic
│ │ ├── src/pin.rs Tool lockfile: canonical JSON hashing, diff, load/save
│ │ ├── src/policy.rs Policy evaluation: tool globs + argument rules -> Decision
│ │ ├── src/recorder.rs Flight recorder: hash-chained JSONL sessions, redaction, verify, timeline
│ │ ├── src/mcp_server/ Stdio proxy (`serve`): handshake forwarding, policy, pinning, audit
│ │ ├── src/guard_tools/ guard/health, guard/metrics, guard/version tools
│ │ ├── src/server/ Axum HTTP gateway, middleware, OAuth endpoints, health, dashboard/billing routes
Expand Down Expand Up @@ -80,6 +81,8 @@ mcp-guard unwrap --client claude-desktop
mcp-guard pin --config ~/.config/mcp-guard/claude-desktop/NAME.toml [--accept] [--show]
mcp-guard policy test --config X.toml --tool write_file --args '{"path": "/etc/passwd"}'
mcp-guard policy suggest --config X.toml [--apply] # from audit log, after mode = "observe"
mcp-guard replay --config X.toml [--list|--denied|--tool T|--json]
mcp-guard verify --config X.toml [--session all] # exit 1 on a broken chain
mcp-guard serve --config X.toml # what wrapped clients launch

# Gateway mode
Expand All @@ -100,7 +103,8 @@ CI runs clippy with `-D warnings` on current stable. New clippy lints on toolcha
- **Shell-injection validation** in `transport` rejects commands/args with shell metacharacters. `wrap` skips such entries with a reason instead of generating a config that fails at launch.
- **Policy evaluation order** (`policy::evaluate`): denied_tools, then allowed_tools, then `[[policy.rules]]` in order, first match wins, no match allows. Rules only run on `tools/call` (they need arguments); `tools/list` visibility uses the globs only. An absent argument fails every operator except `exists = false`.
- **Observe mode** (`policy.mode = "observe"`): nothing blocked, `PolicyWouldDeny` audit events written, denied tools stay visible in `tools/list`. Pinning is independent of mode. `policy suggest` parses the audit JSONL (`event_type` = `tool_call` / `policy_would_deny`) and `--apply` edits the config with `toml_edit` so comments survive.
- **Config struct literals in tests** must include `policy: Default::default()`.
- **Recorder** (`recorder.rs`): one JSONL file per serve session under `recorder.dir_for(config)`. `hash = H(prev + "\n" + canonical_json(record minus hash))`, H = SHA-256 or HMAC-SHA256 when `signing_key_env` is set. Redaction (built-in patterns + audit rules) and truncation happen before hashing; `payload_sha256` is over the original. `McpServer::handle_message` records the incoming message and every outgoing one; `deny()`, observe mode and hidden tools write `decision` records. Recorder failures are logged, never fatal.
- **Config struct literals in tests** must include `policy: Default::default()` and `recorder: Default::default()`.
- **`upstream.transport` defaults to stdio**; multi-server configs may omit `[upstream]` entirely.
- **E2E tests set `MCP_GUARD_SKIP_LICENSE_CHECK`** (in `tests/common/mod.rs`) so pro/enterprise builds start without a key.
- Rate limits are not applied in serve mode (nothing to key them on).
Expand All @@ -110,13 +114,13 @@ CI runs clippy with `-D warnings` on current stable. New clippy lints on toolcha
## Roadmap (agreed direction, 2026-10-22)

1. Result inspection: rules on tool results (secret/PII redaction, size limits), extending the argument rules. Cedar was considered for the policy engine and deferred: the TOML rule format covers the known cases and stays readable in one config file.
2. Flight recorder: hash-chained, redacted per-session recording plus `mcp-guard replay`.
2. Recorder in gateway mode (per identity), retention, HTML session report.
3. Protocol shim: 2026-07-28 stateless revision, relay server-initiated requests (sampling/elicitation/roots), expose stdio servers as compliant remote servers.
4. Human-in-the-loop holds for high-risk tools (approve in terminal/Slack before a `delete_*` call proceeds).
5. Prebuilt binaries + Homebrew tap (release-tiers.yml exists; no published artifacts yet).
6. Re-tier: open core complete (all auth, all transports); charge for policy packs, recorder, fleet control plane, support. `tier.rs` gating of HTTP/SSE/JWKS is the thing to remove when this happens.

Done: local mode (wrap/doctor/pin/serve), argument-level policy rules, shadow mode + `policy suggest`.
Done: local mode (wrap/doctor/pin/serve), argument-level policy rules, shadow mode + `policy suggest`, flight recorder (`replay`/`verify`).

---

Expand All @@ -136,7 +140,8 @@ Done: local mode (wrap/doctor/pin/serve), argument-level policy rules, shadow mo
- 2026-01: Stripe checkout, GitHub OAuth login, landing site, license-signing workers.
- 2026 (to Oct): CI hardening (Windows build, cargo-deny, security audit), link cleanup, docs pointed at in-repo files.
- 2026-10-22: Strategic review. Local mode shipped: `doctor`, `wrap`, `unwrap`, `pin`, `[policy]`, tool pinning, serve-mode handshake forwarding and audit. README rewritten to match the real workspace. (PR #5)
- 2026-10-22: Argument-level `[[policy.rules]]`, `mode = "observe"`, `policy test`, `policy suggest --apply`. Fixed pre-existing OAuth callback and routing test failures.
- 2026-10-22: Argument-level `[[policy.rules]]`, `mode = "observe"`, `policy test`, `policy suggest --apply`. Fixed pre-existing OAuth callback and routing test failures. (PR #6)
- 2026-10-22: Flight recorder: `[recorder]`, hash-chained session files, redaction, `replay`, `verify`, HMAC signing.

---

Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ For the servers your own agent launches on your machine. The MCP client runs `mc
| Restrict which tools the agent may call | `[policy] allowed_tools` and `denied_tools`, with globs |
| Detect tool poisoning and rug pulls | Tool definitions are hashed into a lockfile on first use. Changed or new tools are hidden and rejected until you review them with `mcp-guard pin` |
| Record what happened | Every tool call and every denial is written to an audit log |
| Prove what happened | The flight recorder keeps every request, response and decision in a hash-chained, redacted session file. `replay` renders it, `verify` checks it |
| Keep secrets out of guard configs | Environment variables stay on the client's entry and are inherited by the upstream |
| Get in and out safely | `mcp-guard wrap` backs up the client config; `mcp-guard unwrap` restores it |

Expand All @@ -124,6 +125,7 @@ curl -H "Authorization: Bearer mcp_YOUR_KEY" http://localhost:3000/health
- Argument-level rules (`write_file` only under the workspace, `http_request` only `GET`), tested with `mcp-guard policy test`
- Shadow mode: observe first, then `mcp-guard policy suggest --apply` writes a least-privilege policy from what the agent actually used
- Tool pinning with a reviewable JSON lockfile (`mcp-guard pin`)
- Flight recorder: tamper-evident, redacted per-session recording; `mcp-guard replay` shows what the agent did, `mcp-guard verify` proves nobody edited it
- Per-server audit log
- `doctor`, `wrap`, `unwrap` for Claude Desktop, Claude Code, Cursor, Windsurf, VS Code
- `guard/health`, `guard/metrics`, `guard/version` tools exposed to the agent
Expand Down Expand Up @@ -289,6 +291,8 @@ Local mode
pin Pin, review or accept the upstream's tool definitions
policy test Evaluate the policy against one tool call
policy suggest Propose a least-privilege policy from the audit log
replay Show a recorded session as a timeline
verify Check a recording's hash chain
serve Run as a stdio proxy (what wrapped clients launch)

Gateway mode
Expand All @@ -314,7 +318,7 @@ Options:
The direction: stop competing on authentication, which the MCP spec and every API gateway now cover, and own the layer above it, **what an agent may do and proof of what it did**. In rough order:

1. **Result inspection.** Rules on what comes back from a server (secret and PII redaction, size limits), extending today's argument rules.
2. **Flight recorder.** Tamper-evident, redacted recording of every exchange per session, with `mcp-guard replay`.
2. **Recorder in gateway mode.** Per-identity recording for `mcp-guard run`, retention, and a self-contained HTML session report.
3. **Protocol shim.** Full support for the 2026-07-28 stateless revision, relaying server-initiated requests, and exposing old stdio servers as compliant remote servers.
4. **Human-in-the-loop holds** for high-risk tools.
5. **Prebuilt binaries and a Homebrew tap.**
Expand All @@ -329,6 +333,7 @@ Issues and pull requests on any of these are welcome.
| Topic | Guide |
|-------|-------|
| Local mode | [wrap, doctor, pin, serve](docs/local-mode.md) |
| Flight recorder | [replay, verify, record format](docs/flight-recorder.md) |
| Getting Started | [Quick Start](docs/quickstart.md) |
| Authentication | [Auth Guide](docs/authentication.md) |
| Transports | [Stdio/HTTP/SSE](docs/transports.md) |
Expand Down
Loading
Loading