Skip to content

wrap-mcp

wrap-mcp is a proxy that sits between Claude Code (or any MCP client) and an MCP server. It intercepts JSON-RPC tool calls on stdin/stdout and verifies delegation tokens before forwarding.

Quick Start

bash
kanoniv-auth wrap-mcp --mode strict -- npx my-mcp-server

How It Works

Claude Code  -->  wrap-mcp (verify)  -->  MCP Server
                      |
                ~/.kanoniv/session-token

wrap-mcp spawns the MCP server as a child process. All JSON-RPC messages on stdin are intercepted. For each tools/call request, it extracts the tool name as the required scope and verifies authorization. Non-JSON and non-tool messages are forwarded unchanged.

The child process's stderr is inherited directly - wrap-mcp only interposes on stdin/stdout.

Modes

ModeNo valid proof or tokenUse case
strictReject with JSON-RPC error (-32600)Production
warnLog warning to stderr, forward anywayRollout / testing
auditLog everything, verify nothingObservability only

The default mode is warn.

Verification Priority

Two verification paths, tried in order:

  1. _proof field - If the tool call arguments contain a _proof field, wrap-mcp verifies it as a cryptographic MCP proof (requires --root-key). The _proof is stripped from arguments before forwarding to the MCP server.

  2. Session token - If no _proof or _proof verification fails, wrap-mcp reads the token file (default: ~/.kanoniv/session-token). The tool name is the required scope.

If both fail, the mode determines behavior (reject / warn / audit).

INFO

When no --root-key is specified, _proof verification is disabled and wrap-mcp falls back to the session token path. A note is printed to stderr on startup.

Options

OptionDefaultDescription
--mode, -mwarnEnforcement mode: strict, warn, audit
--root-key, -knoneRoot key file for _proof verification
--token-file~/.kanoniv/session-tokenDelegation token file

INFO

The token file is re-read on every tool call. You can re-delegate mid-session (via /delegate, /scope, or /ttl) without restarting the MCP server.

Scope Matching

The tool name IS the required scope. Matching is hierarchical and case-sensitive:

  • Tool resolve requires scope resolve - exact match
  • Tool resolve.entity is covered by scope resolve - prefix match (the scope plus . is a prefix of the tool name)
  • Scope * matches any tool

If the tool name does not match any scope in the token, the call is denied (in strict mode) or warned (in warn mode).

Usage with Claude Code

In your Claude Code MCP config (.mcp.json or settings.json):

json
{
  "mcpServers": {
    "my-server": {
      "command": "kanoniv-auth",
      "args": ["wrap-mcp", "--mode", "strict", "--", "npx", "my-mcp-server"]
    }
  }
}

With a root key for _proof verification:

json
{
  "mcpServers": {
    "my-server": {
      "command": "kanoniv-auth",
      "args": [
        "wrap-mcp",
        "--mode", "strict",
        "--root-key", "~/.kanoniv/root.key",
        "--", "npx", "my-mcp-server"
      ]
    }
  }
}

Combining with /delegate

When Claude Code runs /delegate, it saves the token to ~/.kanoniv/session-token. wrap-mcp reads this file on every tool call. The two work together:

  1. User runs /delegate --scope resolve,search --ttl 2h
  2. Token saved to ~/.kanoniv/session-token
  3. wrap-mcp reads token, allows resolve and search tool calls
  4. User runs /scope resolve (drops search)
  5. wrap-mcp picks up new token on next call, blocks search

No restart needed at any step.

Error Response (strict mode)

When a tool call is rejected in strict mode, wrap-mcp returns a JSON-RPC error to the client and does not forward the call to the MCP server:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "DENIED: tool 'merge' — tool 'merge' not in token scopes [\"resolve\", \"search\"]"
  }
}

The error code is always -32600 (Invalid Request). The message includes the tool name and the reason for denial.

WARNING

In strict mode, every tool call without a valid proof or session token returns a JSON-RPC error. Make sure the agent has an active delegation before starting work.

Token Verification Details

When verifying a session token, wrap-mcp performs these checks in order:

  1. Read and decode - Reads the token file, decodes from base64url
  2. Expiry check - If the token has an expires_at field, checks it against the current time. Expired tokens are rejected without revealing scope information.
  3. Chain verification - If a --root-key is provided, verifies the delegation chain signatures back to the root identity
  4. Scope check - Verifies the tool name matches at least one scope in the token (exact, prefix, or wildcard)

Stderr Logging

wrap-mcp logs all verification decisions to stderr. The format depends on the mode:

[kanoniv-auth] VERIFIED: resolve — token:ci-agent
[kanoniv-auth] DENIED: merge — tool 'merge' not in token scopes ["resolve"]
[kanoniv-auth] WARNING: merge — token file expired (forwarding anyway)
[kanoniv-auth] AUDIT: resolve — proof=no, token:ci-agent

These logs are visible in the MCP client's server output panel (in Claude Code, check the MCP server logs).

Next Steps

The identity and delegation layer for AI agents.