Skip to content

Make MCP server browser-portable with a Web-standard handler#136

Merged
martin-fleck-at merged 2 commits into
mainfrom
issues/1546
May 19, 2026
Merged

Make MCP server browser-portable with a Web-standard handler#136
martin-fleck-at merged 2 commits into
mainfrom
issues/1546

Conversation

@martin-fleck-at
Copy link
Copy Markdown
Contributor

@martin-fleck-at martin-fleck-at commented May 18, 2026

What it does

Replace the Hono-only Node handler with a Fetch-API handler that runs on Node, Bun, Deno, Cloudflare Workers, and in-page Web Workers. Restructure @eclipse-glsp/server-mcp into a browser/common/node split mirroring @eclipse-glsp/server.

  • New browser entry point with a Web Worker integration helper.
  • VS Code web-extension bundle no longer transitively pulls Node-only deps.
  • Mutating tools report dispatched-command counts for cross-call undo / redo.
  • Port-agnostic Host-header validation — matches the SDK's older Express middleware that the Fetch transport regressed.
  • Workflow example ships an end-to-end browser demo of the portable handler.
  • Non-loopback auth and shared session state remain adopter responsibility.
  • ARCHITECTURE.md refreshed for the portable handler and for the IDE integrations that now register the GLSP MCP server with the host IDE.

Part of eclipse-glsp/glsp#1546

How to test

  • Everything should work as before in our classic cases.
  • Try the browser entry in the bundled browser server test app.

Follow-ups

Changelog

  • This PR should be mentioned in the changelog
  • This PR introduces a breaking change (if yes, provide more details below for the changelog and the migration guide)

@martin-fleck-at martin-fleck-at requested a review from tortmayr May 18, 2026 19:08
Replace the Hono-only Node handler with a Fetch-API handler that runs on
Node, Bun, Deno, Cloudflare Workers, and in-page Web Workers. Restructure
@eclipse-glsp/server-mcp into a browser/common/node split mirroring
@eclipse-glsp/server.

- New browser entry point with a Web Worker integration helper.
- VS Code web-extension bundle no longer transitively pulls Node-only deps.
- Mutating tools report dispatched-command counts for cross-call
  undo / redo.
- Port-agnostic Host-header validation — matches the SDK's older
  Express middleware that the Fetch transport regressed.
- Workflow example ships an end-to-end browser demo of the portable
  handler in its own private `workflow-server-mcp-demo` workspace;
  `workflow-server-bundled-web` stays narrow and ships only the worker
  bundle. The Service Worker scaffolding lives with the demo, not as a
  published asset of `@eclipse-glsp/server-mcp`.
- Root `start:mcp-demo` script builds the worker bundle and launches
  the demo in one step.
- Non-loopback auth and shared session state remain adopter responsibility.
- ARCHITECTURE.md refreshed for the portable handler and for the IDE
  integrations that now register the GLSP MCP server with the host IDE.

Part of eclipse-glsp/glsp#1546
Copy link
Copy Markdown
Contributor

@tortmayr tortmayr left a comment

Choose a reason for hiding this comment

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

Changes look good to me.
Clean split into browser/node entrypoints.
And the MCP browser demo is very nice 👍🏼

export async function launch(argv?: string[]): Promise<void> {
export async function launch(_argv?: string[]): Promise<void> {
// Bridge must be created before any await so postMessages that arrive on the next event-loop
// tick aren't dropped. Requests pile up on the bridge's internal `launcherReady` until the
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.

Keep concise. First sentence is enough

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call, trimmed to the first sentence.


```bash
yarn workspace @eclipse-glsp-examples/workflow-server build
yarn workspace @eclipse-glsp-examples/workflow-server-mcp-demo start
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.

yarn start:mcp-demo should be fine here right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yep, switched to yarn start:mcp-demo. Thanks!


/**
* Browser-compatible {@link McpRequestContext}. Single mutable slot — concurrent requests on
* the same session overwrite each other's frame. Hosts must serialise handler chains.
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.

The comment says "hosts must serialise
handler chains" and the McpWorkerBridge does this via dispatchChain. This is correct but fragile — if an adopter uses
BrowserMcpServerModule directly without the bridge's serialization, concurrent requests will silently corrupt the context.
Consider logging a warning or documenting this more prominently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point. Added a one-shot console.warn when run() is entered while another context is still active, and expanded the doc comment to point adopters at McpWorkerBridge (or an equivalent queue around launcher.handleRequest) so the fix is obvious from the warning as well.

status: response.status,
statusText: response.statusText,
headers,
body: response.body
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.

The type says ReadableStream | null
and it's passed as a Transferable in reply(). However, ReadableStream is only transferable in Chromium (Firefox and Safari
don't support it). The README already says "Chromium-based browser" but this limits portability.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nice catch! Added a feature-detect so that Firefox/Safari fall back to buffering the body into an ArrayBuffer (still transferable) with a warn-once.

- Trim verbose comment in browser workflow example.
- Use `yarn start:mcp-demo` shortcut in demo README.
- Warn once on concurrent BrowserMcpRequestContext.run().
- Feature-detect transferable ReadableStream in McpWorkerBridge; buffer
  to ArrayBuffer (with warn-once) on browsers without support.
@martin-fleck-at
Copy link
Copy Markdown
Contributor Author

@tortmayr Great, thank you! I pushed a follow-up commit to address your concerns

@tortmayr tortmayr self-requested a review May 19, 2026 13:31
Copy link
Copy Markdown
Contributor

@tortmayr tortmayr left a comment

Choose a reason for hiding this comment

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

LGTM!

@martin-fleck-at martin-fleck-at merged commit ea5b153 into main May 19, 2026
5 checks passed
@martin-fleck-at martin-fleck-at deleted the issues/1546 branch May 19, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants