@modelcontextprotocol/server-everything 2025.12.18 → 2026.1.14

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 (45) 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 +52 -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 +73 -0
  21. package/dist/server/logging.js +64 -0
  22. package/dist/server/roots.js +69 -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 +42 -0
  34. package/dist/tools/toggle-simulated-logging.js +41 -0
  35. package/dist/tools/toggle-subscriber-updates.js +44 -0
  36. package/dist/tools/trigger-elicitation-request.js +210 -0
  37. package/dist/tools/trigger-long-running-operation.js +59 -0
  38. package/dist/tools/trigger-sampling-request.js +71 -0
  39. package/dist/{sse.js → transports/sse.js} +25 -17
  40. package/dist/transports/stdio.js +27 -0
  41. package/dist/{streamableHttp.js → transports/streamableHttp.js} +68 -57
  42. package/package.json +10 -7
  43. package/dist/everything.js +0 -978
  44. package/dist/instructions.md +0 -23
  45. package/dist/stdio.js +0 -23
@@ -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,73 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { setSubscriptionHandlers, stopSimulatedResourceUpdates, } from "../resources/subscriptions.js";
3
+ import { registerConditionalTools, registerTools } from "../tools/index.js";
4
+ import { registerResources, readInstructions } from "../resources/index.js";
5
+ import { registerPrompts } from "../prompts/index.js";
6
+ import { stopSimulatedLogging } from "./logging.js";
7
+ import { syncRoots } from "./roots.js";
8
+ /**
9
+ * Server Factory
10
+ *
11
+ * This function initializes a `McpServer` with specific capabilities and instructions,
12
+ * registers tools, resources, and prompts, and configures resource subscription handlers.
13
+ *
14
+ * @returns {ServerFactoryResponse} An object containing the server instance, and a `cleanup`
15
+ * function for handling server-side cleanup when a session ends.
16
+ *
17
+ * Properties of the returned object:
18
+ * - `server` {Object}: The initialized server instance.
19
+ * - `cleanup` {Function}: Function to perform cleanup operations for a closing session.
20
+ */
21
+ export const createServer = () => {
22
+ // Read the server instructions
23
+ const instructions = readInstructions();
24
+ // Create the server
25
+ const server = new McpServer({
26
+ name: "mcp-servers/everything",
27
+ title: "Everything Reference Server",
28
+ version: "2.0.0",
29
+ }, {
30
+ capabilities: {
31
+ tools: {
32
+ listChanged: true,
33
+ },
34
+ prompts: {
35
+ listChanged: true,
36
+ },
37
+ resources: {
38
+ subscribe: true,
39
+ listChanged: true,
40
+ },
41
+ logging: {},
42
+ },
43
+ instructions,
44
+ });
45
+ // Register the tools
46
+ registerTools(server);
47
+ // Register the resources
48
+ registerResources(server);
49
+ // Register the prompts
50
+ registerPrompts(server);
51
+ // Set resource subscription handlers
52
+ setSubscriptionHandlers(server);
53
+ // Perform post-initialization operations
54
+ server.server.oninitialized = async () => {
55
+ // Register conditional tools now that client capabilities are known.
56
+ // This finishes before the `notifications/initialized` handler finishes.
57
+ registerConditionalTools(server);
58
+ // Sync roots if the client supports them.
59
+ // This is delayed until after the `notifications/initialized` handler finishes,
60
+ // otherwise, the request gets lost.
61
+ const sessionId = server.server.transport?.sessionId;
62
+ setTimeout(() => syncRoots(server, sessionId), 350);
63
+ };
64
+ // Return the ServerFactoryResponse
65
+ return {
66
+ server,
67
+ cleanup: (sessionId) => {
68
+ // Stop any simulated logging or resource updates that may have been initiated.
69
+ stopSimulatedLogging(sessionId);
70
+ stopSimulatedResourceUpdates(sessionId);
71
+ },
72
+ };
73
+ };
@@ -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,69 @@
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
+ await server.sendLoggingMessage({
52
+ level: "error",
53
+ logger: "everything-server",
54
+ data: `Failed to request roots from client: ${error instanceof Error ? error.message : String(error)}`,
55
+ }, sessionId);
56
+ }
57
+ };
58
+ // If the roots have not been synced for this client,
59
+ // set notification handler and request initial roots
60
+ if (!roots.has(sessionId)) {
61
+ // Set the list changed notification handler
62
+ server.server.setNotificationHandler(RootsListChangedNotificationSchema, requestRoots);
63
+ // Request the initial roots list immediately
64
+ await requestRoots();
65
+ }
66
+ // Return the roots list for this client
67
+ return roots.get(sessionId);
68
+ }
69
+ };
@@ -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
+ };
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+ import { textResource, textResourceUri, blobResourceUri, blobResource, } from "../resources/templates.js";
3
+ // Tool input schema
4
+ const GetResourceLinksSchema = z.object({
5
+ count: z
6
+ .number()
7
+ .min(1)
8
+ .max(10)
9
+ .default(3)
10
+ .describe("Number of resource links to return (1-10)"),
11
+ });
12
+ // Tool configuration
13
+ const name = "get-resource-links";
14
+ const config = {
15
+ title: "Get Resource Links Tool",
16
+ description: "Returns up to ten resource links that reference different types of resources",
17
+ inputSchema: GetResourceLinksSchema,
18
+ };
19
+ /**
20
+ * Registers the 'get-resource-reference' tool.
21
+ *
22
+ * The registered tool retrieves a specified number of resource links and their metadata.
23
+ * Resource links are dynamically generated as either text or binary blob resources,
24
+ * based on their ID being even or odd.
25
+
26
+ * The response contains a "text" introductory block and multiple "resource_link" blocks.
27
+ *
28
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
29
+ */
30
+ export const registerGetResourceLinksTool = (server) => {
31
+ server.registerTool(name, config, async (args) => {
32
+ const { count } = GetResourceLinksSchema.parse(args);
33
+ // Add intro text content block
34
+ const content = [];
35
+ content.push({
36
+ type: "text",
37
+ text: `Here are ${count} resource links to resources available in this server:`,
38
+ });
39
+ // Create resource link content blocks
40
+ for (let resourceId = 1; resourceId <= count; resourceId++) {
41
+ // Get resource uri for text or blob resource based on odd/even resourceId
42
+ const isOdd = resourceId % 2 === 0;
43
+ const uri = isOdd
44
+ ? textResourceUri(resourceId)
45
+ : blobResourceUri(resourceId);
46
+ // Get resource based on the resource type
47
+ const resource = isOdd
48
+ ? textResource(uri, resourceId)
49
+ : blobResource(uri, resourceId);
50
+ content.push({
51
+ type: "resource_link",
52
+ uri: resource.uri,
53
+ name: `${isOdd ? "Text" : "Blob"} Resource ${resourceId}`,
54
+ description: `Resource ${resourceId}: ${resource.mimeType === "text/plain"
55
+ ? "plaintext resource"
56
+ : "binary blob resource"}`,
57
+ mimeType: resource.mimeType,
58
+ });
59
+ }
60
+ return { content };
61
+ });
62
+ };
@@ -0,0 +1,74 @@
1
+ import { z } from "zod";
2
+ import { textResource, textResourceUri, blobResourceUri, blobResource, RESOURCE_TYPE_BLOB, RESOURCE_TYPE_TEXT, RESOURCE_TYPES, } from "../resources/templates.js";
3
+ // Tool input schema
4
+ const GetResourceReferenceSchema = z.object({
5
+ resourceType: z
6
+ .enum([RESOURCE_TYPE_TEXT, RESOURCE_TYPE_BLOB])
7
+ .default(RESOURCE_TYPE_TEXT),
8
+ resourceId: z
9
+ .number()
10
+ .default(1)
11
+ .describe("ID of the text resource to fetch"),
12
+ });
13
+ // Tool configuration
14
+ const name = "get-resource-reference";
15
+ const config = {
16
+ title: "Get Resource Reference Tool",
17
+ description: "Returns a resource reference that can be used by MCP clients",
18
+ inputSchema: GetResourceReferenceSchema,
19
+ };
20
+ /**
21
+ * Registers the 'get-resource-reference' tool.
22
+ *
23
+ * The registered tool validates and processes arguments for retrieving a resource
24
+ * reference. Supported resource types include predefined `RESOURCE_TYPE_TEXT` and
25
+ * `RESOURCE_TYPE_BLOB`. The retrieved resource's reference will include the resource
26
+ * ID, type, and its associated URI.
27
+ *
28
+ * The tool performs the following operations:
29
+ * 1. Validates the `resourceType` argument to ensure it matches a supported type.
30
+ * 2. Validates the `resourceId` argument to ensure it is a finite positive integer.
31
+ * 3. Constructs a URI for the resource based on its type (text or blob).
32
+ * 4. Retrieves the resource and returns it in a content block.
33
+ *
34
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
35
+ */
36
+ export const registerGetResourceReferenceTool = (server) => {
37
+ server.registerTool(name, config, async (args) => {
38
+ // Validate resource type argument
39
+ const { resourceType } = args;
40
+ if (!RESOURCE_TYPES.includes(resourceType)) {
41
+ throw new Error(`Invalid resourceType: ${args?.resourceType}. Must be ${RESOURCE_TYPE_TEXT} or ${RESOURCE_TYPE_BLOB}.`);
42
+ }
43
+ // Validate resourceId argument
44
+ const resourceId = Number(args?.resourceId);
45
+ if (!Number.isFinite(resourceId) ||
46
+ !Number.isInteger(resourceId) ||
47
+ resourceId < 1) {
48
+ throw new Error(`Invalid resourceId: ${args?.resourceId}. Must be a finite positive integer.`);
49
+ }
50
+ // Get resource based on the resource type
51
+ const uri = resourceType === RESOURCE_TYPE_TEXT
52
+ ? textResourceUri(resourceId)
53
+ : blobResourceUri(resourceId);
54
+ const resource = resourceType === RESOURCE_TYPE_TEXT
55
+ ? textResource(uri, resourceId)
56
+ : blobResource(uri, resourceId);
57
+ return {
58
+ content: [
59
+ {
60
+ type: "text",
61
+ text: `Returning resource reference for Resource ${resourceId}:`,
62
+ },
63
+ {
64
+ type: "resource",
65
+ resource: resource,
66
+ },
67
+ {
68
+ type: "text",
69
+ text: `You can access this resource using the URI: ${resource.uri}`,
70
+ },
71
+ ],
72
+ };
73
+ });
74
+ };