Skip to content

fix(claw-server): admit Electron-based MCP clients past the /mcp hygiene filter - #2536

Closed
Dani Akash (DaniAkash) wants to merge 1 commit into
mainfrom
fix/mcp-sec-fetch-electron-clients
Closed

fix(claw-server): admit Electron-based MCP clients past the /mcp hygiene filter#2536
Dani Akash (DaniAkash) wants to merge 1 commit into
mainfrom
fix/mcp-sec-fetch-electron-clients

Conversation

@DaniAkash

Copy link
Copy Markdown
Contributor

What

The loopback /mcp hygiene filter rejected any request carrying a Sec-Fetch-* header (403 {"error":"unsupported request"}). Chromium/Electron-based desktop MCP clients such as Cherry Studio attach browser-default Fetch Metadata to every outgoing request and cannot strip it, so they could not connect at all.

This drops the Sec-Fetch-* presence check and keeps the Origin rejection.

Why this is safe

The filter exists to reject requests originating from a webpage, so a page the user visits cannot drive their browser through the loopback MCP endpoint. Sec-Fetch-* presence does not identify a webpage; only Origin does:

  • An MCP call is a POST with Content-Type: application/json. That is never a CORS "simple request", so any webpage capable of making one always sends Origin, which stays rejected.
  • The existing application/json content-type gate continues to cover the origin-less page vectors (navigations, no-cors simple requests), none of which can carry a JSON-RPC body.
  • The remote-peer control (LAN callers) is a separate layer and is unchanged.

This restores parity with the previous MCP server, which accepted Sec-Fetch-* and rejected Origin, and which these clients connect to natively.

Tests

  • mcp_hygiene_rejects_browser_originated_requests: Origin still returns 403.
  • mcp_hygiene_admits_electron_sec_fetch_clients (new): an initialize POST carrying Sec-Fetch-Site/Mode/Dest and no Origin reaches the service and returns 200 with a session id.
  • mcp_hygiene_rejects_non_json_writes: unchanged.

Reported behavior and reproduction in #2458.

Fixes #2458

…ene filter

The loopback /mcp hygiene filter rejected any request carrying a
`Sec-Fetch-*` header. Chromium/Electron-based desktop MCP clients (e.g.
Cherry Studio) attach browser-default Fetch Metadata to every outgoing
request and cannot strip it, so they were blocked with
403 "unsupported request".

`Sec-Fetch-*` presence does not identify a webpage: only `Origin` does.
An MCP call is a POST with `application/json`, which is never a CORS
simple request, so any page capable of making one always carries
`Origin`, which stays rejected. The content-type gate continues to cover
the origin-less page vectors. Drop the `Sec-Fetch-*` presence check and
keep the `Origin` rejection.

Fixes #2458
@github-actions github-actions Bot added the fix label Sep 3, 2026
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR changes the Rust loopback MCP hygiene filter to admit Electron clients that attach Fetch Metadata while retaining Origin and JSON content-type checks.

  • Removes rejection based solely on Sec-Fetch-Site.
  • Adds a Rust route test proving an Electron-shaped initialize request succeeds.
  • Leaves a shared transport-contract assertion expecting cross-site Fetch Metadata to be rejected, so the affected contract suite is inconsistent with the new policy.

Confidence Score: 4/5

The policy change appears defensible, but the shared MCP transport contract must be updated with it before merging to avoid a failing affected test suite.

The Rust middleware now admits a request that the repository’s claw-mcp contract explicitly requires to return 403, creating a deterministic conformance-test failure.

Files Needing Attention: packages/browseros-agent/apps/claw-server-rust/src/api/http/mod.rs; packages/browseros-agent/contracts/claw-mcp/tests/cases-transport.ts

Important Files Changed

Filename Overview
packages/browseros-agent/apps/claw-server-rust/src/api/http/mod.rs Relaxes MCP request hygiene as intended, but now conflicts with the shared claw-mcp transport contract.
packages/browseros-agent/apps/claw-server-rust/tests/routes.rs Replaces the old Sec-Fetch rejection coverage with a focused Electron-client admission test while preserving Origin and non-JSON rejection tests.
Prompt To Fix All With AI
### Issue 1
packages/browseros-agent/apps/claw-server-rust/src/api/http/mod.rs:139
**Transport contract rejects admitted requests**

When the claw-mcp contract suite sends its JSON request with `Sec-Fetch-Site: cross-site` and no `Origin`, this middleware now admits it even though the shared transport contract requires a 403, causing the affected conformance suite to fail.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(claw-server): admit Electron-based M..." | Re-trigger Greptile

Comment thread packages/browseros-agent/apps/claw-server-rust/src/api/http/mod.rs
@DaniAkash

Copy link
Copy Markdown
Contributor Author

Closing: the Sec-Fetch-Site rejection here is a deliberate DNS-rebinding/CSRF defense mirrored across both MCP servers and enforced by the shared transport contract, and Electron-based clients are indistinguishable from browser attacks by that header, so this endpoint filter cannot be safely relaxed.

@DaniAkash
Dani Akash (DaniAkash) deleted the fix/mcp-sec-fetch-electron-clients branch September 3, 2026 04:27
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

❌ Tests failed: 13/756 failed

Ran 3 of 16 suites (13 not affected by this change).

Suite Passed Failed Skipped
server-agent n/a n/a not affected
server-api n/a n/a not affected
server-tools n/a n/a not affected
server-browser n/a n/a not affected
server-integration n/a n/a not affected
server-lib n/a n/a not affected
server-root n/a n/a not affected
agent n/a n/a not affected
claw-app n/a n/a not affected
claw-onboard n/a n/a not affected
app-onboard n/a n/a not affected
build n/a n/a not affected
release n/a n/a not affected
claw-server-rust 647/647 0 0
claw-server-rust-quality passed 0 0
claw-mcp 96/109 13 0

passed = ran successfully but emits no JUnit counts (a lint/format gate).

Failed tests
  • claw-mcp Rust /mcp conformance > transport: browser-shaped requests are rejected with 403
  • claw-mcp Rust /mcp conformance > navigate: reload resets in-page state
  • claw-mcp Rust /mcp conformance > snapshot concurrency: cursor refs remain actionable
  • claw-mcp Rust /mcp conformance > act: click_at hits page coordinates
  • claw-mcp Rust /mcp conformance > act: type enters text into a field
  • claw-mcp Rust /mcp conformance > act: type_at enters text at coordinates
  • claw-mcp Rust /mcp conformance > act: fill sets a single field
  • claw-mcp Rust /mcp conformance > act: fill sets a whole form via fields[] in one call
  • claw-mcp Rust /mcp conformance > act: press Enter submits the form
  • claw-mcp Rust /mcp conformance > act: click toggles a checkbox and is repeatable
  • claw-mcp Rust /mcp conformance > act: check and uncheck kinds set checkbox state
  • claw-mcp Rust /mcp conformance > run: SDK end-to-end pages.list -> snapshot -> click -> return
  • claw-mcp Rust /mcp conformance > download: file lands on disk and its path is reported

View workflow run

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

neo MCP endpoint rejects Electron-based MCP clients (e.g., Cherry Studio) — Sec-Fetch-* headers trigger 403 "unsupported request"

1 participant