Skip to content

Move oauthClientSecret out of mcp.json into the OS keychain #1356

@cliffhall

Description

@cliffhall

Summary

InspectorServerSettings.oauthClientSecret currently persists in plaintext inside ~/.mcp-inspector/mcp.json. The file is 0o600, which is appropriate for a local dev tool, but the secret is now mixed into a file users may:

  • Symlink to / from Claude Desktop's claude_desktop_config.json (the spec calls this out as an interop benefit; the file is meant to be tool-shareable).
  • cat for debugging, paste into bug reports, sync via dotfile managers, or commit by accident.

Goal: lift oauthClientSecret out of the on-disk JSON and store it in the OS keychain (macOS Keychain Services, Windows Credential Manager, Linux libsecret) keyed by (servers map key, "oauth-client-secret"). The mcp.json settings.oauthClientSecret field becomes a reference (or is absent) once a value has been promoted to the keychain.

Files

  • core/mcp/types.tsInspectorServerSettings shape; may need a discriminated oauthClientSecret: { stored: "keychain" } or similar.
  • core/mcp/remote/node/server.ts/api/servers POST/PUT/DELETE need to read/write the keychain alongside the on-disk JSON.
  • core/mcp/serverList.ts — converter that hydrates the secret from the keychain into ServerEntry.settings.oauthClientSecret for in-memory use (browser never sees the raw value; it only sees a flag "secret configured").
  • clients/web/src/components/groups/ServerSettingsForm/ServerSettingsForm.tsx — the Client Secret field becomes write-only (show "Configured" placeholder, "Clear" button) rather than echoing the value.
  • specification/v2_servers_file.md — document the keychain integration; explain that other tools reading the file won't see the secret.

Proposal

Recommended library: keytar (mature, cross-platform). Adds a native dep.

  • New helper core/auth/secret-store.ts with getSecret(serverId, field) / setSecret(serverId, field, value) / deleteSecret(serverId, field) backed by keytar.
  • /api/servers POST/PUT: when body contains settings.oauthClientSecret, write to keychain and drop the field from disk.
  • /api/servers GET: rehydrate from keychain on read so useServers sees the secret on the active session.
  • /api/servers DELETE: tombstone keychain entries for that server id.
  • Migration: on first read of a mcp.json that contains a oauthClientSecret value, lift to keychain and overwrite the file with the field removed.

Out of scope / open questions

  • Linux without libsecret installed: keytar falls back to in-memory. Document.
  • Tests in CI: keytar requires platform native bindings; integration tests need a mock backend (keytar provides setPassword/getPassword interfaces that are mockable).
  • Whether to extend the same treatment to stdio env values (which are also secrets in many setups). Argue separately.

Acceptance criteria

  • A oauthClientSecret entered in ServerSettingsForm is persisted to the OS keychain, not to mcp.json.
  • cat ~/.mcp-inspector/mcp.json does not show the secret.
  • Re-opening the settings modal shows "Configured" rather than the raw value.
  • Removing the server (DELETE) also removes the keychain entry.
  • Existing mcp.json files with oauthClientSecret in plaintext are migrated to the keychain on first read.

Metadata

Metadata

Assignees

Labels

v2Issues and PRs for v2

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions