Skip to content

WebMCP: add remote human handoff session notifications - #59

Merged
erinepshovel-code merged 7 commits into
mainfrom
agent/webmcp-remote-handoff
Sep 2, 2026
Merged

erinepshovel-code merged 7 commits into
mainfrom
agent/webmcp-remote-handoff

Conversation

@erinepshovel-code

Copy link
Copy Markdown
Contributor

Purpose

Make human Send reach both kinds of agent from one exact handoff payload.

Human/agent gestalt

  • human and agents see the same curated msdmd-plus-meta skill material
  • human selects a card and writes the desired outcome in ordinary language
  • Send dynamically exposes tiw_human_handoff to browser WebMCP
  • the same Send publishes the same payload to an opaque remote MCP session
  • a connected Streamable HTTP MCP client keeps GET /mcp?session=<opaque> open and receives notifications/tools/list_changed
  • after notification, tools/list exposes tiw_human_handoff, which returns the exact selected skill, dependency closure, provenance, and human request
  • editing the request or changing skill retracts the browser tool and remote handoff; remote records expire automatically

Security / privacy boundaries

  • session URL is a high-entropy bearer read capability only
  • a separate high-entropy write key remains in page memory and is required to publish/delete /handoff/<session>
  • handoff mutations require an explicit interdependentway.org browser origin
  • remote handoffs live only in bounded process memory: default 30-minute TTL, max 256 live records, no disk/database/analytics
  • neither browser nor remote handoff grants repository/filesystem/deployment write authority
  • msdmd remains forge-neutral; target access comes from the agent's separately authorized tools

Compatibility

  • public /mcp remains the same five read-only registry tools
  • base GET /mcp remains 405
  • session GET enables SSE notifications only when ?session= is present
  • session connections advertise tools.listChanged=true; ordinary connections remain false

hmmm

The server can notify a conforming MCP host that the handoff tool appeared. Neither MCP nor WebMCP can force the model to reason or act; the agent host still chooses when to invoke available tools.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T12:30:53.763300Z 7aca621 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@erinepshovel-code
erinepshovel-code merged commit 63ebac4 into main Sep 2, 2026
5 checks passed

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7aca621a1d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/mcp-server.mjs
Comment on lines +303 to +305
if (!isExplicitOriginAllowed(request, handoffAllowedOrigins)) {
return sendJson(response, 403, rpcError(null, -32000, 'Forbidden handoff origin'));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Authenticate handoff creation instead of trusting Origin

A non-browser client can forge Origin: https://interdependentway.org, choose arbitrary valid session/write tokens, and create records without possessing any server-issued capability. Repeating this for more than 256 sessions triggers the store's oldest-record eviction and can continuously remove legitimate handoffs; near-limit request bodies can also consume hundreds of megabytes. Require an authenticated or server-signed creation capability, or enforce equivalent abuse controls, rather than treating Origin as proof that the website initiated the request.

Useful? React with 👍 / 👎.

Comment thread src/assets/js/webmcp.js
Comment on lines 305 to +307
intentInput?.addEventListener('input', () => {
if (currentHandoff) clearPublishedHandoff('Request text changed. Press Send again before the agent receives the revision.');
if (currentHandoff || remotePublished) {
clearPublishedHandoff('Request text changed. Press Send again before either agent surface receives the revision.');

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 Badge Invalidate handoffs that are still being published

If the user edits the request while the remote POST is pending—especially during a Render cold start—both currentHandoff and remotePublished are still false, so this handler does not invalidate anything. When the POST completes, the stale pre-edit request becomes available to the agent and the UI may report it as sent; changing the selected skill has the same race. Track a pending submission generation or abort/retract it whenever either input changes.

Useful? React with 👍 / 👎.

Comment thread server/handoff-store.mjs
Comment on lines +71 to +73
for (const [session, record] of records) {
if (record.expiresAt <= timestamp) records.delete(session);
}

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 Badge Broadcast the tool removal when a handoff expires

When a client has listed tiw_human_handoff and the record later reaches its TTL, this expiry path deletes the record without notifying the session's SSE stream. The server advertises listChanged and tells clients to keep that stream open, so a client can retain the now-stale tool indefinitely and only discover its removal through a failed call or an unsolicited relist. Route expiration through a callback or scheduled cleanup that emits notifications/tools/list_changed for the affected session.

Useful? React with 👍 / 👎.

erinepshovel-code added a commit that referenced this pull request Sep 2, 2026
Roll back only PR #59's remote human-handoff surface after post-merge review found forgeable Origin-based creation plus unresolved pending-submit and TTL notification races. Preserve the prior public registry MCP/browser WebMCP surface. Reintroduce remote handoff only with a server-authenticated creation capability and complete lifecycle semantics.
erinepshovel-code added a commit that referenced this pull request Sep 2, 2026
Roll back only PR #59's remote human-handoff surface after post-merge review found forgeable Origin-based creation plus unresolved pending-submit and TTL notification races. Preserve the prior public registry MCP/browser WebMCP surface. Reintroduce remote handoff only with a server-authenticated creation capability and complete lifecycle semantics.
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.

1 participant