@modelcontextprotocol/server-everything 2025.12.18 → 2026.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +9 -158
  2. package/dist/docs/architecture.md +44 -0
  3. package/dist/docs/extension.md +23 -0
  4. package/dist/docs/features.md +103 -0
  5. package/dist/docs/how-it-works.md +45 -0
  6. package/dist/docs/instructions.md +28 -0
  7. package/dist/docs/startup.md +73 -0
  8. package/dist/docs/structure.md +182 -0
  9. package/dist/index.js +19 -14
  10. package/dist/prompts/args.js +34 -0
  11. package/dist/prompts/completions.js +52 -0
  12. package/dist/prompts/index.js +15 -0
  13. package/dist/prompts/resource.js +60 -0
  14. package/dist/prompts/simple.js +23 -0
  15. package/dist/resources/files.js +83 -0
  16. package/dist/resources/index.js +33 -0
  17. package/dist/resources/session.js +44 -0
  18. package/dist/resources/subscriptions.js +125 -0
  19. package/dist/resources/templates.js +171 -0
  20. package/dist/server/index.js +93 -0
  21. package/dist/server/logging.js +64 -0
  22. package/dist/server/roots.js +65 -0
  23. package/dist/tools/echo.js +29 -0
  24. package/dist/tools/get-annotated-message.js +81 -0
  25. package/dist/tools/get-env.js +28 -0
  26. package/dist/tools/get-resource-links.js +62 -0
  27. package/dist/tools/get-resource-reference.js +74 -0
  28. package/dist/tools/get-roots-list.js +71 -0
  29. package/dist/tools/get-structured-content.js +72 -0
  30. package/dist/tools/get-sum.js +40 -0
  31. package/dist/tools/get-tiny-image.js +41 -0
  32. package/dist/tools/gzip-file-as-resource.js +182 -0
  33. package/dist/tools/index.js +50 -0
  34. package/dist/tools/simulate-research-query.js +249 -0
  35. package/dist/tools/toggle-simulated-logging.js +41 -0
  36. package/dist/tools/toggle-subscriber-updates.js +44 -0
  37. package/dist/tools/trigger-elicitation-request-async.js +202 -0
  38. package/dist/tools/trigger-elicitation-request.js +210 -0
  39. package/dist/tools/trigger-long-running-operation.js +59 -0
  40. package/dist/tools/trigger-sampling-request-async.js +168 -0
  41. package/dist/tools/trigger-sampling-request.js +71 -0
  42. package/dist/{sse.js → transports/sse.js} +25 -17
  43. package/dist/transports/stdio.js +27 -0
  44. package/dist/transports/streamableHttp.js +206 -0
  45. package/package.json +10 -7
  46. package/dist/everything.js +0 -978
  47. package/dist/instructions.md +0 -23
  48. package/dist/stdio.js +0 -23
  49. package/dist/streamableHttp.js +0 -174
