Skip to content

Platform api keys#3024

Open
ignaciojimenezr wants to merge 5 commits into
mainfrom
platform-api-keys
Open

Platform api keys#3024
ignaciojimenezr wants to merge 5 commits into
mainfrom
platform-api-keys

Conversation

@ignaciojimenezr

@ignaciojimenezr ignaciojimenezr commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Fix API key creation (drop WorkOS)

Right now, creating an API key requires the user to belong to a WorkOS "organization" — only three of us are in the org, so it's broken for real users.

This change stops using WorkOS for keys and creates/checks them in Convex instead. We used to do this before WorkOS (for the old mcpjam_ keys), so it's mostly reviving that approach — just scoped to orgs now.

  • Keys are now made, hashed, stored, and validated in Convex — no WorkOS
  • New table + backend routes for create/list/revoke/validate
  • Inspector just forwards your login to the backend, so it works the same hosted, local, and via npx
  • A key stops working if its owner leaves the org
  • No changes for users: keys still look like sk_..., CLI/SDK and the settings UI are untouched

Validated in dev: a newly created sk_mcpjam_... key successfully authenticated against Inspector /api/v1/me with 200 OK via backend platform key validation.


Summary by cubic

Migrated MCPJam authentication to platform API keys validated by the Convex backend, replacing WorkOS. New keys use the sk_mcpjam_… format and are documented; older sk_… keys now return 401.

  • Refactors

    • bearer-auth: gate on sk_mcpjam_[0-9a-f]{48}, hash with SHA-256, validate via backend, memoize per request; rate-limit by key hash (60/min, burst 10) and spray-limit by canonical client IP; cap buckets at 50k.
    • Context stays backward-compatible (authMethod: "workos_api_key", workosApiKeyId, workosUserId, mcpjamUserId, mcpjamOrganizationId).
    • /api/web/api-keys: proxy to backend /web/api-keys with the caller’s bearer; map to existing shapes; unify errors via statusToErrorCode; reject legacy sk_… bearers with 403 before proxying.
    • Docs: update key format to sk_mcpjam_…; drop ORPHANED_KEY; clarify 401/403 copy.
    • Remove WorkOS dependencies (workos-client, workos-key-bindings, identity) and related tests; add platform-api-key-validation (sha256 parity and routing-404 tests).
    • UI: make RevealOnceDialog responsive and prevent overflow on small screens.
  • Migration

    • Recreate any old API keys: non-sk_mcpjam_… keys now 401 ("Invalid API key").
    • Ensure env is set: CONVEX_HTTP_URL and INSPECTOR_SERVICE_TOKEN are required; WORKOS_API_KEY is no longer needed in the inspector.
    • Behavior remains the same for /api/v1/* callers; key management via API is blocked (403) — use Settings → API keys.

Written for commit a64bf42. Summary will update on new commits.

Review in cubic

ignaciojimenezr and others added 2 commits July 5, 2026 14:18
…rkOS

Mint/list/revoke now forward the caller's session bearer to the backend's
/web/api-keys routes; bearer-auth validates sk_mcpjam_ keys with a single
service-token call (format-gated + rate-limited by hash) instead of WorkOS +
binding lookup. Same context fields downstream, same client shapes. Removes
the workos-client / identity / workos-key-bindings services.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…leanup

- request-local: stop collapsing cached null to undefined (invalid keys were
  re-validated when bearer-auth runs on parent + sub-router)
- bearer-auth: cap the rate-limit bucket map at 50k entries (distinct
  valid-format invalid keys could grow it unbounded between sweeps), align
  log labels, cross-reference the key-format contract with the backend
- errors.ts: shared statusToErrorCode, used by oauth + api-keys routes
- types/hono.ts: docstrings updated for the platform-key flow
- docs: drop ORPHANED_KEY (no longer emitted), document sk_mcpjam_ format
- new platform-api-key-validation tests (routing-404 disambiguation, sha256
  parity vector) porting the deleted identity.test.ts coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mcpjam 🟢 Ready View Preview Jul 5, 2026, 10:29 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jul 5, 2026
@chelojimenez

chelojimenez commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

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 Jul 5, 2026

Copy link
Copy Markdown
Contributor

Internal preview

Preview URL: https://mcp-inspector-pr-3024.up.railway.app
Deployed commit: c40cf2d
PR head commit: a64bf42
Backend target: staging fallback.
Health: ✅ Convex reachable
Access is employee-only in non-production environments.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a082ae03-25d5-4d08-aed2-ec76bd800273

📥 Commits

Reviewing files that changed from the base of the PR and between 20e75fb and a64bf42.

📒 Files selected for processing (3)
  • mcpjam-inspector/client/src/components/settings/api-keys/RevealOnceDialog.tsx
  • mcpjam-inspector/server/middleware/__tests__/bearer-auth.test.ts
  • mcpjam-inspector/server/middleware/bearer-auth.ts
✅ Files skipped from review due to trivial changes (1)
  • mcpjam-inspector/client/src/components/settings/api-keys/RevealOnceDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • mcpjam-inspector/server/middleware/tests/bearer-auth.test.ts
  • mcpjam-inspector/server/middleware/bearer-auth.ts

Walkthrough

This PR migrates sk_ API key handling to the sk_mcpjam_ platform format. It adds platform API key hashing and validation, rewrites bearer-auth middleware with format checks, rate limiting, and memoized validation, updates request-local caching, and refreshes tests and Hono context docs. Web API-key routes now proxy to a backend endpoint, and the reference docs were updated to match the new key format and 401 guidance.

Changes

Related issues: None provided
Related PRs: None provided
Suggested labels: authentication, backend, documentation
Suggested reviewers: Not determinable from the provided information

Sequence Diagram(s)

See the embedded diagrams above.

Poem:
From WorkOS paths to platform light,
the keys now hash and pass by rite.
The routes now forward, docs align,
and sk_mcpjam_ marks the line.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

mcpjam-inspector/client/src/components/settings/api-keys/RevealOnceDialog.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: ESLint configuration in --config is invalid:

  • Unexpected top-level property "__esModule".

    at ConfigValidator.validateConfigSchema (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2177:19)
    at ConfigArrayFactory._normalizeConfigData (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3019:19)
    at ConfigArrayFactory._loadConfigData (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:21)
    at ConfigArrayFactory.loadFile (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
    at createCLIConfigArray (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)
    at new CascadingConfigArrayFactory (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3735:29)
    at new CLIEngine (/soundcheck/node_modules/eslint/lib/cli-engine/cli-engine.js:617:36)
    at new ESLint (/soundcheck/node_modules/eslint/lib/eslint/eslint.js:430:27)
    at Object.execute (/soundcheck/node_modules/eslint/lib/cli.js:410:24)
    at async main (/soundcheck/node_modules/eslint/bin/eslint.js:152:22)

mcpjam-inspector/server/middleware/__tests__/bearer-auth.test.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: ESLint configuration in --config is invalid:

  • Unexpected top-level property "__esModule".

    at ConfigValidator.validateConfigSchema (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2177:19)
    at ConfigArrayFactory._normalizeConfigData (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3019:19)
    at ConfigArrayFactory._loadConfigData (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:21)
    at ConfigArrayFactory.loadFile (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
    at createCLIConfigArray (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)
    at new CascadingConfigArrayFactory (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3735:29)
    at new CLIEngine (/soundcheck/node_modules/eslint/lib/cli-engine/cli-engine.js:617:36)
    at new ESLint (/soundcheck/node_modules/eslint/lib/eslint/eslint.js:430:27)
    at Object.execute (/soundcheck/node_modules/eslint/lib/cli.js:410:24)
    at async main (/soundcheck/node_modules/eslint/bin/eslint.js:152:22)

mcpjam-inspector/server/middleware/bearer-auth.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: ESLint configuration in --config is invalid:

  • Unexpected top-level property "__esModule".

    at ConfigValidator.validateConfigSchema (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2177:19)
    at ConfigArrayFactory._normalizeConfigData (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3019:19)
    at ConfigArrayFactory._loadConfigData (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:21)
    at ConfigArrayFactory.loadFile (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
    at createCLIConfigArray (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)
    at new CascadingConfigArrayFactory (/soundcheck/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3735:29)
    at new CLIEngine (/soundcheck/node_modules/eslint/lib/cli-engine/cli-engine.js:617:36)
    at new ESLint (/soundcheck/node_modules/eslint/lib/eslint/eslint.js:430:27)
    at Object.execute (/soundcheck/node_modules/eslint/lib/cli.js:410:24)
    at async main (/soundcheck/node_modules/eslint/bin/eslint.js:152:22)


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.

@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.

Actionable comments posted: 2

🧹 Nitpick comments (4)
mcpjam-inspector/server/routes/v1/__tests__/computer-environments.test.ts (1)

29-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the repeated platform-key mock into a shared test helper.

The same vi.mock("../../../services/platform-api-key-validation.js", ...) block (importOriginal + stub returning null) is duplicated verbatim across this file, harness.test.ts, hosts.test.ts, and tunnels.test.ts. Since all four only need the same "unreachable, stub to null" behavior, a shared mockPlatformApiKeyValidation() test helper would cut the duplication without changing behavior.

🤖 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 `@mcpjam-inspector/server/routes/v1/__tests__/computer-environments.test.ts`
around lines 29 - 37, The platform API-key mock setup is duplicated across
multiple test files, so extract the repeated vi.mock for
platform-api-key-validation.js into a shared test helper and reuse it from
computer-environments.test.ts, harness.test.ts, hosts.test.ts, and
tunnels.test.ts. Keep the helper responsible for the same importOriginal plus
validatePlatformApiKey stub that resolves to null, and update each test file to
call the helper instead of inlining the mock block.
docs/reference/public-api.mdx (1)

106-108: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Same stale sk_… prefix nearby.

Line 107 still says an sk_… bearer fail with 403 FORBIDDEN, while the key format was just updated to sk_mcpjam_… a few lines above (90-91). Minor, but worth a pass for consistency while this file is being edited.

✏️ Suggested tweak
-  with an `sk_…` bearer fail with `403 FORBIDDEN`. Create and revoke keys in
+  with an `sk_mcpjam_…` bearer fail with `403 FORBIDDEN`. Create and revoke keys in
🤖 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 106 - 108, Update the API
key-management note in public-api.mdx to use the new key prefix consistently.
The stale “sk_…” reference in the sentence about `403 FORBIDDEN` should be
changed to match the updated `sk_mcpjam_…` format already used earlier in the
same document, keeping the wording aligned around the API key-management
behavior.
docs/reference/api-keys.mdx (1)

19-19: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stale sk_… reference next to the newly updated format wording.

Line 19 still reads Bearer sk_… while the surrounding bullets (lines 9-13, 22) were just updated to the explicit sk_mcpjam_… format. Worth aligning for consistency now that this doc is being touched.

✏️ Suggested tweak
-**When it's used:** Every `Authorization: Bearer sk_…` request to `/api/v1/*` — validating servers, running the doctor, listing tools/prompts/resources, reading resources, exporting snapshots, and **saving `@mcpjam/sdk` eval results** (set `MCPJAM_API_KEY` to this key; see [Saving Results](/sdk/concepts/saving-results)).
+**When it's used:** Every `Authorization: Bearer sk_mcpjam_…` request to `/api/v1/*` — validating servers, running the doctor, listing tools/prompts/resources, reading resources, exporting snapshots, and **saving `@mcpjam/sdk` eval results** (set `MCPJAM_API_KEY` to this key; see [Saving Results](/sdk/concepts/saving-results)).
🤖 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 19, The API key usage note still refers
to the old generic `Bearer sk_…` token format, which is inconsistent with the
updated `sk_mcpjam_…` wording elsewhere in this doc. Update the “When it’s used”
line in `api-keys.mdx` to use the same explicit `sk_mcpjam_…` format, keeping
the rest of the MCPJAM_API_KEY guidance unchanged.
mcpjam-inspector/server/routes/web/api-keys.ts (1)

85-116: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider reusing the shared CONVEX_HTTP_URL guard and distinguishing timeouts from unreachability.

Two small nits in callBackendApiKeys:

  1. The missing-CONVEX_HTTP_URL check (lines 85-92) duplicates getConvexHttpUrl() in oauth.ts almost verbatim — worth extracting to errors.ts alongside the newly-added statusToErrorCode, following the same pattern this PR just established.
  2. The catch block (106-116) maps every fetch failure — including an AbortError from the 30s AbortSignal.timeout — to 502 SERVER_UNREACHABLE. A timed-out backend and an unreachable one are different failure modes; distinguishing via error.name === "AbortError"ErrorCode.TIMEOUT (504) would give clients a more actionable signal, consistent with ErrorCode.TIMEOUT already existing for this purpose.
♻️ Proposed refactor sketch
+function getConvexHttpUrlOrThrow(): string {
+  const convexUrl = process.env.CONVEX_HTTP_URL;
+  if (!convexUrl) {
+    throw new WebRouteError(
+      500,
+      ErrorCode.INTERNAL_ERROR,
+      "Server missing CONVEX_HTTP_URL configuration",
+    );
+  }
+  return convexUrl;
+}
...
-  const convexUrl = process.env.CONVEX_HTTP_URL;
-  if (!convexUrl) {
-    throw new WebRouteError(
-      500,
-      ErrorCode.INTERNAL_ERROR,
-      "Server missing CONVEX_HTTP_URL configuration",
-    );
-  }
+  const convexUrl = getConvexHttpUrlOrThrow();
   const target = `${convexUrl}/web/api-keys${pathAndQuery}`;
   ...
   } catch (error) {
     logger.error("API key backend request failed", {
       method,
       error: error instanceof Error ? error.message : String(error),
     });
+    if (error instanceof Error && error.name === "AbortError") {
+      throw new WebRouteError(
+        504,
+        ErrorCode.TIMEOUT,
+        "Timed out reaching the MCPJam backend to manage API keys",
+      );
+    }
     throw new WebRouteError(
       502,
       ErrorCode.SERVER_UNREACHABLE,
       "Could not reach the MCPJam backend to manage API keys",
     );
   }
🤖 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 `@mcpjam-inspector/server/routes/web/api-keys.ts` around lines 85 - 116, The
`callBackendApiKeys` backend fetch error handling currently treats all failures
the same and duplicates the `CONVEX_HTTP_URL` guard. Reuse the shared
`getConvexHttpUrl` helper from `errors.ts` instead of inlining the environment
check, and update the `fetch` catch in `callBackendApiKeys` to distinguish
`AbortError` from other failures so timeouts map to `ErrorCode.TIMEOUT` with a
504 response while non-timeout failures remain `SERVER_UNREACHABLE`.
🤖 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.

Inline comments:
In `@mcpjam-inspector/server/middleware/bearer-auth.ts`:
- Around line 178-180: The error logging in bearer-auth’s validation catch block
is passing a plain object as the second argument, so the caught exception is not
being treated as the actual error by logger.error. Update the logger.error call
in the bearer-auth middleware to pass the caught error value itself as the
second argument, and move any structured metadata into the third context
argument so Sentry/Axiom receives the exception correctly.

In `@mcpjam-inspector/server/services/platform-api-key-validation.ts`:
- Around line 46-53: The platform API key validation fetch can hang
indefinitely, stalling `sk_mcpjam_...` auth requests. Update the `fetch` call in
`validatePlatformApiKey` to pass an `AbortSignal.timeout(...)` via the request
options so slow or dead backends are aborted. Keep the existing error handling
path in `bearer-auth.ts` unchanged, since it already handles the abort and
returns the current 500 response.

---

Nitpick comments:
In `@docs/reference/api-keys.mdx`:
- Line 19: The API key usage note still refers to the old generic `Bearer sk_…`
token format, which is inconsistent with the updated `sk_mcpjam_…` wording
elsewhere in this doc. Update the “When it’s used” line in `api-keys.mdx` to use
the same explicit `sk_mcpjam_…` format, keeping the rest of the MCPJAM_API_KEY
guidance unchanged.

In `@docs/reference/public-api.mdx`:
- Around line 106-108: Update the API key-management note in public-api.mdx to
use the new key prefix consistently. The stale “sk_…” reference in the sentence
about `403 FORBIDDEN` should be changed to match the updated `sk_mcpjam_…`
format already used earlier in the same document, keeping the wording aligned
around the API key-management behavior.

In `@mcpjam-inspector/server/routes/v1/__tests__/computer-environments.test.ts`:
- Around line 29-37: The platform API-key mock setup is duplicated across
multiple test files, so extract the repeated vi.mock for
platform-api-key-validation.js into a shared test helper and reuse it from
computer-environments.test.ts, harness.test.ts, hosts.test.ts, and
tunnels.test.ts. Keep the helper responsible for the same importOriginal plus
validatePlatformApiKey stub that resolves to null, and update each test file to
call the helper instead of inlining the mock block.

In `@mcpjam-inspector/server/routes/web/api-keys.ts`:
- Around line 85-116: The `callBackendApiKeys` backend fetch error handling
currently treats all failures the same and duplicates the `CONVEX_HTTP_URL`
guard. Reuse the shared `getConvexHttpUrl` helper from `errors.ts` instead of
inlining the environment check, and update the `fetch` catch in
`callBackendApiKeys` to distinguish `AbortError` from other failures so timeouts
map to `ErrorCode.TIMEOUT` with a 504 response while non-timeout failures remain
`SERVER_UNREACHABLE`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c326faa6-74d1-4953-88f4-28317ea5400e

📥 Commits

Reviewing files that changed from the base of the PR and between 1ed99fb and ea7cd01.

📒 Files selected for processing (21)
  • docs/reference/api-keys.mdx
  • docs/reference/public-api.mdx
  • mcpjam-inspector/server/middleware/__tests__/bearer-auth.test.ts
  • mcpjam-inspector/server/middleware/bearer-auth.ts
  • mcpjam-inspector/server/middleware/request-local.ts
  • mcpjam-inspector/server/routes/v1/__tests__/computer-environments.test.ts
  • mcpjam-inspector/server/routes/v1/__tests__/harness.test.ts
  • mcpjam-inspector/server/routes/v1/__tests__/hosts.test.ts
  • mcpjam-inspector/server/routes/v1/__tests__/tunnels.test.ts
  • mcpjam-inspector/server/routes/v1/__tests__/write-routes.test.ts
  • mcpjam-inspector/server/routes/web/__tests__/api-keys.test.ts
  • mcpjam-inspector/server/routes/web/api-keys.ts
  • mcpjam-inspector/server/routes/web/errors.ts
  • mcpjam-inspector/server/routes/web/oauth.ts
  • mcpjam-inspector/server/services/__tests__/identity.test.ts
  • mcpjam-inspector/server/services/__tests__/platform-api-key-validation.test.ts
  • mcpjam-inspector/server/services/identity.ts
  • mcpjam-inspector/server/services/platform-api-key-validation.ts
  • mcpjam-inspector/server/services/workos-client.ts
  • mcpjam-inspector/server/services/workos-key-bindings.ts
  • mcpjam-inspector/server/types/hono.ts
💤 Files with no reviewable changes (4)
  • mcpjam-inspector/server/services/tests/identity.test.ts
  • mcpjam-inspector/server/services/workos-client.ts
  • mcpjam-inspector/server/services/identity.ts
  • mcpjam-inspector/server/services/workos-key-bindings.ts

Comment on lines +178 to 180
logger.error("Platform API key validation failed", {
error: error instanceof Error ? error.message : String(error),
});

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
ast-grep run --pattern 'error($_, $_, $_) { $$$ }' --lang typescript mcpjam-inspector/server/utils/logger.ts
rg -nP 'logger\.error\(' mcpjam-inspector/server -A2

Repository: MCPJam/inspector

Length of output: 31834


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the logger implementation and its tests for parameter order/serialization.
sed -n '1,260p' mcpjam-inspector/server/utils/logger.ts
printf '\n--- TESTS ---\n'
sed -n '1,180p' mcpjam-inspector/server/utils/__tests__/logger.test.ts

Repository: MCPJam/inspector

Length of output: 10986


Pass the caught error as the second logger argument
logger.error(message, error?, context?) treats the second slot as the exception, so { error: ... } lands as a plain object in Sentry/Axiom. Forward the caught value as error and keep structured fields in the third argument.

🤖 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 `@mcpjam-inspector/server/middleware/bearer-auth.ts` around lines 178 - 180,
The error logging in bearer-auth’s validation catch block is passing a plain
object as the second argument, so the caught exception is not being treated as
the actual error by logger.error. Update the logger.error call in the
bearer-auth middleware to pass the caught error value itself as the second
argument, and move any structured metadata into the third context argument so
Sentry/Axiom receives the exception correctly.

Comment thread mcpjam-inspector/server/services/platform-api-key-validation.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

4 issues found across 21 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="mcpjam-inspector/server/routes/web/errors.ts">

<violation number="1" location="mcpjam-inspector/server/routes/web/errors.ts:156">
P3: HTTP 503 (Service Unavailable) isn't mapped and falls through to `INTERNAL_ERROR`. If an upstream provider returns 503 during a transient outage, the frontend will surface a generic internal error rather than an unreachable-server message. Consider adding `if (status === 503) return ErrorCode.SERVER_UNREACHABLE;` since the semantics align with the existing 502 path.</violation>

<violation number="2" location="mcpjam-inspector/server/routes/web/errors.ts:156">
P2: A private `statusToErrorCode` with identical logic already exists in `server/utils/server-secrets.ts`. Since that file already imports from `./errors.js`, it can import `statusToErrorCode` from the shared module instead — removing the private copy keeps one source of truth for the mapping.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread mcpjam-inspector/server/middleware/bearer-auth.ts
Comment thread mcpjam-inspector/server/services/platform-api-key-validation.ts
* Map an upstream HTTP status onto the matching web ErrorCode when relaying a
* backend/provider error. Shared by the OAuth proxy and API key routes.
*/
export function statusToErrorCode(status: number): ErrorCode {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: A private statusToErrorCode with identical logic already exists in server/utils/server-secrets.ts. Since that file already imports from ./errors.js, it can import statusToErrorCode from the shared module instead — removing the private copy keeps one source of truth for the mapping.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mcpjam-inspector/server/routes/web/errors.ts, line 156:

<comment>A private `statusToErrorCode` with identical logic already exists in `server/utils/server-secrets.ts`. Since that file already imports from `./errors.js`, it can import `statusToErrorCode` from the shared module instead — removing the private copy keeps one source of truth for the mapping.</comment>

<file context>
@@ -149,6 +149,21 @@ export function assertBearerToken(c: any): string {
+ * Map an upstream HTTP status onto the matching web ErrorCode when relaying a
+ * backend/provider error. Shared by the OAuth proxy and API key routes.
+ */
+export function statusToErrorCode(status: number): ErrorCode {
+  if (status === 400) return ErrorCode.VALIDATION_ERROR;
+  if (status === 401) return ErrorCode.UNAUTHORIZED;
</file context>

@@ -149,6 +149,21 @@ export function assertBearerToken(c: any): string {
return authHeader.slice("Bearer ".length);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: HTTP 503 (Service Unavailable) isn't mapped and falls through to INTERNAL_ERROR. If an upstream provider returns 503 during a transient outage, the frontend will surface a generic internal error rather than an unreachable-server message. Consider adding if (status === 503) return ErrorCode.SERVER_UNREACHABLE; since the semantics align with the existing 502 path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mcpjam-inspector/server/routes/web/errors.ts, line 156:

<comment>HTTP 503 (Service Unavailable) isn't mapped and falls through to `INTERNAL_ERROR`. If an upstream provider returns 503 during a transient outage, the frontend will surface a generic internal error rather than an unreachable-server message. Consider adding `if (status === 503) return ErrorCode.SERVER_UNREACHABLE;` since the semantics align with the existing 502 path.</comment>

<file context>
@@ -149,6 +149,21 @@ export function assertBearerToken(c: any): string {
+ * Map an upstream HTTP status onto the matching web ErrorCode when relaying a
+ * backend/provider error. Shared by the OAuth proxy and API key routes.
+ */
+export function statusToErrorCode(status: number): ErrorCode {
+  if (status === 400) return ErrorCode.VALIDATION_ERROR;
+  if (status === 401) return ErrorCode.UNAUTHORIZED;
</file context>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="mcpjam-inspector/server/routes/web/errors.ts">

<violation number="1" location="mcpjam-inspector/server/routes/web/errors.ts:156">
P3: HTTP 503 (Service Unavailable) isn't mapped and falls through to `INTERNAL_ERROR`. If an upstream provider returns 503 during a transient outage, the frontend will surface a generic internal error rather than an unreachable-server message. Consider adding `if (status === 503) return ErrorCode.SERVER_UNREACHABLE;` since the semantics align with the existing 502 path.</violation>

<violation number="2" location="mcpjam-inspector/server/routes/web/errors.ts:156">
P2: A private `statusToErrorCode` with identical logic already exists in `server/utils/server-secrets.ts`. Since that file already imports from `./errors.js`, it can import `statusToErrorCode` from the shared module instead — removing the private copy keeps one source of truth for the mapping.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread mcpjam-inspector/server/middleware/bearer-auth.ts Outdated
Comment thread mcpjam-inspector/server/middleware/bearer-auth.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants