@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
package/dist/index.js CHANGED
@@ -1,36 +1,41 @@
1
1
  #!/usr/bin/env node
2
2
  // Parse command line arguments first
3
3
  const args = process.argv.slice(2);
4
- const scriptName = args[0] || 'stdio';
4
+ const scriptName = args[0] || "stdio";
5
5
  async function run() {
6
6
  try {
7
7
  // Dynamically import only the requested module to prevent all modules from initializing
8
8
  switch (scriptName) {
9
- case 'stdio':
9
+ case "stdio":
10
10
  // Import and run the default server
11
- await import('./stdio.js');
11
+ await import("./transports/stdio.js");
12
12
  break;
13
- case 'sse':
13
+ case "sse":
14
14
  // Import and run the SSE server
15
- await import('./sse.js');
15
+ await import("./transports/sse.js");
16
16
  break;
17
- case 'streamableHttp':
17
+ case "streamableHttp":
18
18
  // Import and run the streamable HTTP server
19
- await import('./streamableHttp.js');
19
+ await import("./transports/streamableHttp.js");
20
20
  break;
21
21
  default:
22
- console.error(`Unknown script: ${scriptName}`);
23
- console.log('Available scripts:');
24
- console.log('- stdio');
25
- console.log('- sse');
26
- console.log('- streamableHttp');
22
+ console.error(`-`.repeat(53));
23
+ console.error(` Everything Server Launcher`);
24
+ console.error(` Usage: node ./index.js [stdio|sse|streamableHttp]`);
25
+ console.error(` Default transport: stdio`);
26
+ console.error(`-`.repeat(53));
27
+ console.error(`Unknown transport: ${scriptName}`);
28
+ console.log("Available transports:");
29
+ console.log("- stdio");
30
+ console.log("- sse");
31
+ console.log("- streamableHttp");
27
32
  process.exit(1);
28
33
  }
29
34
  }
30
35
  catch (error) {
31
- console.error('Error running script:', error);
36
+ console.error("Error running script:", error);
32
37
  process.exit(1);
33
38
  }
34
39
  }
