From 8845118d61e53380f3d78f2d798d4277b613f3bf Mon Sep 17 00:00:00 2001 From: cliffhall Date: Thu, 4 Dec 2025 19:01:18 -0500 Subject: [PATCH] [WIP] Refactor everything server to be more modular and use recommended APIs. * Adding dynamic resources * Add server/index.js - import registerResources from resources/index.js - in createServer() - call registerResources, passing server * Add resources/dynamic.ts - in addDynamicResources() - define formatGmtTimestamp to create a time stamp to include in the resource text or encoded blob - define parseIndex to ensure the index variable of the URI is a number * Add resources/index.ts - import addDynamicResources - export registerResources function - in registerResources() - call addDynamicResources * In package.json - update the start commands to launch each of the transports properly --- src/everything/package.json | 6 +- src/everything/resources/dynamic.ts | 99 +++++++++++++++++++++++++++++ src/everything/resources/index.ts | 11 ++++ src/everything/server/index.ts | 4 ++ 4 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/everything/resources/dynamic.ts create mode 100644 src/everything/resources/index.ts diff --git a/src/everything/package.json b/src/everything/package.json index f82126d6..951edc5a 100644 --- a/src/everything/package.json +++ b/src/everything/package.json @@ -22,9 +22,9 @@ "build": "tsc && shx cp instructions.md dist/ && shx chmod +x dist/*.js", "prepare": "npm run build", "watch": "tsc --watch", - "start": "node dist/index.js", - "start:sse": "node dist/sse.js", - "start:streamableHttp": "node dist/streamableHttp.js" + "start:stdio": "node dist/index.js stdio", + "start:sse": "node dist/index.js sse", + "start:streamableHttp": "node dist/index.js streamableHttp" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.24.0", diff --git a/src/everything/resources/dynamic.ts b/src/everything/resources/dynamic.ts new file mode 100644 index 00000000..2acc9356 --- /dev/null +++ b/src/everything/resources/dynamic.ts @@ -0,0 +1,99 @@ +import {McpServer, ResourceTemplate} from "@modelcontextprotocol/sdk/server/mcp.js"; + +/** + * Register dynamic resources with the MCP server. + * + * - Text and blob resources, dynamically generated from the URI {index} variable + * - Any finite integer is acceptable for the index variable + * - List resources method will not return these resources + * - These are only accessible via template URIs + * - Both blob and text resources: + * - have content that is dynamically generated, including a timestamp + * - have different template URIs + * - Blob: "test://dynamic/resource/blob/{index}" + * - Text: "test://dynamic/resource/text/{index}" + * + * @param server + */ +export const addDynamicResources = (server: McpServer) => { + const uriBase: string = "test://dynamic/resource"; + const textUri: string = `${uriBase}/text/{index}` + const blobUri: string = `${uriBase}/blob/{index}` + + // Format a GMT timestamp like "7:30AM GMT on November 3" + const formatGmtTimestamp = () => { + const d = new Date(); + const h24 = d.getUTCHours(); + const minutes = d.getUTCMinutes(); + const ampm = h24 >= 12 ? "PM" : "AM"; + let h12 = h24 % 12; + if (h12 === 0) h12 = 12; + const mm = String(minutes).padStart(2, "0"); + const months = [ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ]; + const monthName = months[d.getUTCMonth()]; + const day = d.getUTCDate(); + return `${h12}:${mm}${ampm} GMT on ${monthName} ${day}`; + }; + + const parseIndex = (uri: URL, variables: Record) => { + const uriError = `Unknown resource: ${uri}`; + if (uri.toString() !== textUri && uri.toString() !== blobUri) { + throw new Error(uriError); + } + const idxStr = String((variables as any).index ?? ""); + const idx = Number(idxStr); + if (Number.isFinite(idx) && Number.isInteger(idx)) { + return idx; + } else { + throw new Error(uriError); + } + }; + + // Text resource registration + server.registerResource( + "Dynamic Text Resource", + new ResourceTemplate(textUri, { list: undefined }), + { + mimeType: "text/plain", + description: "Plaintext dynamic resource fabricated from the {index} variable, which must be an integer.", + }, + async (uri, variables) => { + const index = parseIndex(uri, variables); + return { + contents: [ + { + uri: uri.toString(), + mimeType: "text/plain", + text: `Resource ${index}: This is a plaintext resource created at ${formatGmtTimestamp()}`, + }, + ], + }; + } + ); + + // Blob resource registration + server.registerResource( + "Dynamic Blob Resource", + new ResourceTemplate(blobUri, { list: undefined }), + { + mimeType: "application/octet-stream", + description: "Binary (base64) dynamic resource fabricated from the {index} variable, which must be an integer.", + }, + async (uri, variables) => { + const index = parseIndex(uri, variables); + const buffer = Buffer.from(`Resource ${index}: This is a base64 blob created at ${formatGmtTimestamp()}`); + return { + contents: [ + { + uri: uri.toString(), + mimeType: "application/octet-stream", + blob: buffer.toString("base64"), + }, + ], + }; + } + ); +}; diff --git a/src/everything/resources/index.ts b/src/everything/resources/index.ts new file mode 100644 index 00000000..6f2c1b18 --- /dev/null +++ b/src/everything/resources/index.ts @@ -0,0 +1,11 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { addDynamicResources } from "./dynamic.js"; + + +/** + * Register the resources with the MCP server. + * @param server + */ +export const registerResources = (server: McpServer) => { + addDynamicResources(server); +}; diff --git a/src/everything/server/index.ts b/src/everything/server/index.ts index 6781c165..f03a0c96 100644 --- a/src/everything/server/index.ts +++ b/src/everything/server/index.ts @@ -1,5 +1,6 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { registerTools } from "../tools/index.js"; +import { registerResources } from "../resources/index.js"; import { dirname, join } from "path"; import { readFileSync } from "fs"; import { fileURLToPath } from "url"; @@ -31,6 +32,9 @@ export const createServer = () => { // Register the tools registerTools(server); + // Register the resources + registerResources(server); + return { server, cleanup: () => {},