Skip to content

Commit 6447edd

Browse files
committed
Add missing execution field to ListTools
1 parent 681cf0d commit 6447edd

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

src/server/mcp.test.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,144 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
17741774
expect(result.tools[0]._meta).toBeUndefined();
17751775
});
17761776

1777+
test('should include execution field in listTools response when tool has execution settings', async () => {
1778+
const taskStore = new InMemoryTaskStore();
1779+
1780+
const mcpServer = new McpServer(
1781+
{
1782+
name: 'test server',
1783+
version: '1.0'
1784+
},
1785+
{
1786+
capabilities: {
1787+
tools: {},
1788+
tasks: {
1789+
requests: {
1790+
tools: {
1791+
call: {}
1792+
}
1793+
}
1794+
}
1795+
},
1796+
taskStore
1797+
}
1798+
);
1799+
1800+
const client = new Client({
1801+
name: 'test client',
1802+
version: '1.0'
1803+
});
1804+
1805+
// Register a tool with execution.taskSupport
1806+
mcpServer.registerToolTask(
1807+
'task-tool',
1808+
{
1809+
description: 'A tool with task support',
1810+
inputSchema: { input: z.string() },
1811+
execution: {
1812+
taskSupport: 'required'
1813+
}
1814+
},
1815+
{
1816+
createTask: async (_args, extra) => {
1817+
const task = await extra.taskStore.createTask({ ttl: 60000 });
1818+
return { task };
1819+
},
1820+
getTask: async (_args, extra) => {
1821+
const task = await extra.taskStore.getTask(extra.taskId);
1822+
if (!task) throw new Error('Task not found');
1823+
return task;
1824+
},
1825+
getTaskResult: async (_args, extra) => {
1826+
return (await extra.taskStore.getTaskResult(extra.taskId)) as CallToolResult;
1827+
}
1828+
}
1829+
);
1830+
1831+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
1832+
1833+
await Promise.all([client.connect(clientTransport), mcpServer.connect(serverTransport)]);
1834+
1835+
const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema);
1836+
1837+
expect(result.tools).toHaveLength(1);
1838+
expect(result.tools[0].name).toBe('task-tool');
1839+
expect(result.tools[0].execution).toEqual({
1840+
taskSupport: 'required'
1841+
});
1842+
1843+
taskStore.cleanup();
1844+
});
1845+
1846+
test('should include execution field with taskSupport optional in listTools response', async () => {
1847+
const taskStore = new InMemoryTaskStore();
1848+
1849+
const mcpServer = new McpServer(
1850+
{
1851+
name: 'test server',
1852+
version: '1.0'
1853+
},
1854+
{
1855+
capabilities: {
1856+
tools: {},
1857+
tasks: {
1858+
requests: {
1859+
tools: {
1860+
call: {}
1861+
}
1862+
}
1863+
}
1864+
},
1865+
taskStore
1866+
}
1867+
);
1868+
1869+
const client = new Client({
1870+
name: 'test client',
1871+
version: '1.0'
1872+
});
1873+
1874+
// Register a tool with execution.taskSupport optional
1875+
mcpServer.registerToolTask(
1876+
'optional-task-tool',
1877+
{
1878+
description: 'A tool with optional task support',
1879+
inputSchema: { input: z.string() },
1880+
execution: {
1881+
taskSupport: 'optional'
1882+
}
1883+
},
1884+
{
1885+
createTask: async (_args, extra) => {
1886+
const task = await extra.taskStore.createTask({ ttl: 60000 });
1887+
return { task };
1888+
},
1889+
getTask: async (_args, extra) => {
1890+
const task = await extra.taskStore.getTask(extra.taskId);
1891+
if (!task) throw new Error('Task not found');
1892+
return task;
1893+
},
1894+
getTaskResult: async (_args, extra) => {
1895+
return (await extra.taskStore.getTaskResult(extra.taskId)) as CallToolResult;
1896+
}
1897+
}
1898+
);
1899+
1900+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
1901+
1902+
await Promise.all([client.connect(clientTransport), mcpServer.connect(serverTransport)]);
1903+
1904+
const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema);
1905+
1906+
expect(result.tools).toHaveLength(1);
1907+
expect(result.tools[0].name).toBe('optional-task-tool');
1908+
expect(result.tools[0].execution).toEqual({
1909+
taskSupport: 'optional'
1910+
});
1911+
1912+
taskStore.cleanup();
1913+
});
1914+
17771915
test('should validate tool names according to SEP specification', () => {
17781916
// Create a new server instance for this test
17791917
const testServer = new McpServer({

src/server/mcp.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export class McpServer {
136136
: EMPTY_OBJECT_JSON_SCHEMA;
137137
})(),
138138
annotations: tool.annotations,
139+
execution: tool.execution,
139140
_meta: tool._meta
140141
};
141142

0 commit comments

Comments
 (0)