Skip to content

Commit e84e1c4

Browse files
committed
mcp tests fix
1 parent 7006c1f commit e84e1c4

File tree

3 files changed

+54
-44
lines changed

3 files changed

+54
-44
lines changed

src/main/mcp.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ export default class {
404404
throw new Error(`Tool ${name} not found`)
405405
}
406406

407-
const tool = name.replace(`___${client.server.uuid.slice(-4)}`, '')
407+
// remove unique suffix
408+
const tool = name.replace(/___....$/, '')
408409
console.log('Calling MCP tool', tool, args)
409410

410411
return await client.client.callTool({
@@ -415,8 +416,7 @@ export default class {
415416
}
416417

417418
protected uniqueToolName(server: McpServer, name: string): string {
418-
const suffix = server.uuid.slice(-4) // use only last 4 characters of UUID to generate uniqueToolName
419-
return `${name}___${suffix}`
419+
return `${name}___${server.uuid.slice(-4)}`
420420
}
421421

422422
protected mcpToOpenAI = (server: McpServer, tool: any): LlmTool => {

tests/fixtures/mcp.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"mcp": {
44
"enabled": true,
55
"servers": [
6-
{ "uuid": "1", "registryId": "1", "state": "enabled", "type": "stdio", "command": "node", "url": "script.js", "env": { "KEY": "value" } },
7-
{ "uuid": "2", "registryId": "2", "state": "enabled", "type": "sse", "url": "http://localhost:3000" },
8-
{ "uuid": "3", "registryId": "3", "state": "disabled", "type": "stdio", "command": "python3", "url": "script.py" }
6+
{ "uuid": "1234-5678-90ab", "registryId": "1234-5678-90ab", "state": "enabled", "type": "stdio", "command": "node", "url": "script.js", "env": { "KEY": "value" } },
7+
{ "uuid": "2345-6789-0abc", "registryId": "2345-6789-0abc", "state": "enabled", "type": "sse", "url": "http://localhost:3000" },
8+
{ "uuid": "3456-7890-abcd", "registryId": "3456-7890-abcd", "state": "disabled", "type": "stdio", "command": "python3", "url": "script.py" }
99
],
1010
"disabledMcpServers": [ "mcp2" ]
1111
}

tests/unit/mcp.test.ts

+48-38
Original file line numberDiff line numberDiff line change
@@ -51,44 +51,48 @@ vi.mock('@modelcontextprotocol/sdk/client/stdio.js', async () => {
5151
})) }
5252
})
5353

