Commit Graph
1 Commits
Author SHA1 Message Date
lukaszraczylo d565c1d4ea feat(mcp): federated /mcp aggregation endpoint
New POST /mcp: a single JSON-RPC 2.0 endpoint aggregating every MCP
server the caller's group can reach, for clients built against the
earlier pre-plugin gateway's one aggregated endpoint (pugbot's
mcpclient, agentkit) rather than this plugin's per-server
/mcp/{name}/... proxy.

Unlike the per-server proxy, this cannot be a byte-level reverse
proxy: aggregating N servers' tools/list results, or routing one
tools/call to the single right server, both require actually parsing
the JSON-RPC envelope. The gateway answers initialize/ping locally
and, for tools/list/tools/call, issues its own outbound JSON-RPC
call(s) to the relevant backend server(s) per incoming request — no
session state persisted across separate client requests, matching the
per-server proxy's own complete absence of gateway-side session
tracking. A backend may answer bare JSON or an SSE stream; both are
accepted (parseBackendJSONRPC).

- tools/list fans out concurrently to every allowed server and merges
  results, prefixing each tool "<serverName>_<toolName>" — the
  underscore convention the earlier agentgateway used and that
  pugbot/agentkit already persist in their own tool-id records (e.g.
  brave-search_brave_web_search, verified live). A failing/unreachable
  server is skipped, not a whole-call failure.
- tools/call resolves the target by LONGEST matching
  "<serverName>_" prefix against the caller's allowed servers
  (disambiguates a server name that prefixes another), strips it,
  forwards, and relays the result/error under the CLIENT's own id. An
  unresolvable prefix (unconfigured, or authz-excluded) is a JSON-RPC
  invalid-params error, not a 404.
- Reuses Feature B's countTargetRequest for per-target attribution —
  every backend server actually contacted increments its own scope.
- notifications/* -> 202 no body; unknown method -> JSON-RPC
  method-not-found; malformed body -> JSON-RPC parse error with
  id:null (spec-required, not omitted).

No new limits config surface. Tests cover prefix resolution
(table-driven, incl. the ambiguous-prefix case), SSE/JSON backend
parsing, group-restricted aggregation (a denied server is never even
contacted), call routing/prefix-stripping, backend error relay,
unreachable-server handling, unknown-prefix errors, and per-target
counter attribution. README's MCP and A2A section documents the
federation contract and naming convention; the architecture diagram
and the total-scope/rejected-before-quota notes are updated to
include the new route.
2026-08-21 18:38:28 +01:00