feat: add MCP server testing and tool listing functionality

- Add MCPTestService for testing MCP server connections
- Support stdio, SSE, and HTTP transport types
- Implement workaround for SSE headers bug (SDK Issue #436)
- Create API routes for /api/mcp/test and /api/mcp/tools
- Add API client methods for MCP operations
- Create MCPToolsList component with collapsible schema display
- Add Test button to MCP servers section with status indicators
- Add Headers field for HTTP/SSE servers
- Add Environment Variables field for stdio servers
- Fix text overflow in tools list display

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kacper
2025-12-28 14:51:49 +01:00
parent 145dcf4b97
commit f0c2860dec
10 changed files with 873 additions and 61 deletions

View File

@@ -0,0 +1,20 @@
/**
* Common utilities for MCP routes
*/
/**
* Extract error message from unknown error
*/
export function getErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message;
}
return String(error);
}
/**
* Log error with prefix
*/
export function logError(error: unknown, message: string): void {
console.error(`[MCP] ${message}:`, error);
}

View File

@@ -0,0 +1,36 @@
/**
* MCP routes - HTTP API for testing MCP servers
*
* Provides endpoints for:
* - Testing MCP server connections
* - Listing available tools from MCP servers
*
* Mounted at /api/mcp in the main server.
*/
import { Router } from 'express';
import type { MCPTestService } from '../../services/mcp-test-service.js';
import { createTestServerHandler } from './routes/test-server.js';
import { createListToolsHandler } from './routes/list-tools.js';
/**
* Create MCP router with all endpoints
*
* Endpoints:
* - POST /test - Test MCP server connection
* - POST /tools - List tools from MCP server
*
* @param mcpTestService - Instance of MCPTestService for testing connections
* @returns Express Router configured with all MCP endpoints
*/
export function createMCPRoutes(mcpTestService: MCPTestService): Router {
const router = Router();
// Test MCP server connection
router.post('/test', createTestServerHandler(mcpTestService));
// List tools from MCP server
router.post('/tools', createListToolsHandler(mcpTestService));
return router;
}

View File

@@ -0,0 +1,67 @@
/**
* POST /api/mcp/tools - List tools for an MCP server
*
* Lists available tools for an MCP server.
* Similar to test but focused on tool discovery.
*
* Request body:
* { serverId: string } - Get tools by server ID from settings
* OR { serverConfig: MCPServerConfig } - Get tools with provided config
*
* Response: { success: boolean, tools?: MCPToolInfo[], error?: string }
*/
import type { Request, Response } from 'express';
import type { MCPTestService } from '../../../services/mcp-test-service.js';
import type { MCPServerConfig } from '@automaker/types';
import { getErrorMessage, logError } from '../common.js';
interface ListToolsRequest {
serverId?: string;
serverConfig?: MCPServerConfig;
}
/**
* Create handler factory for POST /api/mcp/tools
*/
export function createListToolsHandler(mcpTestService: MCPTestService) {
return async (req: Request, res: Response): Promise<void> => {
try {
const body = req.body as ListToolsRequest;
if (!body.serverId && !body.serverConfig) {
res.status(400).json({
success: false,
error: 'Either serverId or serverConfig is required',
});
return;
}
let result;
if (body.serverId) {
result = await mcpTestService.testServerById(body.serverId);
} else if (body.serverConfig) {
result = await mcpTestService.testServer(body.serverConfig);
} else {
res.status(400).json({
success: false,
error: 'Invalid request',
});
return;
}
// Return only tool-related information
res.json({
success: result.success,
tools: result.tools,
error: result.error,
});
} catch (error) {
logError(error, 'List tools failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
});
}
};
}

View File

@@ -0,0 +1,62 @@
/**
* POST /api/mcp/test - Test MCP server connection and list tools
*
* Tests connection to an MCP server and returns available tools.
* Accepts either a serverId to look up config, or a full server config.
*
* Request body:
* { serverId: string } - Test server by ID from settings
* OR { serverConfig: MCPServerConfig } - Test with provided config
*
* Response: { success: boolean, tools?: MCPToolInfo[], error?: string, connectionTime?: number }
*/
import type { Request, Response } from 'express';
import type { MCPTestService } from '../../../services/mcp-test-service.js';
import type { MCPServerConfig } from '@automaker/types';
import { getErrorMessage, logError } from '../common.js';
interface TestServerRequest {
serverId?: string;
serverConfig?: MCPServerConfig;
}
/**
* Create handler factory for POST /api/mcp/test
*/
export function createTestServerHandler(mcpTestService: MCPTestService) {
return async (req: Request, res: Response): Promise<void> => {
try {
const body = req.body as TestServerRequest;
if (!body.serverId && !body.serverConfig) {
res.status(400).json({
success: false,
error: 'Either serverId or serverConfig is required',
});
return;
}
let result;
if (body.serverId) {
result = await mcpTestService.testServerById(body.serverId);
} else if (body.serverConfig) {
result = await mcpTestService.testServer(body.serverConfig);
} else {
res.status(400).json({
success: false,
error: 'Invalid request',
});
return;
}
res.json(result);
} catch (error) {
logError(error, 'Test server failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
});
}
};
}