54+
let count = 1
5455
vi.mock('@modelcontextprotocol/sdk/client/index.js', async () => {
55-
const Client = vi.fn()
56-
Client.prototype.connect = vi.fn()
56+
const Client = vi.fn(function() {
57+
this.id = count++
58+
})
59+
Client.prototype.connect = vi.fn(function(transport) { this.transport = transport })
5760
Client.prototype.close = vi.fn()
5861
Client.prototype.listTools = vi.fn(async () => ({
5962
tools: [
6063
{ name: 'tool1', description: 'tool1 description', inputSchema: { type: 'object', properties: { arg: { type: 'string' }}, required: [] } },
6164
{ name: 'tool2', description: 'tool2 description', inputSchema: { type: 'object', properties: { arg: { type: 'number', description: 'desc' }}, required: [] } },
6265
]
6366
}))
64-
Client.prototype.callTool = vi.fn(async (params) => {
65-
if (JSON.stringify(params.arguments).includes('legacy')) return { toolResult: 'result' }
66-
else return { content: [ { type: 'text', text: 'result' }]}
67+
Client.prototype.callTool = vi.fn(function(params) {
68+
if (this.id == 1) return { toolResult: `${this.id}-${params.name}-${params.arguments.arg}-result` }
69+
else return { content: [ { type: 'text', text: `${this.id}-${params.name}-${params.arguments.arg}-result` }]}
6770
})
6871
return { Client }
6972
})
7073

7174
beforeEach(() => {
75+
count = 1
7276
config = JSON.parse(JSON.stringify(mcpConfig))
7377
vi.clearAllMocks()
7478
})
7579

76-
test('init', async () => {
80+
test('Initialization', async () => {
7781
const mcp = new Mcp(app)
7882
expect(mcp).toBeDefined()
7983
expect(mcp.clients).toBeDefined()
8084
expect(Client.prototype.connect).toHaveBeenCalledTimes(0)
8185
expect(await mcp.getStatus()).toEqual({ servers: [], logs: {} })
8286
expect(mcp.getServers()).toStrictEqual([
83-
{ uuid: '1', registryId: '1', state: 'enabled', type: 'stdio', command: 'node', url: 'script.js', env: { KEY: 'value' } },
84-
{ uuid: '2', registryId: '2', state: 'enabled', type: 'sse', url: 'http://localhost:3000' },
85-
{ uuid: '3', registryId: '3', state: 'disabled', type: 'stdio', command: 'python3', url: 'script.py' },
87+
{ uuid: '1234-5678-90ab', registryId: '1234-5678-90ab', state: 'enabled', type: 'stdio', command: 'node', url: 'script.js', env: { KEY: 'value' } },
88+
{ uuid: '2345-6789-0abc', registryId: '2345-6789-0abc', state: 'enabled', type: 'sse', url: 'http://localhost:3000' },
89+
{ uuid: '3456-7890-abcd', registryId: '3456-7890-abcd', state: 'disabled', type: 'stdio', command: 'python3', url: 'script.py' },
8690
{ uuid: 'mcp1', registryId: '@mcp1', state: 'enabled', type: 'stdio', command: 'npx', url: '-y run mcp1.js', env: { KEY: 'value' } },
8791
{ uuid: 'mcp2', registryId: 'mcp2', state: 'disabled', type: 'stdio', command: 'npx', url: '-y run mcp2.js', env: undefined }
8892
])
8993
})
9094

91-
test('create server', async () => {
95+
test('Create server', async () => {
9296
const mcp = new Mcp(app)
9397
expect(await mcp.editServer({ uuid: null, registryId: null, state: 'enabled', type: 'sse', url: 'http://localhost:3001'})).toBe(true)
9498
expect(mcp.getServers()).toHaveLength(6)
@@ -110,26 +114,26 @@ test('create server', async () => {
110114
})
111115
})
112116

113-
test('edit normal server', async () => {
117+
test('Edit normal server', async () => {
114118
const mcp = new Mcp(app)
115-
expect(await mcp.editServer({ uuid: '2', registryId: '2', state: 'disabled', type: 'sse', url: 'http://localhost:3001'})).toBe(true)
119+
expect(await mcp.editServer({ uuid: '2345-6789-0abc', registryId: '2345-6789-0abc', state: 'disabled', type: 'sse', url: 'http://localhost:3001'})).toBe(true)
116120
expect(mcp.getServers()[1]).toMatchObject({
117-
uuid: '2',
118-
registryId: '2',
121+
uuid: '2345-6789-0abc',
122+
registryId: '2345-6789-0abc',
119123
state: 'disabled',
120124
type: 'sse',
121125
url: 'http://localhost:3001',
122126
})
123127
expect(config.plugins.mcp.servers[1]).toMatchObject({
124-
uuid: '2',
125-
registryId: '2',
128+
uuid: '2345-6789-0abc',
129+
registryId: '2345-6789-0abc',
126130
state: 'disabled',
127131
type: 'sse',
128132
url: 'http://localhost:3001',
129133
})
130134
})
131135

132-
test('edit mcp server', async () => {
136+
test('Edit mcp server', async () => {
133137
const mcp = new Mcp(app)
134138
expect(await mcp.editServer({ uuid: 'mcp1', registryId: '@mcp1', state: 'enabled', type: 'stdio', command: 'node', url: '-f exec mcp1.js'})).toBe(true)
135139

@@ -167,52 +171,56 @@ test('edit mcp server', async () => {
167171
expect(config.plugins.mcp.disabledMcpServers).toEqual(['mcp2', '@mcp1'])
168172
})
169173

170-
test('delete server', async () => {
174+
test('Delete server', async () => {
171175
const mcp = new Mcp(app)
172-
expect(mcp.deleteServer('1')).toBe(true)
173-
expect(mcp.getServers().find(s => s.uuid === '1')).toBeUndefined()
174-
expect(config.plugins.mcp.servers.find(s => s.uuid === '1')).toBeUndefined()
176+
expect(mcp.getServers().length).toBe(5)
177+
expect(mcp.deleteServer('1234-5678-90ab')).toBe(true)
178+
expect(mcp.getServers().length).toBe(4)
179+
expect(mcp.getServers().find(s => s.uuid === '1234-5678-90ab')).toBeUndefined()
180+
expect(config.plugins.mcp.servers.find(s => s.uuid === '1234-5678-90ab')).toBeUndefined()
175181
expect(mcp.deleteServer('@mcp1')).toBe(true)
182+
expect(mcp.getServers().length).toBe(3)
176183
expect(mcp.getServers().find(s => s.uuid === 'mcp1')).toBeUndefined()
177184
expect(config.mcpServers['@mcp1']).toBeUndefined()
178185
expect(mcp.deleteServer('4')).toBe(false)
186+
expect(mcp.getServers().length).toBe(3)
179187
expect(mcp.deleteServer('@mcp2')).toBe(false)
180188
})
181189

182-
test('connect', async () => {
190+
test('Connect', async () => {
183191
const mcp = new Mcp(app)
184192
expect(await mcp.connect())
185193
expect(mcp.clients).toHaveLength(3)
186194
expect(await mcp.getStatus()).toStrictEqual({
187195
servers: [
188-
{ uuid: '1', registryId: '1', state: 'enabled', type: 'stdio', command: 'node', url: 'script.js', env: { KEY: 'value' }, tools: ['tool1___1', 'tool2___1'] },
189-
{ uuid: '2', registryId: '2', state: 'enabled', type: 'sse', url: 'http://localhost:3000', tools: ['tool1___2', 'tool2___2'] },
196+
{ uuid: '1234-5678-90ab', registryId: '1234-5678-90ab', state: 'enabled', type: 'stdio', command: 'node', url: 'script.js', env: { KEY: 'value' }, tools: ['tool1___90ab', 'tool2___90ab'] },
197+
{ uuid: '2345-6789-0abc', registryId: '2345-6789-0abc', state: 'enabled', type: 'sse', url: 'http://localhost:3000', tools: ['tool1___0abc', 'tool2___0abc'] },
190198
{ uuid: 'mcp1', registryId: '@mcp1', state: 'enabled', type: 'stdio', command: 'npx', url: '-y run mcp1.js', env: { KEY: 'value' }, tools: ['tool1___mcp1', 'tool2___mcp1'] },
191199
],
192200
logs: {
193-
'1': [],
194-
'2': [],
195-
'3': [],
201+
'1234-5678-90ab': [],
202+
'2345-6789-0abc': [],
203+
'3456-7890-abcd': [],
196204
'mcp1': [],
197205
'mcp2': [],
198206
}
199207
})
200208
expect(await mcp.getTools()).toStrictEqual([
201209
{
202210
type: 'function',
203-
function: { name: 'tool1___1', description: 'tool1 description', parameters: { type: 'object', properties: { arg: { type: 'string', description: 'arg' }}, required: [] } }
211+
function: { name: 'tool1___90ab', description: 'tool1 description', parameters: { type: 'object', properties: { arg: { type: 'string', description: 'arg' }}, required: [] } }
204212
},
205213
{
206214
type: 'function',
207-
function: { name: 'tool2___1', description: 'tool2 description', parameters: { type: 'object', properties: { arg: { type: 'number', description: 'desc' }}, required: [] } }
215+
function: { name: 'tool2___90ab', description: 'tool2 description', parameters: { type: 'object', properties: { arg: { type: 'number', description: 'desc' }}, required: [] } }
208216
},
209217
{
210218
type: 'function',
211-
function: { name: 'tool1___2', description: 'tool1 description', parameters: { type: 'object', properties: { arg: { type: 'string', description: 'arg' }}, required: [] } }
219+
function: { name: 'tool1___0abc', description: 'tool1 description', parameters: { type: 'object', properties: { arg: { type: 'string', description: 'arg' }}, required: [] } }
212220
},
213221
{
214222
type: 'function',
215-
function: { name: 'tool2___2', description: 'tool2 description', parameters: { type: 'object', properties: { arg: { type: 'number', description: 'desc' }}, required: [] } }
223+
function: { name: 'tool2___0abc', description: 'tool2 description', parameters: { type: 'object', properties: { arg: { type: 'number', description: 'desc' }}, required: [] } }
216224
},
217225
{
218226
type: 'function',
@@ -225,24 +233,26 @@ test('connect', async () => {
225233
])
226234
})
227235

228-
test('call tool', async () => {
236+
test('Call tool', async () => {
229237
const mcp = new Mcp(app)
230238
await mcp.connect()
231-
expect(await mcp.callTool('tool1___1', { arg: 'legacy' })).toStrictEqual({ toolResult: 'result' })
232-
expect(await mcp.callTool('tool2___1', { arg: 'modern' })).toStrictEqual({ content: [{ type: 'text', text: 'result' }] })
239+
expect(await mcp.callTool('tool1___90ab', { arg: 'arg1' })).toStrictEqual({ toolResult: '1-tool1-arg1-result' })
240+
expect(await mcp.callTool('tool2___90ab', { arg: 'arg2' })).toStrictEqual({ toolResult: '1-tool2-arg2-result' })
241+
expect(await mcp.callTool('tool1___0abc', { arg: 'arg3' })).toStrictEqual({ content: [{ type: 'text', text: '2-tool1-arg3-result' }] })
242+
expect(await mcp.callTool('tool2___0abc', { arg: 'arg4' })).toStrictEqual({ content: [{ type: 'text', text: '2-tool2-arg4-result' }] })
233243
await expect(() => mcp.callTool('tool3___1', { arg: 'modern' })).rejects.toThrowError(/not found/)
234244
})
235245

236-
test('disconnect', async () => {
246+
test('Disconnect', async () => {
237247
const mcp = new Mcp(app)
238248
expect(await mcp.connect())
239249
expect(mcp.clients).toHaveLength(3)
240-
expect(mcp.deleteServer('1')).toBe(true)
250+
expect(mcp.deleteServer('1234-5678-90ab')).toBe(true)
241251
expect(Client.prototype.close).toHaveBeenCalledTimes(1)
242252
expect(mcp.clients).toHaveLength(2)
243253
})
244254

245-
test('reload', async () => {
255+
test('Reload', async () => {
246256
const mcp = new Mcp(app)
247257
expect(await mcp.connect())
248258
expect(mcp.clients).toHaveLength(3)
@@ -252,7 +262,7 @@ test('reload', async () => {
252262
expect(Client.prototype.close).toHaveBeenCalledTimes(3)
253263
})
254264

255-
test('install smithery', async () => {
265+
test('Install smithery', async () => {
256266
const mcp = new Mcp(app)
257267
expect(await mcp.getInstallCommand('smithery', 'server')).toBe('npx -y @smithery/cli@latest install server --client witsy')
258268
expect(await mcp.installServer('smithery', 'server')).toBe(true)

0 commit comments

Comments
 (0)