mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-04-17 15:43:24 +02:00
96 lines
3.2 KiB
TypeScript
96 lines
3.2 KiB
TypeScript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import {
|
|
Root,
|
|
RootsListChangedNotificationSchema,
|
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
|
|
// Track roots by session id
|
|
export const roots: Map<string | undefined, Root[]> = new Map<
|
|
string | undefined,
|
|
Root[]
|
|
>();
|
|
|
|
/**
|
|
* Get the latest the client roots list for the session.
|
|
*
|
|
* - Request and cache the roots list for the session if it has not been fetched before.
|
|
* - Return the cached roots list for the session if it exists.
|
|
*
|
|
* When requesting the roots list for a session, it also sets up a `roots/list_changed`
|
|
* notification handler. This ensures that updates are automatically fetched and handled
|
|
* in real-time.
|
|
*
|
|
* This function is idempotent. It should only request roots from the client once per session,
|
|
* returning the cached version thereafter.
|
|
*
|
|
* @param {McpServer} server - An instance of the MCP server used to communicate with the client.
|
|
* @param {string} [sessionId] - An optional session id used to associate the roots list with a specific client session.
|
|
*
|
|
* @throws {Error} In case of a failure to request the roots from the client, an error log message is sent.
|
|
*/
|
|
export const syncRoots = async (server: McpServer, sessionId?: string) => {
|
|
const clientCapabilities = server.server.getClientCapabilities() || {};
|
|
const clientSupportsRoots: boolean = clientCapabilities?.roots !== undefined;
|
|
|
|
// Fetch the roots list for this client
|
|
if (clientSupportsRoots) {
|
|
// Function to request the updated roots list from the client
|
|
const requestRoots = async () => {
|
|
try {
|
|
// Request the updated roots list from the client
|
|
const response = await server.server.listRoots();
|
|
if (response && "roots" in response) {
|
|
// Store the roots list for this client
|
|
roots.set(sessionId, response.roots);
|
|
|
|
// Notify the client of roots received
|
|
await server.sendLoggingMessage(
|
|
{
|
|
level: "info",
|
|
logger: "everything-server",
|
|
data: `Roots updated: ${response?.roots?.length} root(s) received from client`,
|
|
},
|
|
sessionId
|
|
);
|
|
} else {
|
|
await server.sendLoggingMessage(
|
|
{
|
|
level: "info",
|
|
logger: "everything-server",
|
|
data: "Client returned no roots set",
|
|
},
|
|
sessionId
|
|
);
|
|
}
|
|
} catch (error) {
|
|
await server.sendLoggingMessage(
|
|
{
|
|
level: "error",
|
|
logger: "everything-server",
|
|
data: `Failed to request roots from client: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`,
|
|
},
|
|
sessionId
|
|
);
|
|
}
|
|
};
|
|
|
|
// If the roots have not been synced for this client,
|
|
// set notification handler and request initial roots
|
|
if (!roots.has(sessionId)) {
|
|
// Set the list changed notification handler
|
|
server.server.setNotificationHandler(
|
|
RootsListChangedNotificationSchema,
|
|
requestRoots
|
|
);
|
|
|
|
// Request the initial roots list immediately
|
|
await requestRoots();
|
|
}
|
|
|
|
// Return the roots list for this client
|
|
return roots.get(sessionId);
|
|
}
|
|
};
|