[codex] add MCP tools visibility management (#1170)
* feat(mcp): add tools visibility management ## Features - Tools visibility modal with 3 modes: All, Include, Exclude - 'Manage Tools' button on McpServerCard (enabled only when connected) - 'Fetch Tools List' button to refresh available tools (raw mode) - Responsive design for mobile (480px), tablet (768px), desktop (1280px) - i18n translations for 9 languages (zh/en/zh-TW/ja/ko/de/es/fr/pt) ## Technical Details - Add raw parameter to fetchMcpTools API for unfiltered tools - Pass raw parameter through controller → bridgeMcpAction → client - Backend _mcp_tools_list supports raw_mode to skip include/exclude filter - 28 MCP unit tests pass (23 controller + 5 bridge action) ## Files Changed - McpManagerView.vue: Tools visibility modal with mode selector - McpServerCard.vue: Add manage tools button - mcp.ts (client): Add raw parameter to fetchMcpTools - mcp.ts (controller): Pass raw parameter to bridge - mcp.ts (services): Pass raw parameter to client.mcpTools - client.ts: Add raw parameter to mcpTools - hermes_bridge.py: Support raw_mode in _mcp_tools_list - 9 locale files: Add 14 translation keys each - mcp-controller.test.ts: Add 3 new test cases - bridge-mcp-action.test.ts: New test file for parameter passing * Delete projects directory chore: remove accidentally committed projects/ directory * fix MCP tools visibility edge cases * remove MCP docs screenshots --------- Co-authored-by: Crafter-feng <succeed_happu@163.com> Co-authored-by: Crafter-feng <37255449+Crafter-feng@users.noreply.github.com>
This commit is contained in:
@@ -151,6 +151,53 @@ describe('MCP Controller', () => {
|
||||
await updateServer(ctx)
|
||||
expect(ctx.status).toBe(400)
|
||||
})
|
||||
|
||||
it('sends tools.include config for include mode', async () => {
|
||||
mcpUpdateMock.mockResolvedValue({ ok: true })
|
||||
const { updateServer } = await import('../../packages/server/src/controllers/hermes/mcp')
|
||||
const ctx = createCtx({
|
||||
params: { name: 'github' },
|
||||
request: { body: { config: { command: 'npx', args: ['-y', 'server'], tools: { include: ['read_file', 'write_file'] } } } },
|
||||
})
|
||||
await updateServer(ctx)
|
||||
expect(mcpUpdateMock).toHaveBeenCalledWith('github', {
|
||||
command: 'npx',
|
||||
args: ['-y', 'server'],
|
||||
tools: { include: ['read_file', 'write_file'] },
|
||||
}, 'test-profile')
|
||||
expect(ctx.body).toEqual({ ok: true })
|
||||
})
|
||||
|
||||
it('sends tools.exclude config for exclude mode', async () => {
|
||||
mcpUpdateMock.mockResolvedValue({ ok: true })
|
||||
const { updateServer } = await import('../../packages/server/src/controllers/hermes/mcp')
|
||||
const ctx = createCtx({
|
||||
params: { name: 'github' },
|
||||
request: { body: { config: { command: 'npx', args: ['-y', 'server'], tools: { exclude: ['delete_file'] } } } },
|
||||
})
|
||||
await updateServer(ctx)
|
||||
expect(mcpUpdateMock).toHaveBeenCalledWith('github', {
|
||||
command: 'npx',
|
||||
args: ['-y', 'server'],
|
||||
tools: { exclude: ['delete_file'] },
|
||||
}, 'test-profile')
|
||||
expect(ctx.body).toEqual({ ok: true })
|
||||
})
|
||||
|
||||
it('sends config without tools field for all mode', async () => {
|
||||
mcpUpdateMock.mockResolvedValue({ ok: true })
|
||||
const { updateServer } = await import('../../packages/server/src/controllers/hermes/mcp')
|
||||
const ctx = createCtx({
|
||||
params: { name: 'github' },
|
||||
request: { body: { config: { command: 'npx', args: ['-y', 'server'] } } },
|
||||
})
|
||||
await updateServer(ctx)
|
||||
expect(mcpUpdateMock).toHaveBeenCalledWith('github', {
|
||||
command: 'npx',
|
||||
args: ['-y', 'server'],
|
||||
}, 'test-profile')
|
||||
expect(ctx.body).toEqual({ ok: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe('removeServer', () => {
|
||||
@@ -180,7 +227,7 @@ describe('MCP Controller', () => {
|
||||
const { listTools } = await import('../../packages/server/src/controllers/hermes/mcp')
|
||||
const ctx = createCtx({ query: {} })
|
||||
await listTools(ctx)
|
||||
expect(mcpToolsMock).toHaveBeenCalledWith(undefined, 'test-profile')
|
||||
expect(mcpToolsMock).toHaveBeenCalledWith(undefined, 'test-profile', undefined)
|
||||
expect(ctx.body).toEqual(SAMPLE_TOOLS_RESPONSE)
|
||||
})
|
||||
|
||||
@@ -189,7 +236,15 @@ describe('MCP Controller', () => {
|
||||
const { listTools } = await import('../../packages/server/src/controllers/hermes/mcp')
|
||||
const ctx = createCtx({ query: { server: 'github' } })
|
||||
await listTools(ctx)
|
||||
expect(mcpToolsMock).toHaveBeenCalledWith('github', 'test-profile')
|
||||
expect(mcpToolsMock).toHaveBeenCalledWith('github', 'test-profile', undefined)
|
||||
})
|
||||
|
||||
it('passes raw=true to get unfiltered tools', async () => {
|
||||
mcpToolsMock.mockResolvedValue(SAMPLE_TOOLS_RESPONSE)
|
||||
const { listTools } = await import('../../packages/server/src/controllers/hermes/mcp')
|
||||
const ctx = createCtx({ query: { server: 'github', raw: '1' } })
|
||||
await listTools(ctx)
|
||||
expect(mcpToolsMock).toHaveBeenCalledWith('github', 'test-profile', true)
|
||||
})
|
||||
|
||||
it('returns 503 on bridge error', async () => {
|
||||
|
||||
Reference in New Issue
Block a user