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

Claude Desktop connects to MCP servers via `claude_desktop_config.json`. The Agent Receipts proxy wraps any MCP server transparently — Claude Desktop 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`. See [Approval Server](/mcp-proxy/approval-ui/).
:::

:::danger[Never put secrets in claude_desktop_config.json]
`claude_desktop_config.json` is plaintext on disk, and Claude Desktop does **not** expand `${VAR}` references in `env` blocks — anything you write there is stored verbatim. Use a secret-manager wrapper (`op run`, `aws-vault exec`, …) or an OS keychain launcher script — both are documented below. The literal-token snippet at the bottom is a demo-only path; treat the file as compromised the moment you save a real credential to it.
:::

## Prerequisites

- [mcp-proxy installed](/mcp-proxy/installation/)
- A signing key pair generated (see below)
- The MCP server you want to audit. The example below wraps 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
# prints a claude_desktop_config.json snippet — paste it as a starting point
```

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

## Configure claude_desktop_config.json

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows).

Claude Desktop doesn't shell-expand config values, so paste absolute paths. On macOS/Linux, print yours:

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

On Windows (PowerShell), use `(Get-Command mcp-proxy).Source`, `$env:USERPROFILE`, and `(Get-Command github-mcp-server).Source` to obtain the equivalent values.

If the file doesn't exist yet, create it.

If it already contains app preferences (for example, `{"preferences": {...}}`), that's normal. Add `mcpServers` as another top-level key rather than replacing the file — the result should look like `{"preferences": {...}, "mcpServers": {...}}` (mind the comma between sibling keys).

The token needs to reach the MCP server's environment **without being written into the config file**. Pick whichever pattern matches your secrets setup; all three produce an equivalent wrapped server, only the credential plumbing differs.

### 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 Desktop at `op run` — it resolves the `op://` reference at exec time, injects the value into the child process's env, and never writes the token to disk. Find your `op` path with `which op`:

```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 Desktop",
        "-operator-id", "did:web:anthropic.com",
        "-operator-name", "Anthropic",
        "/opt/homebrew/bin/github-mcp-server", "stdio"
      ]
    }
  }
}
```

`aws-vault exec`, `chamber exec` (AWS Parameter Store), and `direnv` with `op://` references all follow the same wrapping pattern — substitute whichever your team already deploys.

### Fallback: OS keychain launcher script

If you don't have a secret manager, store the token in the OS keychain and add a small launcher that execs mcp-proxy with the secret in env. The launcher itself contains no secrets.

**macOS** — store the token, then create the launcher:

```bash
security add-generic-password -s github-mcp -a "$USER" -w
# (paste the PAT when prompted)
```

```bash
#!/usr/bin/env bash
# ~/.local/share/agent-receipts/run-mcp-proxy-github.sh — chmod 700
set -euo pipefail
GITHUB_PERSONAL_ACCESS_TOKEN="$(security find-generic-password -s github-mcp -a "$USER" -w)" \
  exec /Users/YOU/go/bin/mcp-proxy "$@"
```

**Linux**: swap the keychain calls for `secret-tool store --label=github-mcp service github-mcp account "$USER"` and `secret-tool lookup service github-mcp account "$USER"` (matching the same `account` qualifier on store and lookup avoids ambiguity if you ever store more than one entry under the same service name). **Windows**: a `.ps1` wrapper using the [SecretManagement module](https://learn.microsoft.com/en-us/powershell/utility-modules/secretmanagement/overview) (`Get-Secret github-mcp`) plays the same role.

Point Claude Desktop at the launcher — no `env` block, since the script sets it:

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

### Demo only: literal token

Useful for kicking the tyres against a throwaway PAT before wiring up secret management. **Treat the file as compromised the moment you save a real credential**, and rotate the PAT before moving to either pattern above.

```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 Desktop",
        "-operator-id", "did:web:anthropic.com",
        "-operator-name", "Anthropic",
        "/opt/homebrew/bin/github-mcp-server", "stdio"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_TOKEN"
      }
    }
  }
}
```

The approval listener is off by default. If the policy pauses a call (e.g. a high-risk tool your server exposes), it fails immediately with JSON-RPC code `-32003` (`no approver configured`). To enable approvals, add `-http 127.0.0.1:<port>` to `args` in any of the three configurations above and run an approver — see [Approval Server](/mcp-proxy/approval-ui/).

Restart Claude Desktop. The GitHub MCP server now runs behind the proxy — every tool call goes through it transparently.

## Verifying receipts

After making tool calls, 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:64b00b98... github         issue_write                    data.api.write         medium   success  2026-04-24T01:55:09Z
urn:receipt:276a6c2a... github         issue_write                    data.api.write         medium   success  2026-04-24T01:48:55Z
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

4 receipts
```

The SERVER column reflects the `-name github` flag you passed to `mcp-proxy`. Read operations show `data.api.read / low`; writes show `data.api.write / medium`.

## Gotchas

**Absolute paths required.** Claude Desktop 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.

**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.
