@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,210 @@
1
+ import { ElicitResultSchema, } from "@modelcontextprotocol/sdk/types.js";
2
+ // Tool configuration
3
+ const name = "trigger-elicitation-request";
4
+ const config = {
5
+ title: "Trigger Elicitation Request Tool",
6
+ description: "Trigger a Request from the Server for User Elicitation",
7
+ inputSchema: {},
8
+ };
9
+ /**
10
+ * Registers the 'trigger-elicitation-request' tool.
11
+ *
12
+ * If the client does not support the elicitation capability, the tool is not registered.
13
+ *
14
+ * The registered tool sends an elicitation request for the user to provide information
15
+ * based on a pre-defined schema of fields including text inputs, booleans, numbers,
16
+ * email, dates, enums of various types, etc. It uses validation and handles multiple
17
+ * possible outcomes from the user's response, such as acceptance with content, decline,
18
+ * or cancellation of the dialog. The process also ensures parsing and validating
19
+ * the elicitation input arguments at runtime.
20
+ *
21
+ * The elicitation dialog response is returned, formatted into a structured result,
22
+ * which contains both user-submitted input data (if provided) and debugging information,
23
+ * including raw results.
24
+ *
25
+ * @param {McpServer} server - TThe McpServer instance where the tool will be registered.
26
+ */
27
+ export const registerTriggerElicitationRequestTool = (server) => {
28
+ // Does the client support elicitation?
29
+ const clientCapabilities = server.server.getClientCapabilities() || {};
30
+ const clientSupportsElicitation = clientCapabilities.elicitation !== undefined;
31
+ // If so, register tool
32
+ if (clientSupportsElicitation) {
33
+ server.registerTool(name, config, async (args, extra) => {
34
+ const elicitationResult = await extra.sendRequest({
35
+ method: "elicitation/create",
36
+ params: {
37
+ message: "Please provide inputs for the following fields:",
38
+ requestedSchema: {
39
+ type: "object",
40
+ properties: {
41
+ name: {
42
+ title: "String",
43
+ type: "string",
44
+ description: "Your full, legal name",
45
+ },
46
+ check: {
47
+ title: "Boolean",
48
+ type: "boolean",
49
+ description: "Agree to the terms and conditions",
50
+ },
51
+ firstLine: {
52
+ title: "String with default",
53
+ type: "string",
54
+ description: "Favorite first line of a story",
55
+ default: "It was a dark and stormy night.",
56
+ },
57
+ email: {
58
+ title: "String with email format",
59
+ type: "string",
60
+ format: "email",
61
+ description: "Your email address (will be verified, and never shared with anyone else)",
62
+ },
63
+ homepage: {
64
+ type: "string",
65
+ format: "uri",
66
+ title: "String with uri format",
67
+ description: "Portfolio / personal website",
68
+ },
69
+ birthdate: {
70
+ title: "String with date format",
71
+ type: "string",
72
+ format: "date",
73
+ description: "Your date of birth",
74
+ },
75
+ integer: {
76
+ title: "Integer",
77
+ type: "integer",
78
+ description: "Your favorite integer (do not give us your phone number, pin, or other sensitive info)",
79
+ minimum: 1,
80
+ maximum: 100,
81
+ default: 42,
82
+ },
83
+ number: {
84
+ title: "Number in range 1-1000",
85
+ type: "number",
86
+ description: "Favorite number (there are no wrong answers)",
87
+ minimum: 0,
88
+ maximum: 1000,
89
+ default: 3.14,
90
+ },
91
+ untitledSingleSelectEnum: {
92
+ type: "string",
93
+ title: "Untitled Single Select Enum",
94
+ description: "Choose your favorite friend",
95
+ enum: [
96
+ "Monica",
97
+ "Rachel",
98
+ "Joey",
99
+ "Chandler",
100
+ "Ross",
101
+ "Phoebe",
102
+ ],
103
+ default: "Monica",
104
+ },
105
+ untitledMultipleSelectEnum: {
106
+ type: "array",
107
+ title: "Untitled Multiple Select Enum",
108
+ description: "Choose your favorite instruments",
109
+ minItems: 1,
110
+ maxItems: 3,
111
+ items: {
112
+ type: "string",
113
+ enum: ["Guitar", "Piano", "Violin", "Drums", "Bass"],
114
+ },
115
+ default: ["Guitar"],
116
+ },
117
+ titledSingleSelectEnum: {
118
+ type: "string",
119
+ title: "Titled Single Select Enum",
120
+ description: "Choose your favorite hero",
121
+ oneOf: [
122
+ { const: "hero-1", title: "Superman" },
123
+ { const: "hero-2", title: "Green Lantern" },
124
+ { const: "hero-3", title: "Wonder Woman" },
125
+ ],
126
+ default: "hero-1",
127
+ },
128
+ titledMultipleSelectEnum: {
129
+ type: "array",
130
+ title: "Titled Multiple Select Enum",
131
+ description: "Choose your favorite types of fish",
132
+ minItems: 1,
133
+ maxItems: 3,
134
+ items: {
135
+ anyOf: [
136
+ { const: "fish-1", title: "Tuna" },
137
+ { const: "fish-2", title: "Salmon" },
138
+ { const: "fish-3", title: "Trout" },
139
+ ],
140
+ },
141
+ default: ["fish-1"],
142
+ },
143
+ legacyTitledEnum: {
144
+ type: "string",
145
+ title: "Legacy Titled Single Select Enum",
146
+ description: "Choose your favorite type of pet",
147
+ enum: ["pet-1", "pet-2", "pet-3", "pet-4", "pet-5"],
148
+ enumNames: ["Cats", "Dogs", "Birds", "Fish", "Reptiles"],
149
+ default: "pet-1",
150
+ },
151
+ },
152
+ required: ["name"],
153
+ },
154
+ },
155
+ }, ElicitResultSchema, { timeout: 10 * 60 * 1000 /* 10 minutes */ });
156
+ // Handle different response actions
157
+ const content = [];
158
+ if (elicitationResult.action === "accept" &&
159
+ elicitationResult.content) {
160
+ content.push({
161
+ type: "text",
162
+ text: `✅ User provided the requested information!`,
163
+ });
164
+ // Only access elicitationResult.content when action is accept
165
+ const userData = elicitationResult.content;
166
+ const lines = [];
167
+ if (userData.name)
168
+ lines.push(`- Name: ${userData.name}`);
169
+ if (userData.check !== undefined)
170
+ lines.push(`- Agreed to terms: ${userData.check}`);
171
+ if (userData.color)
172
+ lines.push(`- Favorite Color: ${userData.color}`);
173
+ if (userData.email)
174
+ lines.push(`- Email: ${userData.email}`);
175
+ if (userData.homepage)
176
+ lines.push(`- Homepage: ${userData.homepage}`);
177
+ if (userData.birthdate)
178
+ lines.push(`- Birthdate: ${userData.birthdate}`);
179
+ if (userData.integer !== undefined)
180
+ lines.push(`- Favorite Integer: ${userData.integer}`);
181
+ if (userData.number !== undefined)
182
+ lines.push(`- Favorite Number: ${userData.number}`);
183
+ if (userData.petType)
184
+ lines.push(`- Pet Type: ${userData.petType}`);
185
+ content.push({
186
+ type: "text",
187
+ text: `User inputs:\n${lines.join("\n")}`,
188
+ });
189
+ }
190
+ else if (elicitationResult.action === "decline") {
191
+ content.push({
192
+ type: "text",
193
+ text: `❌ User declined to provide the requested information.`,
194
+ });
195
+ }
196
+ else if (elicitationResult.action === "cancel") {
197
+ content.push({
198
+ type: "text",
199
+ text: `⚠️ User cancelled the elicitation dialog.`,
200
+ });
201
+ }
202
+ // Include raw result for debugging
203
+ content.push({
204
+ type: "text",
205
+ text: `\nRaw result: ${JSON.stringify(elicitationResult, null, 2)}`,
206
+ });
207
+ return { content };
208
+ });
209
+ }
210
+ };
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+ // Tool input schema
3
+ const TriggerLongRunningOperationSchema = z.object({
4
+ duration: z
5
+ .number()
6
+ .default(10)
7
+ .describe("Duration of the operation in seconds"),
8
+ steps: z.number().default(5).describe("Number of steps in the operation"),
9
+ });
10
+ // Tool configuration
11
+ const name = "trigger-long-running-operation";
12
+ const config = {
13
+ title: "Trigger Long Running Operation Tool",
14
+ description: "Demonstrates a long running operation with progress updates.",
15
+ inputSchema: TriggerLongRunningOperationSchema,
16
+ };
17
+ /**
18
+ * Registers the 'trigger-tong-running-operation' tool.
19
+ *
20
+ * The registered tool starts a long-running operation defined by a specific duration and
21
+ * number of steps.
22
+ *
23
+ * Progress notifications are sent back to the client at each step if a `progressToken`
24
+ * is provided in the metadata.
25
+ *
26
+ * At the end of the operation, the tool returns a message indicating the completion of the
27
+ * operation, including the total duration and steps.
28
+ *
29
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
30
+ */
31
+ export const registerTriggerLongRunningOperationTool = (server) => {
32
+ server.registerTool(name, config, async (args, extra) => {
33
+ const validatedArgs = TriggerLongRunningOperationSchema.parse(args);
34
+ const { duration, steps } = validatedArgs;
35
+ const stepDuration = duration / steps;
36
+ const progressToken = extra._meta?.progressToken;
37
+ for (let i = 1; i < steps + 1; i++) {
38
+ await new Promise((resolve) => setTimeout(resolve, stepDuration * 1000));
39
+ if (progressToken !== undefined) {
40
+ await server.server.notification({
41
+ method: "notifications/progress",
42
+ params: {
43
+ progress: i,
44
+ total: steps,
45
+ progressToken,
46
+ },
47
+ }, { relatedRequestId: extra.requestId });
48
+ }
49
+ }
50
+ return {
51
+ content: [
52
+ {
53
+ type: "text",
54
+ text: `Long running operation completed. Duration: ${duration} seconds, Steps: ${steps}.`,
55
+ },
56
+ ],
57
+ };
58
+ });
59
+ };
@@ -0,0 +1,168 @@
1
+ import { z } from "zod";
2
+ // Tool input schema
3
+ const TriggerSamplingRequestAsyncSchema = z.object({
4
+ prompt: z.string().describe("The prompt to send to the LLM"),
5
+ maxTokens: z
6
+ .number()
7
+ .default(100)
8
+ .describe("Maximum number of tokens to generate"),
9
+ });
10
+ // Tool configuration
11
+ const name = "trigger-sampling-request-async";
12
+ const config = {
13
+ title: "Trigger Async Sampling Request Tool",
14
+ description: "Trigger an async sampling request that the CLIENT executes as a background task. " +
15
+ "Demonstrates bidirectional MCP tasks where the server sends a request and the client " +
16
+ "executes it asynchronously, allowing the server to poll for progress and results.",
17
+ inputSchema: TriggerSamplingRequestAsyncSchema,
18
+ };
19
+ // Poll interval in milliseconds
20
+ const POLL_INTERVAL = 1000;
21
+ // Maximum poll attempts before timeout
22
+ const MAX_POLL_ATTEMPTS = 60;
23
+ /**
24
+ * Registers the 'trigger-sampling-request-async' tool.
25
+ *
26
+ * This tool demonstrates bidirectional MCP tasks:
27
+ * - Server sends sampling request to client with task metadata
28
+ * - Client creates a task and returns CreateTaskResult
29
+ * - Server polls client's tasks/get endpoint for status
30
+ * - Server fetches final result from client's tasks/result endpoint
31
+ *
32
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
33
+ */
34
+ export const registerTriggerSamplingRequestAsyncTool = (server) => {
35
+ // Check client capabilities
36
+ const clientCapabilities = server.server.getClientCapabilities() || {};
37
+ // Client must support sampling AND tasks.requests.sampling
38
+ const clientSupportsSampling = clientCapabilities.sampling !== undefined;
39
+ const clientTasksCapability = clientCapabilities.tasks;
40
+ const clientSupportsAsyncSampling = clientTasksCapability?.requests?.sampling?.createMessage !== undefined;
41
+ if (clientSupportsSampling && clientSupportsAsyncSampling) {
42
+ server.registerTool(name, config, async (args, extra) => {
43
+ const validatedArgs = TriggerSamplingRequestAsyncSchema.parse(args);
44
+ const { prompt, maxTokens } = validatedArgs;
45
+ // Create the sampling request WITH task metadata
46
+ // The params.task field signals to the client that this should be executed as a task
47
+ const request = {
48
+ method: "sampling/createMessage",
49
+ params: {
50
+ task: {
51
+ ttl: 300000, // 5 minutes
52
+ },
53
+ messages: [
54
+ {
55
+ role: "user",
56
+ content: {
57
+ type: "text",
58
+ text: `Resource ${name} context: ${prompt}`,
59
+ },
60
+ },
61
+ ],
62
+ systemPrompt: "You are a helpful test server.",
63
+ maxTokens,
64
+ temperature: 0.7,
65
+ },
66
+ };
67
+ // Send the sampling request
68
+ // Client may return either:
69
+ // - CreateMessageResult (synchronous execution)
70
+ // - CreateTaskResult (task-based execution with { task } object)
71
+ const samplingResponse = await extra.sendRequest(request, z.union([
72
+ // CreateTaskResult - client created a task
73
+ z.object({
74
+ task: z.object({
75
+ taskId: z.string(),
76
+ status: z.string(),
77
+ pollInterval: z.number().optional(),
78
+ statusMessage: z.string().optional(),
79
+ }),
80
+ }),
81
+ // CreateMessageResult - synchronous execution
82
+ z.object({
83
+ role: z.string(),
84
+ content: z.any(),
85
+ model: z.string(),
86
+ stopReason: z.string().optional(),
87
+ }),
88
+ ]));
89
+ // Check if client returned CreateTaskResult (has task object)
90
+ const isTaskResult = "task" in samplingResponse && samplingResponse.task;
91
+ if (!isTaskResult) {
92
+ // Client executed synchronously - return the direct response
93
+ return {
94
+ content: [
95
+ {
96
+ type: "text",
97
+ text: `[SYNC] Client executed synchronously:\n${JSON.stringify(samplingResponse, null, 2)}`,
98
+ },
99
+ ],
100
+ };
101
+ }
102
+ const taskId = samplingResponse.task.taskId;
103
+ const statusMessages = [];
104
+ statusMessages.push(`Task created: ${taskId}`);
105
+ // Poll for task completion
106
+ let attempts = 0;
107
+ let taskStatus = samplingResponse.task.status;
108
+ let taskStatusMessage;
109
+ while (taskStatus !== "completed" &&
110
+ taskStatus !== "failed" &&
111
+ taskStatus !== "cancelled" &&
112
+ attempts < MAX_POLL_ATTEMPTS) {
113
+ // Wait before polling
114
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
115
+ attempts++;
116
+ // Get task status from client
117
+ const pollResult = await extra.sendRequest({
118
+ method: "tasks/get",
119
+ params: { taskId },
120
+ }, z
121
+ .object({
122
+ status: z.string(),
123
+ statusMessage: z.string().optional(),
124
+ })
125
+ .passthrough());
126
+ taskStatus = pollResult.status;
127
+ taskStatusMessage = pollResult.statusMessage;
128
+ statusMessages.push(`Poll ${attempts}: ${taskStatus}${taskStatusMessage ? ` - ${taskStatusMessage}` : ""}`);
129
+ }
130
+ // Check for timeout
131
+ if (attempts >= MAX_POLL_ATTEMPTS) {
132
+ return {
133
+ content: [
134
+ {
135
+ type: "text",
136
+ text: `[TIMEOUT] Task timed out after ${MAX_POLL_ATTEMPTS} poll attempts\n\nProgress:\n${statusMessages.join("\n")}`,
137
+ },
138
+ ],
139
+ };
140
+ }
141
+ // Check for failure/cancellation
142
+ if (taskStatus === "failed" || taskStatus === "cancelled") {
143
+ return {
144
+ content: [
145
+ {
146
+ type: "text",
147
+ text: `[${taskStatus.toUpperCase()}] ${taskStatusMessage || "No message"}\n\nProgress:\n${statusMessages.join("\n")}`,
148
+ },
149
+ ],
150
+ };
151
+ }
152
+ // Fetch the final result
153
+ const result = await extra.sendRequest({
154
+ method: "tasks/result",
155
+ params: { taskId },
156
+ }, z.any());
157
+ // Return the result with status history
158
+ return {
159
+ content: [
160
+ {
161
+ type: "text",
162
+ text: `[COMPLETED] Async sampling completed!\n\n**Progress:**\n${statusMessages.join("\n")}\n\n**Result:**\n${JSON.stringify(result, null, 2)}`,
163
+ },
164
+ ],
165
+ };
166
+ });
167
+ }
168
+ };
@@ -0,0 +1,71 @@
1
+ import { CreateMessageResultSchema, } from "@modelcontextprotocol/sdk/types.js";
2
+ import { z } from "zod";
3
+ // Tool input schema
4
+ const TriggerSamplingRequestSchema = z.object({
5
+ prompt: z.string().describe("The prompt to send to the LLM"),
6
+ maxTokens: z
7
+ .number()
8
+ .default(100)
9
+ .describe("Maximum number of tokens to generate"),
10
+ });
11
+ // Tool configuration
12
+ const name = "trigger-sampling-request";
13
+ const config = {
14
+ title: "Trigger Sampling Request Tool",
15
+ description: "Trigger a Request from the Server for LLM Sampling",
16
+ inputSchema: TriggerSamplingRequestSchema,
17
+ };
18
+ /**
19
+ * Registers the 'trigger-sampling-request' tool.
20
+ *
21
+ * If the client does not support the sampling capability, the tool is not registered.
22
+ *
23
+ * The registered tool performs the following operations:
24
+ * - Validates incoming arguments using `TriggerSamplingRequestSchema`.
25
+ * - Constructs a `sampling/createMessage` request object using provided prompt and maximum tokens.
26
+ * - Sends the request to the server for sampling.
27
+ * - Formats and returns the sampling result content to the client.
28
+ *
29
+ * @param {McpServer} server - The McpServer instance where the tool will be registered.
30
+ */
31
+ export const registerTriggerSamplingRequestTool = (server) => {
32
+ // Does the client support sampling?
33
+ const clientCapabilities = server.server.getClientCapabilities() || {};
34
+ const clientSupportsSampling = clientCapabilities.sampling !== undefined;
35
+ // If so, register tool
36
+ if (clientSupportsSampling) {
37
+ server.registerTool(name, config, async (args, extra) => {
38
+ const validatedArgs = TriggerSamplingRequestSchema.parse(args);
39
+ const { prompt, maxTokens } = validatedArgs;
40
+ // Create the sampling request
41
+ const request = {
42
+ method: "sampling/createMessage",
43
+ params: {
44
+ messages: [
45
+ {
46
+ role: "user",
47
+ content: {
48
+ type: "text",
49
+ text: `Resource ${name} context: ${prompt}`,
50
+ },
51
+ },
52
+ ],
53
+ systemPrompt: "You are a helpful test server.",
54
+ maxTokens,
55
+ temperature: 0.7,
56
+ },
57
+ };
58
+ // Send the sampling request to the client
59
+ const result = await extra.sendRequest(request, CreateMessageResultSchema);
60
+ // Return the result to the client
61
+ return {
62
+ content: [
63
+ {
64
+ type: "text",
65
+ text: `LLM sampling result: \n${JSON.stringify(result, null, 2)}`,
66
+ },
67
+ ],
68
+ };
69
+ });
70
+ }
71
+ };
@@ -1,43 +1,50 @@
1
1
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
2
2
  import express from "express";
