Context
Story 1 (#7422) was closed early because third-party access was deprioritized in favor of first-party Expert integration. The endpoint at POST /api/v1/mcp exists on main but it's a stub returning 405 ("MCP HTTP endpoints are not available"). No actual MCP server was created. The tool definitions in ee/lib/mcp/tools/ are only consumed internally by the first-party agent over MQTT.
Scoped PATs (#7411) are now in place, and the MCP Gateway has landed as the central broker for all tool invocation. Time to build the actual server.
What needs to happen
A stateless @modelcontextprotocol/sdk McpServer at POST /api/v1/mcp that external agents can connect to with a scoped PAT. Each request creates a fresh server and transport, same pattern the SDK is designed for in stateless mode.
Auth and PAT passthrough
The endpoint authenticates via Bearer token (scoped PAT). The PAT is passed along to the MCP Gateway as-is. The gateway delegates tool calls to the appropriate source:
- Platform automation tools: the gateway sends the request back to the Forge backend through the existing platform automation scaffolding. The scoped PAT travels with it, and
app.inject() enforces readOnly and team scope restrictions through the normal auth stack.
- UI tools and flow building tools: handled by the gateway directly (browser tab targeting, NR instance communication).
No secondary tokens are minted. The original scoped PAT is the only credential that flows through the system.
Invoke variant gating
Before forwarding to the gateway, the endpoint classifies each tools/call by its annotation (readOnlyHint, destructiveHint) and rejects calls that violate the PAT's readOnly restriction. Fast reject at the HTTP layer before anything touches MQTT.
MQTT transport to the gateway
The endpoint communicates with the MCP Gateway using sendCommandAwaitReply (the existing pattern from device comms). Topic structure: ff/v1/mcp/[userId]/[mcp-session-id]/response. No custom inflight maps, no new MQTT patterns.
Browser tab presence
Already handled by the Forge platform (#8182, #8183, #8184). The gateway uses tab presence to target flow building and UI tool calls at the right browser session. No additional work needed here.
References
Context
Story 1 (#7422) was closed early because third-party access was deprioritized in favor of first-party Expert integration. The endpoint at
POST /api/v1/mcpexists on main but it's a stub returning 405 ("MCP HTTP endpoints are not available"). No actual MCP server was created. The tool definitions inee/lib/mcp/tools/are only consumed internally by the first-party agent over MQTT.Scoped PATs (#7411) are now in place, and the MCP Gateway has landed as the central broker for all tool invocation. Time to build the actual server.
What needs to happen
A stateless
@modelcontextprotocol/sdkMcpServer atPOST /api/v1/mcpthat external agents can connect to with a scoped PAT. Each request creates a fresh server and transport, same pattern the SDK is designed for in stateless mode.Auth and PAT passthrough
The endpoint authenticates via Bearer token (scoped PAT). The PAT is passed along to the MCP Gateway as-is. The gateway delegates tool calls to the appropriate source:
app.inject()enforces readOnly and team scope restrictions through the normal auth stack.No secondary tokens are minted. The original scoped PAT is the only credential that flows through the system.
Invoke variant gating
Before forwarding to the gateway, the endpoint classifies each
tools/callby its annotation (readOnlyHint, destructiveHint) and rejects calls that violate the PAT's readOnly restriction. Fast reject at the HTTP layer before anything touches MQTT.MQTT transport to the gateway
The endpoint communicates with the MCP Gateway using
sendCommandAwaitReply(the existing pattern from device comms). Topic structure:ff/v1/mcp/[userId]/[mcp-session-id]/response. No custom inflight maps, no new MQTT patterns.Browser tab presence
Already handled by the Forge platform (#8182, #8183, #8184). The gateway uses tab presence to target flow building and UI tool calls at the right browser session. No additional work needed here.
References
forge/ee/routes/mcp/server.jssendCommandAwaitReplyinforge/comms/devices.jsfeat/mcp-gateway-3p-mqtt: explored an MQTT-proxy approach with scope-capped tokens. The proxy pattern and token minting are not the direction. Invoke variant gating is worth keeping.