Class BowireMcpDualHandlerDispatcher
- Namespace
- Kuestenlogik.Bowire.Mcp
- Assembly
- Kuestenlogik.Bowire.Mcp.dll
Dispatches MCP tools/, resources/ and
prompts/* traffic to the right backing implementation
(full server vs adapter) based on the URL the request hit.
public sealed class BowireMcpDualHandlerDispatcher
- Inheritance
-
BowireMcpDualHandlerDispatcher
- Inherited Members
Remarks
The MCP C# SDK installs a global tool/resource/prompt collection
populated by WithTools<T> + friends, and merges that
collection into every tools/list response — even when a
caller installs a WithListToolsHandler overlay (the SDK
wraps the overlay and *appends* the static tools to its result).
That means the union of static + dynamic tools leaks across
endpoints by default.
The dispatcher closes that leak by combining two SDK mechanisms:
- WithListToolsHandler / WithCallToolHandler / &c: the adapter's dynamic handlers fire here. For Server requests these return empty results so the SDK's union ends up being just the static tools; for Adapter they return the dynamic ones.
- Request filters (post-wrap): a filter runs after the SDK has merged dynamic + static tools and strips out the wrong-side entries based on the URL path. So the adapter URL's tools/list response loses the static tools, and the server URL's response loses any dynamic overlay (none today, but the filter keeps the contract sound). The same gating applies to tools/call: dispatching a server-side tool through the adapter URL throws a clean "tool not found" rather than silently invoking it.
Path routing reads Items[SessionRoutePathItemKey], which Kuestenlogik.Bowire.Mcp.BowireMcpHttpTransportSetup latches at session-init time. Falling back to live Path when Items is empty keeps the path-detection sound in stateless transport mode.
Constructors
BowireMcpDualHandlerDispatcher(BowireMcpEndpointRegistry)
public BowireMcpDualHandlerDispatcher(BowireMcpEndpointRegistry registry)
Parameters
registryBowireMcpEndpointRegistry
Fields
SessionRoutePathItemKey
Key under which the originating request URL is stashed on Items by Kuestenlogik.Bowire.Mcp.BowireMcpHttpTransportSetup.
public const string SessionRoutePathItemKey = "kuestenlogik.bowire.mcp.sessionRoutePath"
Field Value
Properties
HasAdapter
True when an adapter has registered itself with the dispatcher.
The DI registration uses this flag to decide whether to install
any of the With*Handler shims at all — without it, the SDK's
own default ListTools/CallTool path (which reads the static
ToolCollection) is left in place.
public bool HasAdapter { get; }
Property Value
HasInstalledSdkShims
Marker set by AddBowireMcp after it wires the dispatcher
handlers onto the SDK Microsoft.Extensions.DependencyInjection.IMcpServerBuilder. The
adapter's AddBowireMcpAdapter consults this so a host
that wired the server first doesn't install the same
With*Handler shims a second time.
public bool HasInstalledSdkShims { get; set; }
Property Value
Methods
RegisterAdapterHandlers(McpRequestHandler<ListToolsRequestParams, ListToolsResult>, McpRequestHandler<CallToolRequestParams, CallToolResult>, McpRequestHandler<ListResourcesRequestParams, ListResourcesResult>, McpRequestHandler<ReadResourceRequestParams, ReadResourceResult>, McpRequestHandler<ListPromptsRequestParams, ListPromptsResult>, McpRequestHandler<GetPromptRequestParams, GetPromptResult>)
Wire the adapter-side handlers. Called exactly once by the adapter's DI registration; subsequent calls overwrite (so the last AddBowireMcpAdapter wins, which matches the SDK's last-registration-wins convention for global handlers).
public void RegisterAdapterHandlers(McpRequestHandler<ListToolsRequestParams, ListToolsResult> listTools, McpRequestHandler<CallToolRequestParams, CallToolResult> callTool, McpRequestHandler<ListResourcesRequestParams, ListResourcesResult> listResources, McpRequestHandler<ReadResourceRequestParams, ReadResourceResult> readResource, McpRequestHandler<ListPromptsRequestParams, ListPromptsResult> listPrompts, McpRequestHandler<GetPromptRequestParams, GetPromptResult> getPrompt)
Parameters
listToolsMcpRequestHandler<ListToolsRequestParams, ListToolsResult>callToolMcpRequestHandler<CallToolRequestParams, CallToolResult>listResourcesMcpRequestHandler<ListResourcesRequestParams, ListResourcesResult>readResourceMcpRequestHandler<ReadResourceRequestParams, ReadResourceResult>listPromptsMcpRequestHandler<ListPromptsRequestParams, ListPromptsResult>getPromptMcpRequestHandler<GetPromptRequestParams, GetPromptResult>