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

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
This commit is contained in:
cliffhall
2025-12-12 20:12:18 -05:00
parent cb073d877a
commit 9b25a3a41b
16 changed files with 581 additions and 1533 deletions

View File

@@ -1,19 +1,40 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { dirname, join } from "path";
import { readFileSync } from "fs";
import { fileURLToPath } from "url";
import {
setSubscriptionHandlers,
stopSimulatedResourceUpdates,
} from "../resources/subscriptions.js";
import { registerTools } from "../tools/index.js";
import { registerResources } from "../resources/index.js";
import { registerResources, readInstructions } from "../resources/index.js";
import { registerPrompts } from "../prompts/index.js";
import { stopSimulatedLogging } from "./logging.js";
import { setRootsListChangedHandler } from "./roots.js";
import { syncRoots } from "./roots.js";
// Everything Server factory
export const createServer = () => {
// Server Factory response
export type ServerFactoryResponse = {
server: McpServer;
clientConnected: (sessionId?: string) => void;
cleanup: (sessionId?: string) => void;
};
/**
* `ServerInstance` factory
*
* This function initializes a `McpServer` with specific capabilities and instructions,
* registers tools, resources, and prompts, and configures resource subscription handlers.
*
* It returns the server instance along with callbacks for post-connection setup and cleanup tasks.
*
* @function
* @returns {ServerFactoryResponse} An object containing the server instance, a `clientConnected` callback
* for managing new client sessions, and a `cleanup` function for handling server-side cleanup when
* a session ends.
*
* Properties of the returned object:
* - `server` {Object}: The initialized server instance.
* - `clientConnected` {Function}: A post-connect callback to enable operations that require a `sessionId`.
* - `cleanup` {Function}: Function to perform cleanup operations for a closing session.
*/
export const createServer: () => ServerFactoryResponse = () => {
// Read the server instructions
const instructions = readInstructions();
@@ -49,32 +70,17 @@ export const createServer = () => {
// Set resource subscription handlers
setSubscriptionHandlers(server);
// Return server instance, client connection handler, and cleanup function
// Return the ServerFactoryResponse
return {
server,
clientConnected: (sessionId?: string) => {
// Set the roots list changed handler
setRootsListChangedHandler(server, sessionId);
// Set a roots list changed handler and fetch the initial roots list from the client
syncRoots(server, sessionId);
},
cleanup: (sessionId?: string) => {
// Stop any simulated logging or resource updates that may have been initiated.
stopSimulatedLogging(sessionId);
stopSimulatedResourceUpdates(sessionId);
},
};
} satisfies ServerFactoryResponse;
};
// Read the server instructions from a file
function readInstructions(): string {
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const filePath = join(__dirname, "..", "docs", "server-instructions.md");
let instructions;
try {
instructions = readFileSync(filePath, "utf-8");
} catch (e) {
instructions = "Server instructions not loaded: " + e;
}
return instructions;
}