Skip to content

feat(mcp): add third-party MCP gateway door with browser-tab presence - #8072

Draft
andypalmi wants to merge 2 commits into
mainfrom
feat/mcp-gateway-3p-mqtt
Draft

feat(mcp): add third-party MCP gateway door with browser-tab presence#8072
andypalmi wants to merge 2 commits into
mainfrom
feat/mcp-gateway-3p-mqtt

Conversation

@andypalmi

@andypalmi andypalmi commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a third-party MCP front door and proxies it to the central MCP gateway over MQTT, so external agents can reach platform, platform-UI and flow-building tools through the same gateway the Expert uses. Also relays browser-tab heartbeats so the gateway can target a user's open editor/platform tabs.

Changes

  • Front door: POST /api/v1/mcp, gated on the platform AI feature, proxies each request to the gateway over MQTT and returns the gateway response (mcpProxyRequest on app.comms).
  • Ingress topic: reconciled to ff/v1/mcp/<platformId>/<userId>/<mcpSessionId>/(request|response); the entity segment is dropped and a PAT's allow-list travels in a scope object instead of being pinned into the topic.
  • Invoke-variant enforcement: at platform dispatch the invoke variant is checked against the tool class derived from annotations (readOnlyHint maps to read, destructiveHint to delete, else write); mismatches are rejected, and the caller scope is carried through to platform token creation.
  • mcp-gateway identity: a distinct broker identity alongside expert-agent, with admin credential routes, the platform:mcp-gateway:creds permission, a settings flag, and broker topic authorisation.
  • Browser-tab heartbeat: each open tab heartbeats Forge, which republishes to ff/v1/tab-heartbeat/<userId>/<sessionId>/(update|clear) and stores nothing itself; heartbeat routes block PAT sessions.

Testing

Targeted unit suites pass: MCP server door, platform-automation variant enforcement, BrokerClient (mcp-gateway creds), broker auth routes, user heartbeat routes.

Notes

Draft: the runtime counterpart (the MCP gateway) is served separately; some end-to-end paths (exec-channel separation, heartbeat reachability) still need live-stack validation.

Expose a third-party MCP front door and proxy it to the central MCP gateway over MQTT, so external agents can reach platform, platform-UI and flow-building tools through the same gateway the Expert uses.

- Add POST /api/v1/mcp, gated on the platform AI feature, proxying each request to the gateway over MQTT and returning the gateway response.
- Reconcile the MCP ingress topic to ff/v1/mcp/<platformId>/<userId>/<mcpSessionId>/(request|response), dropping the entity segment; a PAT's allow-list travels in a scope object rather than being pinned into the topic.
- Enforce the invoke variant against the tool class at platform dispatch: readOnlyHint maps to read, destructiveHint to delete, and everything else to write; mismatches are rejected. Carry the caller scope through to platform token creation.
- Add a distinct mcp-gateway broker identity alongside expert-agent, with its admin credential routes, the platform:mcp-gateway:creds permission, and a settings flag, and authorise its broker topics.
- Relay browser-tab heartbeats to the gateway over MQTT: each open tab heartbeats Forge, which republishes to ff/v1/tab-heartbeat/<userId>/<sessionId>/(update|clear) and stores no presence itself. Heartbeat routes block PAT sessions.
- Expose mcpProxyRequest and publishTabHeartbeat on app.comms.
Connect the tab's broker session and inflight subscription on mount via
establishPresenceSession, so a tab can receive and answer third-party MCP
action requests without the user first opening the Expert panel or sending
a chat message. The broker credential is single-use, so a tab that never
chats leaks nothing.

Gate inflight handling so flow-building and platform-UI action executions
are accepted whenever they target this tab's session, even with no local
chat turn in flight; chat-progress updates still require a matching
in-flight request. Move the "no outstanding turns" guard out of
_onMqttMessage and into the reply case, so inbound action requests are no
longer dropped when the tab has no chat of its own underway.
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