Skip to content

Commit 5dd7a2b

Browse files
feat: add _meta field support to tool definitions (#922)
Co-authored-by: David Soria Parra <[email protected]>
1 parent 4de54fe commit 5dd7a2b

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

src/server/mcp.test.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,99 @@ describe("tool()", () => {
16331633
),
16341634
).rejects.toThrow(/Tool nonexistent-tool not found/);
16351635
});
1636+
1637+
/***
1638+
* Test: Tool Registration with _meta field
1639+
*/
1640+
test("should register tool with _meta field and include it in list response", async () => {
1641+
const mcpServer = new McpServer({
1642+
name: "test server",
1643+
version: "1.0",
1644+
});
1645+
const client = new Client({
1646+
name: "test client",
1647+
version: "1.0",
1648+
});
1649+
1650+
const metaData = {
1651+
author: "test-author",
1652+
version: "1.2.3",
1653+
category: "utility",
1654+
tags: ["test", "example"]
1655+
};
1656+
1657+
mcpServer.registerTool(
1658+
"test-with-meta",
1659+
{
1660+
description: "A tool with _meta field",
1661+
inputSchema: { name: z.string() },
1662+
_meta: metaData,
1663+
},
1664+
async ({ name }) => ({
1665+
content: [{ type: "text", text: `Hello, ${name}!` }]
1666+
})
1667+
);
1668+
1669+
const [clientTransport, serverTransport] =
1670+
InMemoryTransport.createLinkedPair();
1671+
1672+
await Promise.all([
1673+
client.connect(clientTransport),
1674+
mcpServer.server.connect(serverTransport),
1675+
]);
1676+
1677+
const result = await client.request(
1678+
{ method: "tools/list" },
1679+
ListToolsResultSchema,
1680+
);
1681+
1682+
expect(result.tools).toHaveLength(1);
1683+
expect(result.tools[0].name).toBe("test-with-meta");
1684+
expect(result.tools[0].description).toBe("A tool with _meta field");
1685+
expect(result.tools[0]._meta).toEqual(metaData);
1686+
});
1687+
1688+
/***
1689+
* Test: Tool Registration without _meta field should have undefined _meta
1690+
*/
1691+
test("should register tool without _meta field and have undefined _meta in response", async () => {
1692+
const mcpServer = new McpServer({
1693+
name: "test server",
1694+
version: "1.0",
1695+
});
1696+
const client = new Client({
1697+
name: "test client",
1698+
version: "1.0",
1699+
});
1700+
1701+
mcpServer.registerTool(
1702+
"test-without-meta",
1703+
{
1704+
description: "A tool without _meta field",
1705+
inputSchema: { name: z.string() },
1706+
},
1707+
async ({ name }) => ({
1708+
content: [{ type: "text", text: `Hello, ${name}!` }]
1709+
})
1710+
);
1711+
1712+
const [clientTransport, serverTransport] =
1713+
InMemoryTransport.createLinkedPair();
1714+
1715+
await Promise.all([
1716+
client.connect(clientTransport),
1717+
mcpServer.server.connect(serverTransport),
1718+
]);
1719+
1720+
const result = await client.request(
1721+
{ method: "tools/list" },
1722+
ListToolsResultSchema,
1723+
);
1724+
1725+
expect(result.tools).toHaveLength(1);
1726+
expect(result.tools[0].name).toBe("test-without-meta");
1727+
expect(result.tools[0]._meta).toBeUndefined();
1728+
});
16361729
});
16371730

16381731
describe("resource()", () => {

src/server/mcp.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export class McpServer {
123123
}) as Tool["inputSchema"])
124124
: EMPTY_OBJECT_JSON_SCHEMA,
125125
annotations: tool.annotations,
126+
_meta: tool._meta,
126127
};
127128

128129
if (tool.outputSchema) {
@@ -773,6 +774,7 @@ export class McpServer {
773774
inputSchema: ZodRawShape | undefined,
774775
outputSchema: ZodRawShape | undefined,
775776
annotations: ToolAnnotations | undefined,
777+
_meta: Record<string, unknown> | undefined,
776778
callback: ToolCallback<ZodRawShape | undefined>
777779
): RegisteredTool {
778780
const registeredTool: RegisteredTool = {
@@ -783,6 +785,7 @@ export class McpServer {
783785
outputSchema:
784786
outputSchema === undefined ? undefined : z.object(outputSchema),
785787
annotations,
788+
_meta,
786789
callback,
787790
enabled: true,
788791
disable: () => registeredTool.update({ enabled: false }),
@@ -798,6 +801,7 @@ export class McpServer {
798801
if (typeof updates.paramsSchema !== "undefined") registeredTool.inputSchema = z.object(updates.paramsSchema)
799802
if (typeof updates.callback !== "undefined") registeredTool.callback = updates.callback
800803
if (typeof updates.annotations !== "undefined") registeredTool.annotations = updates.annotations
804+
if (typeof updates._meta !== "undefined") registeredTool._meta = updates._meta
801805
if (typeof updates.enabled !== "undefined") registeredTool.enabled = updates.enabled
802806
this.sendToolListChanged()
803807
},
@@ -915,7 +919,7 @@ export class McpServer {
915919
}
916920
const callback = rest[0] as ToolCallback<ZodRawShape | undefined>;
917921

918-
return this._createRegisteredTool(name, undefined, description, inputSchema, outputSchema, annotations, callback)
922+
return this._createRegisteredTool(name, undefined, description, inputSchema, outputSchema, annotations, undefined, callback)
919923
}
920924

921925
/**
@@ -929,14 +933,15 @@ export class McpServer {
929933
inputSchema?: InputArgs;
930934
outputSchema?: OutputArgs;
931935
annotations?: ToolAnnotations;
936+
_meta?: Record<string, unknown>;
932937
},
933938
cb: ToolCallback<InputArgs>
934939
): RegisteredTool {
935940
if (this._registeredTools[name]) {
936941
throw new Error(`Tool ${name} is already registered`);
937942
}
938943

939-
const { title, description, inputSchema, outputSchema, annotations } = config;
944+
const { title, description, inputSchema, outputSchema, annotations, _meta } = config;
940945

941946
return this._createRegisteredTool(
942947
name,
@@ -945,6 +950,7 @@ export class McpServer {
945950
inputSchema,
946951
outputSchema,
947952
annotations,
953+
_meta,
948954
cb as ToolCallback<ZodRawShape | undefined>
949955
);
950956
}
@@ -1173,6 +1179,7 @@ export type RegisteredTool = {
11731179
inputSchema?: AnyZodObject;
11741180
outputSchema?: AnyZodObject;
11751181
annotations?: ToolAnnotations;
1182+
_meta?: Record<string, unknown>;
11761183
callback: ToolCallback<undefined | ZodRawShape>;
11771184
enabled: boolean;
11781185
enable(): void;
@@ -1185,6 +1192,7 @@ export type RegisteredTool = {
11851192
paramsSchema?: InputArgs,
11861193
outputSchema?: OutputArgs,
11871194
annotations?: ToolAnnotations,
1195+
_meta?: Record<string, unknown>,
11881196
callback?: ToolCallback<InputArgs>,
11891197
enabled?: boolean
11901198
}): void

0 commit comments

Comments
 (0)