From 97baeec104e8106d189e373b6ef34ebe177cd07d Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Mon, 8 Sep 2025 13:13:42 -0400 Subject: [PATCH 1/2] feat: Add development documentation and reorganize test servers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add CONTRIBUTING.md with comprehensive development workflow guide - Add Development section to README.md with link to contributing guide - Move test servers from test-servers/ to test/servers/ for better organization - Create test/config.json for configuration testing - Update package.json scripts to use new test/servers/ paths - Update mcp_config.json to reference new server locations - Update test server README with new paths 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CONTRIBUTING.md | 133 ++++++++++++++++++++++++ README.md | 4 + mcp_config.json | 14 +++ package.json | 10 +- test/config.json | 14 +++ test/servers/README.md | 162 ++++++++++++++++++++++++++++++ test/servers/http-server.js | 146 +++++++++++++++++++++++++++ test/servers/sse-server.js | 189 +++++++++++++++++++++++++++++++++++ test/servers/stdio-server.js | 107 ++++++++++++++++++++ 9 files changed, 778 insertions(+), 1 deletion(-) create mode 100644 CONTRIBUTING.md create mode 100644 mcp_config.json create mode 100644 test/config.json create mode 100644 test/servers/README.md create mode 100644 test/servers/http-server.js create mode 100644 test/servers/sse-server.js create mode 100644 test/servers/stdio-server.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2311d30 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,133 @@ +# Contributing to mcp-cli + +Thank you for your interest in contributing to mcp-cli! This guide will help you get set up for development and understand our workflow. + +## Development Environment Setup + +### Prerequisites +- Node.js (version 18 or higher) +- pnpm (package manager) + +### Initial Setup +```bash +# Clone the repository +git clone https://github.com/wong2/mcp-cli.git +cd mcp-cli + +# Install dependencies +pnpm install +``` + +## Development Workflow + +### Test Servers +The project includes comprehensive test servers for all MCP transport types, located in `test/servers/`: + +- **stdio-server.js** - Standard input/output transport +- **http-server.js** - HTTP transport (port 9100) +- **sse-server.js** - Server-Sent Events transport (port 9101) +- **simple-http-server.js** - Simplified HTTP server + +### Starting Test Servers +```bash +# Start individual servers +pnpm run server:stdio # Stdio server (foreground) +pnpm run server:http # HTTP server on port 9100 +pnpm run server:sse # SSE server on port 9101 + +# See available server commands +pnpm run server:help +``` + +### Testing Your Changes +```bash +# Test with different transport types +pnpm run test:stdio # Test stdio transport +pnpm run test:http # Test HTTP transport (requires HTTP server running) +pnpm run test:sse # Test SSE transport (requires SSE server running) + +# Test with config file +npx mcp-cli -c test/config.json stdio-server + +# Test direct server connections +npx mcp-cli --url http://localhost:9100/mcp +npx mcp-cli --sse http://localhost:9101/sse +``` + +### Manual Testing Scenarios +1. **Interactive Mode**: Test all MCP primitives (tools, resources, prompts) +2. **Non-Interactive Mode**: Test list commands (`list-tools`, `list-resources`, etc.) +3. **Configuration**: Test both config file and direct connection methods +4. **Transport Types**: Verify all three transport types work correctly +5. **OAuth Flows**: Test authentication with protected servers + +## Code Standards + +### Formatting +We use Prettier for code formatting. Configuration is in `.prettierrc`. + +```bash +# Format code (if you have prettier installed globally) +npx prettier --write . +``` + +### Code Quality +- Follow existing patterns in the codebase +- Add error handling for new features +- Ensure compatibility with all transport types +- Test both interactive and non-interactive modes + +## Architecture Overview + +### Key Files +- `src/cli.js` - Main CLI entry point and argument parsing +- `src/mcp.js` - Core MCP client logic and connection handling +- `src/config.js` - Configuration file loading and validation +- `src/oauth/` - OAuth authentication providers +- `src/utils.js` - Shared utility functions + +### Transport Support +The CLI supports three MCP transport types: +1. **Stdio** - Process-based communication via stdin/stdout +2. **HTTP** - Modern HTTP-based transport with session management +3. **SSE** - Server-Sent Events (legacy transport) + +## Making Changes + +### Branch Naming +Use descriptive branch names: +- `feat/new-feature-name` +- `fix/bug-description` +- `docs/documentation-update` + +### Testing Checklist +Before submitting a PR, verify: +- [ ] All transport types work (stdio, HTTP, SSE) +- [ ] Interactive mode functions correctly +- [ ] Non-interactive list commands work +- [ ] Configuration file loading works +- [ ] No regression in existing functionality +- [ ] Code follows existing style patterns + +### Pull Request Process +1. Fork the repository +2. Create a feature branch from `main` +3. Make your changes with clear commit messages +4. Test thoroughly using the test servers +5. Submit a pull request with a clear description + +## Getting Help + +- Check existing issues for similar problems +- Use the test servers to reproduce and debug issues +- Look at the `docs/` directory for detailed technical documentation +- Examine existing code patterns for guidance + +## Development Tips + +- Use `test/config.json` for testing configuration-based connections +- The test servers provide identical functionality across all transport types +- OAuth testing can be done with the HTTP and SSE servers +- Environment variables can be tested with the stdio server using `--pass-env` + +Thank you for contributing to mcp-cli! \ No newline at end of file diff --git a/README.md b/README.md index 3a969de..d1da42b 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,10 @@ This mode is useful for scripting and automation, as it bypasses all interactive npx @wong2/mcp-cli purge ``` +## Development + +- See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup and workflow + ## Related - [mcpservers.org](https://mcpservers.org) - A curated list of MCP servers diff --git a/mcp_config.json b/mcp_config.json new file mode 100644 index 0000000..b31aaff --- /dev/null +++ b/mcp_config.json @@ -0,0 +1,14 @@ +{ + "mcpServers": { + "stdio-server": { + "command": "node", + "args": ["test/servers/stdio-server.js"] + }, + "http-server": { + "url": "http://localhost:9100/mcp" + }, + "sse-server": { + "url": "http://localhost:9101/sse" + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index a992033..0485919 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,15 @@ "src", "README.md" ], - "scripts": {}, + "scripts": { + "server:stdio": "node test/servers/stdio-server.js", + "server:http": "node test/servers/http-server.js", + "server:sse": "node test/servers/sse-server.js", + "server:help": "echo 'Available servers: stdio (pnpm run server:stdio), http (pnpm run server:http), sse (pnpm run server:sse)'", + "test:stdio": "node src/cli.js node test/servers/stdio-server.js", + "test:http": "node src/cli.js --url http://localhost:9100/mcp", + "test:sse": "node src/cli.js --sse http://localhost:9101/sse" + }, "keywords": [ "MCP" ], diff --git a/test/config.json b/test/config.json new file mode 100644 index 0000000..b31aaff --- /dev/null +++ b/test/config.json @@ -0,0 +1,14 @@ +{ + "mcpServers": { + "stdio-server": { + "command": "node", + "args": ["test/servers/stdio-server.js"] + }, + "http-server": { + "url": "http://localhost:9100/mcp" + }, + "sse-server": { + "url": "http://localhost:9101/sse" + } + } +} \ No newline at end of file diff --git a/test/servers/README.md b/test/servers/README.md new file mode 100644 index 0000000..b951754 --- /dev/null +++ b/test/servers/README.md @@ -0,0 +1,162 @@ +# MCP Test Servers + +This directory contains test servers for all three MCP transport types to help test and demonstrate MCP connectivity. + +## Servers + +### Stdio Server (`stdio-server.js`) +- **Transport**: StdioServerTransport +- **Communication**: stdin/stdout +- **Features**: Standard MCP stdio protocol + +### HTTP Server (`http-server.js`) +- **Port**: 9100 +- **Transport**: StreamableHTTPServerTransport +- **Endpoint**: `http://localhost:9100/mcp` +- **Features**: Session management, modern HTTP transport + +### SSE Server (`sse-server.js`) +- **Port**: 9101 +- **Transport**: SSEServerTransport (Legacy) +- **SSE Endpoint**: `http://localhost:9101/sse` +- **Messages Endpoint**: `http://localhost:9101/messages` +- **Features**: Server-Sent Events streaming + +## Usage + +### Starting the Servers + +Using npm scripts (recommended): +```bash +# Start stdio server (runs in foreground) +pnpm run server:stdio + +# Start HTTP server +pnpm run server:http + +# Start SSE server (in another terminal) +pnpm run server:sse + +# Test stdio client connection (launches server directly) +pnpm run test:stdio + +# Test HTTP client connection (requires HTTP server to be running) +pnpm run test:http + +# Test SSE client connection (requires SSE server to be running) +pnpm run test:sse +``` + +Or using node directly: +```bash +# Start stdio server +node test/servers/stdio-server.js + +# Start HTTP server +node test/servers/http-server.js + +# Start SSE server (in another terminal) +node test/servers/sse-server.js +``` + +### Testing with mcp-cli + +```bash +# Test stdio server (direct command - recommended) +mcp-cli node test/servers/stdio-server.js + +# Test stdio server (from config - alternative) +mcp-cli --config mcp_config.json stdio-server + +# Test HTTP server +mcp-cli --url http://localhost:9100/mcp + +# Test SSE server +mcp-cli --sse http://localhost:9101/sse +``` + +## Available Features + +All three servers provide identical MCP functionality: + +### Tools +- **add**: Add two numbers together + - Parameters: `a` (number), `b` (number) +- **echo**: Echo back input text + - Parameters: `message` (string) +- **current-time**: Get current timestamp + - Parameters: none + +### Resources +- **server-info://status**: Server information and status + - Returns JSON with server details, version, transport type, etc. + +## Health Checks + +Both servers provide health check endpoints: + +```bash +# HTTP server health +curl http://localhost:9100/health + +# SSE server health +curl http://localhost:9101/health +``` + +## Example Interactions + +### Using Tools +```bash +# Test addition tool +{"method": "call_tool", "params": {"name": "add", "arguments": {"a": 5, "b": 3}}} + +# Test echo tool +{"method": "call_tool", "params": {"name": "echo", "arguments": {"message": "Hello MCP!"}}} + +# Test time tool +{"method": "call_tool", "params": {"name": "current-time", "arguments": {}}} +``` + +### Reading Resources +```bash +# Get server information +{"method": "read_resource", "params": {"uri": "server-info://status"}} +``` + +## Transport Differences + +### Stdio +- Standard transport for command-line tools +- Uses stdin/stdout for communication +- Most compatible and widely supported +- Process-based isolation + +### HTTP (StreamableHTTP) +- Modern transport protocol +- Single endpoint handles all requests +- Built-in session management +- Better error handling and resilience +- Supports resumable connections + +### SSE (Server-Sent Events) +- Legacy transport (deprecated) +- Separate endpoints for SSE stream and messages +- Simpler but less robust +- Limited error recovery + +## Testing All Transports + +These servers allow you to test the differences between stdio, HTTP and SSE transports: + +1. **Performance**: Compare response times and throughput +2. **Reliability**: Test connection handling and recovery +3. **Features**: Verify all MCP features work on all transports +4. **Client Compatibility**: Ensure clients work with all transport protocols + +## Notes + +- All three servers use the same MCP SDK (`@modelcontextprotocol/sdk`) +- DNS rebinding protection is enabled for security +- Graceful shutdown is implemented (Ctrl+C) +- Session management tracks active connections +- All endpoints include proper error handling \ No newline at end of file diff --git a/test/servers/http-server.js b/test/servers/http-server.js new file mode 100644 index 0000000..e68225f --- /dev/null +++ b/test/servers/http-server.js @@ -0,0 +1,146 @@ +import express from 'express'; +import { randomUUID } from 'node:crypto'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { z } from 'zod'; + +const PORT = 9100; + +// Create the MCP server +const server = new McpServer({ + name: 'test-http-server', + version: '1.0.0' +}, { + capabilities: { + tools: {}, + resources: {} + } +}); + +// Add sample tools +server.registerTool('add', { + title: 'Addition Tool', + description: 'Add two numbers together', + inputSchema: { + a: z.number().describe('First number'), + b: z.number().describe('Second number') + } +}, async ({ a, b }) => ({ + content: [{ + type: 'text', + text: `${a} + ${b} = ${a + b}` + }] +})); + +server.registerTool('echo', { + title: 'Echo Tool', + description: 'Echo back the input text', + inputSchema: { + message: z.string().describe('Text to echo back') + } +}, async ({ message }) => ({ + content: [{ + type: 'text', + text: `Echo: ${message}` + }] +})); + +server.registerTool('current-time', { + title: 'Current Time', + description: 'Get the current date and time', + inputSchema: {} +}, async () => ({ + content: [{ + type: 'text', + text: `Current time: ${new Date().toISOString()}` + }] +})); + +// Add sample resources +server.registerResource('server-info', 'server-info://status', { + title: 'Server Information', + description: 'Information about the test HTTP server' +}, async () => ({ + contents: [{ + uri: 'server-info://status', + text: JSON.stringify({ + server: 'test-http-server', + version: '1.0.0', + transport: 'StreamableHTTP', + port: PORT, + started: new Date().toISOString(), + capabilities: ['tools', 'resources'] + }, null, 2), + mimeType: 'application/json' + }] +})); + +// Create Express app +const app = express(); +app.use(express.json()); + +// Store transports by session ID +const transports = {}; + +// Single transport instance for the server +const transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID(), + enableDnsRebindingProtection: false, + onsessioninitialized: (sessionId) => { + console.log(`[HTTP] New session initialized: ${sessionId}`); + }, + onsessionclosed: (sessionId) => { + console.log(`[HTTP] Session closed: ${sessionId}`); + } +}); + +// Connect the MCP server to the transport once +server.connect(transport).then(() => { + console.log('[HTTP] MCP server connected to transport'); +}).catch(error => { + console.error('[HTTP] Failed to connect MCP server to transport:', error); +}); + +// Handle all MCP requests +app.all('/mcp', async (req, res) => { + try { + console.log(`[HTTP] ${req.method} ${req.url}`); + await transport.handleRequest(req, res, req.body); + } catch (error) { + console.error('[HTTP] Error handling request:', error); + if (!res.headersSent) { + res.status(500).json({ error: 'Internal server error' }); + } + } +}); + +// Health check endpoint +app.get('/health', (req, res) => { + res.json({ + status: 'healthy', + server: 'test-http-server', + transport: 'StreamableHTTP', + port: PORT + }); +}); + +// Start the server +app.listen(PORT, () => { + console.log(`🚀 MCP Test HTTP Server listening on port ${PORT}`); + console.log(`📡 MCP endpoint: http://localhost:${PORT}/mcp`); + console.log(`❤️ Health check: http://localhost:${PORT}/health`); + console.log(`🔧 Test with: mcp-cli --url http://localhost:${PORT}/mcp`); +}); + +// Graceful shutdown +process.on('SIGTERM', () => { + console.log('Shutting down HTTP server...'); + Object.values(transports).forEach(transport => transport.close()); + process.exit(0); +}); + +process.on('SIGINT', () => { + console.log('Shutting down HTTP server...'); + Object.values(transports).forEach(transport => transport.close()); + process.exit(0); +}); \ No newline at end of file diff --git a/test/servers/sse-server.js b/test/servers/sse-server.js new file mode 100644 index 0000000..08eaa38 --- /dev/null +++ b/test/servers/sse-server.js @@ -0,0 +1,189 @@ +import express from 'express'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { z } from 'zod'; + +const PORT = 9101; + +// Create the MCP server +const server = new McpServer({ + name: 'test-sse-server', + version: '1.0.0' +}, { + capabilities: { + tools: {}, + resources: {} + } +}); + +// Add sample tools (same as HTTP server) +server.registerTool('add', { + title: 'Addition Tool', + description: 'Add two numbers together', + inputSchema: { + a: z.number().describe('First number'), + b: z.number().describe('Second number') + } +}, async ({ a, b }) => ({ + content: [{ + type: 'text', + text: `${a} + ${b} = ${a + b}` + }] +})); + +server.registerTool('echo', { + title: 'Echo Tool', + description: 'Echo back the input text', + inputSchema: { + message: z.string().describe('Text to echo back') + } +}, async ({ message }) => ({ + content: [{ + type: 'text', + text: `Echo: ${message}` + }] +})); + +server.registerTool('current-time', { + title: 'Current Time', + description: 'Get the current date and time', + inputSchema: {} +}, async () => ({ + content: [{ + type: 'text', + text: `Current time: ${new Date().toISOString()}` + }] +})); + +// Add sample resources +server.registerResource('server-info', 'server-info://status', { + title: 'Server Information', + description: 'Information about the test SSE server' +}, async () => ({ + contents: [{ + uri: 'server-info://status', + text: JSON.stringify({ + server: 'test-sse-server', + version: '1.0.0', + transport: 'SSE', + port: PORT, + started: new Date().toISOString(), + capabilities: ['tools', 'resources'] + }, null, 2), + mimeType: 'application/json' + }] +})); + +// Create Express app +const app = express(); +app.use(express.json()); + +// Store transports by session ID +const transports = {}; + +// SSE endpoint - establishes the Server-Sent Events stream +app.get('/sse', async (req, res) => { + try { + console.log('[SSE] New SSE connection request'); + + // Create SSE transport + const transport = new SSEServerTransport('/messages', res, { + enableDnsRebindingProtection: false, + allowedHosts: ['127.0.0.1', 'localhost'], + allowedOrigins: ['http://127.0.0.1:' + PORT, 'http://localhost:' + PORT] + }); + + // Store transport by session ID + transports[transport.sessionId] = transport; + console.log(`[SSE] Session created: ${transport.sessionId}`); + + // Handle transport close + transport.onclose = () => { + console.log(`[SSE] Session closed: ${transport.sessionId}`); + delete transports[transport.sessionId]; + }; + + transport.onerror = (error) => { + console.error(`[SSE] Session error: ${transport.sessionId}`, error); + delete transports[transport.sessionId]; + }; + + // Handle client disconnect + res.on('close', () => { + console.log(`[SSE] Client disconnected: ${transport.sessionId}`); + delete transports[transport.sessionId]; + }); + + // Connect the MCP server to this transport + await server.connect(transport); + + // Start the SSE stream + await transport.start(); + + } catch (error) { + console.error('[SSE] Error establishing SSE connection:', error); + if (!res.headersSent) { + res.status(500).json({ error: 'Failed to establish SSE connection' }); + } + } +}); + +// Messages endpoint - handles POST requests from clients +app.post('/messages', async (req, res) => { + try { + const sessionId = req.query.sessionId || req.headers['x-mcp-session-id']; + + if (!sessionId) { + return res.status(400).json({ error: 'Session ID required' }); + } + + const transport = transports[sessionId]; + if (!transport) { + return res.status(404).json({ error: 'Session not found' }); + } + + console.log(`[SSE] Handling message for session: ${sessionId}`); + + // Handle the message through the transport + await transport.handlePostMessage(req, res, req.body); + + } catch (error) { + console.error('[SSE] Error handling message:', error); + if (!res.headersSent) { + res.status(500).json({ error: 'Internal server error' }); + } + } +}); + +// Health check endpoint +app.get('/health', (req, res) => { + res.json({ + status: 'healthy', + server: 'test-sse-server', + transport: 'SSE', + port: PORT, + activeSessions: Object.keys(transports).length + }); +}); + +// Start the server +app.listen(PORT, () => { + console.log(`🚀 MCP Test SSE Server listening on port ${PORT}`); + console.log(`📡 SSE endpoint: http://localhost:${PORT}/sse`); + console.log(`📨 Messages endpoint: http://localhost:${PORT}/messages`); + console.log(`❤️ Health check: http://localhost:${PORT}/health`); + console.log(`🔧 Test with: mcp-cli --sse http://localhost:${PORT}/sse`); +}); + +// Graceful shutdown +process.on('SIGTERM', () => { + console.log('Shutting down SSE server...'); + Object.values(transports).forEach(transport => transport.close()); + process.exit(0); +}); + +process.on('SIGINT', () => { + console.log('Shutting down SSE server...'); + Object.values(transports).forEach(transport => transport.close()); + process.exit(0); +}); \ No newline at end of file diff --git a/test/servers/stdio-server.js b/test/servers/stdio-server.js new file mode 100644 index 0000000..8fe58e3 --- /dev/null +++ b/test/servers/stdio-server.js @@ -0,0 +1,107 @@ +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { z } from 'zod'; + +const PORT = null; // No port for stdio + +// Create the MCP server +const server = new McpServer({ + name: 'test-stdio-server', + version: '1.0.0' +}, { + capabilities: { + tools: {}, + resources: {} + } +}); + +// Add sample tools (same as HTTP/SSE servers) +server.registerTool('add', { + title: 'Addition Tool', + description: 'Add two numbers together', + inputSchema: { + a: z.number().describe('First number'), + b: z.number().describe('Second number') + } +}, async ({ a, b }) => ({ + content: [{ + type: 'text', + text: `${a} + ${b} = ${a + b}` + }] +})); + +server.registerTool('echo', { + title: 'Echo Tool', + description: 'Echo back the input text', + inputSchema: { + message: z.string().describe('Text to echo back') + } +}, async ({ message }) => ({ + content: [{ + type: 'text', + text: `Echo: ${message}` + }] +})); + +server.registerTool('current-time', { + title: 'Current Time', + description: 'Get the current date and time', + inputSchema: {} +}, async () => ({ + content: [{ + type: 'text', + text: `Current time: ${new Date().toISOString()}` + }] +})); + +// Add sample resources +server.registerResource('server-info', 'server-info://status', { + title: 'Server Information', + description: 'Information about the test stdio server' +}, async () => ({ + contents: [{ + uri: 'server-info://status', + text: JSON.stringify({ + server: 'test-stdio-server', + version: '1.0.0', + transport: 'stdio', + port: PORT, + started: new Date().toISOString(), + capabilities: ['tools', 'resources'] + }, null, 2), + mimeType: 'application/json' + }] +})); + +// Create stdio transport +const transport = new StdioServerTransport(); + +// Connect the MCP server to the transport +async function main() { + try { + await server.connect(transport); + + // Log to stderr so it doesn't interfere with MCP protocol on stdout + console.error('🚀 MCP Test Stdio Server started'); + console.error('📡 Transport: stdio (stdin/stdout)'); + console.error('🔧 Test with: node src/cli.js stdio-server'); + + } catch (error) { + console.error('Failed to start stdio server:', error); + process.exit(1); + } +} + +// Graceful shutdown +process.on('SIGTERM', () => { + console.error('Shutting down stdio server...'); + process.exit(0); +}); + +process.on('SIGINT', () => { + console.error('Shutting down stdio server...'); + process.exit(0); +}); + +// Start the server +main(); \ No newline at end of file From 7ba7553c999e42c0e0370829e6a81aada4311c0b Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Mon, 8 Sep 2025 13:33:00 -0400 Subject: [PATCH 2/2] Remove root mcp_config.json in favor of test/config.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the test/config.json file for development configurations instead of having duplicate configuration files. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- mcp_config.json | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 mcp_config.json diff --git a/mcp_config.json b/mcp_config.json deleted file mode 100644 index b31aaff..0000000 --- a/mcp_config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "mcpServers": { - "stdio-server": { - "command": "node", - "args": ["test/servers/stdio-server.js"] - }, - "http-server": { - "url": "http://localhost:9100/mcp" - }, - "sse-server": { - "url": "http://localhost:9101/sse" - } - } -} \ No newline at end of file