@@ -0,0 +1,125 @@
1
+ import { SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
2
+ // Track subscriber session id lists by URI
3
+ const subscriptions = new Map();
4
+ // Interval to send notifications to subscribers
5
+ const subsUpdateIntervals = new Map();
6
+ /**
7
+ * Sets up the subscription and unsubscription handlers for the provided server.
8
+ *
9
+ * The function defines two request handlers:
10
+ * 1. A `Subscribe` handler that allows clients to subscribe to specific resource URIs.
11
+ * 2. An `Unsubscribe` handler that allows clients to unsubscribe from specific resource URIs.
12
+ *
13
+ * The `Subscribe` handler performs the following actions:
14
+ * - Extracts the URI and session ID from the request.
15
+ * - Logs a message acknowledging the subscription request.
16
+ * - Updates the internal tracking of subscribers for the given URI.
17
+ *
18
+ * The `Unsubscribe` handler performs the following actions:
19
+ * - Extracts the URI and session ID from the request.
20
+ * - Logs a message acknowledging the unsubscription request.
21
+ * - Removes the subscriber for the specified URI.
22
+ *
23
+ * @param {McpServer} server - The server instance to which subscription handlers will be attached.
24
+ */
25
+ export const setSubscriptionHandlers = (server) => {
26
+ // Set the subscription handler
27
+ server.server.setRequestHandler(SubscribeRequestSchema, async (request, extra) => {
28
+ // Get the URI to subscribe to
29
+ const { uri } = request.params;
30
+ // Get the session id (can be undefined for stdio)
31
+ const sessionId = extra.sessionId;
32
+ // Acknowledge the subscribe request
33
+ await server.sendLoggingMessage({
34
+ level: "info",
35
+ data: `Received Subscribe Resource request for URI: ${uri} ${sessionId ? `from session ${sessionId}` : ""}`,
36
+ }, sessionId);
37
+ // Get the subscribers for this URI
38
+ const subscribers = subscriptions.has(uri)
39
+ ? subscriptions.get(uri)
40
+ : new Set();
41
+ subscribers.add(sessionId);
42
+ subscriptions.set(uri, subscribers);
43
+ return {};
44
+ });
45
+ // Set the unsubscription handler
46
+ server.server.setRequestHandler(UnsubscribeRequestSchema, async (request, extra) => {
47
+ // Get the URI to subscribe to
48
+ const { uri } = request.params;
49
+ // Get the session id (can be undefined for stdio)
50
+ const sessionId = extra.sessionId;
51
+ // Acknowledge the subscribe request
52
+ await server.sendLoggingMessage({
53
+ level: "info",
54
+ data: `Received Unsubscribe Resource request: ${uri} ${sessionId ? `from session ${sessionId}` : ""}`,
55
+ }, sessionId);
56
+ // Remove the subscriber
57
+ if (subscriptions.has(uri)) {
58
+ const subscribers = subscriptions.get(uri);
59
+ if (subscribers.has(sessionId))
60
+ subscribers.delete(sessionId);
61
+ }
62
+ return {};
63
+ });
64
+ };
65
+ /**
66
+ * Sends simulated resource update notifications to the subscribed client.
67
+ *
68
+ * This function iterates through all resource URIs stored in the subscriptions
69
+ * and checks if the specified session ID is subscribed to them. If so, it sends
70
+ * a notification through the provided server. If the session ID is no longer valid
71
+ * (disconnected), it removes the session ID from the list of subscribers.
72
+ *
73
+ * @param {McpServer} server - The server instance used to send notifications.
74
+ * @param {string | undefined} sessionId - The session ID of the client to check for subscriptions.
75
+ * @returns {Promise<void>} Resolves once all applicable notifications are sent.
76
+ */
77
+ const sendSimulatedResourceUpdates = async (server, sessionId) => {
78
+ // Search all URIs for ones this client is subscribed to
79
+ for (const uri of subscriptions.keys()) {
80
+ const subscribers = subscriptions.get(uri);
81
+ // If this client is subscribed, send the notification
82
+ if (subscribers.has(sessionId)) {
83
+ await server.server.notification({
84
+ method: "notifications/resources/updated",
85
+ params: { uri },
86
+ });
87
+ }
88
+ else {
89
+ subscribers.delete(sessionId); // subscriber has disconnected
90
+ }
91
+ }
92
+ };
93
+ /**
94
+ * Starts the process of simulating resource updates and sending server notifications
95
+ * to the client for the resources they are subscribed to. If the update interval is
96
+ * already active, invoking this function will not start another interval.
97
+ *
98
+ * @param server
99
+ * @param sessionId
100
+ */
101
+ export const beginSimulatedResourceUpdates = (server, sessionId) => {
102
+ if (!subsUpdateIntervals.has(sessionId)) {
103
+ // Send once immediately
104
+ sendSimulatedResourceUpdates(server, sessionId);
105
+ // Set the interval to send later resource update notifications to this client
106
+ subsUpdateIntervals.set(sessionId, setInterval(() => sendSimulatedResourceUpdates(server, sessionId), 5000));
107
+ }
108
+ };
109
+ /**
110
+ * Stops simulated resource updates for a given session.
111
+ *
112
+ * This function halts any active intervals associated with the provided session ID
113
+ * and removes the session's corresponding entries from resource management collections.
114
+ * Session ID can be undefined for stdio.
115
+ *
116
+ * @param {string} [sessionId]
117
+ */
118
+ export const stopSimulatedResourceUpdates = (sessionId) => {
119
+ // Remove active intervals
120
+ if (subsUpdateIntervals.has(sessionId)) {
121
+ const subsUpdateInterval = subsUpdateIntervals.get(sessionId);
122
+ clearInterval(subsUpdateInterval);
123
+ subsUpdateIntervals.delete(sessionId);
124
+ }
125
+ };
@@ -0,0 +1,171 @@
1
+ import { z } from "zod";
2
+ import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { completable } from "@modelcontextprotocol/sdk/server/completable.js";
4
+ // Resource types
5
+ export const RESOURCE_TYPE_TEXT = "Text";
6
+ export const RESOURCE_TYPE_BLOB = "Blob";
7
+ export const RESOURCE_TYPES = [
8
+ RESOURCE_TYPE_TEXT,
9
+ RESOURCE_TYPE_BLOB,
10
+ ];
11
+ /**
12
+ * A completer function for resource types.
13
+ *
14
+ * This variable provides functionality to perform autocompletion for the resource types based on user input.
15
+ * It uses a schema description to validate the input and filters through a predefined list of resource types
16
+ * to return suggestions that start with the given input.
17
+ *
18
+ * The input value is expected to be a string representing the type of resource to fetch.
19
+ * The completion logic matches the input against available resource types.
20
+ */
21
+ export const resourceTypeCompleter = completable(z.string().describe("Type of resource to fetch"), (value) => {
22
+ return RESOURCE_TYPES.filter((t) => t.startsWith(value));
23
+ });
24
+ /**
25
+ * A completer function for resource IDs as strings.
26
+ *
27
+ * The `resourceIdCompleter` accepts a string input representing the ID of a text resource
28
+ * and validates whether the provided value corresponds to an integer resource ID.
29
+ *
30
+ * NOTE: Currently, prompt arguments can only be strings since type is not field of `PromptArgument`
31
+ * Consequently, we must define it as a string and convert the argument to number before using it
32
+ * https://modelcontextprotocol.io/specification/2025-11-25/schema#promptargument
33
+ *
34
+ * If the value is a valid integer, it returns the value within an array.
35
+ * Otherwise, it returns an empty array.
36
+ *
37
+ * The input string is first transformed into a number and checked to ensure it is an integer.
38
+ * This helps validate and suggest appropriate resource IDs.
39
+ */
40
+ export const resourceIdForPromptCompleter = completable(z.string().describe("ID of the text resource to fetch"), (value) => {
41
+ const resourceId = Number(value);
42
+ return Number.isInteger(resourceId) && resourceId > 0 ? [value] : [];
43
+ });
44
+ /**
45
+ * A callback function that acts as a completer for resource ID values, validating and returning
46
+ * the input value as part of a resource template.
47
+ *
48
+ * @typedef {CompleteResourceTemplateCallback}
49
+ * @param {string} value - The input string value to be evaluated as a resource ID.
50
+ * @returns {string[]} Returns an array containing the input value if it represents a positive
51
+ * integer resource ID, otherwise returns an empty array.
52
+ */
53
+ export const resourceIdForResourceTemplateCompleter = (value) => {
54
+ const resourceId = Number(value);
55
+ return Number.isInteger(resourceId) && resourceId > 0 ? [value] : [];
56
+ };
57
+ const uriBase = "demo://resource/dynamic";
58
+ const textUriBase = `${uriBase}/text`;
59
+ const blobUriBase = `${uriBase}/blob`;
60
+ const textUriTemplate = `${textUriBase}/{resourceId}`;
61
+ const blobUriTemplate = `${blobUriBase}/{resourceId}`;
62
+ /**
63
+ * Create a dynamic text resource
64
+ * - Exposed for use by embedded resource prompt example
65
+ * @param uri
66
+ * @param resourceId
67
+ */
68
+ export const textResource = (uri, resourceId) => {
69
+ const timestamp = new Date().toLocaleTimeString();
70
+ return {
71
+ uri: uri.toString(),
72
+ mimeType: "text/plain",
73
+ text: `Resource ${resourceId}: This is a plaintext resource created at ${timestamp}`,
74
+ };
75
+ };
76
+ /**
77
+ * Create a dynamic blob resource
78
+ * - Exposed for use by embedded resource prompt example
79
+ * @param uri
80
+ * @param resourceId
81
+ */
82
+ export const blobResource = (uri, resourceId) => {
83
+ const timestamp = new Date().toLocaleTimeString();
84
+ const resourceText = Buffer.from(`Resource ${resourceId}: This is a base64 blob created at ${timestamp}`).toString("base64");
85
+ return {
86
+ uri: uri.toString(),
87
+ mimeType: "text/plain",
88
+ blob: resourceText,
89
+ };
90
+ };
91
+ /**
92
+ * Create a dynamic text resource URI
93
+ * - Exposed for use by embedded resource prompt example
94
+ * @param resourceId
95
+ */
96
+ export const textResourceUri = (resourceId) => new URL(`${textUriBase}/${resourceId}`);
97
+ /**
98
+ * Create a dynamic blob resource URI
99
+ * - Exposed for use by embedded resource prompt example
100
+ * @param resourceId
101
+ */
102
+ export const blobResourceUri = (resourceId) => new URL(`${blobUriBase}/${resourceId}`);
103
+ /**
104
+ * Parses the resource identifier from the provided URI and validates it
105
+ * against the given variables. Throws an error if the URI corresponds
106
+ * to an unknown resource or if the resource identifier is invalid.
107
+ *
108
+ * @param {URL} uri - The URI of the resource to be parsed.
109
+ * @param {Record<string, unknown>} variables - A record containing context-specific variables that include the resourceId.
110
+ * @returns {number} The parsed and validated resource identifier as an integer.
111
+ * @throws {Error} Throws an error if the URI matches unsupported base URIs or if the resourceId is invalid.
112
+ */
113
+ const parseResourceId = (uri, variables) => {
114
+ const uriError = `Unknown resource: ${uri.toString()}`;
115
+ if (uri.toString().startsWith(textUriBase) &&
116
+ uri.toString().startsWith(blobUriBase)) {
117
+ throw new Error(uriError);
118
+ }
119
+ else {
120
+ const idxStr = String(variables.resourceId ?? "");
121
+ const idx = Number(idxStr);
122
+ if (Number.isFinite(idx) && Number.isInteger(idx) && idx > 0) {
123
+ return idx;
124
+ }
125
+ else {
126
+ throw new Error(uriError);
127
+ }
128
+ }
129
+ };
130
+ /**
131
+ * Register resource templates with the MCP server.
132
+ * - Text and blob resources, dynamically generated from the URI {resourceId} variable
133
+ * - Any finite positive integer is acceptable for the resourceId variable
134
+ * - List resources method will not return these resources
135
+ * - These are only accessible via template URIs
136
+ * - Both blob and text resources:
137
+ * - have content that is dynamically generated, including a timestamp
138
+ * - have different template URIs
139
+ * - Blob: "demo://resource/dynamic/blob/{resourceId}"
140
+ * - Text: "demo://resource/dynamic/text/{resourceId}"
141
+ *
142
+ * @param server
143
+ */
144
+ export const registerResourceTemplates = (server) => {
145
+ // Register the text resource template
146
+ server.registerResource("Dynamic Text Resource", new ResourceTemplate(textUriTemplate, {
147
+ list: undefined,
148
+ complete: { resourceId: resourceIdForResourceTemplateCompleter },
149
+ }), {
150
+ mimeType: "text/plain",
151
+ description: "Plaintext dynamic resource fabricated from the {resourceId} variable, which must be an integer.",
152
+ }, async (uri, variables) => {
153
+ const resourceId = parseResourceId(uri, variables);
154
+ return {
155
+ contents: [textResource(uri, resourceId)],
156
+ };
157
+ });
158
+ // Register the blob resource template
159
+ server.registerResource("Dynamic Blob Resource", new ResourceTemplate(blobUriTemplate, {
160
+ list: undefined,
161
+ complete: { resourceId: resourceIdForResourceTemplateCompleter },
162
+ }), {
163
+ mimeType: "application/octet-stream",
164
+ description: "Binary (base64) dynamic resource fabricated from the {resourceId} variable, which must be an integer.",
165
+ }, async (uri, variables) => {
166
+ const resourceId = parseResourceId(uri, variables);
167
+ return {
168
+ contents: [blobResource(uri, resourceId)],
169
+ };
170
+ });
171
+ };
@@ -0,0 +1,93 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { InMemoryTaskStore, InMemoryTaskMessageQueue, } from "@modelcontextprotocol/sdk/experimental/tasks";
3
+ import { setSubscriptionHandlers, stopSimulatedResourceUpdates, } from "../resources/subscriptions.js";
4
+ import { registerConditionalTools, registerTools } from "../tools/index.js";
5
+ import { registerResources, readInstructions } from "../resources/index.js";
6
+ import { registerPrompts } from "../prompts/index.js";
7
+ import { stopSimulatedLogging } from "./logging.js";
8
+ import { syncRoots } from "./roots.js";
9
+ /**
10
+ * Server Factory
11
+ *
12
+ * This function initializes a `McpServer` with specific capabilities and instructions,
13
+ * registers tools, resources, and prompts, and configures resource subscription handlers.
14
+ *
15
+ * @returns {ServerFactoryResponse} An object containing the server instance, and a `cleanup`
16
+ * function for handling server-side cleanup when a session ends.
17
+ *
18
+ * Properties of the returned object:
19
+ * - `server` {Object}: The initialized server instance.
20
+ * - `cleanup` {Function}: Function to perform cleanup operations for a closing session.
21
+ */
22
+ export const createServer = () => {
23
+ // Read the server instructions
24
+ const instructions = readInstructions();
25
+ // Create task store and message queue for task support
26
+ const taskStore = new InMemoryTaskStore();
27
+ const taskMessageQueue = new InMemoryTaskMessageQueue();
28
+ let initializeTimeout = null;
29
+ // Create the server
30
+ const server = new McpServer({
31
+ name: "mcp-servers/everything",
32
+ title: "Everything Reference Server",
33
+ version: "2.0.0",
34
+ }, {
35
+ capabilities: {
36
+ tools: {
37
+ listChanged: true,
38
+ },
39
+ prompts: {
40
+ listChanged: true,
41
+ },
42
+ resources: {
43
+ subscribe: true,
44
+ listChanged: true,
45
+ },
46
+ logging: {},
47
+ tasks: {
48
+ list: {},
49
+ cancel: {},
50
+ requests: {
51
+ tools: {
52
+ call: {},
53
+ },
54
+ },
55
+ },
56
+ },
57
+ instructions,
58
+ taskStore,
59
+ taskMessageQueue,
60
+ });
61
+ // Register the tools
62
+ registerTools(server);
63
+ // Register the resources
64
+ registerResources(server);
65
+ // Register the prompts
66
+ registerPrompts(server);
67
+ // Set resource subscription handlers
68
+ setSubscriptionHandlers(server);
69
+ // Perform post-initialization operations
70
+ server.server.oninitialized = async () => {
71
+ // Register conditional tools now that client capabilities are known.
72
+ // This finishes before the `notifications/initialized` handler finishes.
73
+ registerConditionalTools(server);
74
+ // Sync roots if the client supports them.
75
+ // This is delayed until after the `notifications/initialized` handler finishes,
76
+ // otherwise, the request gets lost.
77
+ const sessionId = server.server.transport?.sessionId;
78
+ initializeTimeout = setTimeout(() => syncRoots(server, sessionId), 350);
79
+ };
80
+ // Return the ServerFactoryResponse
81
+ return {
82
+ server,
83
+ cleanup: (sessionId) => {
84
+ // Stop any simulated logging or resource updates that may have been initiated.
85
+ stopSimulatedLogging(sessionId);
86
+ stopSimulatedResourceUpdates(sessionId);
87
+ // Clean up task store timers
88
+ taskStore.cleanup();
89
+ if (initializeTimeout)
90
+ clearTimeout(initializeTimeout);
91
+ },
92
+ };
93
+ };
@@ -0,0 +1,64 @@
1
+ // Map session ID to the interval for sending logging messages to the client
2
+ const logsUpdateIntervals = new Map();
3
+ /**
4
+ * Initiates a simulated logging process by sending random log messages to the client at a
5
+ * fixed interval. Each log message contains a random logging level and optional session ID.
6
+ *
7
+ * @param {McpServer} server - The server instance responsible for handling the logging messages.
8
+ * @param {string | undefined} sessionId - An optional identifier for the session. If provided,
9
+ * the session ID will be appended to log messages.
10
+ */
11
+ export const beginSimulatedLogging = (server, sessionId) => {
12
+ const maybeAppendSessionId = sessionId ? ` - SessionId ${sessionId}` : "";
13
+ const messages = [
14
+ { level: "debug", data: `Debug-level message${maybeAppendSessionId}` },
15
+ { level: "info", data: `Info-level message${maybeAppendSessionId}` },
16
+ { level: "notice", data: `Notice-level message${maybeAppendSessionId}` },
17
+ {
18
+ level: "warning",
19
+ data: `Warning-level message${maybeAppendSessionId}`,
20
+ },
21
+ { level: "error", data: `Error-level message${maybeAppendSessionId}` },
22
+ {
23
+ level: "critical",
24
+ data: `Critical-level message${maybeAppendSessionId}`,
25
+ },
26
+ { level: "alert", data: `Alert level-message${maybeAppendSessionId}` },
27
+ {
28
+ level: "emergency",
29
+ data: `Emergency-level message${maybeAppendSessionId}`,
30
+ },
31
+ ];
32
+ /**
33
+ * Send a simulated logging message to the client
34
+ */
35
+ const sendSimulatedLoggingMessage = async (sessionId) => {
36
+ // By using the `sendLoggingMessage` function to send the message, we
37
+ // ensure that the client's chosen logging level will be respected
38
+ await server.sendLoggingMessage(messages[Math.floor(Math.random() * messages.length)], sessionId);
39
+ };
40
+ // Set the interval to send later logging messages to this client
41
+ if (!logsUpdateIntervals.has(sessionId)) {
42
+ // Send once immediately
43
+ sendSimulatedLoggingMessage(sessionId);
44
+ // Send a randomly-leveled log message every 5 seconds
45
+ logsUpdateIntervals.set(sessionId, setInterval(() => sendSimulatedLoggingMessage(sessionId), 5000));
46
+ }
47
+ };
48
+ /**
49
+ * Stops the simulated logging process for a given session.
50
+ *
51
+ * This function halts the periodic logging updates associated with the specified
52
+ * session ID by clearing the interval and removing the session's tracking
53
+ * reference. Session ID can be undefined for stdio.
54
+ *
55
+ * @param {string} [sessionId] - The optional unique identifier of the session.
56
+ */
57
+ export const stopSimulatedLogging = (sessionId) => {
58
+ // Remove active intervals
59
+ if (logsUpdateIntervals.has(sessionId)) {
60
+ const logsUpdateInterval = logsUpdateIntervals.get(sessionId);
61
+ clearInterval(logsUpdateInterval);
62
+ logsUpdateIntervals.delete(sessionId);
63
+ }
64
+ };
@@ -0,0 +1,65 @@
1
+ import { RootsListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
2
+ // Track roots by session id
3
+ export const roots = new Map();
4
+ /**
5
+ * Get the latest the client roots list for the session.
6
+ *
7
+ * - Request and cache the roots list for the session if it has not been fetched before.
8
+ * - Return the cached roots list for the session if it exists.
9
+ *
10
+ * When requesting the roots list for a session, it also sets up a `roots/list_changed`
11
+ * notification handler. This ensures that updates are automatically fetched and handled
12
+ * in real-time.
13
+ *
14
+ * This function is idempotent. It should only request roots from the client once per session,
15
+ * returning the cached version thereafter.
16
+ *
17
+ * @param {McpServer} server - An instance of the MCP server used to communicate with the client.
18
+ * @param {string} [sessionId] - An optional session id used to associate the roots list with a specific client session.
19
+ *
20
+ * @throws {Error} In case of a failure to request the roots from the client, an error log message is sent.
21
+ */
22
+ export const syncRoots = async (server, sessionId) => {
23
+ const clientCapabilities = server.server.getClientCapabilities() || {};
24
+ const clientSupportsRoots = clientCapabilities?.roots !== undefined;
25
+ // Fetch the roots list for this client
26
+ if (clientSupportsRoots) {
27
+ // Function to request the updated roots list from the client
28
+ const requestRoots = async () => {
29
+ try {
30
+ // Request the updated roots list from the client
31
+ const response = await server.server.listRoots();
32
+ if (response && "roots" in response) {
33
+ // Store the roots list for this client
34
+ roots.set(sessionId, response.roots);
35
+ // Notify the client of roots received
36
+ await server.sendLoggingMessage({
37
+ level: "info",
38
+ logger: "everything-server",
39
+ data: `Roots updated: ${response?.roots?.length} root(s) received from client`,
40
+ }, sessionId);
41
+ }
42
+ else {
43
+ await server.sendLoggingMessage({
44
+ level: "info",
45
+ logger: "everything-server",
46
+ data: "Client returned no roots set",
47
+ }, sessionId);
48
+ }
49
+ }
50
+ catch (error) {
51
+ console.error(`Failed to request roots from client ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
52
+ }
53
+ };
54
+ // If the roots have not been synced for this client,
55
+ // set notification handler and request initial roots
56
+ if (!roots.has(sessionId)) {
57
+ // Set the list changed notification handler
58
+ server.server.setNotificationHandler(RootsListChangedNotificationSchema, requestRoots);
59
+ // Request the initial roots list immediately
60
+ await requestRoots();
61
+ }
62
+ // Return the roots list for this client
63
+ return roots.get(sessionId);
64
+ }
65
+ };
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ // Tool input schema
3
+ export const EchoSchema = z.object({
4
+ message: z.string().describe("Message to echo"),
5
+ });
6
+ // Tool configuration
7
+ const name = "echo";
8
+ const config = {
9
+ title: "Echo Tool",
10
+ description: "Echoes back the input string",
11
+ inputSchema: EchoSchema,
12
+ };
13
+ /**
14
+ * Registers the 'echo' tool.
15
+ *
16
+ * The registered tool validates input arguments using the EchoSchema and
17
+ * returns a response that echoes the message provided in the arguments.
18
+ *
19
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
20
+ * @returns {void}
21
+ */
22
+ export const registerEchoTool = (server) => {
23
+ server.registerTool(name, config, async (args) => {
24
+ const validatedArgs = EchoSchema.parse(args);
25
+ return {
26
+ content: [{ type: "text", text: `Echo: ${validatedArgs.message}` }],
27
+ };
28
+ });
29
+ };
@@ -0,0 +1,81 @@
1
+ import { z } from "zod";
2
+ import { MCP_TINY_IMAGE } from "./get-tiny-image.js";
3
+ // Tool input schema
4
+ const GetAnnotatedMessageSchema = z.object({
5
+ messageType: z
6
+ .enum(["error", "success", "debug"])
7
+ .describe("Type of message to demonstrate different annotation patterns"),
8
+ includeImage: z
9
+ .boolean()
10
+ .default(false)
11
+ .describe("Whether to include an example image"),
12
+ });
13
+ // Tool configuration
14
+ const name = "get-annotated-message";
15
+ const config = {
16
+ title: "Get Annotated Message Tool",
17
+ description: "Demonstrates how annotations can be used to provide metadata about content.",
18
+ inputSchema: GetAnnotatedMessageSchema,
19
+ };
20
+ /**
21
+ * Registers the 'get-annotated-message' tool.
22
+ *
23
+ * The registered tool generates and sends messages with specific types, such as error,
24
+ * success, or debug, carrying associated annotations like priority level and intended
25
+ * audience.
26
+ *
27
+ * The response will have annotations and optionally contain an annotated image.
28
+ *
29
+ * @function
30
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
31
+ */
32
+ export const registerGetAnnotatedMessageTool = (server) => {
33
+ server.registerTool(name, config, async (args) => {
34
+ const { messageType, includeImage } = GetAnnotatedMessageSchema.parse(args);
35
+ const content = [];
36
+ // Main message with different priorities/audiences based on type
37
+ if (messageType === "error") {
38
+ content.push({
39
+ type: "text",
40
+ text: "Error: Operation failed",
41
+ annotations: {
42
+ priority: 1.0, // Errors are highest priority
43
+ audience: ["user", "assistant"], // Both need to know about errors
44
+ },
45
+ });
46
+ }
47
+ else if (messageType === "success") {
48
+ content.push({
49
+ type: "text",
50
+ text: "Operation completed successfully",
51
+ annotations: {
52
+ priority: 0.7, // Success messages are important but not critical
53
+ audience: ["user"], // Success mainly for user consumption
54
+ },
55
+ });
56
+ }
57
+ else if (messageType === "debug") {
58
+ content.push({
59
+ type: "text",
60
+ text: "Debug: Cache hit ratio 0.95, latency 150ms",
61
+ annotations: {
62
+ priority: 0.3, // Debug info is low priority
63
+ audience: ["assistant"], // Technical details for assistant
64
+ },
65
+ });
66
+ }
67
+ // Optional image with its own annotations
68
+ if (includeImage) {
69
+ content.push({
70
+ type: "image",
71
+ data: MCP_TINY_IMAGE,
72
+ mimeType: "image/png",
73
+ annotations: {
74
+ priority: 0.5,
75
+ audience: ["user"], // Images primarily for user visualization
76
+ },
77
+ });
78
+ }
79
+ return { content };
80
+ });
81
+ };
@@ -0,0 +1,28 @@
1
+ // Tool configuration
2
+ const name = "get-env";
3
+ const config = {
4
+ title: "Print Environment Tool",
5
+ description: "Returns all environment variables, helpful for debugging MCP server configuration",
6
+ inputSchema: {},
7
+ };
8
+ /**
9
+ * Registers the 'get-env' tool.
10
+ *
11
+ * The registered tool Retrieves and returns the environment variables
12
+ * of the current process as a JSON-formatted string encapsulated in a text response.
13
+ *
14
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
15
+ * @returns {void}
16
+ */
17
+ export const registerGetEnvTool = (server) => {
18
+ server.registerTool(name, config, async (args) => {
19
+ return {
20
+ content: [
21
+ {
22
+ type: "text",
23
+ text: JSON.stringify(process.env, null, 2),
24
+ },
25
+ ],
26
+ };
27
+ });
28
+ };