import type { Request, Response } from 'express';
import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { getServer } from './server.js';
const PORT = parseInt(process.env.PORT || '3000', 10);
const app = createMcpExpressApp();
/**
* POST /mcp - Handle MCP JSON-RPC requests (stateless mode)
* Each request creates a fresh McpServer and StreamableHTTPServerTransport.
*/
app.post('/mcp', async (req: Request, res: Response) => {
const server = getServer();
try {
// Create stateless transport (no session ID)
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined, // Stateless mode
});
// Connect server to transport
await server.connect(transport);
// Handle the request
await transport.handleRequest(req, res, req.body);
// Cleanup on connection close
res.on('close', () => {
transport.close().catch(console.error);
server.close().catch(console.error);
});
} catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
/**
* GET /mcp - Not used in stateless mode
* (In stateful mode, this would handle SSE streams for server->client notifications)
*/
app.get('/mcp', async (req: Request, res: Response) => {
res.writeHead(405).end(
JSON.stringify({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Method not allowed. This server operates in stateless mode.',
},
id: null,
})
);
});
/**
* DELETE /mcp - Not used in stateless mode
* (In stateful mode, this would handle session termination)
*/
app.delete('/mcp', async (req: Request, res: Response) => {
res.writeHead(405).end(
JSON.stringify({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Method not allowed. This server operates in stateless mode.',
},
id: null,
})
);
});
app.listen(PORT, () => {
console.log(`MCP-CLIO server listening on http://localhost:${PORT}/mcp`);
console.log('Mode: Stateless');
console.log('Available tools: clio-environment, clio-raw');
});