---
title: Claude Code Integration
description: How to route Claude Code MCP servers through the Agent Receipts proxy for cryptographic audit trails.
---

Claude Code is a CLI-based agent that connects to MCP servers for tools like GitHub, databases, and file systems. The Agent Receipts proxy wraps any MCP server transparently — Claude Code doesn't know or care that the proxy is there.

:::note[Approval workflow]
The default policy includes a `pause_high_risk` rule. When you generate a config with `mcp-proxy init`, the snippet includes `-http 127.0.0.1:7778` so the approval listener starts automatically. If you run the proxy manually without `-http`, the listener is off and paused calls fail fast with `-32003`. Pass `--no-approval` to `mcp-proxy init` to generate a snippet without `-http`. If you're seeing `-32002` on tools that shouldn't pause, suspect client-side denial first — see [troubleshooting](/mcp-proxy/configuration/#-32002-errors-on-tool-calls).
:::

:::danger[Never put secrets in the config file]
Both `claude mcp add-json` and `.mcp.json` persist their content as plaintext on disk (`~/.claude.json` and committed project files respectively). **Never** paste a token, API key, or other credential as a literal string into either one. Use a secret-manager wrapper (`op run`, `aws-vault exec`, …) to inject credentials at exec time — or reference them via `${VAR}` placeholders, which Claude Code expands at server-launch time from its environment. Both patterns are documented below.
:::

## Prerequisites

- [mcp-proxy installed](/mcp-proxy/installation/)
- A signing key pair generated (see below)
- Claude Code installed (`npm install -g @anthropic-ai/claude-code`)
- The MCP server you want to audit. The examples below wrap GitHub's official MCP server:

  ```bash
  brew install github-mcp-server
  ```

  This puts a `github-mcp-server` binary on your `$PATH`. Verify with `which github-mcp-server`.

## Generate a signing key

```bash
mcp-proxy init --name github-proxy
# creates ~/.local/share/agent-receipts/github-proxy.pem (0600) and ~/.local/share/agent-receipts/github-proxy.pem.pub
```

Re-running `init` is safe — it warns and skips if the key already exists. Use absolute paths everywhere — Claude Code launches MCP servers with a clean environment where `~` expansion and `$PATH` may not behave as expected.

## Register the proxy with Claude Code

Use `claude mcp add-json` to register a proxied server. The example below wraps `github-mcp-server`. Your shell resolves the proxy, key, and server paths at paste time.

The token needs to reach `mcp-proxy`'s environment **without being written into the stored config**. Pick whichever pattern matches your secrets setup.

### Recommended: secret manager (`op run`, `aws-vault exec`, …)

Install the 1Password CLI (`brew install 1password-cli`), sign in (`op signin`), and create a referenced env file:

```ini
# ~/.local/share/agent-receipts/mcp.env  (chmod 600)
GITHUB_PERSONAL_ACCESS_TOKEN=op://Personal/GitHub/token
```

Point Claude Code at `op run` — it resolves the `op://` reference at exec time and injects the value into `mcp-proxy`'s env. No `env` block is needed in the config. Find your `op` path with `which op`.

**bash / zsh:**

```bash
# heredoc terminator (JSON) must be alone on its line; closing ) follows on the next
JSON_BODY=$(cat <<JSON
{
  "command": "$(which op)",
  "args": [
    "run",
    "--env-file=$HOME/.local/share/agent-receipts/mcp.env",
    "--",
    "$(which mcp-proxy)",
    "-name", "github",
    "-key", "$HOME/.local/share/agent-receipts/github-proxy.pem",
    "-issuer-name", "Claude Code",
    "-operator-id", "did:web:anthropic.com",
    "-operator-name", "Anthropic",
    "$(which github-mcp-server)", "stdio"
  ]
}
JSON
)

claude mcp add-json github-audited --scope user "$JSON_BODY"
```

**fish:**

```fish
set OP (which op)
set MCP_PROXY (which mcp-proxy)
set GITHUB_MCP (which github-mcp-server)
set KEY $HOME/.local/share/agent-receipts/github-proxy.pem
set ENV_FILE $HOME/.local/share/agent-receipts/mcp.env

set json (printf '{
  "command": "%s",
  "args": [
    "run",
    "--env-file=%s",
    "--",
    "%s",
    "-name", "github",
    "-key", "%s",
    "-issuer-name", "Claude Code",
    "-operator-id", "did:web:anthropic.com",
    "-operator-name", "Anthropic",
    "%s", "stdio"
  ]
}' $OP $ENV_FILE $MCP_PROXY $KEY $GITHUB_MCP | string collect)

claude mcp add-json github-audited --scope user "$json"
```

`aws-vault exec`, `chamber exec` (AWS Parameter Store), and similar tools follow the same wrapping pattern — substitute whichever your team already deploys.

### Alternative: shell environment (Claude Code only)

Unlike Claude Desktop, Claude Code expands `${VAR}` placeholders in `env` blocks at server-launch time. This means you can keep the credential in your shell environment and reference it by name in the config.

**bash / zsh** — `\$` escapes the placeholder so bash leaves it intact at paste time:

```bash
# heredoc terminator (JSON) must be alone on its line; closing ) follows on the next
JSON_BODY=$(cat <<JSON
{
  "command": "$(which mcp-proxy)",
  "args": [
    "-name", "github",
    "-key", "$HOME/.local/share/agent-receipts/github-proxy.pem",
    "-issuer-name", "Claude Code",
    "-operator-id", "did:web:anthropic.com",
    "-operator-name", "Anthropic",
    "$(which github-mcp-server)", "stdio"
  ],
  "env": {
    "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_PERSONAL_ACCESS_TOKEN}"
  }
}
JSON
)

claude mcp add-json github-audited --scope user "$JSON_BODY"
```

**fish** (no heredoc support — build JSON via `printf` instead; the single-quoted format string passes the placeholder through literally):

```fish
set MCP_PROXY (which mcp-proxy)
set GITHUB_MCP (which github-mcp-server)
set KEY $HOME/.local/share/agent-receipts/github-proxy.pem

set json (printf '{
  "command": "%s",
  "args": [
    "-name", "github",
    "-key", "%s",
    "-issuer-name", "Claude Code",
    "-operator-id", "did:web:anthropic.com",
    "-operator-name", "Anthropic",
    "%s", "stdio"
  ],
  "env": {
    "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
  }
}' $MCP_PROXY $KEY $GITHUB_MCP | string collect)

claude mcp add-json github-audited --scope user "$json"
```

Set `GITHUB_PERSONAL_ACCESS_TOKEN` in your shell rc (`~/.zshrc`, `~/.config/fish/config.fish`, etc.) before launching Claude Code. Verify the placeholder reached the stored config (and was *not* expanded at paste time) with `claude mcp get github-audited`.

`--scope user` makes the server available across all projects. Omit it for project-local scope only.

`-issuer-name`, `-operator-id`, and `-operator-name` stamp the signed receipt with the agent and the organisation running it. Setting `-issuer-name` to `Claude Code` here (and to `Codex` in the [Codex integration](/mcp-proxy/codex/)) is what lets you tell at receipt-inspection time which client made a given call — without it, every receipt just shows the default `did:agent:mcp-proxy` issuer. See the [configuration reference](/mcp-proxy/configuration/#cli-flags) for the full set of identity flags.

Verify the server is registered:

```bash
claude mcp list
```

## Project-scoped setup via .mcp.json

For a shared team configuration, add a `.mcp.json` file at the project root. This is committed to version control — do not put tokens directly in it.

Since `.mcp.json` is a static JSON file, print the absolute paths you need first and paste them into the template below:

```bash
echo "command: $(which mcp-proxy)"
echo "key:     $HOME/.local/share/agent-receipts/github-proxy.pem"
echo "server:  $(which github-mcp-server)"
```

### Recommended: secret manager

Point Claude Code at `op run`, same as the `claude mcp add-json` pattern above. Each developer needs `~/.local/share/agent-receipts/mcp.env` on their machine with their own `op://` reference (or whichever secret manager the team uses).

```json
{
  "mcpServers": {
    "github-audited": {
      "command": "/opt/homebrew/bin/op",
      "args": [
        "run",
        "--env-file=/Users/YOU/.local/share/agent-receipts/mcp.env",
        "--",
        "/Users/YOU/go/bin/mcp-proxy",
        "-name", "github",
        "-key", "/Users/YOU/.local/share/agent-receipts/github-proxy.pem",
        "-issuer-name", "Claude Code",
        "-operator-id", "did:web:anthropic.com",
        "-operator-name", "Anthropic",
        "/opt/homebrew/bin/github-mcp-server", "stdio"
      ]
    }
  }
}
```

### Alternative: shell environment

Claude Code expands `${VAR}` placeholders at server-launch time, so each developer can set `GITHUB_PERSONAL_ACCESS_TOKEN` in their shell environment and have it picked up automatically.

```json
{
  "mcpServers": {
    "github-audited": {
      "command": "/Users/YOU/go/bin/mcp-proxy",
      "args": [
        "-name", "github",
        "-key", "/Users/YOU/.local/share/agent-receipts/github-proxy.pem",
        "-issuer-name", "Claude Code",
        "-operator-id", "did:web:anthropic.com",
        "-operator-name", "Anthropic",
        "/opt/homebrew/bin/github-mcp-server", "stdio"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
      }
    }
  }
}
```

The proxy path and key path will need to be consistent across the team, or handled via a wrapper script.

## Verifying receipts

After making tool calls through Claude Code, inspect the receipt store from your terminal:

```bash
# List all receipts (uses the default ~/.local/share/agent-receipts/receipts.db)
mcp-proxy list

# Verify chain integrity
mcp-proxy verify \
  -key ~/.local/share/agent-receipts/github-proxy.pem.pub \
  <chain-id>
```

```
$ mcp-proxy list
ID                     SERVER         TOOL                           ACTION                 RISK     STATUS   TIMESTAMP
---
urn:receipt:a72ee10b... github         list_issues                    data.api.read          low      success  2026-04-24T01:45:07Z
urn:receipt:a125fd30... github         list_pull_requests             data.api.read          low      success  2026-04-24T01:44:20Z
urn:receipt:67fede57... github         add_reply_to_pull_reques...    data.api.write         medium   success  2026-04-24T00:51:57Z
urn:receipt:013bfc43... github         request_copilot_review         data.api.write         medium   success  2026-04-24T00:43:40Z
urn:receipt:7ae4f1b2... github         issue_write                    data.api.write         medium   success  2026-04-24T00:19:35Z

5 receipts
```

Read tools like `list_issues` and `list_pull_requests` show `data.api.read / low`; write tools like `issue_write` show `data.api.write / medium`. The SERVER column reflects the `-name github` flag you passed to `mcp-proxy`.

## Gotchas

**Absolute paths required.** Claude Code launches MCP servers with a clean `PATH`. Use the full path to `mcp-proxy` (find it with `which mcp-proxy`) and the full path to the wrapped server binary.

**fish shell.** Fish does not support heredocs — pasting the bash/zsh snippet as-is fails with `Expected a string, but found a redirection`. Use the [fish alternative above](#register-the-proxy-with-claude-code), which builds the JSON via `printf` and stores it in a variable.

**Want human-in-the-loop approvals? Opt in with `-http`.** The approval listener is off by default. If your server exposes tools that cross the risk-score threshold (e.g. `create_token` = 50, `update_auth_config` = 70), pass `-http 127.0.0.1:<port>` and run an approver — see [Approval Server](/mcp-proxy/approval-ui/). Without it, a paused call fails immediately with JSON-RPC code `-32003` (`no approver configured`). To prevent pausing entirely, drop `pause`/`block` rules from a custom `-rules` YAML.

**Classic PATs for org-owned repos.** GitHub's fine-grained PATs can fail for org-level write operations even when permissions appear correct. Use a classic PAT with `repo` scope for org-owned repositories.

**Per-session chain IDs.** By default the proxy generates a new chain ID each session. Pass `-chain <id>` to persist a chain across sessions.

**Old receipts show `unknown`.** If you upgraded from a version before v0.2.0, existing receipts in the DB will always show `Action: unknown` — the tool name was never stored. Clear the DB and start fresh after upgrading.
