[WIP] Refactor everything server to be more modular and use recommended APIs.

Adding resource subscriptions:

* Updated architecture.md

* In server/index.ts
  - imported Transport, setSubscriptionHandlers,beginSimulatedResourceUpdates, and stopSimulatedResourceUpdates
  - call setSubscriptionHandlers passing server
  - in returned object,
    - refactor/renamed startNotificationIntervals placehodler to clientConnected, which takes a transport argument and calls beginSimulatedResourceUpdates, passing the transport
    - replaced cleanup placeholder with a function that takes an optional sessionId and calls stopSimulatedResourceUpdates, passing the sessionId

* In sse.ts, stdio.ts, and streamableHttp.ts
  - when transport is connected, called clientConnect, passing transport
  - when disconnecting, called cleanup, passing sessionId

* Added subscriptions.ts
  - tracks subscriber session id lists by URI
  - tracks transport by session id
  - tracks subscription update intervals by sessionId
  - in setSubscriptionHandlers
    - set request handlers for SubscribeRequestSchema and UnsubscribeRequestSchema
  - in beginSimulatedResourceUpdates
    - starts an interval to send updates to the transport for all subscribed resources
  - in stopSimulatedResourceUpdates
    - removes intervals and transport for gien session id
This commit is contained in:
cliffhall
2025-12-06 19:44:07 -05:00
parent 7b2ff6b064
commit 07867a5dd5
6 changed files with 231 additions and 21 deletions

View File

@@ -35,7 +35,7 @@ app.post("/mcp", async (req: Request, res: Response) => {
// Reuse existing transport
transport = transports.get(sessionId)!;
} else if (!sessionId) {
const { server } = createServer();
const { server, clientConnected, cleanup } = createServer();
// New initialization request
const eventStore = new InMemoryEventStore();
@@ -43,10 +43,13 @@ app.post("/mcp", async (req: Request, res: Response) => {
sessionIdGenerator: () => randomUUID(),
eventStore, // Enable resumability
onsessioninitialized: (sessionId: string) => {
// Store the transport by session ID when session is initialized
// Store the transport by session ID when a session is initialized
// This avoids race conditions where requests might come in before the session is stored
console.log(`Session initialized with ID: ${sessionId}`);
transports.set(sessionId, transport);
// Start simulated logging and subscription updates when a client connects
clientConnected(transport);
},
});
@@ -58,6 +61,7 @@ app.post("/mcp", async (req: Request, res: Response) => {
`Transport closed for session ${sid}, removing from transports map`
);
transports.delete(sid);
cleanup(sid);
}
};