From 5087426af738ab711ef03026b906810d1024a2de Mon Sep 17 00:00:00 2001 From: liqoingyu Date: Mon, 19 Jan 2026 11:46:48 +0800 Subject: [PATCH] test(cli): cover MCP resource edge cases --- .../src/ui/hooks/atCommandProcessor.test.ts | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts index 3b91dd269..9b1f9635a 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts @@ -386,6 +386,103 @@ describe('handleAtCommand', () => { expect(mockAddItem).not.toHaveBeenCalled(); }); + it('should not expand MCP resources in untrusted folders', async () => { + (mockConfig as unknown as { getMcpServers: () => unknown }).getMcpServers = + () => + ({ + github: {}, + }) as unknown; + const configWithTrust = mockConfig as unknown as { + isTrustedFolder: () => boolean; + }; + configWithTrust.isTrustedFolder = () => false; + + const readMcpResourceSpy = vi.spyOn(registry, 'readMcpResource'); + + const query = 'Show me the data from @github: repos/owner/repo/issues'; + + const result = await handleAtCommand({ + query, + config: mockConfig, + addItem: mockAddItem, + onDebugMessage: mockOnDebugMessage, + messageId: 1004, + signal: abortController.signal, + }); + + expect(result).toEqual({ + processedQuery: null, + shouldProceed: false, + }); + expect(readMcpResourceSpy).toHaveBeenCalledWith( + 'github', + 'github://repos/owner/repo/issues', + ); + expect(mockAddItem).toHaveBeenCalledWith( + expect.objectContaining({ + type: 'tool_group', + tools: [ + expect.objectContaining({ + status: ToolCallStatus.Error, + resultDisplay: expect.stringContaining('untrusted'), + }), + ], + }), + 1004, + ); + }); + + it('should preserve trailing punctuation after an MCP resource reference', async () => { + (mockConfig as unknown as { getMcpServers: () => unknown }).getMcpServers = + () => + ({ + github: {}, + }) as unknown; + + vi.spyOn(registry, 'readMcpResource').mockResolvedValue({ + contents: [ + { + uri: 'github://repos/owner/repo/issues', + mimeType: 'application/json', + text: '{"ok":true}', + }, + ], + } as unknown as Awaited>); + + const query = 'Show me the data from @github: repos/owner/repo/issues.'; + + const result = await handleAtCommand({ + query, + config: mockConfig, + addItem: mockAddItem, + onDebugMessage: mockOnDebugMessage, + messageId: 1005, + signal: abortController.signal, + }); + + expect(result).toEqual({ + processedQuery: [ + { text: 'Show me the data from @github:repos/owner/repo/issues.' }, + { text: '\n--- Content from referenced MCP resources ---' }, + { text: '\nContent from @github:repos/owner/repo/issues:\n' }, + { text: '{"ok":true}' }, + { text: '\n--- End of MCP resource content ---' }, + ], + shouldProceed: true, + }); + expect(registry.readMcpResource).toHaveBeenCalledWith( + 'github', + 'github://repos/owner/repo/issues', + ); + expect(mockAddItem).toHaveBeenCalledWith( + expect.objectContaining({ + type: 'tool_group', + tools: [expect.objectContaining({ status: ToolCallStatus.Success })], + }), + 1005, + ); + }); + it('should handle query with text before and after @command', async () => { const fileContent = 'Markdown content.'; const filePath = await createTestFile(