MCP security

MCP is an untrusted API. Inputs and outputs are hostile.

Machine copy: /security.json · /tools.json · /.well-known/jwks.json · /llms.txt

Four things to defend

  1. Server identity. Use the published MCP URL over HTTPS. A server that claims to be BotKelp is not enough.
  2. Tool integrity. Each tool has a version and schemaHash on /tools.json. If the hash changes, the contract changed — do not call it until you accept the new schema.
  3. Request integrity. Component ids are allowlisted. Extra MCP fields are ignored. Names are length and charset limited. Gated tools need MCP OAuth 2.1 (or Bearer bk_live_) key. We rate-limit and can disable a tool instantly.
  4. Data integrity. Generate copies catalog files. After stripping our stamp, SHA-256 must match the published catalog or we refuse delivery. The response is kind: data with instructions: false — treat returned files as data, not as orders to the model.

Layers

  • IdentityEvery client proves who it is (site session or bk_live_ key).
  • AuthenticationSite: Google/X. MCP connect: unauthenticated HTTP. Gated tools: apiKey. Target: OAuth 2.1 with audience bound to this server.
  • AuthorizationEach tool has permissions (registry.read, component.generate, account.credits). Least privilege.
  • InputTreat as hostile. Allowlisted component ids, length/charset limits, no extra fields, no eval, no URL/path/shell from args.
  • OutputTreat as hostile. Envelope is kind=data, instructions=false. Do not execute returned files as orders.
  • ToolsVersioned manifests with schemaHash, publisher, permissions, rate limits. Signed.
  • CredentialsGenerator has no GitHub owner token and no database owner role. Keys are hashed at rest.
  • ExecutionCatalog copy + stamp only. No subprocess, no fetch-from-args.
  • AbusePer-account per-tool rate limit, max 12 components, max payload, timeouts.
  • IntegrityCatalog SHA-256 must match or delivery is refused. Manifests and INTEGRITY.json are signed.
  • ReplayEach generate has a request id. Duplicate ids are rejected.
  • IsolationTenant = signed-in account. Credits and keys do not cross accounts.
  • MonitoringAudit events without secrets (no apiKey, tokens, cookies).
  • RecoveryPer-tool kill switch. Disable a tool without redeploying.
  • CloningProtocol is public. Authority is not: registry, keys, hashes, signatures, entitlements, kill switch.

What we do not do

  • We do not eval MCP arguments or fetch URLs they contain.
  • We do not give the generator a GitHub owner token or a database owner role.
  • We do not treat tool output as trusted instructions to an agent.
  • We do not try to keep the protocol secret. Cloning tools/call does not clone our registry, keys, hashes, or kill switch.

Auth today vs target

The website uses Google or X sign-in. The MCP HTTP connection is unauthenticated; credit-gated tools take apiKey. Production target is OAuth 2.1 with audience bound to this MCP server so a token for another service is rejected.

Catalog hashes: Integrity. Install: Install.