Skip to content

Commit 79715c6

Browse files
committed
Merge branch 'improvement/AIX-752-guardian-tool-annotation' into q/133.0
2 parents 4b73b6c + f4f8272 commit 79715c6

2 files changed

Lines changed: 31 additions & 2 deletions

File tree

shell-ui/src/mcp/MCPRegistrar.test.tsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ToolDescriptor } from '@mcp-b/webmcp-types';
1+
import type { ToolAnnotations, ToolDescriptor } from '@mcp-b/webmcp-types';
22
import { render } from '@testing-library/react';
33
import type { FederatedModuleInfo } from '../initFederation/ConfigurationProviders';
44
import { _InternalMCPRegistrar } from './MCPRegistrar';
@@ -28,6 +28,7 @@ type RegisteredTool = {
2828
name: string;
2929
description: string;
3030
inputSchema: Record<string, unknown>;
31+
annotations?: ToolAnnotations;
3132
execute: (params: unknown, client: unknown) => Promise<unknown>;
3233
};
3334

@@ -41,10 +42,11 @@ const mockModelContext = {
4142
delete registeredTools[name];
4243
}),
4344
listTools: jest.fn(() =>
44-
Object.values(registeredTools).map(({ name, description, inputSchema }) => ({
45+
Object.values(registeredTools).map(({ name, description, inputSchema, annotations }) => ({
4546
name,
4647
description,
4748
inputSchema,
49+
...(annotations && { annotations }),
4850
})),
4951
),
5052
};
@@ -160,6 +162,32 @@ describe('_InternalMCPRegistrar', () => {
160162
await expect(capturedContext!.getToken()).resolves.toBe('refreshed-token');
161163
});
162164

165+
it('forwards annotations including readOnlyHint to registerTool', () => {
166+
const tool = makeTool({
167+
annotations: { readOnlyHint: true, openWorldHint: true },
168+
});
169+
const moduleExports = {
170+
[MODULE_KEY]: { createTools: () => [tool] },
171+
};
172+
173+
render(
174+
<_InternalMCPRegistrar
175+
moduleExports={moduleExports}
176+
mcpToolsModuleInfo={mcpToolsModuleInfo}
177+
selfConfiguration={selfConfiguration}
178+
navigate={mockNavigate}
179+
/>,
180+
);
181+
182+
expect(mockModelContext.registerTool).toHaveBeenCalledWith(
183+
expect.objectContaining({
184+
annotations: { readOnlyHint: true, openWorldHint: true },
185+
}),
186+
);
187+
const listed = mockModelContext.listTools();
188+
expect(listed[0].annotations).toEqual({ readOnlyHint: true, openWorldHint: true });
189+
});
190+
163191
it('registers multiple tools', () => {
164192
const tool1 = makeTool({ name: 'tool1' });
165193
const tool2 = makeTool({ name: 'tool2' });

shell-ui/src/mcp/MCPRegistrar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export const _InternalMCPRegistrar = ({
7575
description: tool.description,
7676
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7777
inputSchema: tool.inputSchema,
78+
...(tool.annotations && { annotations: tool.annotations }),
7879
execute: async (params: unknown, client: ModelContextClient) => {
7980
// For createTools-based modules, context is already baked into the
8081
// tool's execute closure. For legacy tools, inject context here.

0 commit comments

Comments
 (0)