mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 20:20:57 +00:00
MCP OAuth Part 3 - CLI/UI/Documentation (#4319)
Co-authored-by: Greg Shikhman <shikhman@google.com>
This commit is contained in:
parent
258c848909
commit
4d653c833a
3 changed files with 431 additions and 4 deletions
|
|
@ -30,6 +30,13 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
|||
...actual,
|
||||
getMCPServerStatus: vi.fn(),
|
||||
getMCPDiscoveryState: vi.fn(),
|
||||
MCPOAuthProvider: {
|
||||
authenticate: vi.fn(),
|
||||
},
|
||||
MCPOAuthTokenStorage: {
|
||||
getToken: vi.fn(),
|
||||
isTokenExpired: vi.fn(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
|
|
@ -810,4 +817,163 @@ describe('mcpCommand', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('auth subcommand', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should list OAuth-enabled servers when no server name is provided', async () => {
|
||||
const context = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
getMcpServers: vi.fn().mockReturnValue({
|
||||
'oauth-server': { oauth: { enabled: true } },
|
||||
'regular-server': {},
|
||||
'another-oauth': { oauth: { enabled: true } },
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const authCommand = mcpCommand.subCommands?.find(
|
||||
(cmd) => cmd.name === 'auth',
|
||||
);
|
||||
expect(authCommand).toBeDefined();
|
||||
|
||||
const result = await authCommand!.action!(context, '');
|
||||
expect(isMessageAction(result)).toBe(true);
|
||||
if (isMessageAction(result)) {
|
||||
expect(result.messageType).toBe('info');
|
||||
expect(result.content).toContain('oauth-server');
|
||||
expect(result.content).toContain('another-oauth');
|
||||
expect(result.content).not.toContain('regular-server');
|
||||
expect(result.content).toContain('/mcp auth <server-name>');
|
||||
}
|
||||
});
|
||||
|
||||
it('should show message when no OAuth servers are configured', async () => {
|
||||
const context = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
getMcpServers: vi.fn().mockReturnValue({
|
||||
'regular-server': {},
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const authCommand = mcpCommand.subCommands?.find(
|
||||
(cmd) => cmd.name === 'auth',
|
||||
);
|
||||
const result = await authCommand!.action!(context, '');
|
||||
|
||||
expect(isMessageAction(result)).toBe(true);
|
||||
if (isMessageAction(result)) {
|
||||
expect(result.messageType).toBe('info');
|
||||
expect(result.content).toBe(
|
||||
'No MCP servers configured with OAuth authentication.',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should authenticate with a specific server', async () => {
|
||||
const mockToolRegistry = {
|
||||
discoverToolsForServer: vi.fn(),
|
||||
};
|
||||
const mockGeminiClient = {
|
||||
setTools: vi.fn(),
|
||||
};
|
||||
|
||||
const context = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
getMcpServers: vi.fn().mockReturnValue({
|
||||
'test-server': {
|
||||
url: 'http://localhost:3000',
|
||||
oauth: { enabled: true },
|
||||
},
|
||||
}),
|
||||
getToolRegistry: vi.fn().mockResolvedValue(mockToolRegistry),
|
||||
getGeminiClient: vi.fn().mockReturnValue(mockGeminiClient),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { MCPOAuthProvider } = await import('@google/gemini-cli-core');
|
||||
|
||||
const authCommand = mcpCommand.subCommands?.find(
|
||||
(cmd) => cmd.name === 'auth',
|
||||
);
|
||||
const result = await authCommand!.action!(context, 'test-server');
|
||||
|
||||
expect(MCPOAuthProvider.authenticate).toHaveBeenCalledWith(
|
||||
'test-server',
|
||||
{ enabled: true },
|
||||
'http://localhost:3000',
|
||||
);
|
||||
expect(mockToolRegistry.discoverToolsForServer).toHaveBeenCalledWith(
|
||||
'test-server',
|
||||
);
|
||||
expect(mockGeminiClient.setTools).toHaveBeenCalled();
|
||||
|
||||
expect(isMessageAction(result)).toBe(true);
|
||||
if (isMessageAction(result)) {
|
||||
expect(result.messageType).toBe('info');
|
||||
expect(result.content).toContain('Successfully authenticated');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle authentication errors', async () => {
|
||||
const context = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
getMcpServers: vi.fn().mockReturnValue({
|
||||
'test-server': { oauth: { enabled: true } },
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { MCPOAuthProvider } = await import('@google/gemini-cli-core');
|
||||
(
|
||||
MCPOAuthProvider.authenticate as ReturnType<typeof vi.fn>
|
||||
).mockRejectedValue(new Error('Auth failed'));
|
||||
|
||||
const authCommand = mcpCommand.subCommands?.find(
|
||||
(cmd) => cmd.name === 'auth',
|
||||
);
|
||||
const result = await authCommand!.action!(context, 'test-server');
|
||||
|
||||
expect(isMessageAction(result)).toBe(true);
|
||||
if (isMessageAction(result)) {
|
||||
expect(result.messageType).toBe('error');
|
||||
expect(result.content).toContain('Failed to authenticate');
|
||||
expect(result.content).toContain('Auth failed');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle non-existent server', async () => {
|
||||
const context = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
getMcpServers: vi.fn().mockReturnValue({
|
||||
'existing-server': {},
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const authCommand = mcpCommand.subCommands?.find(
|
||||
(cmd) => cmd.name === 'auth',
|
||||
);
|
||||
const result = await authCommand!.action!(context, 'non-existent');
|
||||
|
||||
expect(isMessageAction(result)).toBe(true);
|
||||
if (isMessageAction(result)) {
|
||||
expect(result.messageType).toBe('error');
|
||||
expect(result.content).toContain("MCP server 'non-existent' not found");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue