@fgv/ts-extras-mcp 5.1.0-37 → 5.1.0-39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.rush/temp/{8523ec7cdfdd100d7242d368a2a014f4283131ad.tar.log → 28abef25194b96c733b5ec1c8816ab85532589aa.tar.log} +2 -2
  2. package/.rush/temp/chunked-rush-logs/ts-extras-mcp.build.chunks.jsonl +4 -4
  3. package/.rush/temp/operation/build/all.log +4 -4
  4. package/.rush/temp/operation/build/log-chunks.jsonl +4 -4
  5. package/.rush/temp/operation/build/state.json +1 -1
  6. package/.rush/temp/shrinkwrap-deps.json +227 -226
  7. package/config/jest.config.json +1 -1
  8. package/dist/packlets/mcp/adapter.js +2 -7
  9. package/dist/packlets/mcp/adapter.js.map +1 -1
  10. package/dist/packlets/mcp/model.js.map +1 -1
  11. package/dist/packlets/mcp/operations.js +31 -6
  12. package/dist/packlets/mcp/operations.js.map +1 -1
  13. package/dist/packlets/mcp/sdk.js.map +1 -1
  14. package/dist/test/unit/mcp.test.js +113 -0
  15. package/dist/test/unit/mcp.test.js.map +1 -1
  16. package/dist/ts-extras-mcp.d.ts +31 -0
  17. package/dist/tsdoc-metadata.json +1 -1
  18. package/etc/ts-extras-mcp.api.md +10 -0
  19. package/lib/packlets/mcp/adapter.d.ts.map +1 -1
  20. package/lib/packlets/mcp/adapter.js +2 -7
  21. package/lib/packlets/mcp/adapter.js.map +1 -1
  22. package/lib/packlets/mcp/model.d.ts +30 -0
  23. package/lib/packlets/mcp/model.d.ts.map +1 -1
  24. package/lib/packlets/mcp/model.js.map +1 -1
  25. package/lib/packlets/mcp/operations.d.ts.map +1 -1
  26. package/lib/packlets/mcp/operations.js +30 -5
  27. package/lib/packlets/mcp/operations.js.map +1 -1
  28. package/lib/packlets/mcp/sdk.d.ts +6 -0
  29. package/lib/packlets/mcp/sdk.d.ts.map +1 -1
  30. package/lib/packlets/mcp/sdk.js.map +1 -1
  31. package/lib/test/unit/mcp.test.js +113 -0
  32. package/lib/test/unit/mcp.test.js.map +1 -1
  33. package/package.json +9 -9
  34. package/rush-logs/ts-extras-mcp.build.cache.log +1 -1
  35. package/rush-logs/ts-extras-mcp.build.log +4 -4
  36. package/src/packlets/mcp/adapter.ts +5 -2
  37. package/src/packlets/mcp/model.ts +31 -0
  38. package/src/packlets/mcp/operations.ts +46 -3
  39. package/src/packlets/mcp/sdk.ts +6 -0
  40. package/src/test/unit/mcp.test.ts +128 -0
  41. package/temp/build/lint/_eslint-5eVG3S6w.json +6 -6
  42. package/temp/build/typescript/ts_8nwakTlr.json +1 -1
  43. package/temp/ts-extras-mcp.api.json +182 -1
  44. package/temp/ts-extras-mcp.api.md +10 -0
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.test.js","sourceRoot":"","sources":["../../../src/test/unit/mcp.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n// Mock the SDK-isolation seam so no live MCP server / subprocess is required. The factories\n// return controllable fakes; `makeClient` is configured per-test. The jest.mock call must\n// precede the regular imports (hoist-jest-mock).\njest.mock('../../packlets/mcp/sdk', () => ({\n makeClient: jest.fn(),\n makeStdioTransport: jest.fn(() => ({ sentinel: 'stdio' })),\n makeHttpTransport: jest.fn(() => ({ sentinel: 'http' }))\n}));\n\nimport '@fgv/ts-utils-jest';\nimport { Logging, type Result } from '@fgv/ts-utils';\nimport { type JsonObject, type JsonValue } from '@fgv/ts-json-base';\n\n// eslint-disable-next-line @rushstack/packlets/mechanics\nimport * as sdk from '../../packlets/mcp/sdk';\nimport {\n type IAdaptMcpToolsResult,\n type IMcpSession,\n type IMcpToolDescriptor,\n type IMcpTransport,\n adaptMcpTools,\n callMcpTool,\n closeMcpSession,\n connectMcpSession,\n createHttpTransport,\n createStdioTransport,\n listMcpTools\n} from '../../packlets/mcp';\n\nconst mockSdk = sdk as jest.Mocked<typeof sdk>;\n\ninterface IFakeClient {\n connect: jest.Mock;\n getServerVersion: jest.Mock;\n listTools: jest.Mock;\n callTool: jest.Mock;\n close: jest.Mock;\n}\n\nfunction makeFakeClient(overrides: Partial<IFakeClient> = {}): IFakeClient {\n return {\n connect: jest.fn(async () => undefined),\n getServerVersion: jest.fn(() => ({ name: 'fake-server', version: '1.2.3' })),\n listTools: jest.fn(async () => ({ tools: [] })),\n callTool: jest.fn(async () => ({ content: [] })),\n close: jest.fn(async () => undefined),\n ...overrides\n };\n}\n\n/** Connect a session backed by the given fake client (and a stdio transport). */\nasync function connectWith(fake: IFakeClient): Promise<IMcpSession> {\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n return (await connectMcpSession({ transport })).orThrow();\n}\n\n/** A foreign (non-package) handle, to exercise the loud narrowing-failure paths. */\nconst FOREIGN_TRANSPORT = { transportKind: 'stdio' } as unknown as IMcpTransport;\nconst FOREIGN_SESSION = {\n clientName: 'x',\n clientVersion: 'y',\n serverInfo: undefined\n} as unknown as IMcpSession;\n\nbeforeEach(() => {\n jest.clearAllMocks();\n mockSdk.makeStdioTransport.mockReturnValue({ sentinel: 'stdio' } as unknown as sdk.ISdkTransport);\n mockSdk.makeHttpTransport.mockReturnValue({ sentinel: 'http' } as unknown as sdk.ISdkTransport);\n});\n\n// ===========================================================================\n// Transports\n// ===========================================================================\n\ndescribe('createStdioTransport', () => {\n test('succeeds for a valid command', () => {\n expect(createStdioTransport({ command: 'node', args: ['x'] })).toSucceedAndSatisfy((t: IMcpTransport) => {\n expect(t.transportKind).toBe('stdio');\n });\n expect(mockSdk.makeStdioTransport).toHaveBeenCalledWith(\n expect.objectContaining({ command: 'node', args: ['x'] })\n );\n });\n\n test('fails for an empty/whitespace command', () => {\n expect(createStdioTransport({ command: '' })).toFailWith(/command must be a non-empty string/);\n expect(createStdioTransport({ command: ' ' })).toFailWith(/command must be a non-empty string/);\n });\n\n test('fails (Result) when the SDK constructor throws', () => {\n mockSdk.makeStdioTransport.mockImplementationOnce(() => {\n throw new Error('spawn boom');\n });\n expect(createStdioTransport({ command: 'node' })).toFailWith(/createStdioTransport:.*spawn boom/);\n });\n});\n\ndescribe('createHttpTransport', () => {\n test('succeeds for http and https urls and forwards headers', () => {\n expect(createHttpTransport({ url: 'http://localhost:9000/mcp' })).toSucceedAndSatisfy(\n (t: IMcpTransport) => {\n expect(t.transportKind).toBe('http');\n }\n );\n expect(\n createHttpTransport({ url: 'https://example.com/mcp', headers: { authorization: 'Bearer t' } })\n ).toSucceed();\n expect(mockSdk.makeHttpTransport).toHaveBeenCalledWith(expect.any(URL), { authorization: 'Bearer t' });\n });\n\n test('fails for an unparseable url', () => {\n expect(createHttpTransport({ url: 'not a url' })).toFailWith(/invalid url 'not a url'/);\n });\n\n test('fails for a non-http(s) protocol', () => {\n expect(createHttpTransport({ url: 'ftp://example.com' })).toFailWith(/must use http or https/);\n });\n\n test('fails (Result) when the SDK constructor throws', () => {\n mockSdk.makeHttpTransport.mockImplementationOnce(() => {\n throw new Error('http boom');\n });\n expect(createHttpTransport({ url: 'http://localhost' })).toFailWith(/createHttpTransport:.*http boom/);\n });\n});\n\n// ===========================================================================\n// Session lifecycle\n// ===========================================================================\n\ndescribe('connectMcpSession', () => {\n test('fails loudly for a foreign transport handle', async () => {\n expect(await connectMcpSession({ transport: FOREIGN_TRANSPORT })).toFailWith(/invalid MCP transport/);\n });\n\n test('connects and reports server identity, logging when a logger is supplied', async () => {\n const logger = new Logging.InMemoryLogger('all');\n const fake = makeFakeClient();\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(\n await connectMcpSession({ transport, clientName: 'me', clientVersion: '0.0.1', logger })\n ).toSucceedAndSatisfy((session: IMcpSession) => {\n expect(session.clientName).toBe('me');\n expect(session.clientVersion).toBe('0.0.1');\n expect(session.serverInfo).toEqual({ name: 'fake-server', version: '1.2.3' });\n });\n expect(mockSdk.makeClient).toHaveBeenCalledWith('me', '0.0.1');\n expect(fake.connect).toHaveBeenCalledTimes(1);\n expect(logger.logged.join('\\n')).toMatch(/connected to server fake-server@1.2.3/);\n });\n\n test('connects with default identity and no server info, no logger', async () => {\n const fake = makeFakeClient({ getServerVersion: jest.fn(() => undefined) });\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(await connectMcpSession({ transport })).toSucceedAndSatisfy((session: IMcpSession) => {\n expect(session.clientName).toBe('@fgv/ts-extras-mcp');\n expect(session.serverInfo).toBeUndefined();\n });\n });\n\n test('logs the no-identity case when a logger is supplied', async () => {\n const logger = new Logging.InMemoryLogger('all');\n const fake = makeFakeClient({ getServerVersion: jest.fn(() => undefined) });\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(await connectMcpSession({ transport, logger })).toSucceed();\n expect(logger.logged.join('\\n')).toMatch(/connected \\(server did not report identity\\)/);\n });\n\n test('fails when the connect handshake throws', async () => {\n const fake = makeFakeClient({\n connect: jest.fn(async () => {\n throw new Error('handshake refused');\n })\n });\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(await connectMcpSession({ transport })).toFailWith(/connectMcpSession:.*handshake refused/);\n });\n});\n\ndescribe('closeMcpSession', () => {\n test('fails loudly for a foreign session handle', async () => {\n expect(await closeMcpSession(FOREIGN_SESSION)).toFailWith(/invalid MCP session/);\n });\n\n test('closes a connected session', async () => {\n const fake = makeFakeClient();\n const session = await connectWith(fake);\n expect(await closeMcpSession(session)).toSucceedWith(true);\n expect(fake.close).toHaveBeenCalledTimes(1);\n });\n\n test('fails when close throws', async () => {\n const fake = makeFakeClient({\n close: jest.fn(async () => {\n throw new Error('already closed');\n })\n });\n const session = await connectWith(fake);\n expect(await closeMcpSession(session)).toFailWith(/closeMcpSession:.*already closed/);\n });\n});\n\n// ===========================================================================\n// Tool discovery + invocation\n// ===========================================================================\n\ndescribe('listMcpTools', () => {\n test('fails loudly for a foreign session handle', async () => {\n expect(await listMcpTools(FOREIGN_SESSION)).toFailWith(/invalid MCP session/);\n });\n\n test('returns a single-page catalog', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [{ name: 'a', description: 'tool a', inputSchema: { type: 'object' } }]\n }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools).toHaveLength(1);\n expect(tools[0]).toEqual({ name: 'a', description: 'tool a', inputSchema: { type: 'object' } });\n });\n });\n\n test('follows nextCursor across pages', async () => {\n const listTools = jest\n .fn()\n .mockResolvedValueOnce({ tools: [{ name: 'a', inputSchema: { type: 'object' } }], nextCursor: 'p2' })\n .mockResolvedValueOnce({ tools: [{ name: 'b', inputSchema: { type: 'object' } }] });\n const fake = makeFakeClient({ listTools });\n const session = await connectWith(fake);\n\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools.map((t) => t.name)).toEqual(['a', 'b']);\n });\n expect(listTools).toHaveBeenNthCalledWith(1, undefined);\n expect(listTools).toHaveBeenNthCalledWith(2, { cursor: 'p2' });\n });\n\n test('coerces a missing/invalid inputSchema to null and a missing description to undefined', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'noschema' }] }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools[0]).toEqual({ name: 'noschema', description: undefined, inputSchema: null });\n });\n });\n\n test('fails when listTools throws', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => {\n throw new Error('protocol error');\n })\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toFailWith(/listMcpTools:.*protocol error/);\n });\n});\n\ndescribe('callMcpTool', () => {\n const args: JsonObject = { q: 'hi' };\n\n test('fails loudly for a foreign session handle', async () => {\n expect(await callMcpTool(FOREIGN_SESSION, 'a', args)).toFailWith(/invalid MCP session/);\n });\n\n test('concatenates text blocks', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => ({\n content: [\n { type: 'text', text: 'line one' },\n { type: 'text', text: 'line two' }\n ]\n }))\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toSucceedWith({\n content: 'line one\\nline two'\n });\n expect(fake.callTool).toHaveBeenCalledWith({ name: 'a', arguments: args });\n });\n\n test('summarizes non-text blocks', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => ({\n content: [\n { type: 'text', text: 'caption' },\n { type: 'image', data: 'base64==' }\n ]\n }))\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toSucceedWith({\n content: 'caption\\n[image block]'\n });\n });\n\n test('projects an empty/absent content list to an empty string', async () => {\n const fake = makeFakeClient({ callTool: jest.fn(async () => ({})) });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toSucceedWith({ content: '' });\n });\n\n test('maps isError:true to a Failure carrying the projected content', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => ({ content: [{ type: 'text', text: 'bad input' }], isError: true }))\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toFailWith(/^bad input$/);\n });\n\n test('maps isError:true with no content to a generic error', async () => {\n const fake = makeFakeClient({ callTool: jest.fn(async () => ({ isError: true })) });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'broken', args)).toFailWith(/tool 'broken' reported an error/);\n });\n\n test('fails when callTool throws', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => {\n throw new Error('timeout');\n })\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toFailWith(/callMcpTool 'a':.*timeout/);\n });\n});\n\n// ===========================================================================\n// adaptMcpTools — the headline (Constraint 1)\n// ===========================================================================\n\ndescribe('adaptMcpTools', () => {\n const goodSchema: JsonValue = {\n type: 'object',\n properties: { q: { type: 'string' } },\n required: ['q']\n };\n // `pattern` is outside the JsonSchema.fromJson supported subset → fromJson fails with a pointer.\n const forbiddenSchema: JsonValue = {\n type: 'object',\n properties: { name: { type: 'string', pattern: '^a' } }\n };\n\n function mixedCatalogClient(): IFakeClient {\n return makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [\n { name: 'good', description: 'a good tool', inputSchema: goodSchema },\n { name: 'forbidden', inputSchema: forbiddenSchema },\n { name: 'nonobject', description: 'bad', inputSchema: 'not-a-schema' }\n ]\n }))\n });\n }\n\n test('propagates a tool-discovery failure', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => {\n throw new Error('discovery down');\n })\n });\n const session = await connectWith(fake);\n expect(await adaptMcpTools(session)).toFailWith(/adaptMcpTools:.*discovery down/);\n });\n\n test('adapts good tools and surfaces skipped tools structurally + NOISY warn', async () => {\n const logger = new Logging.InMemoryLogger('all');\n const session = await connectWith(mixedCatalogClient());\n\n expect(await adaptMcpTools(session, { logger })).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools).toHaveLength(1);\n expect(result.tools[0].config.name).toBe('good');\n expect(result.tools[0].config.description).toBe('a good tool');\n\n expect(result.skipped).toHaveLength(2);\n const byName = new Map(result.skipped.map((s) => [s.name, s]));\n expect(byName.get('forbidden')?.reason).toMatch(/pattern/);\n expect(byName.get('forbidden')?.schema).toEqual(forbiddenSchema);\n expect(byName.get('nonobject')?.reason).toMatch(/not a JSON object/);\n expect(byName.get('nonobject')?.schema).toBe('not-a-schema');\n });\n\n // NOISY warn: tool name + pointer reason + the raw failing schema verbatim.\n const warned = logger.logged.join('\\n');\n expect(warned).toMatch(/skipping tool 'forbidden'/);\n expect(warned).toMatch(/pattern/);\n expect(warned).toContain(JSON.stringify(forbiddenSchema));\n expect(warned).toMatch(/skipping tool 'nonobject'/);\n });\n\n test('surfaces skips structurally even without a logger', async () => {\n const session = await connectWith(mixedCatalogClient());\n expect(await adaptMcpTools(session)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools).toHaveLength(1);\n expect(result.skipped).toHaveLength(2);\n });\n });\n\n test('falls back to the tool name when no description is provided', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'nodesc', inputSchema: goodSchema }] }))\n });\n const session = await connectWith(fake);\n expect(await adaptMcpTools(session)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools[0].config.description).toBe('nodesc');\n });\n });\n\n describe('adapted tool execute', () => {\n async function adaptGood(callTool: jest.Mock): Promise<(args: unknown) => Promise<Result<unknown>>> {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'good', inputSchema: goodSchema }] })),\n callTool\n });\n const session = await connectWith(fake);\n const result = (await adaptMcpTools(session)).orThrow();\n return result.tools[0].execute;\n }\n\n test('forwards validated args to callMcpTool and returns the projected content', async () => {\n const callTool = jest.fn(async () => ({ content: [{ type: 'text', text: 'tool output' }] }));\n const execute = await adaptGood(callTool);\n expect(await execute({ q: 'hello' })).toSucceedWith('tool output');\n expect(callTool).toHaveBeenCalledWith({ name: 'good', arguments: { q: 'hello' } });\n });\n\n test('fails when the model supplies non-object arguments', async () => {\n const callTool = jest.fn();\n const execute = await adaptGood(callTool);\n expect(await execute('not-an-object')).toFailWith(/tool 'good': arguments must be a JSON object/);\n expect(callTool).not.toHaveBeenCalled();\n });\n\n test('propagates an MCP tool error as a Failure', async () => {\n const callTool = jest.fn(async () => ({ content: [{ type: 'text', text: 'denied' }], isError: true }));\n const execute = await adaptGood(callTool);\n expect(await execute({ q: 'hello' })).toFailWith(/denied/);\n });\n });\n});\n"]}
1
+ {"version":3,"file":"mcp.test.js","sourceRoot":"","sources":["../../../src/test/unit/mcp.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n// Mock the SDK-isolation seam so no live MCP server / subprocess is required. The factories\n// return controllable fakes; `makeClient` is configured per-test. The jest.mock call must\n// precede the regular imports (hoist-jest-mock).\njest.mock('../../packlets/mcp/sdk', () => ({\n makeClient: jest.fn(),\n makeStdioTransport: jest.fn(() => ({ sentinel: 'stdio' })),\n makeHttpTransport: jest.fn(() => ({ sentinel: 'http' }))\n}));\n\nimport '@fgv/ts-utils-jest';\nimport { Logging, type Result } from '@fgv/ts-utils';\nimport { type JsonObject, type JsonValue } from '@fgv/ts-json-base';\n\n// eslint-disable-next-line @rushstack/packlets/mechanics\nimport * as sdk from '../../packlets/mcp/sdk';\nimport {\n type IAdaptMcpToolsResult,\n type IMcpSession,\n type IMcpToolDescriptor,\n type IMcpTransport,\n adaptMcpTools,\n callMcpTool,\n closeMcpSession,\n connectMcpSession,\n createHttpTransport,\n createStdioTransport,\n listMcpTools\n} from '../../packlets/mcp';\n\nconst mockSdk = sdk as jest.Mocked<typeof sdk>;\n\ninterface IFakeClient {\n connect: jest.Mock;\n getServerVersion: jest.Mock;\n listTools: jest.Mock;\n callTool: jest.Mock;\n close: jest.Mock;\n}\n\nfunction makeFakeClient(overrides: Partial<IFakeClient> = {}): IFakeClient {\n return {\n connect: jest.fn(async () => undefined),\n getServerVersion: jest.fn(() => ({ name: 'fake-server', version: '1.2.3' })),\n listTools: jest.fn(async () => ({ tools: [] })),\n callTool: jest.fn(async () => ({ content: [] })),\n close: jest.fn(async () => undefined),\n ...overrides\n };\n}\n\n/** Connect a session backed by the given fake client (and a stdio transport). */\nasync function connectWith(fake: IFakeClient): Promise<IMcpSession> {\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n return (await connectMcpSession({ transport })).orThrow();\n}\n\n/** A foreign (non-package) handle, to exercise the loud narrowing-failure paths. */\nconst FOREIGN_TRANSPORT = { transportKind: 'stdio' } as unknown as IMcpTransport;\nconst FOREIGN_SESSION = {\n clientName: 'x',\n clientVersion: 'y',\n serverInfo: undefined\n} as unknown as IMcpSession;\n\nbeforeEach(() => {\n jest.clearAllMocks();\n mockSdk.makeStdioTransport.mockReturnValue({ sentinel: 'stdio' } as unknown as sdk.ISdkTransport);\n mockSdk.makeHttpTransport.mockReturnValue({ sentinel: 'http' } as unknown as sdk.ISdkTransport);\n});\n\n// ===========================================================================\n// Transports\n// ===========================================================================\n\ndescribe('createStdioTransport', () => {\n test('succeeds for a valid command', () => {\n expect(createStdioTransport({ command: 'node', args: ['x'] })).toSucceedAndSatisfy((t: IMcpTransport) => {\n expect(t.transportKind).toBe('stdio');\n });\n expect(mockSdk.makeStdioTransport).toHaveBeenCalledWith(\n expect.objectContaining({ command: 'node', args: ['x'] })\n );\n });\n\n test('fails for an empty/whitespace command', () => {\n expect(createStdioTransport({ command: '' })).toFailWith(/command must be a non-empty string/);\n expect(createStdioTransport({ command: ' ' })).toFailWith(/command must be a non-empty string/);\n });\n\n test('fails (Result) when the SDK constructor throws', () => {\n mockSdk.makeStdioTransport.mockImplementationOnce(() => {\n throw new Error('spawn boom');\n });\n expect(createStdioTransport({ command: 'node' })).toFailWith(/createStdioTransport:.*spawn boom/);\n });\n});\n\ndescribe('createHttpTransport', () => {\n test('succeeds for http and https urls and forwards headers', () => {\n expect(createHttpTransport({ url: 'http://localhost:9000/mcp' })).toSucceedAndSatisfy(\n (t: IMcpTransport) => {\n expect(t.transportKind).toBe('http');\n }\n );\n expect(\n createHttpTransport({ url: 'https://example.com/mcp', headers: { authorization: 'Bearer t' } })\n ).toSucceed();\n expect(mockSdk.makeHttpTransport).toHaveBeenCalledWith(expect.any(URL), { authorization: 'Bearer t' });\n });\n\n test('fails for an unparseable url', () => {\n expect(createHttpTransport({ url: 'not a url' })).toFailWith(/invalid url 'not a url'/);\n });\n\n test('fails for a non-http(s) protocol', () => {\n expect(createHttpTransport({ url: 'ftp://example.com' })).toFailWith(/must use http or https/);\n });\n\n test('fails (Result) when the SDK constructor throws', () => {\n mockSdk.makeHttpTransport.mockImplementationOnce(() => {\n throw new Error('http boom');\n });\n expect(createHttpTransport({ url: 'http://localhost' })).toFailWith(/createHttpTransport:.*http boom/);\n });\n});\n\n// ===========================================================================\n// Session lifecycle\n// ===========================================================================\n\ndescribe('connectMcpSession', () => {\n test('fails loudly for a foreign transport handle', async () => {\n expect(await connectMcpSession({ transport: FOREIGN_TRANSPORT })).toFailWith(/invalid MCP transport/);\n });\n\n test('connects and reports server identity, logging when a logger is supplied', async () => {\n const logger = new Logging.InMemoryLogger('all');\n const fake = makeFakeClient();\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(\n await connectMcpSession({ transport, clientName: 'me', clientVersion: '0.0.1', logger })\n ).toSucceedAndSatisfy((session: IMcpSession) => {\n expect(session.clientName).toBe('me');\n expect(session.clientVersion).toBe('0.0.1');\n expect(session.serverInfo).toEqual({ name: 'fake-server', version: '1.2.3' });\n });\n expect(mockSdk.makeClient).toHaveBeenCalledWith('me', '0.0.1');\n expect(fake.connect).toHaveBeenCalledTimes(1);\n expect(logger.logged.join('\\n')).toMatch(/connected to server fake-server@1.2.3/);\n });\n\n test('connects with default identity and no server info, no logger', async () => {\n const fake = makeFakeClient({ getServerVersion: jest.fn(() => undefined) });\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(await connectMcpSession({ transport })).toSucceedAndSatisfy((session: IMcpSession) => {\n expect(session.clientName).toBe('@fgv/ts-extras-mcp');\n expect(session.serverInfo).toBeUndefined();\n });\n });\n\n test('logs the no-identity case when a logger is supplied', async () => {\n const logger = new Logging.InMemoryLogger('all');\n const fake = makeFakeClient({ getServerVersion: jest.fn(() => undefined) });\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(await connectMcpSession({ transport, logger })).toSucceed();\n expect(logger.logged.join('\\n')).toMatch(/connected \\(server did not report identity\\)/);\n });\n\n test('fails when the connect handshake throws', async () => {\n const fake = makeFakeClient({\n connect: jest.fn(async () => {\n throw new Error('handshake refused');\n })\n });\n mockSdk.makeClient.mockReturnValueOnce(fake as unknown as sdk.ISdkClient);\n const transport = createStdioTransport({ command: 'node' }).orThrow();\n\n expect(await connectMcpSession({ transport })).toFailWith(/connectMcpSession:.*handshake refused/);\n });\n});\n\ndescribe('closeMcpSession', () => {\n test('fails loudly for a foreign session handle', async () => {\n expect(await closeMcpSession(FOREIGN_SESSION)).toFailWith(/invalid MCP session/);\n });\n\n test('closes a connected session', async () => {\n const fake = makeFakeClient();\n const session = await connectWith(fake);\n expect(await closeMcpSession(session)).toSucceedWith(true);\n expect(fake.close).toHaveBeenCalledTimes(1);\n });\n\n test('fails when close throws', async () => {\n const fake = makeFakeClient({\n close: jest.fn(async () => {\n throw new Error('already closed');\n })\n });\n const session = await connectWith(fake);\n expect(await closeMcpSession(session)).toFailWith(/closeMcpSession:.*already closed/);\n });\n});\n\n// ===========================================================================\n// Tool discovery + invocation\n// ===========================================================================\n\ndescribe('listMcpTools', () => {\n test('fails loudly for a foreign session handle', async () => {\n expect(await listMcpTools(FOREIGN_SESSION)).toFailWith(/invalid MCP session/);\n });\n\n test('returns a single-page catalog', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [{ name: 'a', description: 'tool a', inputSchema: { type: 'object' } }]\n }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools).toHaveLength(1);\n expect(tools[0]).toEqual({ name: 'a', description: 'tool a', inputSchema: { type: 'object' } });\n });\n });\n\n test('follows nextCursor across pages', async () => {\n const listTools = jest\n .fn()\n .mockResolvedValueOnce({ tools: [{ name: 'a', inputSchema: { type: 'object' } }], nextCursor: 'p2' })\n .mockResolvedValueOnce({ tools: [{ name: 'b', inputSchema: { type: 'object' } }] });\n const fake = makeFakeClient({ listTools });\n const session = await connectWith(fake);\n\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools.map((t) => t.name)).toEqual(['a', 'b']);\n });\n expect(listTools).toHaveBeenNthCalledWith(1, undefined);\n expect(listTools).toHaveBeenNthCalledWith(2, { cursor: 'p2' });\n });\n\n test('coerces a missing/invalid inputSchema to null and a missing description to undefined', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'noschema' }] }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools[0]).toEqual({ name: 'noschema', description: undefined, inputSchema: null });\n });\n });\n\n test('fails when listTools throws', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => {\n throw new Error('protocol error');\n })\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toFailWith(/listMcpTools:.*protocol error/);\n });\n});\n\ndescribe('callMcpTool', () => {\n const args: JsonObject = { q: 'hi' };\n\n test('fails loudly for a foreign session handle', async () => {\n expect(await callMcpTool(FOREIGN_SESSION, 'a', args)).toFailWith(/invalid MCP session/);\n });\n\n test('concatenates text blocks', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => ({\n content: [\n { type: 'text', text: 'line one' },\n { type: 'text', text: 'line two' }\n ]\n }))\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toSucceedWith({\n content: 'line one\\nline two'\n });\n expect(fake.callTool).toHaveBeenCalledWith({ name: 'a', arguments: args });\n });\n\n test('summarizes non-text blocks', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => ({\n content: [\n { type: 'text', text: 'caption' },\n { type: 'image', data: 'base64==' }\n ]\n }))\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toSucceedWith({\n content: 'caption\\n[image block]'\n });\n });\n\n test('projects an empty/absent content list to an empty string', async () => {\n const fake = makeFakeClient({ callTool: jest.fn(async () => ({})) });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toSucceedWith({ content: '' });\n });\n\n test('maps isError:true to a Failure carrying the projected content', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => ({ content: [{ type: 'text', text: 'bad input' }], isError: true }))\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toFailWith(/^bad input$/);\n });\n\n test('maps isError:true with no content to a generic error', async () => {\n const fake = makeFakeClient({ callTool: jest.fn(async () => ({ isError: true })) });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'broken', args)).toFailWith(/tool 'broken' reported an error/);\n });\n\n test('fails when callTool throws', async () => {\n const fake = makeFakeClient({\n callTool: jest.fn(async () => {\n throw new Error('timeout');\n })\n });\n const session = await connectWith(fake);\n expect(await callMcpTool(session, 'a', args)).toFailWith(/callMcpTool 'a':.*timeout/);\n });\n});\n\n// ===========================================================================\n// adaptMcpTools — the headline (Constraint 1)\n// ===========================================================================\n\ndescribe('adaptMcpTools', () => {\n const goodSchema: JsonValue = {\n type: 'object',\n properties: { q: { type: 'string' } },\n required: ['q']\n };\n // `pattern` is outside the JsonSchema.fromJson supported subset → fromJson fails with a pointer.\n const forbiddenSchema: JsonValue = {\n type: 'object',\n properties: { name: { type: 'string', pattern: '^a' } }\n };\n\n function mixedCatalogClient(): IFakeClient {\n return makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [\n { name: 'good', description: 'a good tool', inputSchema: goodSchema },\n { name: 'forbidden', inputSchema: forbiddenSchema },\n { name: 'nonobject', description: 'bad', inputSchema: 'not-a-schema' }\n ]\n }))\n });\n }\n\n test('propagates a tool-discovery failure', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => {\n throw new Error('discovery down');\n })\n });\n const session = await connectWith(fake);\n expect(await adaptMcpTools(session)).toFailWith(/adaptMcpTools:.*discovery down/);\n });\n\n test('adapts good tools and surfaces skipped tools structurally + NOISY warn', async () => {\n const logger = new Logging.InMemoryLogger('all');\n const session = await connectWith(mixedCatalogClient());\n\n expect(await adaptMcpTools(session, { logger })).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools).toHaveLength(1);\n expect(result.tools[0].config.name).toBe('good');\n expect(result.tools[0].config.description).toBe('a good tool');\n\n expect(result.skipped).toHaveLength(2);\n const byName = new Map(result.skipped.map((s) => [s.name, s]));\n expect(byName.get('forbidden')?.reason).toMatch(/pattern/);\n expect(byName.get('forbidden')?.schema).toEqual(forbiddenSchema);\n expect(byName.get('nonobject')?.reason).toMatch(/not a JSON object/);\n expect(byName.get('nonobject')?.schema).toBe('not-a-schema');\n });\n\n // NOISY warn: tool name + pointer reason + the raw failing schema verbatim.\n const warned = logger.logged.join('\\n');\n expect(warned).toMatch(/skipping tool 'forbidden'/);\n expect(warned).toMatch(/pattern/);\n expect(warned).toContain(JSON.stringify(forbiddenSchema));\n expect(warned).toMatch(/skipping tool 'nonobject'/);\n });\n\n test('surfaces skips structurally even without a logger', async () => {\n const session = await connectWith(mixedCatalogClient());\n expect(await adaptMcpTools(session)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools).toHaveLength(1);\n expect(result.skipped).toHaveLength(2);\n });\n });\n\n test('falls back to the tool name when no description is provided', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'nodesc', inputSchema: goodSchema }] }))\n });\n const session = await connectWith(fake);\n expect(await adaptMcpTools(session)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools[0].config.description).toBe('nodesc');\n });\n });\n\n describe('adapted tool execute', () => {\n async function adaptGood(callTool: jest.Mock): Promise<(args: unknown) => Promise<Result<unknown>>> {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'good', inputSchema: goodSchema }] })),\n callTool\n });\n const session = await connectWith(fake);\n const result = (await adaptMcpTools(session)).orThrow();\n return result.tools[0].execute;\n }\n\n test('forwards validated args to callMcpTool and returns the projected content', async () => {\n const callTool = jest.fn(async () => ({ content: [{ type: 'text', text: 'tool output' }] }));\n const execute = await adaptGood(callTool);\n expect(await execute({ q: 'hello' })).toSucceedWith('tool output');\n expect(callTool).toHaveBeenCalledWith({ name: 'good', arguments: { q: 'hello' } });\n });\n\n test('fails when the model supplies non-object arguments', async () => {\n const callTool = jest.fn();\n const execute = await adaptGood(callTool);\n expect(await execute('not-an-object')).toFailWith(/tool 'good': arguments must be a JSON object/);\n expect(callTool).not.toHaveBeenCalled();\n });\n\n test('propagates an MCP tool error as a Failure', async () => {\n const callTool = jest.fn(async () => ({ content: [{ type: 'text', text: 'denied' }], isError: true }));\n const execute = await adaptGood(callTool);\n expect(await execute({ q: 'hello' })).toFailWith(/denied/);\n });\n });\n\n // ==========================================================================\n // C2 — MCP Tool.annotations passthrough (normalized, never raw)\n // ==========================================================================\n\n describe('annotations passthrough (C2)', () => {\n const goodSchema2: JsonValue = { type: 'object', properties: { q: { type: 'string' } }, required: ['q'] };\n\n test('all five hints round-trip onto descriptor.annotations and config.annotations', async () => {\n const annotations = {\n title: 'Recall Memory',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false\n };\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [{ name: 'recall', description: 'r', inputSchema: goodSchema2, annotations }]\n }))\n });\n const session = await connectWith(fake);\n\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools[0].annotations).toEqual(annotations);\n });\n\n const session2 = await connectWith(\n makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [{ name: 'recall', description: 'r', inputSchema: goodSchema2, annotations }]\n }))\n })\n );\n expect(await adaptMcpTools(session2)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools[0].config.annotations).toEqual(annotations);\n });\n });\n\n test('a tool with no annotations leaves the field absent', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'plain', inputSchema: goodSchema2 }] }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools[0]).not.toHaveProperty('annotations');\n });\n\n const session2 = await connectWith(\n makeFakeClient({\n listTools: jest.fn(async () => ({ tools: [{ name: 'plain', inputSchema: goodSchema2 }] }))\n })\n );\n expect(await adaptMcpTools(session2)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools[0].config).not.toHaveProperty('annotations');\n });\n });\n\n test('a malformed annotations blob is normalized (known fields kept, junk dropped), never raw-propagated', async () => {\n // readOnlyHint is the wrong type (dropped); bogusField is unknown (dropped); title is valid (kept).\n const rawAnnotations = {\n title: 'Keep Me',\n readOnlyHint: 'yes-please',\n destructiveHint: true,\n bogusField: { nested: 42 }\n };\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [{ name: 'messy', inputSchema: goodSchema2, annotations: rawAnnotations }]\n }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n // Only the well-typed known fields survive; the malformed readOnlyHint and unknown\n // bogusField are dropped; the raw blob is never propagated.\n expect(tools[0].annotations).toEqual({ title: 'Keep Me', destructiveHint: true });\n expect(tools[0].annotations).not.toHaveProperty('readOnlyHint');\n expect(tools[0].annotations).not.toHaveProperty('bogusField');\n });\n });\n\n test('an all-junk annotations blob normalizes to an absent field (not an empty object)', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [\n { name: 'junk', inputSchema: goodSchema2, annotations: { unknownOnly: 1, readOnlyHint: 3 } }\n ]\n }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools[0]).not.toHaveProperty('annotations');\n });\n });\n\n test('a non-object annotations value is dropped', async () => {\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [{ name: 'weird', inputSchema: goodSchema2, annotations: 'not-an-object' }]\n }))\n });\n const session = await connectWith(fake);\n expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {\n expect(tools[0]).not.toHaveProperty('annotations');\n });\n });\n\n test('the skipped-tool path is unaffected by annotations', async () => {\n // A tool with annotations but an unsupported inputSchema is still skipped; annotations do\n // not rescue it or leak onto the skip record.\n const forbidden: JsonValue = {\n type: 'object',\n properties: { name: { type: 'string', pattern: '^a' } }\n };\n const fake = makeFakeClient({\n listTools: jest.fn(async () => ({\n tools: [{ name: 'blocked', inputSchema: forbidden, annotations: { destructiveHint: true } }]\n }))\n });\n const session = await connectWith(fake);\n expect(await adaptMcpTools(session)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {\n expect(result.tools).toHaveLength(0);\n expect(result.skipped).toHaveLength(1);\n expect(result.skipped[0].name).toBe('blocked');\n expect(result.skipped[0]).not.toHaveProperty('annotations');\n });\n });\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-extras-mcp",
3
- "version": "5.1.0-37",
3
+ "version": "5.1.0-39",
4
4
  "description": "Result-integration boundary over @modelcontextprotocol/sdk: connect to MCP servers, discover tools, and adapt them into @fgv/ts-extras ai-assist client tools",
5
5
  "main": "lib/index.js",
6
6
  "types": "dist/ts-extras-mcp.d.ts",
@@ -61,16 +61,16 @@
61
61
  "ts-jest": "^29.4.6",
62
62
  "ts-node": "^10.9.2",
63
63
  "typescript": "5.9.3",
64
- "@fgv/heft-dual-rig": "5.1.0-37",
65
- "@fgv/ts-utils": "5.1.0-37",
66
- "@fgv/ts-json-base": "5.1.0-37",
67
- "@fgv/ts-extras": "5.1.0-37",
68
- "@fgv/ts-utils-jest": "5.1.0-37"
64
+ "@fgv/heft-dual-rig": "5.1.0-39",
65
+ "@fgv/ts-extras": "5.1.0-39",
66
+ "@fgv/ts-utils": "5.1.0-39",
67
+ "@fgv/ts-utils-jest": "5.1.0-39",
68
+ "@fgv/ts-json-base": "5.1.0-39"
69
69
  },
70
70
  "peerDependencies": {
71
- "@fgv/ts-utils": "5.1.0-37",
72
- "@fgv/ts-extras": "5.1.0-37",
73
- "@fgv/ts-json-base": "5.1.0-37"
71
+ "@fgv/ts-utils": "5.1.0-39",
72
+ "@fgv/ts-json-base": "5.1.0-39",
73
+ "@fgv/ts-extras": "5.1.0-39"
74
74
  },
75
75
  "scripts": {
76
76
  "build": "heft build --clean",
@@ -1,3 +1,3 @@
1
1
  Caching build output folders: dist, lib, temp, .rush/temp/operation/build
2
2
  Successfully set cache entry.
3
- Cache key: 8523ec7cdfdd100d7242d368a2a014f4283131ad
3
+ Cache key: 28abef25194b96c733b5ec1c8816ab85532589aa
@@ -2,8 +2,8 @@ Invoking: heft build --clean
2
2
  ---- build started ----
3
3
  [build:typescript] The TypeScript compiler version 5.9.3 is newer than the latest version that was tested with Heft (5.8); it may not work correctly.
4
4
  [build:typescript] Using TypeScript version 5.9.3
5
- [build:lint] Using ESLint version 9.39.4
6
- [build:api-extractor] Using API Extractor version 7.58.7
5
+ [build:lint] Using ESLint version 9.39.5
6
+ [build:api-extractor] Using API Extractor version 7.58.9
7
7
  [build:api-extractor] Analysis will use the bundled TypeScript version 5.9.3
8
- ---- build finished (12.372s) ----
9
- -------------------- Finished (12.378s) --------------------
8
+ ---- build finished (10.270s) ----
9
+ -------------------- Finished (10.278s) --------------------
@@ -71,7 +71,7 @@ function _makeExecute(session: IMcpSession, name: string): (args: unknown) => Pr
71
71
  * tool's `inputSchema` is not a JSON object or is outside the `JsonSchema.fromJson` subset.
72
72
  */
73
73
  function _adaptOne(session: IMcpSession, descriptor: IMcpToolDescriptor): IAdaptOutcome {
74
- const { name, description, inputSchema } = descriptor;
74
+ const { name, description, inputSchema, annotations } = descriptor;
75
75
 
76
76
  const skip = (reason: string, schema: JsonValue): IAdaptOutcome => ({
77
77
  kind: 'skipped',
@@ -92,7 +92,10 @@ function _adaptOne(session: IMcpSession, descriptor: IMcpToolDescriptor): IAdapt
92
92
  type: 'client_tool',
93
93
  name,
94
94
  description: description ?? name,
95
- parametersSchema: schemaResult.value
95
+ parametersSchema: schemaResult.value,
96
+ // IMcpToolAnnotations maps 1:1 onto AiAssist.IAiToolAnnotations. Only set the field when the
97
+ // server provided usable annotations, so a tool without them stays exactly as before.
98
+ ...(annotations !== undefined ? { annotations } : {})
96
99
  };
97
100
  return {
98
101
  kind: 'tool',
@@ -124,6 +124,31 @@ export interface IMcpSession {
124
124
  // Tool discovery + invocation
125
125
  // ============================================================================
126
126
 
127
+ /**
128
+ * Normalized MCP `Tool.annotations` — the five known host-advisory behavior hints.
129
+ *
130
+ * @remarks
131
+ * Field names mirror MCP's `ToolAnnotations` 1:1 (and map straight onto
132
+ * `AiAssist.IAiToolAnnotations`). Per the MCP spec these are hints only, and per the
133
+ * untrusted-server warning they are validated/normalized (known fields kept, malformed
134
+ * or unknown fields dropped) before they reach {@link IMcpToolDescriptor} — the raw
135
+ * server blob is never propagated.
136
+ *
137
+ * @public
138
+ */
139
+ export interface IMcpToolAnnotations {
140
+ /** Optional human-readable display title for the tool. */
141
+ readonly title?: string;
142
+ /** Hint: the tool does not modify its environment (read-only). */
143
+ readonly readOnlyHint?: boolean;
144
+ /** Hint: the tool may perform destructive updates (only meaningful when not read-only). */
145
+ readonly destructiveHint?: boolean;
146
+ /** Hint: repeated calls with the same arguments have no additional effect. */
147
+ readonly idempotentHint?: boolean;
148
+ /** Hint: the tool interacts with an open world of external entities. */
149
+ readonly openWorldHint?: boolean;
150
+ }
151
+
127
152
  /**
128
153
  * A tool descriptor discovered from an MCP server via {@link listMcpTools}.
129
154
  * @public
@@ -140,6 +165,12 @@ export interface IMcpToolDescriptor {
140
165
  * supported subset).
141
166
  */
142
167
  readonly inputSchema: JsonValue;
168
+ /**
169
+ * The tool's normalized behavior annotations, when the server provided any usable ones.
170
+ * Absent when the server declared no annotations (or only malformed/unknown fields).
171
+ * See {@link IMcpToolAnnotations}.
172
+ */
173
+ readonly annotations?: IMcpToolAnnotations;
143
174
  }
144
175
 
145
176
  /**
@@ -26,23 +26,66 @@
26
26
  * @packageDocumentation
27
27
  */
28
28
 
29
- import { type Result, captureAsyncResult, fail, succeed } from '@fgv/ts-utils';
29
+ import { Converters as UtilsConverters, type Result, captureAsyncResult, fail, succeed } from '@fgv/ts-utils';
30
30
  import { Converters, type JsonObject } from '@fgv/ts-json-base';
31
31
 
32
- import { type IMcpSession, type IMcpToolCallResult, type IMcpToolDescriptor } from './model';
32
+ import {
33
+ type IMcpSession,
34
+ type IMcpToolAnnotations,
35
+ type IMcpToolCallResult,
36
+ type IMcpToolDescriptor
37
+ } from './model';
33
38
  import { type ISdkContentBlock, type ISdkToolDescriptor } from './sdk';
34
39
  import { McpSession } from './session';
35
40
 
41
+ /**
42
+ * Validates/normalizes a raw (untrusted) MCP `Tool.annotations` blob into an
43
+ * {@link IMcpToolAnnotations}, keeping only the five known fields that convert cleanly.
44
+ *
45
+ * @remarks
46
+ * Each known field is converted independently with its own Converter, so a present-but-malformed
47
+ * field is dropped (never failing the whole blob) and unknown keys are ignored. Returns
48
+ * `undefined` when the blob is absent, not a JSON object, or normalizes to no usable known
49
+ * fields — so a tool with no (usable) annotations leaves {@link IMcpToolDescriptor.annotations}
50
+ * absent. The raw server value is never propagated verbatim (per the MCP untrusted-server
51
+ * warning).
52
+ */
53
+ function _normalizeAnnotations(raw: unknown): IMcpToolAnnotations | undefined {
54
+ const objResult = Converters.jsonObject.convert(raw);
55
+ if (objResult.isFailure()) {
56
+ return undefined;
57
+ }
58
+ const obj = objResult.value;
59
+ const title = UtilsConverters.string.convert(obj.title).orDefault();
60
+ const readOnlyHint = UtilsConverters.boolean.convert(obj.readOnlyHint).orDefault();
61
+ const destructiveHint = UtilsConverters.boolean.convert(obj.destructiveHint).orDefault();
62
+ const idempotentHint = UtilsConverters.boolean.convert(obj.idempotentHint).orDefault();
63
+ const openWorldHint = UtilsConverters.boolean.convert(obj.openWorldHint).orDefault();
64
+
65
+ const normalized: IMcpToolAnnotations = {
66
+ ...(title !== undefined ? { title } : {}),
67
+ ...(readOnlyHint !== undefined ? { readOnlyHint } : {}),
68
+ ...(destructiveHint !== undefined ? { destructiveHint } : {}),
69
+ ...(idempotentHint !== undefined ? { idempotentHint } : {}),
70
+ ...(openWorldHint !== undefined ? { openWorldHint } : {})
71
+ };
72
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
73
+ }
74
+
36
75
  /**
37
76
  * Projects a single SDK tool descriptor into a public {@link IMcpToolDescriptor}. The
38
77
  * `inputSchema` field is validated as a `JsonValue`; an absent/non-JSON schema becomes `null`
39
78
  * (which {@link adaptMcpTools} then reports as un-adaptable rather than offering it to the model).
79
+ * The raw `annotations` blob is validated/normalized (never propagated raw) per the MCP
80
+ * untrusted-server warning.
40
81
  */
41
82
  function _toDescriptor(tool: ISdkToolDescriptor): IMcpToolDescriptor {
83
+ const annotations = _normalizeAnnotations(tool.annotations);
42
84
  return {
43
85
  name: tool.name,
44
86
  description: tool.description,
45
- inputSchema: Converters.jsonValue.convert(tool.inputSchema).orDefault(null)
87
+ inputSchema: Converters.jsonValue.convert(tool.inputSchema).orDefault(null),
88
+ ...(annotations !== undefined ? { annotations } : {})
46
89
  };
47
90
  }
48
91
 
@@ -72,6 +72,12 @@ export interface ISdkToolDescriptor {
72
72
  readonly name: string;
73
73
  readonly description?: string;
74
74
  readonly inputSchema?: unknown;
75
+ /**
76
+ * Raw MCP `Tool.annotations` (untrusted). Declared as `unknown` so the SDK field survives
77
+ * narrowing; the operations layer validates/normalizes it (never propagates raw) per the MCP
78
+ * spec's untrusted-server warning.
79
+ */
80
+ readonly annotations?: unknown;
75
81
  }
76
82
 
77
83
  /**
@@ -470,4 +470,132 @@ describe('adaptMcpTools', () => {
470
470
  expect(await execute({ q: 'hello' })).toFailWith(/denied/);
471
471
  });
472
472
  });
473
+
474
+ // ==========================================================================
475
+ // C2 — MCP Tool.annotations passthrough (normalized, never raw)
476
+ // ==========================================================================
477
+
478
+ describe('annotations passthrough (C2)', () => {
479
+ const goodSchema2: JsonValue = { type: 'object', properties: { q: { type: 'string' } }, required: ['q'] };
480
+
481
+ test('all five hints round-trip onto descriptor.annotations and config.annotations', async () => {
482
+ const annotations = {
483
+ title: 'Recall Memory',
484
+ readOnlyHint: true,
485
+ destructiveHint: false,
486
+ idempotentHint: true,
487
+ openWorldHint: false
488
+ };
489
+ const fake = makeFakeClient({
490
+ listTools: jest.fn(async () => ({
491
+ tools: [{ name: 'recall', description: 'r', inputSchema: goodSchema2, annotations }]
492
+ }))
493
+ });
494
+ const session = await connectWith(fake);
495
+
496
+ expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {
497
+ expect(tools[0].annotations).toEqual(annotations);
498
+ });
499
+
500
+ const session2 = await connectWith(
501
+ makeFakeClient({
502
+ listTools: jest.fn(async () => ({
503
+ tools: [{ name: 'recall', description: 'r', inputSchema: goodSchema2, annotations }]
504
+ }))
505
+ })
506
+ );
507
+ expect(await adaptMcpTools(session2)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {
508
+ expect(result.tools[0].config.annotations).toEqual(annotations);
509
+ });
510
+ });
511
+
512
+ test('a tool with no annotations leaves the field absent', async () => {
513
+ const fake = makeFakeClient({
514
+ listTools: jest.fn(async () => ({ tools: [{ name: 'plain', inputSchema: goodSchema2 }] }))
515
+ });
516
+ const session = await connectWith(fake);
517
+ expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {
518
+ expect(tools[0]).not.toHaveProperty('annotations');
519
+ });
520
+
521
+ const session2 = await connectWith(
522
+ makeFakeClient({
523
+ listTools: jest.fn(async () => ({ tools: [{ name: 'plain', inputSchema: goodSchema2 }] }))
524
+ })
525
+ );
526
+ expect(await adaptMcpTools(session2)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {
527
+ expect(result.tools[0].config).not.toHaveProperty('annotations');
528
+ });
529
+ });
530
+
531
+ test('a malformed annotations blob is normalized (known fields kept, junk dropped), never raw-propagated', async () => {
532
+ // readOnlyHint is the wrong type (dropped); bogusField is unknown (dropped); title is valid (kept).
533
+ const rawAnnotations = {
534
+ title: 'Keep Me',
535
+ readOnlyHint: 'yes-please',
536
+ destructiveHint: true,
537
+ bogusField: { nested: 42 }
538
+ };
539
+ const fake = makeFakeClient({
540
+ listTools: jest.fn(async () => ({
541
+ tools: [{ name: 'messy', inputSchema: goodSchema2, annotations: rawAnnotations }]
542
+ }))
543
+ });
544
+ const session = await connectWith(fake);
545
+ expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {
546
+ // Only the well-typed known fields survive; the malformed readOnlyHint and unknown
547
+ // bogusField are dropped; the raw blob is never propagated.
548
+ expect(tools[0].annotations).toEqual({ title: 'Keep Me', destructiveHint: true });
549
+ expect(tools[0].annotations).not.toHaveProperty('readOnlyHint');
550
+ expect(tools[0].annotations).not.toHaveProperty('bogusField');
551
+ });
552
+ });
553
+
554
+ test('an all-junk annotations blob normalizes to an absent field (not an empty object)', async () => {
555
+ const fake = makeFakeClient({
556
+ listTools: jest.fn(async () => ({
557
+ tools: [
558
+ { name: 'junk', inputSchema: goodSchema2, annotations: { unknownOnly: 1, readOnlyHint: 3 } }
559
+ ]
560
+ }))
561
+ });
562
+ const session = await connectWith(fake);
563
+ expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {
564
+ expect(tools[0]).not.toHaveProperty('annotations');
565
+ });
566
+ });
567
+
568
+ test('a non-object annotations value is dropped', async () => {
569
+ const fake = makeFakeClient({
570
+ listTools: jest.fn(async () => ({
571
+ tools: [{ name: 'weird', inputSchema: goodSchema2, annotations: 'not-an-object' }]
572
+ }))
573
+ });
574
+ const session = await connectWith(fake);
575
+ expect(await listMcpTools(session)).toSucceedAndSatisfy((tools: ReadonlyArray<IMcpToolDescriptor>) => {
576
+ expect(tools[0]).not.toHaveProperty('annotations');
577
+ });
578
+ });
579
+
580
+ test('the skipped-tool path is unaffected by annotations', async () => {
581
+ // A tool with annotations but an unsupported inputSchema is still skipped; annotations do
582
+ // not rescue it or leak onto the skip record.
583
+ const forbidden: JsonValue = {
584
+ type: 'object',
585
+ properties: { name: { type: 'string', pattern: '^a' } }
586
+ };
587
+ const fake = makeFakeClient({
588
+ listTools: jest.fn(async () => ({
589
+ tools: [{ name: 'blocked', inputSchema: forbidden, annotations: { destructiveHint: true } }]
590
+ }))
591
+ });
592
+ const session = await connectWith(fake);
593
+ expect(await adaptMcpTools(session)).toSucceedAndSatisfy((result: IAdaptMcpToolsResult) => {
594
+ expect(result.tools).toHaveLength(0);
595
+ expect(result.skipped).toHaveLength(1);
596
+ expect(result.skipped[0].name).toBe('blocked');
597
+ expect(result.skipped[0]).not.toHaveProperty('annotations');
598
+ });
599
+ });
600
+ });
473
601
  });
@@ -1,13 +1,13 @@
1
1
  {
2
- "cacheVersion": "9.39.4_v22.22.0",
2
+ "cacheVersion": "9.39.5_v24.15.0",
3
3
  "fileVersions": [
4
4
  [
5
5
  "packlets/mcp/model.ts",
6
- "b6be99c7f76f1434478a5361a343e356ffb0007be2fd764f116a5550563866ca_IYqsapbGB6B3yx4UV6LqpWK0OYg="
6
+ "d6a1b0cb728e973b27e77a8c1bbf20511d8343410e62ce042c1e44a78faa6658_IYqsapbGB6B3yx4UV6LqpWK0OYg="
7
7
  ],
8
8
  [
9
9
  "packlets/mcp/sdk.ts",
10
- "bff9c56c6730036468fd0291b9666d71896e1b6684768947ca75f686239a5f08_IYqsapbGB6B3yx4UV6LqpWK0OYg="
10
+ "e9a4ea9fdec673682cdf5b658da06a01af002b67c850ba00df7a71a0c81ab197_IYqsapbGB6B3yx4UV6LqpWK0OYg="
11
11
  ],
12
12
  [
13
13
  "packlets/mcp/transports.ts",
@@ -19,11 +19,11 @@
19
19
  ],
20
20
  [
21
21
  "packlets/mcp/operations.ts",
22
- "e4febfd8217dcef9851039d2f3ef22adaa9d8a06ee4dd7e3b22f717d0e90b543_IYqsapbGB6B3yx4UV6LqpWK0OYg="
22
+ "8cd2c4ef8d3e4e8d0c7acbb335308ac9fa492e2bf84d649c51c93be7a6c8ca7b_IYqsapbGB6B3yx4UV6LqpWK0OYg="
23
23
  ],
24
24
  [
25
25
  "packlets/mcp/adapter.ts",
26
- "66fbecd9acc4d027ca68232f9b99c20c1f5ba83e48c88fc0248ee55dc5e9cbfa_IYqsapbGB6B3yx4UV6LqpWK0OYg="
26
+ "2f605d2ed0473c9c5af9387f74cf853a67e952446d453d2392d89fe2b884a821_IYqsapbGB6B3yx4UV6LqpWK0OYg="
27
27
  ],
28
28
  [
29
29
  "packlets/mcp/index.ts",
@@ -43,7 +43,7 @@
43
43
  ],
44
44
  [
45
45
  "test/unit/mcp.test.ts",
46
- "da2a2ede0f2897396ac07571107a1a8b1fc9bbb11707739ea8579f4bddca8d20_ZiNeDEwwOmFLuy7OqvYfMbZKmpo="
46
+ "537d4565661800e0417c93048ca48526c78a36ba9295a28d4c66f0a5f2fe62fe_ZiNeDEwwOmFLuy7OqvYfMbZKmpo="
47
47
  ],
48
48
  [
49
49
  "test/unit/sdk.test.ts",