import express from 'express';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
const PORT = parseInt(process.env['PORT'] ?? '8080', 10);
// Simulated weather data
const WEATHER: Record<string, { temp: number; condition: string }> = {
chicago: { temp: 22, condition: 'partly cloudy' },
amsterdam: { temp: 14, condition: 'rainy' },
sydney: { temp: 28, condition: 'sunny' },
};
function createMcpServer(): Server {
const server = new Server(
{ name: 'weather-server', version: '1.0.0' },
{ capabilities: { tools: {} } },
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'get_weather',
description: 'Get current weather for a city.',
inputSchema: {
type: 'object',
properties: {
city: { type: 'string', description: 'City name (chicago, amsterdam, sydney).' },
},
required: ['city'],
},
},
{
name: 'list_cities',
description: 'List cities with available weather data.',
inputSchema: { type: 'object', properties: {} },
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === 'list_cities') {
return { content: [{ type: 'text', text: Object.keys(WEATHER).join(', ') }] };
}
if (name === 'get_weather') {
const { city } = args as { city: string };
const w = WEATHER[city.toLowerCase()];
if (!w) throw new McpError(ErrorCode.InvalidParams, `Unknown city: ${city}`);
return { content: [{ type: 'text', text: `${city}: ${w.temp}°C, ${w.condition}` }] };
}
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
});
return server;
}
const app = express();
const transports = new Map<string, SSEServerTransport>();
app.get('/healthz', (_req, res) => { res.status(200).json({ status: 'ok' }); });
app.get('/sse', async (_req, res) => {
const transport = new SSEServerTransport('/message', res);
transports.set(transport.sessionId, transport);
transport.onclose = () => { transports.delete(transport.sessionId); };
await createMcpServer().connect(transport);
});
app.post('/message', express.json(), async (req, res) => {
const sessionId = req.query['sessionId'] as string;
const transport = transports.get(sessionId);
if (!transport) { res.status(404).json({ error: 'Session not found' }); return; }
await transport.handlePostMessage(req, res);
});
app.listen(PORT, () => console.log(`Weather server listening on port ${PORT}`));