From 1ad87acffc3494807a7ecf7b12c509b8ac3f22ba Mon Sep 17 00:00:00 2001 From: Gavin Uhma Date: Fri, 13 Jun 2025 11:14:01 -0300 Subject: [PATCH 1/2] fix tool commands and add integration tests --- src/commands/tool.ts | 13 +++++++++---- src/commands/tools.ts | 2 ++ test/integration.test.ts | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 test/integration.test.ts diff --git a/src/commands/tool.ts b/src/commands/tool.ts index 3c0080c..ed6911d 100644 --- a/src/commands/tool.ts +++ b/src/commands/tool.ts @@ -7,13 +7,16 @@ import { computeChildProcess } from '../utils/spawn.js' // Define the expected shape for parsed arguments. export default class Tool extends Command { - // Use array syntax for positional args. - // Oclif will use the 'name' field to build an object in the parsed output. + // Arguments must be declared in the order they are expected on the + // command line. Required arguments cannot come after optional ones, + // otherwise oclif will throw an "Invalid argument spec" error. + /* eslint-disable perfectionist/sort-objects */ static args = { - properties: Args.string({ description: 'Tool properties as key=value pairs', multiple: true }), server: Args.string({ description: 'the MCP server', required: true }), - tool: Args.string({ description: 'the tool to call', required: true }) + tool: Args.string({ description: 'the tool to call', required: true }), + properties: Args.string({ description: 'Tool properties as key=value pairs', multiple: true }), } + /* eslint-enable perfectionist/sort-objects */ static description = 'Call a tool on a server' static flags = { json: Flags.boolean({ char: 'j', description: 'Output result in JSON format' }) @@ -82,5 +85,7 @@ static strict = false console.log('Tool call result:', result) } + await client.close() + } } diff --git a/src/commands/tools.ts b/src/commands/tools.ts index 62019f0..c118405 100644 --- a/src/commands/tools.ts +++ b/src/commands/tools.ts @@ -97,5 +97,7 @@ static strict = false for (const tool of toolsArray) { printTool(tool) } + + await client.close() } } diff --git a/test/integration.test.ts b/test/integration.test.ts new file mode 100644 index 0000000..ad8c838 --- /dev/null +++ b/test/integration.test.ts @@ -0,0 +1,32 @@ +import {expect} from 'chai' +import {spawnSync} from 'node:child_process' + +function runCli(args: string[]) { + return spawnSync('node', ['--loader','ts-node/esm','--disable-warning=ExperimentalWarning', './bin/dev.js', ...args], {encoding: 'utf8', timeout: 5000}) +} + +describe('integration', () => { + it('lists tools for python server', () => { + const res = runCli(['tools', './mcp-server.py']) + expect(res.status).to.equal(0) + expect(res.stdout).to.contain('echo') + }) + + it('calls tool on python server', () => { + const res = runCli(['tool', './mcp-server.py', 'echo', 'message=hi']) + expect(res.status).to.equal(0) + expect(res.stdout).to.contain('hi') + }) + + it('lists tools for node server', () => { + const res = runCli(['tools', './mcp-server-node.mjs']) + expect(res.status).to.equal(0) + expect(res.stdout).to.contain('echo') + }) + + it('calls tool on node server', () => { + const res = runCli(['tool', './mcp-server-node.mjs', 'echo', 'message=hi']) + expect(res.status).to.equal(0) + expect(res.stdout).to.contain('hi') + }) +}) From 26b200a074a3d7fe3621102951d61f66c174f1a9 Mon Sep 17 00:00:00 2001 From: Gavin Uhma Date: Fri, 13 Jun 2025 11:28:44 -0300 Subject: [PATCH 2/2] test: increase timeout for integration --- test/integration.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration.test.ts b/test/integration.test.ts index ad8c838..1ea87ee 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -2,7 +2,7 @@ import {expect} from 'chai' import {spawnSync} from 'node:child_process' function runCli(args: string[]) { - return spawnSync('node', ['--loader','ts-node/esm','--disable-warning=ExperimentalWarning', './bin/dev.js', ...args], {encoding: 'utf8', timeout: 5000}) + return spawnSync(process.execPath, ['--loader','ts-node/esm','--disable-warning=ExperimentalWarning', './bin/dev.js', ...args], {encoding: 'utf8', timeout: 15_000}) } describe('integration', () => {