diff --git a/src/tools/mcp/mcp.test.mjs b/src/tools/mcp/mcp.test.mjs index ff94659f0..0df9bb955 100644 --- a/src/tools/mcp/mcp.test.mjs +++ b/src/tools/mcp/mcp.test.mjs @@ -233,6 +233,7 @@ test('resources are listed and read, and tools name their UI resource', async () }); assert.deepEqual((await call('tools/list')).tools[0]._meta, { ui: { resourceUri: 'ui://fixture/view' }, + 'ui/resourceUri': 'ui://fixture/view', }); assert.deepEqual((await call('resources/list')).resources, [ { diff --git a/src/tools/mcp/protocol.js b/src/tools/mcp/protocol.js index 67858833e..446d01869 100644 --- a/src/tools/mcp/protocol.js +++ b/src/tools/mcp/protocol.js @@ -40,7 +40,14 @@ export function toMcpTools(catalog, { descriptions = {}, decorate } = {}) { inputSchema: tool.inputSchema, annotations: { title, ...tool.annotations }, ...(tool.ui - ? { _meta: { ui: { resourceUri: tool.ui.resourceUri } } } + ? { + // The flat key is the earlier form of the same field, which some + // hosts still read; the MCP Apps SDK sends both. + _meta: { + ui: { resourceUri: tool.ui.resourceUri }, + 'ui/resourceUri': tool.ui.resourceUri, + }, + } : {}), }; return decorate