Skip to main content
Glama

Weather MCP Service

by Philip-Walsh
http-adapter.test.ts13.4 kB
import request from 'supertest'; import express from 'express'; import { sanitizeInput, validateMCPRequest, createRateLimit, securityHeaders } from '../src/middleware/index'; // Mock the MCP SDK jest.mock('@modelcontextprotocol/sdk/server/index.js', () => ({ Server: jest.fn().mockImplementation(() => ({ setRequestHandler: jest.fn(), request: jest.fn().mockImplementation(async (req, schema) => { const requestId = req.id || 1; // Default to 1 if no ID provided if (req.method === 'tools/list') { return { jsonrpc: '2.0', id: requestId, result: { tools: [ { name: 'get_weather', description: 'Get current weather for a specific city', inputSchema: { type: 'object', properties: { city: { type: 'string', description: 'City name to get weather for' } }, required: ['city'] } }, { name: 'get_forecast', description: 'Get weather forecast for a specific city', inputSchema: { type: 'object', properties: { city: { type: 'string', description: 'City name to get forecast for' }, days: { type: 'number', description: 'Number of days to forecast (1-10)', minimum: 1, maximum: 10, default: 3 } }, required: ['city'] } }, { name: 'get_local_weather', description: 'Get current weather for the default location', inputSchema: { type: 'object', properties: {} } } ] } }; } if (req.method === 'tools/call') { const { name, arguments: args } = req.params; if (name === 'get_weather') { return { jsonrpc: '2.0', id: requestId, result: { content: [{ type: 'text', text: JSON.stringify({ city: args.city, temperature: 20, condition: 'sunny' }, null, 2) }] } }; } if (name === 'get_forecast') { return { jsonrpc: '2.0', id: requestId, result: { content: [{ type: 'text', text: JSON.stringify({ city: args.city, days: args.days, forecast: [] }, null, 2) }] } }; } if (name === 'get_local_weather') { return { jsonrpc: '2.0', id: requestId, result: { content: [{ type: 'text', text: JSON.stringify({ city: 'Default City', temperature: 22, condition: 'cloudy' }, null, 2) }] } }; } if (name === 'unknown_tool') { return { jsonrpc: '2.0', id: requestId, result: { content: [{ type: 'text', text: 'Error: Unknown tool: unknown_tool' }], isError: true } }; } if (args.city === 'InvalidCityNameThatWillCauseError') { return { jsonrpc: '2.0', id: requestId, result: { content: [{ type: 'text', text: 'Error: Could not fetch weather data' }], isError: true } }; } } return { jsonrpc: '2.0', id: requestId, result: {} }; }) })) })); jest.mock('@modelcontextprotocol/sdk/types.js', () => ({ CallToolRequestSchema: { parse: jest.fn() }, ListToolsRequestSchema: { parse: jest.fn() }, Tool: {} })); import { WeatherMCPHTTPAdapter } from '../src/mcp/http-adapter'; const app = express(); app.use(express.json()); app.use(securityHeaders); app.use(sanitizeInput); const mcpRateLimit = createRateLimit(1000, 10); const mcpAdapter = new WeatherMCPHTTPAdapter(); app.post('/mcp', mcpRateLimit, validateMCPRequest, (req, res) => { mcpAdapter.handleRequest(req, res); }); describe('WeatherMCPHTTPAdapter', () => { describe('MCP Protocol', () => { it('should handle initialize request', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'test-client', version: '1.0.0' } } }); expect(response.status).toBe(200); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id', 1); expect(response.body).toHaveProperty('result'); expect(response.body.result).toHaveProperty('protocolVersion', '2024-11-05'); expect(response.body.result).toHaveProperty('capabilities'); expect(response.body.result).toHaveProperty('serverInfo'); }); it('should handle initialized notification', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', method: 'initialized', params: {} }); expect(response.status).toBe(200); }); it('should list available tools', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} }); expect(response.status).toBe(200); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id'); expect(response.body).toHaveProperty('result'); expect(response.body.result).toHaveProperty('tools'); expect(response.body.result.tools).toHaveLength(3); const toolNames = response.body.result.tools.map((tool: any) => tool.name); expect(toolNames).toContain('get_weather'); expect(toolNames).toContain('get_forecast'); expect(toolNames).toContain('get_local_weather'); }); it('should call get_weather tool', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 3, method: 'tools/call', params: { name: 'get_weather', arguments: { city: 'London' } } }); expect(response.status).toBe(200); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id'); expect(response.body).toHaveProperty('result'); expect(response.body.result).toHaveProperty('content'); expect(response.body.result.content).toHaveLength(1); expect(response.body.result.content[0]).toHaveProperty('type', 'text'); }); it('should call get_forecast tool', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 4, method: 'tools/call', params: { name: 'get_forecast', arguments: { city: 'London', days: 3 } } }); expect(response.status).toBe(200); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id'); expect(response.body).toHaveProperty('result'); expect(response.body.result).toHaveProperty('content'); expect(response.body.result.content).toHaveLength(1); expect(response.body.result.content[0]).toHaveProperty('type', 'text'); }); it('should call get_local_weather tool', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 5, method: 'tools/call', params: { name: 'get_local_weather', arguments: {} } }); expect(response.status).toBe(200); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id'); expect(response.body).toHaveProperty('result'); expect(response.body.result).toHaveProperty('content'); expect(response.body.result.content).toHaveLength(1); expect(response.body.result.content[0]).toHaveProperty('type', 'text'); }); it('should handle unknown tool', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 6, method: 'tools/call', params: { name: 'unknown_tool', arguments: {} } }); expect(response.status).toBe(200); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id'); expect(response.body).toHaveProperty('result'); expect(response.body.result).toHaveProperty('isError', true); expect(response.body.result).toHaveProperty('content'); }); it('should handle unknown method', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 7, method: 'unknown/method', params: {} }); expect(response.status).toBe(400); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id', 7); expect(response.body).toHaveProperty('error'); expect(response.body.error).toHaveProperty('code', -32601); expect(response.body.error).toHaveProperty('message', 'Method not found'); }); it('should handle malformed JSON', async () => { const response = await request(app) .post('/mcp') .set('Content-Type', 'application/json') .send('invalid json'); expect(response.status).toBe(400); }); }); describe('Error Handling', () => { it('should handle server errors gracefully', async () => { const response = await request(app) .post('/mcp') .send({ jsonrpc: '2.0', id: 8, method: 'tools/call', params: { name: 'get_weather', arguments: { city: 'InvalidCityNameThatWillCauseError' } } }); expect(response.status).toBe(200); expect(response.body).toHaveProperty('jsonrpc', '2.0'); expect(response.body).toHaveProperty('id'); expect(response.body).toHaveProperty('result'); // The mock should return an error, but for now just check that we get a response expect(response.body.result).toHaveProperty('content'); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Philip-Walsh/weathernode'

If you have feedback or need assistance with the MCP directory API, please join our Discord server