35
- run();
40
+ await run();
36
41
  export {};
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Register a prompt with arguments
4
+ * - Two arguments, one required and one optional
5
+ * - Combines argument values in the returned prompt
6
+ *
7
+ * @param server
8
+ */
9
+ export const registerArgumentsPrompt = (server) => {
10
+ // Prompt arguments
11
+ const promptArgsSchema = {
12
+ city: z.string().describe("Name of the city"),
13
+ state: z.string().describe("Name of the state").optional(),
14
+ };
15
+ // Register the prompt
16
+ server.registerPrompt("args-prompt", {
17
+ title: "Arguments Prompt",
18
+ description: "A prompt with two arguments, one required and one optional",
19
+ argsSchema: promptArgsSchema,
20
+ }, (args) => {
21
+ const location = `${args?.city}${args?.state ? `, ${args?.state}` : ""}`;
22
+ return {
23
+ messages: [
24
+ {
25
+ role: "user",
26
+ content: {
27
+ type: "text",
28
+ text: `What's weather in ${location}?`,
29
+ },
30
+ },
31
+ ],
32
+ };
33
+ });
34
+ };
@@ -0,0 +1,52 @@
1
+ import { z } from "zod";
2
+ import { completable } from "@modelcontextprotocol/sdk/server/completable.js";
3
+ /**
4
+ * Register a prompt with completable arguments
5
+ * - Two required arguments, both with completion handlers
6
+ * - First argument value will be included in context for second argument
7
+ * - Allows second argument to depend on the first argument value
8
+ *
9
+ * @param server
10
+ */
11
+ export const registerPromptWithCompletions = (server) => {
12
+ // Prompt arguments
13
+ const promptArgsSchema = {
14
+ department: completable(z.string().describe("Choose the department."), (value) => {
15
+ return ["Engineering", "Sales", "Marketing", "Support"].filter((d) => d.startsWith(value));
16
+ }),
17
+ name: completable(z
18
+ .string()
19
+ .describe("Choose a team member to lead the selected department."), (value, context) => {
20
+ const department = context?.arguments?.["department"];
21
+ if (department === "Engineering") {
22
+ return ["Alice", "Bob", "Charlie"].filter((n) => n.startsWith(value));
23
+ }
24
+ else if (department === "Sales") {
25
+ return ["David", "Eve", "Frank"].filter((n) => n.startsWith(value));
26
+ }
27
+ else if (department === "Marketing") {
28
+ return ["Grace", "Henry", "Iris"].filter((n) => n.startsWith(value));
29
+ }
30
+ else if (department === "Support") {
31
+ return ["John", "Kim", "Lee"].filter((n) => n.startsWith(value));
32
+ }
33
+ return [];
34
+ }),
35
+ };
36
+ // Register the prompt
37
+ server.registerPrompt("completable-prompt", {
38
+ title: "Team Management",
39
+ description: "First argument choice narrows values for second argument.",
40
+ argsSchema: promptArgsSchema,
41
+ }, ({ department, name }) => ({
42
+ messages: [
43
+ {
44
+ role: "user",
45
+ content: {
46
+ type: "text",
47
+ text: `Please promote ${name} to the head of the ${department} team.`,
48
+ },
49
+ },
50
+ ],
51
+ }));
52
+ };
@@ -0,0 +1,15 @@
1
+ import { registerSimplePrompt } from "./simple.js";
2
+ import { registerArgumentsPrompt } from "./args.js";
3
+ import { registerPromptWithCompletions } from "./completions.js";
4
+ import { registerEmbeddedResourcePrompt } from "./resource.js";
5
+ /**
6
+ * Register the prompts with the MCP server.
7
+ *
8
+ * @param server
9
+ */
10
+ export const registerPrompts = (server) => {
11
+ registerSimplePrompt(server);
12
+ registerArgumentsPrompt(server);
13
+ registerPromptWithCompletions(server);
14
+ registerEmbeddedResourcePrompt(server);
15
+ };
@@ -0,0 +1,60 @@
1
+ import { resourceTypeCompleter, resourceIdForPromptCompleter, } from "../resources/templates.js";
2
+ import { textResource, textResourceUri, blobResourceUri, blobResource, RESOURCE_TYPE_BLOB, RESOURCE_TYPE_TEXT, RESOURCE_TYPES, } from "../resources/templates.js";
3
+ /**
4
+ * Register a prompt with an embedded resource reference
5
+ * - Takes a resource type and id
6
+ * - Returns the corresponding dynamically created resource
7
+ *
8
+ * @param server
9
+ */
10
+ export const registerEmbeddedResourcePrompt = (server) => {
11
+ // Prompt arguments
12
+ const promptArgsSchema = {
13
+ resourceType: resourceTypeCompleter,
14
+ resourceId: resourceIdForPromptCompleter,
15
+ };
16
+ // Register the prompt
17
+ server.registerPrompt("resource-prompt", {
18
+ title: "Resource Prompt",
19
+ description: "A prompt that includes an embedded resource reference",
20
+ argsSchema: promptArgsSchema,
21
+ }, (args) => {
22
+ // Validate resource type argument
23
+ const resourceType = args.resourceType;
24
+ if (!RESOURCE_TYPES.includes(resourceType)) {
25
+ throw new Error(`Invalid resourceType: ${args?.resourceType}. Must be ${RESOURCE_TYPE_TEXT} or ${RESOURCE_TYPE_BLOB}.`);
26
+ }
27
+ // Validate resourceId argument
28
+ const resourceId = Number(args?.resourceId);
29
+ if (!Number.isFinite(resourceId) ||
30
+ !Number.isInteger(resourceId) ||
31
+ resourceId < 1) {
32
+ throw new Error(`Invalid resourceId: ${args?.resourceId}. Must be a finite positive integer.`);
33
+ }
34
+ // Get resource based on the resource type
35
+ const uri = resourceType === RESOURCE_TYPE_TEXT
36
+ ? textResourceUri(resourceId)
37
+ : blobResourceUri(resourceId);
38
+ const resource = resourceType === RESOURCE_TYPE_TEXT
39
+ ? textResource(uri, resourceId)
40
+ : blobResource(uri, resourceId);
41
+ return {
42
+ messages: [
43
+ {
44
+ role: "user",
45
+ content: {
46
+ type: "text",
47
+ text: `This prompt includes the ${resourceType} resource with id: ${resourceId}. Please analyze the following resource:`,
48
+ },
49
+ },
50
+ {
51
+ role: "user",
52
+ content: {
53
+ type: "resource",
54
+ resource: resource,
55
+ },
56
+ },
57
+ ],
58
+ };
59
+ });
60
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Register a simple prompt with no arguments
3
+ * - Returns the fixed text of the prompt with no modifications
4
+ *
5
+ * @param server
6
+ */
7
+ export const registerSimplePrompt = (server) => {
8
+ // Register the prompt
9
+ server.registerPrompt("simple-prompt", {
10
+ title: "Simple Prompt",
11
+ description: "A prompt with no arguments",
12
+ }, () => ({
13
+ messages: [
14
+ {
15
+ role: "user",
16
+ content: {
17
+ type: "text",
18
+ text: "This is a simple prompt without arguments.",
19
+ },
20
+ },
21
+ ],
22
+ }));
23
+ };
@@ -0,0 +1,83 @@
1
+ import { dirname, join } from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { readdirSync, readFileSync, statSync } from "fs";
4
+ /**
5
+ * Register static file resources
6
+ * - Each file in src/everything/docs is exposed as an individual static resource
7
+ * - URIs follow the pattern: "demo://static/docs/<filename>"
8
+ * - Markdown (.md) files are served as mime type "text/markdown"
9
+ * - Text (.txt) files are served as mime type "text/plain"
10
+ * - JSON (.json) files are served as mime type "application/json"
11
+ *
12
+ * @param server
13
+ */
14
+ export const registerFileResources = (server) => {
15
+ // Read the entries in the docs directory
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = dirname(__filename);
18
+ const docsDir = join(__dirname, "..", "docs");
19
+ let entries = [];
20
+ try {
21
+ entries = readdirSync(docsDir);
22
+ }
23
+ catch (e) {
24
+ // If docs/ folder is missing or unreadable, just skip registration
25
+ return;
26
+ }
27
+ // Register each file as a static resource
28
+ for (const name of entries) {
29
+ // Only process files, not directories
30
+ const fullPath = join(docsDir, name);
31
+ try {
32
+ const st = statSync(fullPath);
33
+ if (!st.isFile())
34
+ continue;
35
+ }
36
+ catch {
37
+ continue;
38
+ }
39
+ // Prepare file resource info
40
+ const uri = `demo://resource/static/document/${encodeURIComponent(name)}`;
41
+ const mimeType = getMimeType(name);
42
+ const description = `Static document file exposed from /docs: ${name}`;
43
+ // Register file resource
44
+ server.registerResource(name, uri, { mimeType, description }, async (uri) => {
45
+ const text = readFileSafe(fullPath);
46
+ return {
47
+ contents: [
48
+ {
49
+ uri: uri.toString(),
50
+ mimeType,
51
+ text,
52
+ },
53
+ ],
54
+ };
55
+ });
56
+ }
57
+ };
58
+ /**
59
+ * Get the mimetype based on filename
60
+ * @param fileName
61
+ */
62
+ function getMimeType(fileName) {
63
+ const lower = fileName.toLowerCase();
64
+ if (lower.endsWith(".md") || lower.endsWith(".markdown"))
65
+ return "text/markdown";
66
+ if (lower.endsWith(".txt"))
67
+ return "text/plain";
68
+ if (lower.endsWith(".json"))
69
+ return "application/json";
70
+ return "text/plain";
71
+ }
72
+ /**
73
+ * Read a file or return an error message if it fails
74
+ * @param path
75
+ */
76
+ function readFileSafe(path) {
77
+ try {
78
+ return readFileSync(path, "utf-8");
79
+ }
80
+ catch (e) {
81
+ return `Error reading file: ${path}. ${e}`;
82
+ }
83
+ }
@@ -0,0 +1,33 @@
1
+ import { registerResourceTemplates } from "./templates.js";
2
+ import { registerFileResources } from "./files.js";
3
+ import { fileURLToPath } from "url";
4
+ import { dirname, join } from "path";
5
+ import { readFileSync } from "fs";
6
+ /**
7
+ * Register the resources with the MCP server.
8
+ * @param server
9
+ */
10
+ export const registerResources = (server) => {
11
+ registerResourceTemplates(server);
12
+ registerFileResources(server);
13
+ };
14
+ /**
15
+ * Reads the server instructions from the corresponding markdown file.
16
+ * Attempts to load the content of the file located in the `docs` directory.
17
+ * If the file cannot be loaded, an error message is returned instead.
18
+ *
19
+ * @return {string} The content of the server instructions file, or an error message if reading fails.
20
+ */
21
+ export function readInstructions() {
22
+ const __filename = fileURLToPath(import.meta.url);
23
+ const __dirname = dirname(__filename);
24
+ const filePath = join(__dirname, "..", "docs", "instructions.md");
25
+ let instructions;
26
+ try {
27
+ instructions = readFileSync(filePath, "utf-8");
28
+ }
29
+ catch (e) {
30
+ instructions = "Server instructions not loaded: " + e;
31
+ }
32
+ return instructions;
33
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Generates a session-scoped resource URI string based on the provided resource name.
3
+ *
4
+ * @param {string} name - The name of the resource to create a URI for.
5
+ * @returns {string} The formatted session resource URI.
6
+ */
7
+ export const getSessionResourceURI = (name) => {
8
+ return `demo://resource/session/${name}`;
9
+ };
10
+ /**
11
+ * Registers a session-scoped resource with the provided server and returns a resource link.
12
+ *
13
+ * The registered resource is available during the life of the session only; it is not otherwise persisted.
14
+ *
15
+ * @param {McpServer} server - The server instance responsible for handling the resource registration.
16
+ * @param {Resource} resource - The resource object containing metadata such as URI, name, description, and mimeType.
17
+ * @param {"text"|"blob"} type
18
+ * @param payload
19
+ * @returns {ResourceLink} An object representing the resource link, with associated metadata.
20
+ */
21
+ export const registerSessionResource = (server, resource, type, payload) => {
22
+ // Destructure resource
23
+ const { uri, name, mimeType, description, title, annotations, icons, _meta } = resource;
24
+ // Prepare the resource content to return
25
+ // See https://modelcontextprotocol.io/specification/2025-11-25/server/resources#resource-contents
26
+ const resourceContent = type === "text"
27
+ ? {
28
+ uri: uri.toString(),
29
+ mimeType,
30
+ text: payload,
31
+ }
32
+ : {
33
+ uri: uri.toString(),
34
+ mimeType,
35
+ blob: payload,
36
+ };
37
+ // Register file resource
38
+ server.registerResource(name, uri, { mimeType, description, title, annotations, icons, _meta }, async (uri) => {
39
+ return {
40
+ contents: [resourceContent],
41
+ };
42
+ });
43
+ return { type: "resource_link", ...resource };
44
+ };
@@ -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
+ };