Problem
McpAdapter.request<T>() unwraps the MCP CallToolResult and returns only the parsed data payload (from structuredContent or content[0].text). This makes it impossible for consumers to:
- Access
_meta.ui.resourceUri — needed to discover MCP App HTML resources for interactive rendering
- Get the full
CallToolResult — needed by @mcp-ui/client's AppRenderer component (the toolResult prop)
- Access the
content[] array — which may contain multiple content blocks (text, image, resource)
Since mcpClient and transport are private, there's no workaround without modifying the SDK.
Impact
Any app that wants to render MCP App UIs from Scope3 tool responses (like Claude Desktop and ChatGPT do) cannot use McpAdapter today. This affects our own product (Goldie/Bayes) and will affect any third-party consumer building MCP Apps-compatible hosts.
Proposed Solution
Add a callTool() method to McpAdapter that returns the raw CallToolResult:
async callTool(
method: HttpMethod,
path: string,
body?: unknown,
options?: RequestOptions
): Promise<CallToolResult> {
if (!this.connected) await this.connect();
const fullPath = this.buildPath(path, options);
const args = { method, path: fullPath, ...(body ? { body } : {}) };
return this.mcpClient.callTool({ name: 'api_call', arguments: args });
}
Also add readResource() for fetching MCP App HTML:
async readResource(uri: string): Promise<ReadResourceResult> {
if (!this.connected) await this.connect();
return this.mcpClient.readResource({ uri });
}
Extract the path-building logic from request() into a private buildPath() method so both request() and callTool() share it.
Add these as optional methods on BaseAdapter (non-breaking — RestAdapter doesn't implement them):
export interface BaseAdapter {
// ... existing ...
callTool?(method: HttpMethod, path: string, body?: unknown, options?: RequestOptions): Promise<CallToolResult>;
readResource?(uri: string): Promise<ReadResourceResult>;
}
Backwards Compatibility
request<T>() behavior is unchanged
- New methods are additive
BaseAdapter additions are optional (no breaking change for RestAdapter)
Problem
McpAdapter.request<T>()unwraps the MCPCallToolResultand returns only the parsed data payload (fromstructuredContentorcontent[0].text). This makes it impossible for consumers to:_meta.ui.resourceUri— needed to discover MCP App HTML resources for interactive renderingCallToolResult— needed by@mcp-ui/client'sAppRenderercomponent (thetoolResultprop)content[]array — which may contain multiple content blocks (text, image, resource)Since
mcpClientandtransportareprivate, there's no workaround without modifying the SDK.Impact
Any app that wants to render MCP App UIs from Scope3 tool responses (like Claude Desktop and ChatGPT do) cannot use
McpAdaptertoday. This affects our own product (Goldie/Bayes) and will affect any third-party consumer building MCP Apps-compatible hosts.Proposed Solution
Add a
callTool()method toMcpAdapterthat returns the rawCallToolResult:Also add
readResource()for fetching MCP App HTML:Extract the path-building logic from
request()into aprivate buildPath()method so bothrequest()andcallTool()share it.Add these as optional methods on
BaseAdapter(non-breaking —RestAdapterdoesn't implement them):Backwards Compatibility
request<T>()behavior is unchangedBaseAdapteradditions are optional (no breaking change forRestAdapter)