[WIP] Refactor everything server to be more modular and use recommended APIs.
Adding simulated logging and refactoring subscriptions to not need to track transports
* Updated architecture.md
* In server/index.ts
- remove import of Transport
- import beginSimulatedLogging and stopSimulatedLogging
- in clientConnected()
- change argument to sessionId? instead of transport
- add call to beginSimulatedLogging
- send server and sessionId to beginSimulatedResourceUpdates and beginSimulatedLogging
- in cleanup()
- add call to stopSimulatedLogging passing sessionId
* Added server/logging.ts
- Initialize logsUpdateIntervals to Map session ID to the interval for sending logging messages to the client
- in beginSimulatedLogging()
- create an array of logging meesages, customized with the sessionId if present
- if the interval for the sessionId hasn't been set, create one, calling server.sendLoggingMessage with a random message to the client each time the interval elapses
- in stopSimulatedLogging()
- if a logging interval exists for the sessionId, clear it and remove it
* In subscriptions.ts
- remove import of Transport
- remove transports map
- in beginSimulatedResourceUpdates()
- change arguments to server and sessionId
- check for the subsUpdateInterval for the session
- remove all transport storage and interaction
- instead use the server to send the notification
- in stopSimulatedResourceUpdates()
- remove management of transports map
* In sse.ts and streamableHttp.ts
- when calling clientConnected, pass sessionId instead of transport
* In stdio.ts,
- when calling clientConnected, pass nothing instead of transport
* In subscriptions.ts
- updated inline doc
This commit is contained in:
parent
8559fbd5a4
commit
16ed05957c
3 changed files with 129 additions and 56 deletions
|
|
@ -171,7 +171,6 @@ export const createServer = () => {
|
|||
|
||||
let subscriptions: Set<string> = new Set();
|
||||
let subsUpdateInterval: NodeJS.Timeout | undefined;
|
||||
let stdErrUpdateInterval: NodeJS.Timeout | undefined;
|
||||
|
||||
let logsUpdateInterval: NodeJS.Timeout | undefined;
|
||||
// Store client capabilities
|
||||
|
|
@ -1147,7 +1146,6 @@ export const createServer = () => {
|
|||
const cleanup = async () => {
|
||||
if (subsUpdateInterval) clearInterval(subsUpdateInterval);
|
||||
if (logsUpdateInterval) clearInterval(logsUpdateInterval);
|
||||
if (stdErrUpdateInterval) clearInterval(stdErrUpdateInterval);
|
||||
};
|
||||
|
||||
return { server, cleanup, startNotificationIntervals };
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|||
import { dirname, join } from "path";
|
||||
import { readFileSync } from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
||||
import {
|
||||
setSubscriptionHandlers,
|
||||
beginSimulatedResourceUpdates,
|
||||
|
|
@ -11,6 +10,7 @@ import {
|
|||
import { registerTools } from "../tools/index.js";
|
||||
import { registerResources } from "../resources/index.js";
|
||||
import { registerPrompts } from "../prompts/index.js";
|
||||
import { beginSimulatedLogging, stopSimulatedLogging } from "./logging.js";
|
||||
|
||||
// Everything Server factory
|
||||
export const createServer = () => {
|
||||
|
|
@ -51,12 +51,15 @@ export const createServer = () => {
|
|||
|
||||
return {
|
||||
server,
|
||||
clientConnected: (transport: Transport) => {
|
||||
beginSimulatedResourceUpdates(transport);
|
||||
// TODO simulated logging
|
||||
// When the client connects, begin simulated resource updates and logging
|
||||
clientConnected: (sessionId?: string) => {
|
||||
beginSimulatedResourceUpdates(server, sessionId);
|
||||
beginSimulatedLogging(server, sessionId);
|
||||
},
|
||||
// When the client disconnects, stop simulated resource updates and logging
|
||||
cleanup: (sessionId?: string) => {
|
||||
stopSimulatedResourceUpdates(sessionId);
|
||||
stopSimulatedLogging(sessionId);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
73
src/everything/server/logging.ts
Normal file
73
src/everything/server/logging.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { LoggingLevel } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
|
||||
// Map session ID to the interval for sending logging messages to the client
|
||||
const logsUpdateIntervals: Map<string | undefined, NodeJS.Timeout | undefined> =
|
||||
new Map<string | undefined, NodeJS.Timeout | undefined>();
|
||||
|
||||
/**
|
||||
* Initiates a simulated logging process by sending random log messages to the client at a
|
||||
* fixed interval. Each log message contains a random logging level and optional session ID.
|
||||
*
|
||||
* @param {McpServer} server - The server instance responsible for handling the logging messages.
|
||||
* @param {string | undefined} sessionId - An optional identifier for the session. If provided,
|
||||
* the session ID will be appended to log messages.
|
||||
*/
|
||||
export const beginSimulatedLogging = (
|
||||
server: McpServer,
|
||||
sessionId: string | undefined
|
||||
) => {
|
||||
const maybeAppendSessionId = sessionId ? ` - SessionId ${sessionId}` : "";
|
||||
const messages: { level: LoggingLevel; data: string }[] = [
|
||||
{ level: "debug", data: `Debug-level message${maybeAppendSessionId}` },
|
||||
{ level: "info", data: `Info-level message${maybeAppendSessionId}` },
|
||||
{ level: "notice", data: `Notice-level message${maybeAppendSessionId}` },
|
||||
{
|
||||
level: "warning",
|
||||
data: `Warning-level message${maybeAppendSessionId}`,
|
||||
},
|
||||
{ level: "error", data: `Error-level message${maybeAppendSessionId}` },
|
||||
{
|
||||
level: "critical",
|
||||
data: `Critical-level message${maybeAppendSessionId}`,
|
||||
},
|
||||
{ level: "alert", data: `Alert level-message${maybeAppendSessionId}` },
|
||||
{
|
||||
level: "emergency",
|
||||
data: `Emergency-level message${maybeAppendSessionId}`,
|
||||
},
|
||||
];
|
||||
|
||||
// Set the interval to send logging messages to this client
|
||||
if (!logsUpdateIntervals.has(sessionId)) {
|
||||
logsUpdateIntervals.set(
|
||||
sessionId,
|
||||
setInterval(async () => {
|
||||
// By using the `sendLoggingMessage` function to send the message, we
|
||||
// ensure that the client's chosen logging level will be respected
|
||||
await server.sendLoggingMessage(
|
||||
messages[Math.floor(Math.random() * messages.length)],
|
||||
sessionId
|
||||
);
|
||||
}, 15000)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stops the simulated logging process for a given session.
|
||||
*
|
||||
* This function halts the periodic logging updates associated with the specified
|
||||
* session ID by clearing the interval and removing the session's tracking
|
||||
* reference. Session ID can be undefined for stdio.
|
||||
*
|
||||
* @param {string} [sessionId] - The optional unique identifier of the session.
|
||||
*/
|
||||
export const stopSimulatedLogging = (sessionId?: string) => {
|
||||
// Remove active intervals
|
||||
if (logsUpdateIntervals.has(sessionId)) {
|
||||
const logsUpdateInterval = logsUpdateIntervals.get(sessionId);
|
||||
clearInterval(logsUpdateInterval);
|
||||
logsUpdateIntervals.delete(sessionId);
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue