Skip to main content
Glama

platform-mcp-stub

A minimal MCP server (TypeScript, stdio transport, official @modelcontextprotocol/sdk) that demonstrates agent-native platform onboarding with human-in-the-loop provisioning: an agent can discover its usage and limits on its own, but getting a credential always routes through a visible human approval gate.

Tools

Tool

What it does

Real vs fixture

request_api_key(scope, justification)

Files a pending approval request in a local approvals.json ledger and returns pending human approval: <id>. Nothing is minted by the agent. A human runs the companion approve <id> CLI to flip it, which attaches a deliberately fake key (sk-ant-demo-...). The agent can poll with scope="status:<id>" and re-fetch an already-approved scope.

The gate is real (ledger + CLI); the key is intentionally fake — this stub never touches real credential minting.

get_usage_summary()

Last 7 days of org token usage, daily buckets grouped by model, via the Anthropic Usage Admin API (GET /v1/organizations/usage_report/messages).

Live when ANTHROPIC_ADMIN_KEY is set (real HTTP call, real schema). Otherwise returns a fixture explicitly labeled _fixture: true whose shape mirrors the documented response.

get_limit_status()

The org's configured rate-limit groups (per-model-group RPM / input-TPM / output-TPM, batch queue limits) via the Rate Limits Admin API (GET /v1/organizations/rate_limits).

Same pattern: live with an admin key, labeled fixture without.

The human-approval gate is the whole point: the agent's request, the human's decision, and the resulting (fake) credential are all visible in one plain-JSON ledger.

What is real vs fixture

  • Real: the MCP protocol surface (official SDK, stdio JSON-RPC), the approvals ledger and CLI flow, and — when ANTHROPIC_ADMIN_KEY is present — the HTTP calls to the two Admin API endpoints above (correct headers: anthropic-version: 2023-06-01, x-api-key).

  • Fixture: without an admin key, get_usage_summary / get_limit_status return synthetic data labeled _fixture: true with a _note, matching the real response schemas so downstream handling is identical.

  • Always fake: issued keys. Format sk-ant-demo-<hex>; they mint nothing and authenticate nowhere.

Note: the Admin API requires an Admin API key (sk-ant-admin01-...), which is a different credential from a regular Claude API key, and is only available on organization (not individual) accounts.

Run it

npm install
npm run build
npm start            # MCP server on stdio (Ctrl-C to stop)

Demo the approval flow end to end:

# 1. In an MCP client (or via raw JSON-RPC — see below), call:
#    request_api_key(scope="usage:read", justification="dashboard prototype")
#    -> "pending human approval: apprq_xxxxxxxx"

# 2. As the human operator:
npm run approve -- list
npm run approve -- apprq_xxxxxxxx
#    -> approved; prints the FAKE sk-ant-demo-... key
#    (to reject instead: npm run approve -- deny apprq_xxxxxxxx)

# 3. Agent re-calls request_api_key (same scope, or scope="status:apprq_xxxxxxxx")
#    -> gets the demo key

No MCP client handy? Drive the server with raw JSON-RPC over stdio. Pipe into node dist/server.js directly — not npm start, because npm prints its script banner to stdout, which pollutes the JSON-RPC stream:

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"0.0.1"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"request_api_key","arguments":{"scope":"usage:read","justification":"dashboard prototype"}}}' \
  | node dist/server.js

The same pattern works for get_usage_summary and get_limit_status (empty arguments).

To exercise the live Admin API paths:

export ANTHROPIC_ADMIN_KEY=sk-ant-admin01-...
npm start

Wire into Claude Code

claude mcp add platform-stub -- node /absolute/path/to/platform-mcp-stub/dist/server.js

Optionally pass the admin key through:

claude mcp add platform-stub -e ANTHROPIC_ADMIN_KEY=sk-ant-admin01-... -- \
  node /absolute/path/to/platform-mcp-stub/dist/server.js

Then in a Claude Code session: "Request an API key for scope messages:write and check our current usage and limits." Approve from a second terminal with npm run approve -- <id>.

Honest scope notes (v1)

  • Evening-sized prototype, not a provisioning product: single-file JSON ledger, no auth on the approve CLI, no expiry/rotation, no real key minting (by design — the Admin API does support key management, which a v2 could gate behind the same approval flow).

  • Usage summary is a fixed query (7 days, 1d buckets, group_by[]=model); the real endpoint supports much richer filtering/grouping.

  • approvals.json lives at the repo root by default; override with APPROVALS_FILE.

Requirements

  • Node 20+

  • ANTHROPIC_ADMIN_KEY (admin key, sk-ant-admin01-...) only for live usage/limit data — everything else works offline.