mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-04-21 13:25:20 +02:00
* In how-it-works.md, - added a section on conditional tool registration * In server/index.ts - import registerConditionalTools - in an oninitialized handler for the server, call registerConditionalTools - removed clientConnected from ServerFactoryResponse and all mentions in docs * In tools/index.ts - export a registerConditionalTools function - refactor/move calls to registerGetRootsListTool, registerTriggerElicitationRequestTool, and registerTriggerSamplingRequestTool out of registerTools and into registerConditionalTools * In server/roots.ts - only act if client supports roots - remove setInterval from call to requestRoots. It isn't happening during the initialze handshake anymore, so it doesn't interfere with that process if called immediaately * In get-roots-list.ts, trigger-elicitation-request.ts, and trigger-sampling-request.ts, - only register tool if client supports capability * Throughout the rest of the files, removing all references to `clientConnected`
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
import express from "express";
|
|
import { createServer } from "../server/index.js";
|
|
import cors from "cors";
|
|
|
|
console.error("Starting SSE server...");
|
|
|
|
// Express app with permissive CORS for testing with Inspector direct connect mode
|
|
const app = express();
|
|
app.use(
|
|
cors({
|
|
origin: "*", // use "*" with caution in production
|
|
methods: "GET,POST",
|
|
preflightContinue: false,
|
|
optionsSuccessStatus: 204,
|
|
})
|
|
);
|
|
|
|
// Map sessionId to transport for each client
|
|
const transports: Map<string, SSEServerTransport> = new Map<
|
|
string,
|
|
SSEServerTransport
|
|
>();
|
|
|
|
// Handle GET requests for new SSE streams
|
|
app.get("/sse", async (req, res) => {
|
|
let transport: SSEServerTransport;
|
|
const { server, cleanup } = createServer();
|
|
|
|
// Session Id should not exist for GET /sse requests
|
|
if (req?.query?.sessionId) {
|
|
const sessionId = req?.query?.sessionId as string;
|
|
transport = transports.get(sessionId) as SSEServerTransport;
|
|
console.error(
|
|
"Client Reconnecting? This shouldn't happen; when client has a sessionId, GET /sse should not be called again.",
|
|
transport.sessionId
|
|
);
|
|
} else {
|
|
// Create and store transport for the new session
|
|
transport = new SSEServerTransport("/message", res);
|
|
transports.set(transport.sessionId, transport);
|
|
|
|
// Connect server to transport
|
|
await server.connect(transport);
|
|
const sessionId = transport.sessionId;
|
|
console.error("Client Connected: ", sessionId);
|
|
|
|
// Handle close of connection
|
|
server.server.onclose = async () => {
|
|
const sessionId = transport.sessionId;
|
|
console.error("Client Disconnected: ", sessionId);
|
|
transports.delete(sessionId);
|
|
cleanup(sessionId);
|
|
};
|
|
}
|
|
});
|
|
|
|
// Handle POST requests for client messages
|
|
app.post("/message", async (req, res) => {
|
|
// Session Id should exist for POST /message requests
|
|
const sessionId = req?.query?.sessionId as string;
|
|
|
|
// Get the transport for this session and use it to handle the request
|
|
const transport = transports.get(sessionId);
|
|
if (transport) {
|
|
console.error("Client Message from", sessionId);
|
|
await transport.handlePostMessage(req, res);
|
|
} else {
|
|
console.error(`No transport found for sessionId ${sessionId}`);
|
|
}
|
|
});
|
|
|
|
// Start the express server
|
|
const PORT = process.env.PORT || 3001;
|
|
app.listen(PORT, () => {
|
|
console.error(`Server is running on port ${PORT}`);
|
|
});
|