Skip to content

docs: MCPJam API (preview) reference#2536

Merged
chelojimenez merged 14 commits into
mainfrom
claude/confident-fermi-egdjco
Jun 10, 2026
Merged

docs: MCPJam API (preview) reference#2536
chelojimenez merged 14 commits into
mainfrom
claude/confident-fermi-egdjco

Conversation

@chelojimenez

@chelojimenez chelojimenez commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Documents the v1 public API (shipped in #2523) exactly as it exists today, flagged as Preview per standard practice for an unannounced surface that may still change.

What's in it

New page: reference/public-api.mdx (sidebar-tagged "Preview")

  • Up-front preview disclaimer: not announced, may change (including breaking changes) until GA, changelog pointer, feedback channels
  • Base URL (https://app.mcpjam.com/api/v1) and sk_… key auth: creation in Settings → API keys, one-time reveal, org scoping at mint, immediate revocation, key-hygiene guidance
  • Documented restrictions: API keys can't manage API keys (403), guests rejected, ORPHANED_KEY 401 path
  • Response conventions: single-resource / {items, nextCursor} collection / {code, message, details} error envelopes, opaque cursor pagination
  • The full 10-code error contract with HTTP status mapping (incl. OAUTH_REQUIRED vs UNAUTHORIZED distinction), additive-codes note
  • Per-key rate limits (60/min sustained, burst 10) with Retry-After + backoff guidance
  • All 8 live endpoints with curl examples: validate, doctor, check-oauth, tools, prompts, resources, resources/read, export
  • Honest "Not in the API yet" section (no tool execution, no project/server listing, key management UI-only) and a versioning & stability policy (path-versioned, tolerant-reader guidance)

Updated reference/api-keys.mdx — adds the sk_… MCPJam API key as the fourth key type with its error signatures; quick-reference table updated.

docs.json — page added to the SDK tab's Reference group.

Accuracy notes

Everything stated was verified against the shipped code rather than the design docs: endpoint list from server/routes/v1/*, error contract from routes/v1/contract.ts, rate-limit numbers from middleware/bearer-auth.ts, key restrictions from routes/web/api-keys.ts. Notably, the Convex product-state routes (/v1/me, /v1/projects, …) are deliberately not documented — they don't accept sk_ keys today (Inspector-delegated or session-JWT only), so documenting them under key auth would be wrong; the page lists project/server listing under "not yet" instead.

mint broken-links passes for all touched pages (5 pre-existing broken links in untouched contributing/* pages remain).

https://claude.ai/code/session_011asM4GkyWv5TQp35PAC3cC


Generated by Claude Code


Note

Low Risk
Docs-only changes with no runtime, auth, or data-path impact.

Overview
Adds preview documentation for the shipped v1 public API at https://app.mcpjam.com/api/v1, linked from the SDK tab Reference group in docs.json.

The new reference/public-api.mdx page covers sk_… bearer auth, org scoping, response/error conventions, rate limits (60/min, burst 10), all eight live POST endpoints (validate, doctor, check-oauth, tools/prompts/resources, resources/read, export), explicit “not in the API yet” scope, and versioning/stability expectations for preview.

reference/api-keys.mdx is updated from three to four key types: a dedicated section for the MCPJam API key (sk_…) with common 401/403/429 errors, plus a new row in the quick-reference table pointing at the public API page.

Reviewed by Cursor Bugbot for commit d90410a. Bugbot is set up for automated code reviews on this repo. Configure here.

chelojimenez and others added 14 commits June 8, 2026 18:14
…dation

Adds the boring infrastructure that PRs 2-5 build on:

- `@workos-inc/node` ^10.2.0 dependency (server-side SDK; the existing
  `@workos-inc/authkit-react` only covers the browser flow).
- `server/services/workos-client.ts` — memoized `getWorkOSClient()`
  reading `WORKOS_API_KEY`. Mirrors the backend `createWorkOSClient`
  factory in `convex/lib/vault.ts`.
- `server/middleware/request-local.ts` — typed wrappers over Hono's
  `c.set`/`c.get` so the bearer middleware and `authorizeBatch` can
  share a single WorkOS validation result per request without paying
  ~200ms twice.
- `server/services/identity.ts` — `resolveUserByExternalId(externalId)`
  via `ConvexHttpClient`, matching the string-path call style used by
  `local-server-resolver.ts` and `servers.ts`. The `users:getByExternalId`
  query is added in the parallel backend PR `claude/workos-api-keys-backend`;
  the call is cast to bypass codegen drift until that PR lands.

No call sites use these yet — wired up in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…key rate limit

Adds a new `sk_` branch to `bearerAuthMiddleware` BEFORE the guest-JWT
branch. Real WorkOS JWTs always begin with `eyJ`, so the prefix is
unambiguous and never falls through.

On `sk_…`:
- Check request-local cache; otherwise call
  `WorkOS.apiKeys.createValidation`. ~200ms latency, single global
  WorkOS endpoint — memoization is non-optional because the same
  request later hits `authorizeBatch` and would re-validate.
- Per-key token bucket (60/min sustained, burst 10) rejects floods
  with `429` + `Retry-After`. Rejection happens BEFORE the Convex
  user lookup so a flood can't tie up the DB either.
- Resolve the WorkOS user id to an MCPJam user via the new
  `resolveUserByExternalId` helper. Set `authMethod="workos_api_key"`,
  `workosApiKeyId`, `workosUserId`, `mcpjamUserId` for downstream
  handlers (next commit consumes these in `authorizeBatch`).
- Structured `auth.workos_api_key` log carries metadata only — no key
  value, no full token.

Extends `ContextVariableMap` so the four new variables are typed.
Adds `resetWorkOSRateLimitForTests` so the test in commit 6 can
exercise rate-limit behavior deterministically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s when calling Convex

When `bearerAuthMiddleware` resolves the caller via a WorkOS `sk_` key,
the original bearer is the API key itself — Convex's identity layer
can't validate it (it only knows JWTs and guest tokens). Instead,
Inspector exchanges:

    Authorization: Bearer <sk_…>
      ↓
    Authorization: Bearer <INSPECTOR_SERVICE_TOKEN>
    x-mcpjam-acting-as: <mcpjamUserId>

This keeps WorkOS validation at a single layer (Inspector) and reuses
the durable-worker service token pattern. The companion backend PR
(`claude/workos-api-keys-backend`) teaches Convex `requestIdentity`
to honor delegated-identity mode and audit-log every use.

Touched call sites — every Inspector→Convex `/web/*` fetch reached
from the `/api/v1/*` ephemeral-connection flow:

- `authorizeServer` (`auth.ts`) — single-server authorize.
- `authorizeBatch` (`auth.ts`) — multi-server authorize, the load-
  bearing one for `/api/v1/.../tools` etc.
- `fetchRuntimeServerSecrets` (`utils/server-secrets.ts`) — secret
  reveal that `createAuthorizedManager` calls inline when server has
  hasHeaders=true but no inline headers.

A shared `buildConvexAuthHeaders(c, originalBearer)` helper in auth.ts
keeps the branching consistent for the two `authorize*` paths.
`fetchRuntimeServerSecrets` takes the equivalent context via a new
optional `workosApiKeyActingAs` arg so it can stay free of Hono types.

NOT touched (out of scope for `/api/v1/*` today; flagged for follow-up
if API keys start reaching them): `chat-history.ts` proxy helpers,
`hosted-oauth-refresh.ts`, `local-server-resolver.ts`. Each is on an
OAuth-flow or local-mode path that doesn't accept `sk_` bearers in v1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…OS REST

Adds a new sub-router for managing WorkOS API keys from the inspector UI.

The router calls WorkOS REST directly with the server-side `WORKOS_API_KEY`:
the Node SDK only exposes org-scoped helpers (`createOrganizationApiKey`
/ `listOrganizationApiKeys`), but v1 mints user-scoped keys via documented
user_management endpoints.

Auth gating, top-to-bottom:
1. `sessionAuthMiddleware` bypasses `/api/web/*` entirely (per
   `session-auth.ts:103`), so this router explicitly attaches
   `bearerAuthMiddleware`.
2. After bearer auth runs, a follow-up middleware rejects
   `authMethod === "workos_api_key"` with 403. This is the privilege
   isolation guard: `sk_…` keys cannot mint or revoke other `sk_…`
   keys.

Endpoints:
- `POST /api/web/api-keys` `{ name }` → WorkOS user_management create.
  Returns the full create response (one-shot `value`, `obfuscated_value`,
  `id`). MCPJam neither persists nor logs the raw value.
- `GET /api/web/api-keys` → list for the session user/org. Returns
  `{ items: [...] }` with `obfuscated_value` only.
- `DELETE /api/web/api-keys/:id` → fetches the key first, verifies
  `owner.id === session.userId`, then deletes via WorkOS `DELETE
  /api_keys/{id}`. A user passing another user's key id sees a 404
  (not 403 — same response shape as "doesn't exist").

WorkOS userId / org_id are read from the session JWT's `sub` / `org_id`
claims (decoded payload only; signature is enforced upstream by
`bearerAuthMiddleware`'s WorkOS pass-through and by Convex). Structured
`api_key_created` / `api_key_revoked` audit logs carry the key id and
actor user id, never the value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a new /settings/api-keys page where users can mint, list, and
revoke WorkOS-backed API keys for the v1 public API.

- ApiKeysRoute: table of existing keys with create + revoke actions.
- CreateApiKeyDialog: name input + Create.
- RevealOnceDialog: shows the full sk_... value once with copy-to-clipboard
  and a "won't be shown again" warning. Mirrors the SkillsTab copy
  feedback pattern (Copy → Check icon).
- RevokeApiKeyDialog: type-the-key-name to confirm, mirroring the
  ChatboxDeleteConfirmDialog pattern.
- api-keys client lib: typed wrappers (create/list/revoke) over the new
  /api/web/api-keys/* endpoints via authFetch.
- Router: new /settings/api-keys route registered alongside /settings.
- Sidebar: "API Keys" entry added to the settings section with the Key
  icon from lucide-react.

Toasts via sonner. All session-authenticated through the bearer
middleware applied by the sub-router (sk_ keys cannot reach this UI).
Focused tests for the security-critical new code in the bearer
middleware:

- Missing or non-Bearer Authorization header → 401.
- sk_ token with WorkOS-rejected key → 401 UNAUTHORIZED (Convex
  identity resolution is NOT invoked in this path).
- sk_ token validated but MCPJam user missing → 401 "Unknown user".
- sk_ token valid → next() runs with c.set keys for authMethod,
  workosApiKeyId, workosUserId, mcpjamUserId.
- Per-key token bucket admits >=10 burst then 429s.
- Cross-key bucket isolation (sk_a drained does not affect sk_b).
- Request-local memoization: the middleware running twice in a single
  request only invokes WorkOS validate once (covers /api/web/api-keys
  sub-router stacking).

WorkOS SDK, identity resolver, and guest-JWT validator are mocked at
module level. Uses resetWorkOSRateLimitForTests() exported from the
middleware for clean state.

Follow-up: dedicated test suite for /api/web/api-keys/* routes —
needs JWT-claim mocking + WorkOS REST stubbing, deferred to a smaller
PR for review clarity.
Completes the v1 public-API key flow against the merged backend resolver,
which now requires BOTH x-mcpjam-acting-as (WorkOS externalId) and
x-mcpjam-acting-in-org (Convex org id).

Bearer middleware:
- After resolving the MCPJam user, look up the key's org binding (memoized
  per request). Missing binding -> 401 ORPHANED_KEY. Store the org id in
  Hono context.

Delegated Convex calls (auth.ts + server-secrets.ts):
- Send x-mcpjam-acting-as = WorkOS user id (was incorrectly the Convex user
  id, which the backend resolver would 404), plus x-mcpjam-acting-in-org.

API key mint/revoke (routes/web/api-keys.ts):
- Create accepts { name, organizationId }, resolves the Convex user id, and
  writes the backend binding; on binding failure the WorkOS key is revoked.
- Revoke removes the binding best-effort.

Client:
- Create dialog adds MCPJam org selection (auto-selects a sole org, requires
  explicit choice when there are several); posts organizationId.

New service client for the backend binding endpoints. Tests: orphaned-key
401, acting-as = WorkOS id (not Convex id), both headers present; fixed the
sk_ validate mock (createValidation) and made auth Context test mocks
faithful (c.get).

https://claude.ai/code/session_011asM4GkyWv5TQp35PAC3cC
Return the canonical UNAUTHORIZED code for an unbound WorkOS key and carry
the specific reason in the opaque details bag (details.reason = "ORPHANED_KEY")
instead of inventing a new wire code. ORPHANED_KEY is not in V1_ERROR_CODES
(routes/v1/contract.ts), and the v1 boundary mapper would otherwise collapse
it to INTERNAL_ERROR; the envelope already allows details. Removes the
ORPHANED_KEY entry from the internal ErrorCode enum and updates the test to
assert code=UNAUTHORIZED + details.reason=ORPHANED_KEY.

https://claude.ai/code/session_011asM4GkyWv5TQp35PAC3cC
…EX_URL

resolveUserByExternalId hard-required process.env.CONVEX_URL, but Inspector
boot only requires CONVEX_HTTP_URL; a deployment honoring that contract would
throw 'CONVEX_URL is not set', 500-ing all sk_ API-key auth and minting.
Use getInspectorClientRuntimeConfig().convexUrl (the .convex.cloud URL derived
from CONVEX_HTTP_URL, matching the rest of the server), falling back to
CONVEX_URL. Also harden the result type guard to require a non-null object.

https://claude.ai/code/session_011asM4GkyWv5TQp35PAC3cC
The /api/web/api-keys routes decoded the bearer's payload WITHOUT verifying the
signature and trusted claims.sub to drive WorkOS key mint/list/revoke with the
server's admin key. Unlike other /api/web/* routes, these never forward the
bearer to Convex, so nothing verified it — a forged bearer could target another
user's WorkOS id for key lifecycle operations.

- Add services/authkit-jwt.ts: verify the WorkOS AuthKit access token via JWKS,
  pinning issuer + audience(client id) + RS256 + exp/nbf. Issuer/JWKS/audience
  set mirrors mcpjam-backend convex/auth.config.ts so Inspector accepts exactly
  the tokens Convex already accepts. Only sub/org_id are read from verified
  claims; guest issuer excluded (key management is JWT-only).
- api-keys resolveSessionContext now awaits verification and returns 401 before
  any WorkOS or Convex-binding side effect; 500 only on missing config.
- Tests: forged (untrusted key), unsigned (alg none), wrong issuer, wrong
  audience, expired, malformed, valid. Declare jose as a direct dependency.

https://claude.ai/code/session_011asM4GkyWv5TQp35PAC3cC
… once per request

Addresses two Cursor Bugbot findings on the api-key management surface:

- api-keys: move the sk_ privilege-isolation guard BEFORE bearerAuthMiddleware.
  sk_ keys can never manage keys, and the sk_ prefix is the same discriminator
  the middleware uses, so an up-front 403 is equivalent to the old
  post-validation authMethod check while skipping a ~200ms WorkOS validate plus
  Convex identity/binding lookups on a request that always 403s. Also yields a
  uniform 403 for invalid/revoked keys (no validity probing via 401-vs-403).

- bearer-auth: memoize the per-key WorkOS rate-limit debit per request
  (workosRateLimitConsumed), matching the existing validation/binding memo, so
  the limit can't be double counted if the middleware ever runs on both a
  parent and child router.

Auth-cluster suite green (48 tests), including the rate-limit burst test.

https://claude.ai/code/session_011asM4GkyWv5TQp35PAC3cC
Document the v1 public API exactly as it ships today, flagged as preview per
standard practice for unannounced surfaces (may change, path-versioned,
tolerant-reader guidance, changelog pointer):

- New reference/public-api page: base URL, sk_ key auth (Settings -> API keys,
  one-time reveal, org scoping, revocation), envelope + cursor pagination, the
  10-code error contract with status mapping, per-key rate limits (60/min,
  burst 10, Retry-After), and the 8 live-MCP endpoints (validate, doctor,
  check-oauth, tools/prompts/resources list, resources/read, export) with curl
  examples. Honest 'not in the API yet' list (no tool execution, no listing
  endpoints, key management UI-only).
- reference/api-keys: add the sk_ MCPJam API key as the fourth key type with
  its error signatures; update quick-reference table.
- docs.json: add the page to the SDK tab reference group.

https://claude.ai/code/session_011asM4GkyWv5TQp35PAC3cC
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. documentation Improvements or additions to documentation labels Jun 10, 2026
@chelojimenez

Copy link
Copy Markdown
Contributor Author

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Internal preview

Preview URL: https://mcp-inspector-pr-2536.up.railway.app
Deployed commit: d6f0ea8
PR head commit: d90410a
Backend target: staging fallback.
Health: ❌ Convex unreachable — see job logs (staging may need convex deploy)
Access is employee-only in non-production environments.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds documentation for the MCPJam Preview API (/api/v1), a new headless interface for live MCP server diagnostics. The change clarifies a new MCPJam API key type (prefixed sk_…) alongside existing API keys, documents authentication, request/response conventions, error codes, rate limits, and available endpoints for validation, capability inspection, and full server snapshots. The new reference page is integrated into the documentation site navigation.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/reference/api-keys.mdx (1)

3-3: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update description to match "four" key types.

The frontmatter description still references "three different things" but the content now documents four key types. This creates confusion for users and search engines.

📝 Proposed fix
-description: "The three different things called 'API key' in MCPJam, and when you need each one."
+description: "The four different things called 'API key' in MCPJam, and when you need each one."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/api-keys.mdx` at line 3, Update the frontmatter description
string that currently reads "The three different things called 'API key' in
MCPJam, and when you need each one." to reflect four key types (e.g., "The four
different things called 'API key' in MCPJam, and when you need each one.") so it
matches the document body that documents four key types; ensure the frontmatter
description value (the description key) is changed to mention "four" and remains
concise and consistent with the rest of the content.
🧹 Nitpick comments (1)
docs/reference/public-api.mdx (1)

48-54: ⚡ Quick win

Consider clarifying the $MCPJAM_API_KEY variable name.

The curl examples use $MCPJAM_API_KEY for the new sk_… bearer key, but api-keys.mdx documents MCPJAM_API_KEY as the CLI/SDK authentication token (a different key type with different scoping). While context makes clear these examples are for the API key, users scanning both pages might conflate them.

Either use a distinct variable name in examples (e.g., $MCPJAM_SK_KEY or $MCPJAM_API_SECRET_KEY) or add a brief note that this is the sk_… API key, not the CLI token.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/public-api.mdx` around lines 48 - 54, Update the curl examples
in public-api.mdx to avoid confusing the CLI token with the new sk_… API key by
either renaming the environment variable (e.g., use $MCPJAM_SK_KEY or
$MCPJAM_API_SECRET_KEY instead of $MCPJAM_API_KEY) and updating all occurrences
in the example, or add a single inline note next to the Authorization header
that clarifies this must be the sk_… API key (not the CLI/SDK token documented
in api-keys.mdx); ensure the change is applied to the curl snippet shown and any
adjacent explanatory text so readers won’t conflate the two keys.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/reference/api-keys.mdx`:
- Line 3: Update the frontmatter description string that currently reads "The
three different things called 'API key' in MCPJam, and when you need each one."
to reflect four key types (e.g., "The four different things called 'API key' in
MCPJam, and when you need each one.") so it matches the document body that
documents four key types; ensure the frontmatter description value (the
description key) is changed to mention "four" and remains concise and consistent
with the rest of the content.

---

Nitpick comments:
In `@docs/reference/public-api.mdx`:
- Around line 48-54: Update the curl examples in public-api.mdx to avoid
confusing the CLI token with the new sk_… API key by either renaming the
environment variable (e.g., use $MCPJAM_SK_KEY or $MCPJAM_API_SECRET_KEY instead
of $MCPJAM_API_KEY) and updating all occurrences in the example, or add a single
inline note next to the Authorization header that clarifies this must be the
sk_… API key (not the CLI/SDK token documented in api-keys.mdx); ensure the
change is applied to the curl snippet shown and any adjacent explanatory text so
readers won’t conflate the two keys.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aac92a18-337c-4dbf-a083-e1e44118c8ff

📥 Commits

Reviewing files that changed from the base of the PR and between c318ab7 and d90410a.

📒 Files selected for processing (3)
  • docs/docs.json
  • docs/reference/api-keys.mdx
  • docs/reference/public-api.mdx

@chelojimenez chelojimenez merged commit 818d2d8 into main Jun 10, 2026
13 checks passed
@chelojimenez chelojimenez deleted the claude/confident-fermi-egdjco branch June 10, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant