Skip to content

fix(harness): sweep remaining PR #2996 review findings (COMP-10)#3041

Open
ignaciojimenezr wants to merge 1 commit into
mainfrom
fix/comp10-2996-review-findings
Open

fix(harness): sweep remaining PR #2996 review findings (COMP-10)#3041
ignaciojimenezr wants to merge 1 commit into
mainfrom
fix/comp10-2996-review-findings

Conversation

@ignaciojimenezr

@ignaciojimenezr ignaciojimenezr commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator
  • Garbage or malformed JSON-RPC sent to the harness proxy routes (hosted harness-mcp and local adapter-http) now gets a proper JSON-RPC error (-32700 / -32600) instead of a 202 that made dropped messages look delivered. Covered by tests on both routes; real notifications still 202.
  • Fixed the hosted-send preflight races: resolved server ids now travel with the exact server-name snapshot they were resolved from (a selection change mid-preflight can no longer pair stale ids with fresh names), and the send button no longer deadlocks for ad-hoc/App servers that only get ids once the preflight runs. Race reproduced in a test.
  • A tool-approval request on a turn with no resumable continuity lane now fails closed instead of showing the user an approval prompt that can never resume.
  • Hardened the small stuff from the same review: isPubliclyReachableUrl no longer treats fc*/fd* hostnames as private and judges IPv4-mapped IPv6 by the embedded IPv4; the proxy-token client validates Convex payloads strictly, keeps config errors on its result contract, and accepts any bearer-scheme casing; upload failures mid-batch report which files landed; the auto-typed ls after upload quotes the path; the harness workdir validator requires a trimmed absolute path.
  • Cleanup: one shared scoped tunnel-ensure flow for both planes, dead skills option and dead HarnessMcpConfigError removed, reset-reason set typed with its union, test env-var swap wrapped in try/finally.

Disposition of all 22 cubic findings on #2996 (verified against current main):

Finding Disposition
harness-proxy-strategy cleartext-HTTP direct mode already fixed (#2998)
token expiry > vs >= already fixed (#2998)
web-body-limit non-POST carve-out already fixed (#2998)
computer-upload ?token= auth already fixed (#2998); full query-fallback removal tracked in COMP-2
Electron server missing upload route deferred to COMP-8 (own task)
harness-mcp 202 on garbage JSON-RPC fixed here (+ same guard on adapter-http streamable POST; SSE /messages keeps 202 per SSE transport semantics)
use-chat-session ids/names preflight race fixed here
PlaygroundMain preflight unreachable (submit blocked) fixed here (gate lives in use-chat-session)
approval pause without continuity lane fixed here
localhost-check fc/fd hostname false-positive fixed here
localhost-check IPv4-mapped bypass fixed here
token-client: tokens typeof check / URL-construction throw / bearer normalization fixed here (3 findings)
computer-upload partial-batch reporting fixed here
ComputerTerminal unquoted ls path fixed here
harness-session workdir validator fixed here
reset-reason set typed as string fixed here
dead skills option fixed here (removed)
dead HarnessMcpConfigError fixed here (removed)
duplicated tunnel-ensure flow fixed here
proxy-token test env-var restore fixed here

Verification: full vitest run green (7647 passed, 0 failed), typecheck:client green, server tsc errors unchanged from main's baseline.

🤖 Generated with Claude Code


Summary by cubic

Fixes the remaining findings from PR #2996 for COMP-10, improving reliability of harness JSON-RPC handling, hosted preflight selection, and upload reporting.

  • Bug Fixes

    • harness-mcp and adapter-http: malformed JSON-RPC now returns -32700/-32600 (not 202); real notifications still 202.
    • use-chat-session: preflight-resolved server ids are tied to the names snapshot; submit isn’t blocked when ensureServerIds is provided.
    • Tool approval now fails closed when no resumable continuity lane exists.
    • Uploads: partial failures report written files and failedAt; ComputerTerminal auto-typed ls now quotes the path.
    • isPubliclyReachableUrl: treat fc*/fd* only for IPv6 literals; judge IPv4-mapped IPv6 by the embedded IPv4.
    • harness-proxy-token-client: strict Convex payload validation; endpoint-config errors returned on the result; case-insensitive bearer handling.
    • shared/harness-session: require trimmed absolute workdir; reset-reason uses its union type.
  • Refactors

    • Unified tunnel ensure flow for both scopes (ensureServerTunnel, ensureHarnessWebTunnel); removed dead skills option and HarnessMcpConfigError; minor test cleanup.

Written for commit 2e392cc. Summary will update on new commits.

Review in cubic

Dispositions for all 22 cubic findings on #2996, verified against current
main (4 were already fixed by #2998; Electron upload 404 is COMP-8 and the
?token= fallback removal is COMP-2):

- harness-mcp + adapter-http (streamable POST): malformed JSON-RPC now gets
  -32700/-32600 instead of a 202 that fakes delivery (SSE /messages keeps
  202 per SSE transport semantics)
- use-chat-session: preflight-resolved server ids now ride with the names
  snapshot they were resolved from (mid-preflight selection change race);
  submit no longer deadlocks for ad-hoc/App servers when a send-time
  resolver exists
- run-harness-turn: fail closed on tool-approval-request without a
  continuity lane (was an unresumable pause)
- localhost-check: fc/fd ULA prefixes only for IPv6 literals; IPv4-mapped
  addresses judged by the embedded IPv4 (dotted + URL-normalized hex forms)
- harness-proxy-token-client: tokens payload validated as a string record;
  endpoint-config errors stay on the result contract; bearer scheme
  normalized case-insensitively
- computer-upload: mid-batch write failure reports written files + failedAt
- ComputerTerminal: quote the upload dir in the auto-typed ls
- shared/harness-session: workdir must be a trimmed absolute path;
  reset-reason set typed with the union
- ensure-server-tunnel: one shared scoped ensure flow for both planes
- mcpjam-stream-handler: drop dead `skills` option; mcp-config: drop dead
  HarnessMcpConfigError; proxy-token test: env swap in try/finally

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@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 size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Jul 7, 2026
@chelojimenez

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

Copy link
Copy Markdown
Contributor

Internal preview

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

@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 18 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/mcp/http-adapters.ts">

<violation number="1" location="mcpjam-inspector/server/routes/mcp/http-adapters.ts:343">
P2: Valid JSON-RPC batch requests to adapter-http/manager-http now fail with `-32600` because the new validation rejects every top-level array. If these routes need JSON-RPC 2.0 compatibility beyond single requests, this should distinguish malformed arrays from batches and process each request element.</violation>
</file>

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

<violation number="1" location="mcpjam-inspector/server/routes/web/harness-mcp.ts:151">
P2: Malformed JSON-RPC without `jsonrpc: "2.0"` can still be accepted or forwarded. Since this gate is meant to stop invalid JSON-RPC before the notification `202` path, it should also require the JSON-RPC version field.</violation>

<violation number="2" location="mcpjam-inspector/server/routes/web/harness-mcp.ts:154">
P2: Invalid-request responses can echo an invalid `id` value such as an object or array. Normalizing non-string/non-number/non-null ids to `null` keeps the error response valid JSON-RPC and easier for clients to parse.</violation>
</file>

<file name="mcpjam-inspector/server/utils/localhost-check.ts">

<violation number="1" location="mcpjam-inspector/server/utils/localhost-check.ts:46">
P2: Link-local IPv6 URLs such as `http://[fe90::1]` are still treated as publicly reachable, so hosted URL strategy can choose direct access for a non-routable address. The link-local check should cover the full `fe80::/10` range, not only addresses whose first hextet is exactly `fe80`.</violation>
</file>

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

Re-trigger cubic

if (
!body ||
typeof body !== "object" ||
Array.isArray(body) ||

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: Valid JSON-RPC batch requests to adapter-http/manager-http now fail with -32600 because the new validation rejects every top-level array. If these routes need JSON-RPC 2.0 compatibility beyond single requests, this should distinguish malformed arrays from batches and process each request element.

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

<comment>Valid JSON-RPC batch requests to adapter-http/manager-http now fail with `-32600` because the new validation rejects every top-level array. If these routes need JSON-RPC 2.0 compatibility beyond single requests, this should distinguish malformed arrays from batches and process each request element.</comment>

<file context>
@@ -321,11 +321,42 @@ function createHttpHandler(mode: BridgeMode, routePrefix: string) {
+    if (
+      !body ||
+      typeof body !== "object" ||
+      Array.isArray(body) ||
+      typeof body.method !== "string" ||
+      body.method.length === 0
</file context>

Comment on lines +154 to +157
const id =
body && typeof body === "object" && !Array.isArray(body)
? (body.id ?? null)
: null;

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: Invalid-request responses can echo an invalid id value such as an object or array. Normalizing non-string/non-number/non-null ids to null keeps the error response valid JSON-RPC and easier for clients to parse.

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/harness-mcp.ts, line 154:

<comment>Invalid-request responses can echo an invalid `id` value such as an object or array. Normalizing non-string/non-number/non-null ids to `null` keeps the error response valid JSON-RPC and easier for clients to parse.</comment>

<file context>
@@ -128,11 +128,41 @@ async function handle(c: any) {
+    typeof body.method !== "string" ||
+    body.method.length === 0
+  ) {
+    const id =
+      body && typeof body === "object" && !Array.isArray(body)
+        ? (body.id ?? null)
</file context>
Suggested change
const id =
body && typeof body === "object" && !Array.isArray(body)
? (body.id ?? null)
: null;
const rawId =
body && typeof body === "object" && !Array.isArray(body)
? (body.id ?? null)
: null;
const id =
typeof rawId === "string" || typeof rawId === "number" || rawId === null
? rawId
: null;

Comment on lines +151 to +152
typeof body.method !== "string" ||
body.method.length === 0

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: Malformed JSON-RPC without jsonrpc: "2.0" can still be accepted or forwarded. Since this gate is meant to stop invalid JSON-RPC before the notification 202 path, it should also require the JSON-RPC version field.

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/harness-mcp.ts, line 151:

<comment>Malformed JSON-RPC without `jsonrpc: "2.0"` can still be accepted or forwarded. Since this gate is meant to stop invalid JSON-RPC before the notification `202` path, it should also require the JSON-RPC version field.</comment>

<file context>
@@ -128,11 +128,41 @@ async function handle(c: any) {
+    !body ||
+    typeof body !== "object" ||
+    Array.isArray(body) ||
+    typeof body.method !== "string" ||
+    body.method.length === 0
+  ) {
</file context>
Suggested change
typeof body.method !== "string" ||
body.method.length === 0
body.jsonrpc !== "2.0" ||
typeof body.method !== "string" ||
body.method.length === 0

if (h.includes(":")) {
// IPv6 literal (a hostname like "fc.example.com" must NOT hit these).
if (h === "::1" || h === "::") return false;
if (h.startsWith("fe80:") || h.startsWith("fc") || h.startsWith("fd")) {

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: Link-local IPv6 URLs such as http://[fe90::1] are still treated as publicly reachable, so hosted URL strategy can choose direct access for a non-routable address. The link-local check should cover the full fe80::/10 range, not only addresses whose first hextet is exactly fe80.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mcpjam-inspector/server/utils/localhost-check.ts, line 46:

<comment>Link-local IPv6 URLs such as `http://[fe90::1]` are still treated as publicly reachable, so hosted URL strategy can choose direct access for a non-routable address. The link-local check should cover the full `fe80::/10` range, not only addresses whose first hextet is exactly `fe80`.</comment>

<file context>
@@ -39,10 +39,38 @@ export function isPubliclyReachableUrl(raw: string): boolean {
+  if (h.includes(":")) {
+    // IPv6 literal (a hostname like "fc.example.com" must NOT hit these).
+    if (h === "::1" || h === "::") return false;
+    if (h.startsWith("fe80:") || h.startsWith("fc") || h.startsWith("fd")) {
+      return false; // link-local / unique-local
+    }
</file context>
Suggested change
if (h.startsWith("fe80:") || h.startsWith("fc") || h.startsWith("fd")) {
if (/^fe[89ab][0-9a-f]:/.test(h) || h.startsWith("fc") || h.startsWith("fd")) {

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

This PR tightens JSON-RPC request validation on both the adapter-http and harness-mcp routes, returning proper -32700/-32600 error responses instead of treating malformed bodies as notifications. It refines hosted chat session logic to pair resolved server IDs with the exact server names used during resolution, preventing stale mismatches during async preflight races. Network security is hardened via stricter IPv6/IPv4-mapped address filtering, a unified scoped tunnel-provisioning helper, and stronger harness proxy token payload/URL validation. Additional changes include quoting terminal directory paths against shell injection, a fail-closed guard for unresumable tool-approval requests, stricter harness session data-part validation, richer computer-upload failure responses, and removal of unused exports (HarnessMcpConfigError, skills option). Extensive new tests accompany each area.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant HttpAdapterRoute
  participant HarnessMcpRoute
  Client->>HttpAdapterRoute: POST JSON-RPC body
  HttpAdapterRoute->>HttpAdapterRoute: parse and validate
  alt malformed JSON
    HttpAdapterRoute-->>Client: 400, error -32700
  else invalid structure
    HttpAdapterRoute-->>Client: 400, error -32600
  else notification
    HttpAdapterRoute-->>Client: 202 Accepted
  end
  Client->>HarnessMcpRoute: POST JSON-RPC body
  HarnessMcpRoute->>HarnessMcpRoute: parse and validate
  alt malformed JSON
    HarnessMcpRoute-->>Client: 400, error -32700
  else invalid structure
    HarnessMcpRoute-->>Client: 400, error -32600
  else notification
    HarnessMcpRoute-->>Client: 202 Accepted
  end
Loading

Compact metadata

Related issues: None found.
Related PRs: None found.

Suggested labels: security, bug, tests, server, client

Suggested reviewers: None specified.

Poem
A rabbit checks each byte with care,
-32700 when bodies tear,
IDs and names now travel paired,
IPv6 masks no longer spared,
Through tunnels shared, one path we build—
strict little checks, and bugs are stilled. 🐇

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/computer/ComputerTerminal.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/client/src/hooks/__tests__/use-chat-session.hosted.test.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/client/src/hooks/use-chat-session.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)

  • 13 others

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: 1

🤖 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/routes/mcp/http-adapters.ts`:
- Around line 324-359: The JSON-RPC parse/validation block in the HTTP route is
duplicated and should be centralized. Move the shared `c.req.json()` parsing
plus `-32700`/`-32600` response construction into a helper in
`services/mcp-http-bridge` such as `parseAndValidateJsonRpc(rawRequest)`, and
have both `http-adapters.ts` and `harness-mcp.ts` call it and short-circuit on
an error result. Keep the helper responsible for returning either the validated
body or a ready-made response tuple so the `handleMcp`/route code stays
consistent and correctness-critical error handling does not drift.
🪄 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: 48834ffe-7a6e-41c7-bad9-80c2631d1a10

📥 Commits

Reviewing files that changed from the base of the PR and between 2baa8c5 and 2e392cc.

📒 Files selected for processing (18)
  • mcpjam-inspector/client/src/components/computer/ComputerTerminal.tsx
  • mcpjam-inspector/client/src/hooks/__tests__/use-chat-session.hosted.test.tsx
  • mcpjam-inspector/client/src/hooks/use-chat-session.ts
  • mcpjam-inspector/server/routes/mcp/__tests__/http-adapters.streamable-http.test.ts
  • mcpjam-inspector/server/routes/mcp/http-adapters.ts
  • mcpjam-inspector/server/routes/web/__tests__/harness-mcp.test.ts
  • mcpjam-inspector/server/routes/web/computer-upload.ts
  • mcpjam-inspector/server/routes/web/harness-mcp.ts
  • mcpjam-inspector/server/services/ensure-server-tunnel.ts
  • mcpjam-inspector/server/utils/harness/__tests__/harness-proxy-strategy.test.ts
  • mcpjam-inspector/server/utils/harness/__tests__/harness-proxy-token.test.ts
  • mcpjam-inspector/server/utils/harness/harness-proxy-token-client.ts
  • mcpjam-inspector/server/utils/harness/mcp-config.ts
  • mcpjam-inspector/server/utils/harness/run-harness-turn.ts
  • mcpjam-inspector/server/utils/localhost-check.ts
  • mcpjam-inspector/server/utils/mcpjam-stream-handler.ts
  • mcpjam-inspector/shared/__tests__/harness-session.test.ts
  • mcpjam-inspector/shared/harness-session.ts
💤 Files with no reviewable changes (2)
  • mcpjam-inspector/server/utils/harness/mcp-config.ts
  • mcpjam-inspector/server/utils/mcpjam-stream-handler.ts

Comment on lines +324 to +359
// Malformed payloads must NOT fall through to the notification → 202 path
// (the bridge treats a missing method as a notification): a garbage body
// acknowledged as "Accepted" looks like a delivered message to the client.
let body: any = undefined;
try {
body = await c.req.json();
} catch {}
} catch {
return c.json(
{
jsonrpc: "2.0",
id: null,
error: { code: -32700, message: "Parse error" },
},
400
);
}
if (
!body ||
typeof body !== "object" ||
Array.isArray(body) ||
typeof body.method !== "string" ||
body.method.length === 0
) {
const id =
body && typeof body === "object" && !Array.isArray(body)
? (body.id ?? null)
: null;
return c.json(
{
jsonrpc: "2.0",
id,
error: { code: -32600, message: "Invalid Request" },
},
400
);
}

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Extract shared JSON-RPC parse/validate logic.

This block is duplicated verbatim in harness-mcp.ts (lines 131-166). Both files already import from ../../services/mcp-http-bridge, which is a natural home for a parseAndValidateJsonRpc(rawRequest) helper returning either a parsed body or a ready-made {status, response} error tuple. Keeping this correctness-critical error-code logic (-32700/-32600) in one place avoids future drift between the two routes.

♻️ Sketch of a shared helper
+// services/mcp-http-bridge.ts
+export async function parseAndValidateJsonRpcBody(
+  req: { json(): Promise<any> }
+): Promise<{ ok: true; body: any } | { ok: false; status: number; response: any }> {
+  let body: any;
+  try {
+    body = await req.json();
+  } catch {
+    return {
+      ok: false,
+      status: 400,
+      response: { jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } },
+    };
+  }
+  if (
+    !body ||
+    typeof body !== "object" ||
+    Array.isArray(body) ||
+    typeof body.method !== "string" ||
+    body.method.length === 0
+  ) {
+    const id = body && typeof body === "object" && !Array.isArray(body) ? (body.id ?? null) : null;
+    return {
+      ok: false,
+      status: 400,
+      response: { jsonrpc: "2.0", id, error: { code: -32600, message: "Invalid Request" } },
+    };
+  }
+  return { ok: true, body };
+}

Then both routes call this helper and short-circuit on !result.ok.

🤖 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/mcp/http-adapters.ts` around lines 324 - 359,
The JSON-RPC parse/validation block in the HTTP route is duplicated and should
be centralized. Move the shared `c.req.json()` parsing plus `-32700`/`-32600`
response construction into a helper in `services/mcp-http-bridge` such as
`parseAndValidateJsonRpc(rawRequest)`, and have both `http-adapters.ts` and
`harness-mcp.ts` call it and short-circuit on an error result. Keep the helper
responsible for returning either the validated body or a ready-made response
tuple so the `handleMcp`/route code stays consistent and correctness-critical
error handling does not drift.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants