Files
lda-wf/docs/superpowers/specs/2026-05-15-mcp-protocol-relay-design.md
T
lda Verified 1397993217 another bug report has hit the fastmcp
also docs.

codex tried a hell ton, and then deleted them all.
2026-05-16 16:50:57 +07:00

9.1 KiB

MCP Protocol Relay Design

Goal

Make wf-mcp a truthful high-quality MCP proxy, not merely a tool forwarder.

The next phase is about understanding and then projecting advanced MCP protocol behavior correctly:

  • upstream notifications
  • server capability advertisement
  • downstream client capability relay
  • later request forwarding for client-side features such as elicitation, roots, sampling, and task-augmented requests

The immediate next work is still investigation first, because advertising a capability before we can bridge it end to end would make wf-mcp lie to clients.

Current State

wf-mcp already has:

  • a unified MCP surface
  • proxy mounting with stable public names
  • local list-changed notifications after reload
  • ordinary tool/resource/prompt proxying
  • resource-link URI rewriting for ordinary tool-returned ResourceLinks

Known remaining uncertainty:

  • which advanced MCP requests FastMCP can already bridge
  • how initialization capabilities should be projected through a broker with multiple enabled upstream connections

Resolved after this spec was written:

  • generic upstream notifications such as list-changed, resource-updated, and logging notifications do not automatically reach downstream clients through the current proxy path
  • current capability negotiation is not the reason for that gap

See ../../mcp_protocol_proxy_inventory.md for the measured facts and ../../wf_mcp_proxy_reality_and_roadmap.md for the current practical roadmap.

Core Distinction

MCP has two different capability directions.

Server capabilities

These are advertised by wf-mcp to its downstream client:

  • tools
  • resources
  • prompts
  • logging
  • completions
  • tasks

wf-mcp may advertise a server capability only when the unified server can actually serve it. The correct eventual shape is a selected union:

  • local capabilities implemented by wf-mcp
  • plus enabled upstream server capabilities that wf-mcp can proxy safely

Client capabilities

These are advertised by the downstream client to wf-mcp:

  • roots
  • sampling
  • elicitation
  • client-side tasks

wf-mcp must not advertise these as its own server capabilities. Instead, when an upstream server needs one of them, wf-mcp may relay the downstream client's real capabilities upstream only if the corresponding request path can also be forwarded correctly.

Examples:

  • If the downstream client supports elicitation and wf-mcp can relay elicitation/create, an upstream server may use elicitation through the proxy.
  • If the downstream client supports roots and wf-mcp can relay roots/list, an upstream server may request roots through the proxy.

Design Principles

  1. Truthful advertisement Never advertise a capability solely because some upstream declares it.

  2. Direction-aware relay Keep server-side projection and client-side relay as separate concepts.

  3. Selected union, not blind union Disabled upstreams and unsupported bridge paths must not inflate the public capability set.

  4. Protocol first, workflow later This phase improves MCP proxy behavior. Workflow artifacts and planner-facing source models should not absorb this complexity.

  5. Use official MCP boundary types Model protocol behavior with mcp.types capability and notification models where possible. Do not create parallel ad hoc protocol dicts.

  6. Consent at source connection time A connected proxy source should normally be able to use the capabilities it declares, but powerful client-side relays should be visible to the user when the source is connected, similar to an app-permissions screen. Later admin UI may disable individual relays such as sampling, roots, or elicitation for a source without changing the base protocol model.

Phase 1: Upstream Notification Inventory

Questions

  1. Does FastMCP already forward upstream:
    • notifications/tools/list_changed
    • notifications/resources/list_changed
    • notifications/prompts/list_changed
    • notifications/resources/updated
    • notifications/message
    • notifications/progress
    • notifications/tasks/status
  2. If some notifications are forwarded, are payloads transformed correctly?
  3. For resource updates, are resource URIs projected into downstream namespace form or leaked as raw upstream URIs?
  4. Do local client surfaces we can inspect, such as Inspector or Codex, visibly react to the forwarded notifications?

Method

  1. Extend the fixture server only where needed to emit deterministic events.
  2. Probe direct upstream behavior first.
  3. Probe the same behavior through wf-mcp.
  4. Record observed behavior in docs/mcp_protocol_proxy_inventory.md.
  5. Do not implement forwarding until the behavior gap is proven.

Expected Outputs

  • a table of each notification kind:
    • direct upstream behavior
    • through-proxy behavior
    • payload correctness
    • whether action is needed
  • regression tests for any behavior we decide to rely on

Phase 2: Capability Negotiation Inventory

Questions

  1. What server capabilities does the current unified wf-mcp server advertise?
  2. What server capabilities do configured upstreams advertise?
  3. What downstream client capabilities are visible to wf-mcp during initialization?
  4. Which advanced features can FastMCP already bridge today?
  5. Which advertised upstream capabilities would be false for wf-mcp to expose until request forwarding is added?

Expected Outputs

  • a server-capability projection matrix
  • a client-capability relay matrix
  • a concrete list of:
    • already safe to advertise
    • bridgeable with small glue
    • unsupported until a larger forwarding subsystem exists

Intended Architecture

Likely later modules:

wf_mcp.protocol_relay/
  server_capabilities.py
  client_capabilities.py
  notifications.py

Conceptually:

enabled upstream capabilities
        +
local wf-mcp capabilities
        |
        v
ServerCapabilityProjection
        |
        v
downstream initialize result

downstream client capabilities
        |
        v
ClientCapabilityRelay
        |
        v
selected upstream initialize requests

The exact module names may change after the inventory. The separation should not:

  • projecting what wf-mcp offers as a server
  • relaying what the downstream client offers to upstream servers

Mixed upstream support should not be hidden. MCP's top-level capability object is coarse, so wf-mcp should eventually expose per-source and, where useful, per-capability detail through its admin inventory tools even when the public server capability advertisement is a selected union.

Feature Notes

Elicitation

Elicitation is a client capability, not a server capability. Supporting it through wf-mcp means forwarding upstream elicitation requests to the downstream client and returning the response.

Roots

Roots are also a client capability. They represent client-exposed filesystem or workspace roots that a server may query. Supporting roots through wf-mcp means relaying roots/list, not pretending wf-mcp itself owns roots.

Sampling

Sampling is another client capability. It lets a server ask the client-side LLM to generate content. This is powerful and should remain explicit because it can cross trust boundaries.

Tasks

Tasks exist in both directions:

  • server tasks: downstream client task-augments calls into wf-mcp
  • client tasks: upstream servers task-augment requests they send toward the downstream client

Treat these as separate negotiated capabilities. Do not assume “tasks supported” is one global boolean.

MCP Apps And _meta.ui

_meta.ui belongs to the MCP Apps extension layer, not the base server/client capability split above. wf-mcp should still preserve and proxy it faithfully.

Expected proxy behavior:

  • preserve upstream _meta.ui values
  • rewrite referenced UI resource URIs when they cross a namespace boundary, the same way ordinary proxied resource URIs are projected
  • do not rely on _meta.ui for core protocol correctness, because clients may ignore extension metadata they do not understand

Possible later use:

  • wf-mcp may expose its own source-consent, login/logout, catalog, and toggle surfaces as MCP Apps UI resources/tools
  • that is a UI delivery choice, not a reason to mix UI metadata into the core capability negotiation model

Non-Goals For The Next Pass

  • Do not blindly union all upstream capability dicts.
  • Do not build a custom protocol stack around FastMCP before measuring what it already forwards.
  • Do not solve workflow-artifact dependency validation here.
  • Do not build UI controls here.
  • Do not claim support for elicitation, roots, sampling, or tasks until an end-to-end relay path is demonstrated.

Success Criteria

The next pass is successful when we can answer, with evidence:

  1. Which upstream notifications already survive the proxy?
  2. Which server capabilities may wf-mcp advertise truthfully today?
  3. Which downstream client capabilities can safely be relayed upstream today?
  4. What exact small implementation should happen next, instead of guessing?