You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The MCP endpoint (POST /api/v1/mcp) aggregates tools from two sources into a unified tools/list and routes tools/call to the right executor. 3rd party agents talk only to the Forge backend, never directly to the expert agent.
Why
The MCP endpoint is the single entry point for 3rd party agents. It needs to present a unified tool list that combines platform tools (defined in code on the Forge backend) with the first-party agent's tools (flow/NR tools, frontend tools like context/navigation/routes). The agent never knows which backend handles what.
The first-party agent's tool list is fetched over MQTT rather than HTTP. MQTT gives better control for horizontal scaling and per-customer isolation later. The Forge backend sends an MQTT request to the expert agent asking for its tool list, the agent responds, and the Forge backend merges the result with platform tools.
For tool execution, the Forge backend routes based on tool source: platform tools are executed via app.inject(), agent tools are proxied to the expert agent via MQTT. PAT enforcement (#7559) runs at the Forge layer before any execution or proxying.
What to do
Tool aggregation (tools/list)
Fetch the expert agent's tool list via MQTT request/response
Timeout handling for agent tool calls (expert agent or browser unresponsive)
MQTT communication with expert agent
Publishes tool calls on ff/v1/mcp/<platformId>/<userId>/<sessionId>/<entityType>/<entityId>/req with correlation ID and tool details in payload
Subscribes to ff/v1/mcp/<platformId>/<userId>/<sessionId>/<entityType>/<entityId>/res per active user/session/entity combination (not a broad wildcard)
Matches responses via correlation ID in payload as a safety net, but MQTT topic-level filtering is the primary routing mechanism
Uses the existing long-lived platform MQTT client, no new connections
ACL rules for ff/v1/mcp/ topics: validate forge_platform client only, no user/team/RBAC checks
Subscription caching
Per-context response subscriptions (one per active user/session/entity combination) are cached in an in-process LRU cache (lru-cache directly, not the global app.caches abstraction, since subscription state is per-process and bound to the local MQTT client connection)
~24h TTL, extended on reuse. Each subsequent tool call for the same user/session/entity prolongs the subscription's life.
On eviction (TTL expiry or LRU overflow), the dispose callback triggers an MQTT unsubscribe, so stale subscriptions don't accumulate on the platform client
ACL check happens per new subscription, but it's cheap (client validation only, no DB queries)
A broad wildcard subscription was considered and rejected: it creates message noise (Forge receives responses for all users, discards non-matching ones), weak isolation between users, and relies entirely on correlation IDs for routing rather than MQTT-level filtering
Summary
The MCP endpoint (
POST /api/v1/mcp) aggregates tools from two sources into a unifiedtools/listand routestools/callto the right executor. 3rd party agents talk only to the Forge backend, never directly to the expert agent.Why
The MCP endpoint is the single entry point for 3rd party agents. It needs to present a unified tool list that combines platform tools (defined in code on the Forge backend) with the first-party agent's tools (flow/NR tools, frontend tools like context/navigation/routes). The agent never knows which backend handles what.
The first-party agent's tool list is fetched over MQTT rather than HTTP. MQTT gives better control for horizontal scaling and per-customer isolation later. The Forge backend sends an MQTT request to the expert agent asking for its tool list, the agent responds, and the Forge backend merges the result with platform tools.
For tool execution, the Forge backend routes based on tool source: platform tools are executed via
app.inject(), agent tools are proxied to the expert agent via MQTT. PAT enforcement (#7559) runs at the Forge layer before any execution or proxying.What to do
Tool aggregation (
tools/list)Tool routing (
tools/call)app.inject()with forwarded PAT (existing pattern from MCP Platform Tool Definitions #7430)MQTT communication with expert agent
ff/v1/mcp/<platformId>/<userId>/<sessionId>/<entityType>/<entityId>/reqwith correlation ID and tool details in payloadff/v1/mcp/<platformId>/<userId>/<sessionId>/<entityType>/<entityId>/resper active user/session/entity combination (not a broad wildcard)ff/v1/mcp/topics: validate forge_platform client only, no user/team/RBAC checksSubscription caching
lru-cachedirectly, not the globalapp.cachesabstraction, since subscription state is per-process and bound to the local MQTT client connection)disposecallback triggers an MQTT unsubscribe, so stale subscriptions don't accumulate on the platform clientlru-cache, both are per-process, but they serve different purposes.Tests
tools/listreturns the union of platform tools and expert agent toolsapp.inject()and returns the resultReferences
forge/comms/commsClient.jssendCommandAwaitReplypattern:forge/comms/devices.js