3
- import { createServer } from "./everything.js";
4
- import cors from 'cors';
5
- console.error('Starting SSE server...');
3
+ import { createServer } from "../server/index.js";
4
+ import cors from "cors";
5
+ console.error("Starting SSE server...");
6
+ // Express app with permissive CORS for testing with Inspector direct connect mode
6
7
  const app = express();
7
8
  app.use(cors({
8
- "origin": "*", // use "*" with caution in production
9
- "methods": "GET,POST",
10
- "preflightContinue": false,
11
- "optionsSuccessStatus": 204,
12
- })); // Enable CORS for all routes so Inspector can connect
9
+ origin: "*", // use "*" with caution in production
10
+ methods: "GET,POST",
11
+ preflightContinue: false,
12
+ optionsSuccessStatus: 204,
13
+ }));
14
+ // Map sessionId to transport for each client
13
15
  const transports = new Map();
16
+ // Handle GET requests for new SSE streams
14
17
  app.get("/sse", async (req, res) => {
15
18
  let transport;
16
- const { server, cleanup, startNotificationIntervals } = createServer();
19
+ const { server, cleanup } = createServer();
20
+ // Session Id should not exist for GET /sse requests
17
21
  if (req?.query?.sessionId) {
18
22
  const sessionId = req?.query?.sessionId;
19
23
  transport = transports.get(sessionId);
20
24
  console.error("Client Reconnecting? This shouldn't happen; when client has a sessionId, GET /sse should not be called again.", transport.sessionId);
21
25
  }
22
26
  else {
23
- // Create and store transport for new session
27
+ // Create and store transport for the new session
24
28
  transport = new SSEServerTransport("/message", res);
25
29
  transports.set(transport.sessionId, transport);
26
30
  // Connect server to transport
27
31
  await server.connect(transport);
28
- console.error("Client Connected: ", transport.sessionId);
29
- // Start notification intervals after client connects
30
- startNotificationIntervals(transport.sessionId);
32
+ const sessionId = transport.sessionId;
33
+ console.error("Client Connected: ", sessionId);
31
34
  // Handle close of connection
32
- server.onclose = async () => {
33
- console.error("Client Disconnected: ", transport.sessionId);
34
- transports.delete(transport.sessionId);
35
- await cleanup();
35
+ server.server.onclose = async () => {
36
+ const sessionId = transport.sessionId;
37
+ console.error("Client Disconnected: ", sessionId);
38
+ transports.delete(sessionId);
39
+ cleanup(sessionId);
36
40
  };
37
41
  }
38
42
  });
43
+ // Handle POST requests for client messages
39
44
  app.post("/message", async (req, res) => {
45
+ // Session Id should exist for POST /message requests
40
46
  const sessionId = req?.query?.sessionId;
47
+ // Get the transport for this session and use it to handle the request
41
48
  const transport = transports.get(sessionId);
42
49
  if (transport) {
43
50
  console.error("Client Message from", sessionId);
@@ -47,6 +54,7 @@ app.post("/message", async (req, res) => {
47
54
  console.error(`No transport found for sessionId ${sessionId}`);
48
55
  }
49
56
  });
57
+ // Start the express server
50
58
  const PORT = process.env.PORT || 3001;
51
59
  app.listen(PORT, () => {
52
60
  console.error(`Server is running on port ${PORT}`);
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { createServer } from "../server/index.js";
4
+ console.error("Starting default (STDIO) server...");
5
+ /**
6
+ * The main method
7
+ * - Initializes the StdioServerTransport, sets up the server,
8
+ * - Handles cleanup on process exit.
9
+ *
10
+ * @return {Promise<void>} A promise that resolves when the main function has executed and the process exits.
11
+ */
12
+ async function main() {
13
+ const transport = new StdioServerTransport();
14
+ const { server, cleanup } = createServer();
15
+ // Connect transport to server
16
+ await server.connect(transport);
17
+ // Cleanup on exit
18
+ process.on("SIGINT", async () => {
19
+ await server.close();
20
+ cleanup();
21
+ process.exit(0);
22
+ });
23
+ }
24
+ main().catch((error) => {
25
+ console.error("Server error:", error);
26
+ process.exit(1);
27
+ });