Finalized Roots list changed handling and initial request. Final fit and finish work.
* Updated architecture.md
- Added links to other docs
- Refactor/extracted sections into extension.md, features.md, how-it-works.md, startup.md, and structure.md
* Removed everything.ts
- all features are ported
* In roots.ts
- refactor/renaned setRootsListChangedHandler to syncRoots
- refactor handler logic to requestRoots function
- Calls for roots list directly to get initial list
* In server/index.ts
- import setRootsListChangedHandler
- in clientConnected callback
- call setRootsListChangedHandler passing server and sessionId
* In sse.ts, stdio.ts, and streamableHttp.ts
- update inline and function docs
* In index.ts,
- updated usage output
* In server/index.ts
- refactor/extracted readInstructions to resources/index.ts
- defined ServerFactoryResponse response type
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import {
|
|
Root,
|
|
RootsListChangedNotificationSchema,
|
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
|
|
// Track roots by session id
|
|
const roots: Map<string | undefined, Root[]> = new Map<
|
|
string | undefined,
|
|
Root[]
|
|
>();
|
|
|
|
/**
|
|
* Sync the root directories from the client by requesting and updating the roots list for
|
|
* the specified session.
|
|
*
|
|
* Also sets up a notification handler to listen for changes in the roots list, ensuring that
|
|
* updates are automatically fetched and handled in real-time.
|
|
*
|
|
* @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 = (server: McpServer, sessionId?: string) => {
|
|
// 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
|
|
);
|
|
}
|
|
};
|
|
|
|
// Set the list changed notification handler
|
|
server.server.setNotificationHandler(
|
|
RootsListChangedNotificationSchema,
|
|
requestRoots
|
|
);
|
|
|
|
// Request initial roots list after a brief delay
|
|
// Allows initial POST request to complete on streamableHttp transports
|
|
setTimeout(() => requestRoots(), 350);
|
|
};
|