Skip to main content
Glama
README.md
# 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

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

Demo the approval flow end to end:

```bash
# 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:

```bash
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:

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

## Wire into Claude Code

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

Optionally pass the admin key through:

```bash
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.

TDQS

A4.6/5.0

Scored across 3 tools

Disambiguation5/5

Each tool addresses a distinct domain area: rate limits, API key requests, and usage summaries. There is no meaningful overlap between them, and the status-checking behavior inside request_api_key is clearly documented rather than being a separate ambiguous tool.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case: get_limit_status, request_api_key, get_usage_summary. The verbs are descriptive and the naming style is uniform across the set.

Tool Count5/5

Three tools is a reasonable scope for a platform admin stub focused on limits, usage, and key requests. Each tool covers a distinct administrative area without unnecessary bloat or redundant operations.

Completeness4/5

The set covers the main admin concerns suggested by the server name: rate limits, usage reporting, and API key access requests. Minor gaps exist, such as no direct approval or managed key listing, but these appear intentionally delegated to an out-of-band CLI process.

Maintenance

ActivitySlowing
ResponsivenessNo issues