|
1 | 1 | import type { DevframeHost } from 'devframe/types' |
2 | 2 | import { Client, InMemoryTransport } from '@modelcontextprotocol/client' |
3 | 3 | import { createHostContext } from 'devframe/node' |
| 4 | +import * as v from 'valibot' |
4 | 5 | import { describe, expect, it } from 'vitest' |
5 | 6 | import { buildMcpServerFromContext } from '../build-server' |
6 | 7 |
|
@@ -165,6 +166,35 @@ describe('mcp adapter (in-memory)', () => { |
165 | 166 | } |
166 | 167 | }) |
167 | 168 |
|
| 169 | + it('calls an rpc-backed tool whose return schema has no native converter', async () => { |
| 170 | + const { ctx, client, cleanup } = await bootPair() |
| 171 | + try { |
| 172 | + ctx.rpc.register({ |
| 173 | + name: 'list-things', |
| 174 | + type: 'query', |
| 175 | + jsonSerializable: true, |
| 176 | + args: [], |
| 177 | + returns: v.array(v.object({ id: v.string() })), |
| 178 | + agent: { description: 'Lists things.' }, |
| 179 | + handler: () => [{ id: 'a' }, { id: 'b' }], |
| 180 | + } as never) |
| 181 | + |
| 182 | + const listed = await client.listTools() |
| 183 | + const tool = listed.tools.find(t => t.name.endsWith('list-things')) |
| 184 | + expect(tool).toBeDefined() |
| 185 | + expect(tool!.outputSchema).toBeUndefined() |
| 186 | + |
| 187 | + const result = await client.callTool({ name: tool!.name, arguments: {} }) |
| 188 | + expect(result.isError).toBeFalsy() |
| 189 | + const content = result.content as Array<{ type: string, text: string }> |
| 190 | + expect(JSON.parse(content[0]!.text)).toEqual([{ id: 'a' }, { id: 'b' }]) |
| 191 | + expect(result.structuredContent).toBeUndefined() |
| 192 | + } |
| 193 | + finally { |
| 194 | + await cleanup() |
| 195 | + } |
| 196 | + }) |
| 197 | + |
168 | 198 | it('coerces non-JSON values returned from a tool', async () => { |
169 | 199 | const { ctx, client, cleanup } = await bootPair() |
170 | 200 | try { |
|
0 commit comments