@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
@@ -1,978 +0,0 @@
1
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
- import { CallToolRequestSchema, CompleteRequestSchema, CreateMessageResultSchema, ElicitResultSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, RootsListChangedNotificationSchema, SubscribeRequestSchema, UnsubscribeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
3
- import { z } from "zod";
4
- import { zodToJsonSchema } from "zod-to-json-schema";
5
- import { readFileSync } from "fs";
6
- import { fileURLToPath } from "url";
7
- import { dirname, join } from "path";
8
- import JSZip from "jszip";
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = dirname(__filename);
11
- const instructions = readFileSync(join(__dirname, "instructions.md"), "utf-8");
12
- /* Input schemas for tools implemented in this server */
13
- const EchoSchema = z.object({
14
- message: z.string().describe("Message to echo"),
15
- });
16
- const AddSchema = z.object({
17
- a: z.number().describe("First number"),
18
- b: z.number().describe("Second number"),
19
- });
20
- const LongRunningOperationSchema = z.object({
21
- duration: z
22
- .number()
23
- .default(10)
24
- .describe("Duration of the operation in seconds"),
25
- steps: z
26
- .number()
27
- .default(5)
28
- .describe("Number of steps in the operation"),
29
- });
30
- const PrintEnvSchema = z.object({});
31
- const SampleLLMSchema = z.object({
32
- prompt: z.string().describe("The prompt to send to the LLM"),
33
- maxTokens: z
34
- .number()
35
- .default(100)
36
- .describe("Maximum number of tokens to generate"),
37
- });
38
- const GetTinyImageSchema = z.object({});
39
- const AnnotatedMessageSchema = z.object({
40
- messageType: z
41
- .enum(["error", "success", "debug"])
42
- .describe("Type of message to demonstrate different annotation patterns"),
43
- includeImage: z
44
- .boolean()
45
- .default(false)
46
- .describe("Whether to include an example image"),
47
- });
48
- const GetResourceReferenceSchema = z.object({
49
- resourceId: z
50
- .number()
51
- .min(1)
52
- .max(100)
53
- .describe("ID of the resource to reference (1-100)"),
54
- });
55
- const ElicitationSchema = z.object({});
56
- const GetResourceLinksSchema = z.object({
57
- count: z
58
- .number()
59
- .min(1)
60
- .max(10)
61
- .default(3)
62
- .describe("Number of resource links to return (1-10)"),
63
- });
64
- const ListRootsSchema = z.object({});
65
- const StructuredContentSchema = {
66
- input: z.object({
67
- location: z
68
- .string()
69
- .trim()
70
- .min(1)
71
- .describe("City name or zip code"),
72
- }),
73
- output: z.object({
74
- temperature: z
75
- .number()
76
- .describe("Temperature in celsius"),
77
- conditions: z
78
- .string()
79
- .describe("Weather conditions description"),
80
- humidity: z
81
- .number()
82
- .describe("Humidity percentage"),
83
- })
84
- };
85
- const ZipResourcesInputSchema = z.object({
86
- files: z.record(z.string().url().describe("URL of the file to include in the zip")).describe("Mapping of file names to URLs to include in the zip"),
87
- });
88
- var ToolName;
89
- (function (ToolName) {
90
- ToolName["ECHO"] = "echo";
91
- ToolName["ADD"] = "add";
92
- ToolName["LONG_RUNNING_OPERATION"] = "longRunningOperation";
93
- ToolName["PRINT_ENV"] = "printEnv";
94
- ToolName["SAMPLE_LLM"] = "sampleLLM";
95
- ToolName["GET_TINY_IMAGE"] = "getTinyImage";
96
- ToolName["ANNOTATED_MESSAGE"] = "annotatedMessage";
97
- ToolName["GET_RESOURCE_REFERENCE"] = "getResourceReference";
98
- ToolName["ELICITATION"] = "startElicitation";
99
- ToolName["GET_RESOURCE_LINKS"] = "getResourceLinks";
100
- ToolName["STRUCTURED_CONTENT"] = "structuredContent";
101
- ToolName["ZIP_RESOURCES"] = "zip";
102
- ToolName["LIST_ROOTS"] = "listRoots";
103
- })(ToolName || (ToolName = {}));
104
- var PromptName;
105
- (function (PromptName) {
106
- PromptName["SIMPLE"] = "simple_prompt";
107
- PromptName["COMPLEX"] = "complex_prompt";
108
- PromptName["RESOURCE"] = "resource_prompt";
109
- })(PromptName || (PromptName = {}));
110
- // Example completion values
111
- const EXAMPLE_COMPLETIONS = {
112
- style: ["casual", "formal", "technical", "friendly"],
113
- temperature: ["0", "0.5", "0.7", "1.0"],
114
- resourceId: ["1", "2", "3", "4", "5"],
115
- };
116
- export const createServer = () => {
117
- const server = new Server({
118
- name: "example-servers/everything",
119
- title: "Everything Example Server",
120
- version: "1.0.0",
121
- }, {
122
- capabilities: {
123
- prompts: {},
124
- resources: { subscribe: true },
125
- tools: {},
126
- logging: {},
127
- completions: {}
128
- },
129
- instructions
130
- });
131
- let subscriptions = new Set();
132
- let subsUpdateInterval;
133
- let stdErrUpdateInterval;
134
- let logsUpdateInterval;
135
- // Store client capabilities
136
- let clientCapabilities;
137
- // Roots state management
138
- let currentRoots = [];
139
- let clientSupportsRoots = false;
140
- let sessionId;
141
- // Function to start notification intervals when a client connects
142
- const startNotificationIntervals = (sid) => {
143
- sessionId = sid;
144
- if (!subsUpdateInterval) {
145
- subsUpdateInterval = setInterval(() => {
146
- for (const uri of subscriptions) {
147
- server.notification({
148
- method: "notifications/resources/updated",
149
- params: { uri },
150
- });
151
- }
152
- }, 10000);
153
- }
154
- const maybeAppendSessionId = sessionId ? ` - SessionId ${sessionId}` : "";
155
- const messages = [
156
- { level: "debug", data: `Debug-level message${maybeAppendSessionId}` },
157
- { level: "info", data: `Info-level message${maybeAppendSessionId}` },
158
- { level: "notice", data: `Notice-level message${maybeAppendSessionId}` },
159
- { level: "warning", data: `Warning-level message${maybeAppendSessionId}` },
160
- { level: "error", data: `Error-level message${maybeAppendSessionId}` },
161
- { level: "critical", data: `Critical-level message${maybeAppendSessionId}` },
162
- { level: "alert", data: `Alert level-message${maybeAppendSessionId}` },
163
- { level: "emergency", data: `Emergency-level message${maybeAppendSessionId}` },
164
- ];
165
- if (!logsUpdateInterval) {
166
- console.error("Starting logs update interval");
167
- logsUpdateInterval = setInterval(async () => {
168
- await server.sendLoggingMessage(messages[Math.floor(Math.random() * messages.length)], sessionId);
169
- }, 15000);
170
- }
171
- };
172
- // Helper method to request sampling from client
173
- const requestSampling = async (context, uri, maxTokens = 100, sendRequest) => {
174
- const request = {
175
- method: "sampling/createMessage",
176
- params: {
177
- messages: [
178
- {
179
- role: "user",
180
- content: {
181
- type: "text",
182
- text: `Resource ${uri} context: ${context}`,
183
- },
184
- },
185
- ],
186
- systemPrompt: "You are a helpful test server.",
187
- maxTokens,
188
- temperature: 0.7,
189
- includeContext: "thisServer",
190
- },
191
- };
192
- return await sendRequest(request, CreateMessageResultSchema);
193
- };
194
- const ALL_RESOURCES = Array.from({ length: 100 }, (_, i) => {
195
- const uri = `test://static/resource/${i + 1}`;
196
- if (i % 2 === 0) {
197
- return {
198
- uri,
199
- name: `Resource ${i + 1}`,
200
- mimeType: "text/plain",
201
- text: `Resource ${i + 1}: This is a plaintext resource`,
202
- };
203
- }
204
- else {
205
- const buffer = Buffer.from(`Resource ${i + 1}: This is a base64 blob`);
206
- return {
207
- uri,
208
- name: `Resource ${i + 1}`,
209
- mimeType: "application/octet-stream",
210
- blob: buffer.toString("base64"),
211
- };
212
- }
213
- });
214
- const PAGE_SIZE = 10;
215
- server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
216
- const cursor = request.params?.cursor;
217
- let startIndex = 0;
218
- if (cursor) {
219
- const decodedCursor = parseInt(atob(cursor), 10);
220
- if (!isNaN(decodedCursor)) {
221
- startIndex = decodedCursor;
222
- }
223
- }
224
- const endIndex = Math.min(startIndex + PAGE_SIZE, ALL_RESOURCES.length);
225
- const resources = ALL_RESOURCES.slice(startIndex, endIndex);
226
- let nextCursor;
227
- if (endIndex < ALL_RESOURCES.length) {
228
- nextCursor = btoa(endIndex.toString());
229
- }
230
- return {
231
- resources,
232
- nextCursor,
233
- };
234
- });
235
- server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
236
- return {
237
- resourceTemplates: [
238
- {
239
- uriTemplate: "test://static/resource/{id}",
240
- name: "Static Resource",
241
- description: "A static resource with a numeric ID",
242
- },
243
- ],
244
- };
245
- });
246
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
247
- const uri = request.params.uri;
248
- if (uri.startsWith("test://static/resource/")) {
249
- const index = parseInt(uri.split("/").pop() ?? "", 10) - 1;
250
- if (index >= 0 && index < ALL_RESOURCES.length) {
251
- const resource = ALL_RESOURCES[index];
252
- return {
253
- contents: [resource],
254
- };
255
- }
256
- }
257
- throw new Error(`Unknown resource: ${uri}`);
258
- });
259
- server.setRequestHandler(SubscribeRequestSchema, async (request, extra) => {
260
- const { uri } = request.params;
261
- subscriptions.add(uri);
262
- return {};
263
- });
264
- server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
265
- subscriptions.delete(request.params.uri);
266
- return {};
267
- });
268
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
269
- return {
270
- prompts: [
271
- {
272
- name: PromptName.SIMPLE,
273
- description: "A prompt without arguments",
274
- },
275
- {
276
- name: PromptName.COMPLEX,
277
- description: "A prompt with arguments",
278
- arguments: [
279
- {
280
- name: "temperature",
281
- description: "Temperature setting",
282
- required: true,
283
- },
284
- {
285
- name: "style",
286
- description: "Output style",
287
- required: false,
288
- },
289
- ],
290
- },
291
- {
292
- name: PromptName.RESOURCE,
293
- description: "A prompt that includes an embedded resource reference",
294
- arguments: [
295
- {
296
- name: "resourceId",
297
- description: "Resource ID to include (1-100)",
298
- required: true,
299
- },
300
- ],
301
- },
302
- ],
303
- };
304
- });
305
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
306
- const { name, arguments: args } = request.params;
307
- if (name === PromptName.SIMPLE) {
308
- return {
309
- messages: [
310
- {
311
- role: "user",
312
- content: {
313
- type: "text",
314
- text: "This is a simple prompt without arguments.",
315
- },
316
- },
317
- ],
318
- };
319
- }
320
- if (name === PromptName.COMPLEX) {
321
- return {
322
- messages: [
323
- {
324
- role: "user",
325
- content: {
326
- type: "text",
327
- text: `This is a complex prompt with arguments: temperature=${args?.temperature}, style=${args?.style}`,
328
- },
329
- },
330
- {
331
- role: "assistant",
332
- content: {
333
- type: "text",
334
- text: "I understand. You've provided a complex prompt with temperature and style arguments. How would you like me to proceed?",
335
- },
336
- },
337
- {
338
- role: "user",
339
- content: {
340
- type: "image",
341
- data: MCP_TINY_IMAGE,
342
- mimeType: "image/png",
343
- },
344
- },
345
- ],
346
- };
347
- }
348
- if (name === PromptName.RESOURCE) {
349
- const resourceId = parseInt(args?.resourceId, 10);
350
- if (isNaN(resourceId) || resourceId < 1 || resourceId > 100) {
351
- throw new Error(`Invalid resourceId: ${args?.resourceId}. Must be a number between 1 and 100.`);
352
- }
353
- const resourceIndex = resourceId - 1;
354
- const resource = ALL_RESOURCES[resourceIndex];
355
- return {
356
- messages: [
357
- {
358
- role: "user",
359
- content: {
360
- type: "text",
361
- text: `This prompt includes Resource ${resourceId}. Please analyze the following resource:`,
362
- },
363
- },
364
- {
365
- role: "user",
366
- content: {
367
- type: "resource",
368
- resource: resource,
369
- },
370
- },
371
- ],
372
- };
373
- }
374
- throw new Error(`Unknown prompt: ${name}`);
375
- });
376
- server.setRequestHandler(ListToolsRequestSchema, async () => {
377
- const tools = [
378
- {
379
- name: ToolName.ECHO,
380
- description: "Echoes back the input",
381
- inputSchema: zodToJsonSchema(EchoSchema),
382
- },
383
- {
384
- name: ToolName.ADD,
385
- description: "Adds two numbers",
386
- inputSchema: zodToJsonSchema(AddSchema),
387
- },
388
- {
389
- name: ToolName.LONG_RUNNING_OPERATION,
390
- description: "Demonstrates a long running operation with progress updates",
391
- inputSchema: zodToJsonSchema(LongRunningOperationSchema),
392
- },
393
- {
394
- name: ToolName.PRINT_ENV,
395
- description: "Prints all environment variables, helpful for debugging MCP server configuration",
396
- inputSchema: zodToJsonSchema(PrintEnvSchema),
397
- },
398
- {
399
- name: ToolName.SAMPLE_LLM,
400
- description: "Samples from an LLM using MCP's sampling feature",
401
- inputSchema: zodToJsonSchema(SampleLLMSchema),
402
- },
403
- {
404
- name: ToolName.GET_TINY_IMAGE,
405
- description: "Returns the MCP_TINY_IMAGE",
406
- inputSchema: zodToJsonSchema(GetTinyImageSchema),
407
- },
408
- {
409
- name: ToolName.ANNOTATED_MESSAGE,
410
- description: "Demonstrates how annotations can be used to provide metadata about content",
411
- inputSchema: zodToJsonSchema(AnnotatedMessageSchema),
412
- },
413
- {
414
- name: ToolName.GET_RESOURCE_REFERENCE,
415
- description: "Returns a resource reference that can be used by MCP clients",
416
- inputSchema: zodToJsonSchema(GetResourceReferenceSchema),
417
- },
418
- {
419
- name: ToolName.GET_RESOURCE_LINKS,
420
- description: "Returns multiple resource links that reference different types of resources",
421
- inputSchema: zodToJsonSchema(GetResourceLinksSchema),
422
- },
423
- {
424
- name: ToolName.STRUCTURED_CONTENT,
425
- description: "Returns structured content along with an output schema for client data validation",
426
- inputSchema: zodToJsonSchema(StructuredContentSchema.input),
427
- outputSchema: zodToJsonSchema(StructuredContentSchema.output),
428
- },
429
- {
430
- name: ToolName.ZIP_RESOURCES,
431
- description: "Compresses the provided resource files (mapping of name to URI, which can be a data URI) to a zip file, which it returns as a data URI resource link.",
432
- inputSchema: zodToJsonSchema(ZipResourcesInputSchema),
433
- }
434
- ];
435
- if (clientCapabilities.roots)
436
- tools.push({
437
- name: ToolName.LIST_ROOTS,
438
- description: "Lists the current MCP roots provided by the client. Demonstrates the roots protocol capability even though this server doesn't access files.",
439
- inputSchema: zodToJsonSchema(ListRootsSchema),
440
- });
441
- if (clientCapabilities.elicitation)
442
- tools.push({
443
- name: ToolName.ELICITATION,
444
- description: "Elicitation test tool that demonstrates how to request user input with various field types (string, boolean, email, uri, date, integer, number, enum)",
445
- inputSchema: zodToJsonSchema(ElicitationSchema),
446
- });
447
- return { tools };
448
- });
449
- server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
450
- const { name, arguments: args } = request.params;
451
- if (name === ToolName.ECHO) {
452
- const validatedArgs = EchoSchema.parse(args);
453
- return {
454
- content: [{ type: "text", text: `Echo: ${validatedArgs.message}` }],
455
- };
456
- }
457
- if (name === ToolName.ADD) {
458
- const validatedArgs = AddSchema.parse(args);
459
- const sum = validatedArgs.a + validatedArgs.b;
460
- return {
461
- content: [
462
- {
463
- type: "text",
464
- text: `The sum of ${validatedArgs.a} and ${validatedArgs.b} is ${sum}.`,
465
- },
466
- ],
467
- };
468
- }
469
- if (name === ToolName.LONG_RUNNING_OPERATION) {
470
- const validatedArgs = LongRunningOperationSchema.parse(args);
471
- const { duration, steps } = validatedArgs;
472
- const stepDuration = duration / steps;
473
- const progressToken = request.params._meta?.progressToken;
474
- for (let i = 1; i < steps + 1; i++) {
475
- await new Promise((resolve) => setTimeout(resolve, stepDuration * 1000));
476
- if (progressToken !== undefined) {
477
- await server.notification({
478
- method: "notifications/progress",
479
- params: {
480
- progress: i,
481
- total: steps,
482
- progressToken,
483
- },
484
- }, { relatedRequestId: extra.requestId });
485
- }
486
- }
487
- return {
488
- content: [
489
- {
490
- type: "text",
491
- text: `Long running operation completed. Duration: ${duration} seconds, Steps: ${steps}.`,
492
- },
493
- ],
494
- };
495
- }
496
- if (name === ToolName.PRINT_ENV) {
497
- return {
498
- content: [
499
- {
500
- type: "text",
501
- text: JSON.stringify(process.env, null, 2),
502
- },
503
- ],
504
- };
505
- }
506
- if (name === ToolName.SAMPLE_LLM) {
507
- const validatedArgs = SampleLLMSchema.parse(args);
508
- const { prompt, maxTokens } = validatedArgs;
509
- const result = await requestSampling(prompt, ToolName.SAMPLE_LLM, maxTokens, extra.sendRequest);
510
- return {
511
- content: [
512
- { type: "text", text: `LLM sampling result: ${Array.isArray(result.content) ? result.content.map(c => c.type === "text" ? c.text : JSON.stringify(c)).join("") : (result.content.type === "text" ? result.content.text : JSON.stringify(result.content))}` },
513
- ],
514
- };
515
- }
516
- if (name === ToolName.GET_TINY_IMAGE) {
517
- GetTinyImageSchema.parse(args);
518
- return {
519
- content: [
520
- {
521
- type: "text",
522
- text: "This is a tiny image:",
523
- },
524
- {
525
- type: "image",
526
- data: MCP_TINY_IMAGE,
527
- mimeType: "image/png",
528
- },
529
- {
530
- type: "text",
531
- text: "The image above is the MCP tiny image.",
532
- },
533
- ],
534
- };
535
- }
536
- if (name === ToolName.ANNOTATED_MESSAGE) {
537
- const { messageType, includeImage } = AnnotatedMessageSchema.parse(args);
538
- const content = [];
539
- // Main message with different priorities/audiences based on type
540
- if (messageType === "error") {
541
- content.push({
542
- type: "text",
543
- text: "Error: Operation failed",
544
- annotations: {
545
- priority: 1.0, // Errors are highest priority
546
- audience: ["user", "assistant"], // Both need to know about errors
547
- },
548
- });
549
- }
550
- else if (messageType === "success") {
551
- content.push({
552
- type: "text",
553
- text: "Operation completed successfully",
554
- annotations: {
555
- priority: 0.7, // Success messages are important but not critical
556
- audience: ["user"], // Success mainly for user consumption
557
- },
558
- });
559
- }
560
- else if (messageType === "debug") {
561
- content.push({
562
- type: "text",
563
- text: "Debug: Cache hit ratio 0.95, latency 150ms",
564
- annotations: {
565
- priority: 0.3, // Debug info is low priority
566
- audience: ["assistant"], // Technical details for assistant
567
- },
568
- });
569
- }
570
- // Optional image with its own annotations
571
- if (includeImage) {
572
- content.push({
573
- type: "image",
574
- data: MCP_TINY_IMAGE,
575
- mimeType: "image/png",
576
- annotations: {
577
- priority: 0.5,
578
- audience: ["user"], // Images primarily for user visualization
579
- },
580
- });
581
- }
582
- return { content };
583
- }
584
- if (name === ToolName.GET_RESOURCE_REFERENCE) {
585
- const validatedArgs = GetResourceReferenceSchema.parse(args);
586
- const resourceId = validatedArgs.resourceId;
587
- const resourceIndex = resourceId - 1;
588
- if (resourceIndex < 0 || resourceIndex >= ALL_RESOURCES.length) {
589
- throw new Error(`Resource with ID ${resourceId} does not exist`);
590
- }
591
- const resource = ALL_RESOURCES[resourceIndex];
592
- return {
593
- content: [
594
- {
595
- type: "text",
596
- text: `Returning resource reference for Resource ${resourceId}:`,
597
- },
598
- {
599
- type: "resource",
600
- resource: resource,
601
- },
602
- {
603
- type: "text",
604
- text: `You can access this resource using the URI: ${resource.uri}`,
605
- },
606
- ],
607
- };
608
- }
609
- if (name === ToolName.ELICITATION) {
610
- ElicitationSchema.parse(args);
611
- const elicitationResult = await extra.sendRequest({
612
- method: 'elicitation/create',
613
- params: {
614
- message: 'Please provide inputs for the following fields:',
615
- requestedSchema: {
616
- type: 'object',
617
- properties: {
618
- name: {
619
- title: 'String',
620
- type: 'string',
621
- description: 'Your full, legal name',
622
- },
623
- check: {
624
- title: 'Boolean',
625
- type: 'boolean',
626
- description: 'Agree to the terms and conditions',
627
- },
628
- firstLine: {
629
- title: 'String with default',
630
- type: 'string',
631
- description: 'Favorite first line of a story',
632
- default: 'It was a dark and stormy night.',
633
- },
634
- email: {
635
- title: 'String with email format',
636
- type: 'string',
637
- format: 'email',
638
- description: 'Your email address (will be verified, and never shared with anyone else)',
639
- },
640
- homepage: {
641
- type: 'string',
642
- format: 'uri',
643
- title: 'String with uri format',
644
- description: 'Portfolio / personal website',
645
- },
646
- birthdate: {
647
- title: 'String with date format',
648
- type: 'string',
649
- format: 'date',
650
- description: 'Your date of birth',
651
- },
652
- integer: {
653
- title: 'Integer',
654
- type: 'integer',
655
- description: 'Your favorite integer (do not give us your phone number, pin, or other sensitive info)',
656
- minimum: 1,
657
- maximum: 100,
658
- default: 42,
659
- },
660
- number: {
661
- title: 'Number in range 1-1000',
662
- type: 'number',
663
- description: 'Favorite number (there are no wrong answers)',
664
- minimum: 0,
665
- maximum: 1000,
666
- default: 3.14,
667
- },
668
- untitledSingleSelectEnum: {
669
- type: 'string',
670
- title: 'Untitled Single Select Enum',
671
- description: 'Choose your favorite friend',
672
- enum: ['Monica', 'Rachel', 'Joey', 'Chandler', 'Ross', 'Phoebe'],
673
- default: 'Monica'
674
- },
675
- untitledMultipleSelectEnum: {
676
- type: 'array',
677
- title: 'Untitled Multiple Select Enum',
678
- description: 'Choose your favorite instruments',
679
- minItems: 1,
680
- maxItems: 3,
681
- items: { type: 'string', enum: ['Guitar', 'Piano', 'Violin', 'Drums', 'Bass'] },
682
- default: ['Guitar']
683
- },
684
- titledSingleSelectEnum: {
685
- type: 'string',
686
- title: 'Titled Single Select Enum',
687
- description: 'Choose your favorite hero',
688
- oneOf: [
689
- { const: 'hero-1', title: 'Superman' },
690
- { const: 'hero-2', title: 'Green Lantern' },
691
- { const: 'hero-3', title: 'Wonder Woman' }
692
- ],
693
- default: 'hero-1'
694
- },
695
- titledMultipleSelectEnum: {
696
- type: 'array',
697
- title: 'Titled Multiple Select Enum',
698
- description: 'Choose your favorite types of fish',
699
- minItems: 1,
700
- maxItems: 3,
701
- items: {
702
- anyOf: [
703
- { const: 'fish-1', title: 'Tuna' },
704
- { const: 'fish-2', title: 'Salmon' },
705
- { const: 'fish-3', title: 'Trout' }
706
- ]
707
- },
708
- default: ['fish-1']
709
- },
710
- legacyTitledEnum: {
711
- type: 'string',
712
- title: 'Legacy Titled Single Select Enum',
713
- description: 'Choose your favorite type of pet',
714
- enum: ['pet-1', 'pet-2', 'pet-3', 'pet-4', 'pet-5'],
715
- enumNames: ['Cats', 'Dogs', 'Birds', 'Fish', 'Reptiles'],
716
- default: 'pet-1',
717
- }
718
- },
719
- required: ['name'],
720
- },
721
- },
722
- }, ElicitResultSchema, { timeout: 10 * 60 * 1000 /* 10 minutes */ });
723
- // Handle different response actions
724
- const content = [];
725
- if (elicitationResult.action === 'accept' && elicitationResult.content) {
726
- content.push({
727
- type: "text",
728
- text: `✅ User provided the requested information!`,
729
- });
730
- // Only access elicitationResult.content when action is accept
731
- const userData = elicitationResult.content;
732
- const lines = [];
733
- if (userData.name)
734
- lines.push(`- Name: ${userData.name}`);
735
- if (userData.check !== undefined)
736
- lines.push(`- Agreed to terms: ${userData.check}`);
737
- if (userData.color)
738
- lines.push(`- Favorite Color: ${userData.color}`);
739
- if (userData.email)
740
- lines.push(`- Email: ${userData.email}`);
741
- if (userData.homepage)
742
- lines.push(`- Homepage: ${userData.homepage}`);
743
- if (userData.birthdate)
744
- lines.push(`- Birthdate: ${userData.birthdate}`);
745
- if (userData.integer !== undefined)
746
- lines.push(`- Favorite Integer: ${userData.integer}`);
747
- if (userData.number !== undefined)
748
- lines.push(`- Favorite Number: ${userData.number}`);
749
- if (userData.petType)
750
- lines.push(`- Pet Type: ${userData.petType}`);
751
- content.push({
752
- type: "text",
753
- text: `User inputs:\n${lines.join('\n')}`,
754
- });
755
- }
756
- else if (elicitationResult.action === 'decline') {
757
- content.push({
758
- type: "text",
759
- text: `❌ User declined to provide the requested information.`,
760
- });
761
- }
762
- else if (elicitationResult.action === 'cancel') {
763
- content.push({
764
- type: "text",
765
- text: `⚠️ User cancelled the elicitation dialog.`,
766
- });
767
- }
768
- // Include raw result for debugging
769
- content.push({
770
- type: "text",
771
- text: `\nRaw result: ${JSON.stringify(elicitationResult, null, 2)}`,
772
- });
773
- return { content };
774
- }
775
- if (name === ToolName.GET_RESOURCE_LINKS) {
776
- const { count } = GetResourceLinksSchema.parse(args);
777
- const content = [];
778
- // Add intro text
779
- content.push({
780
- type: "text",
781
- text: `Here are ${count} resource links to resources available in this server (see full output in tool response if your client does not support resource_link yet):`,
782
- });
783
- // Return resource links to actual resources from ALL_RESOURCES
784
- const actualCount = Math.min(count, ALL_RESOURCES.length);
785
- for (let i = 0; i < actualCount; i++) {
786
- const resource = ALL_RESOURCES[i];
787
- content.push({
788
- type: "resource_link",
789
- uri: resource.uri,
790
- name: resource.name,
791
- description: `Resource ${i + 1}: ${resource.mimeType === "text/plain"
792
- ? "plaintext resource"
793
- : "binary blob resource"}`,
794
- mimeType: resource.mimeType,
795
- });
796
- }
797
- return { content };
798
- }
799
- if (name === ToolName.STRUCTURED_CONTENT) {
800
- // The same response is returned for every input.
801
- const validatedArgs = StructuredContentSchema.input.parse(args);
802
- const weather = {
803
- temperature: 22.5,
804
- conditions: "Partly cloudy",
805
- humidity: 65
806
- };
807
- const backwardCompatiblecontent = {
808
- type: "text",
809
- text: JSON.stringify(weather)
810
- };
811
- return {
812
- content: [backwardCompatiblecontent],
813
- structuredContent: weather
814
- };
815
- }
816
- if (name === ToolName.ZIP_RESOURCES) {
817
- const { files } = ZipResourcesInputSchema.parse(args);
818
- const zip = new JSZip();
819
- for (const [fileName, fileUrl] of Object.entries(files)) {
820
- try {
821
- const response = await fetch(fileUrl);
822
- if (!response.ok) {
823
- throw new Error(`Failed to fetch ${fileUrl}: ${response.statusText}`);
824
- }
825
- const arrayBuffer = await response.arrayBuffer();
826
- zip.file(fileName, arrayBuffer);
827
- }
828
- catch (error) {
829
- throw new Error(`Error fetching file ${fileUrl}: ${error instanceof Error ? error.message : String(error)}`);
830
- }
831
- }
832
- const uri = `data:application/zip;base64,${await zip.generateAsync({ type: "base64" })}`;
833
- return {
834
- content: [
835
- {
836
- type: "resource_link",
837
- mimeType: "application/zip",
838
- uri,
839
- },
840
- ],
841
- };
842
- }
843
- if (name === ToolName.LIST_ROOTS) {
844
- ListRootsSchema.parse(args);
845
- if (!clientSupportsRoots) {
846
- return {
847
- content: [
848
- {
849
- type: "text",
850
- text: "The MCP client does not support the roots protocol.\n\n" +
851
- "This means the server cannot access information about the client's workspace directories or file system roots."
852
- }
853
- ]
854
- };
855
- }
856
- if (currentRoots.length === 0) {
857
- return {
858
- content: [
859
- {
860
- type: "text",
861
- text: "The client supports roots but no roots are currently configured.\n\n" +
862
- "This could mean:\n" +
863
- "1. The client hasn't provided any roots yet\n" +
864
- "2. The client provided an empty roots list\n" +
865
- "3. The roots configuration is still being loaded"
866
- }
867
- ]
868
- };
869
- }
870
- const rootsList = currentRoots.map((root, index) => {
871
- return `${index + 1}. ${root.name || 'Unnamed Root'}\n URI: ${root.uri}`;
872
- }).join('\n\n');
873
- return {
874
- content: [
875
- {
876
- type: "text",
877
- text: `Current MCP Roots (${currentRoots.length} total):\n\n${rootsList}\n\n` +
878
- "Note: This server demonstrates the roots protocol capability but doesn't actually access files. " +
879
- "The roots are provided by the MCP client and can be used by servers that need file system access."
880
- }
881
- ]
882
- };
883
- }
884
- throw new Error(`Unknown tool: ${name}`);
885
- });
886
- server.setRequestHandler(CompleteRequestSchema, async (request) => {
887
- const { ref, argument } = request.params;
888
- if (ref.type === "ref/resource") {
889
- const resourceId = ref.uri.split("/").pop();
890
- if (!resourceId)
891
- return { completion: { values: [] } };
892
- // Filter resource IDs that start with the input value
893
- const values = EXAMPLE_COMPLETIONS.resourceId.filter((id) => id.startsWith(argument.value));
894
- return { completion: { values, hasMore: false, total: values.length } };
895
- }
896
- if (ref.type === "ref/prompt") {
897
- // Handle completion for prompt arguments
898
- const completions = EXAMPLE_COMPLETIONS[argument.name];
899
- if (!completions)
900
- return { completion: { values: [] } };
901
- const values = completions.filter((value) => value.startsWith(argument.value));
902
- return { completion: { values, hasMore: false, total: values.length } };
903
- }
904
- throw new Error(`Unknown reference type`);
905
- });
906
- // Roots protocol handlers
907
- server.setNotificationHandler(RootsListChangedNotificationSchema, async () => {
908
- try {
909
- // Request the updated roots list from the client
910
- const response = await server.listRoots();
911
- if (response && 'roots' in response) {
912
- currentRoots = response.roots;
913
- // Log the roots update for demonstration
914
- await server.sendLoggingMessage({
915
- level: "info",
916
- logger: "everything-server",
917
- data: `Roots updated: ${currentRoots.length} root(s) received from client`,
918
- }, sessionId);
919
- }
920
- }
921
- catch (error) {
922
- await server.sendLoggingMessage({
923
- level: "error",
924
- logger: "everything-server",
925
- data: `Failed to request roots from client: ${error instanceof Error ? error.message : String(error)}`,
926
- }, sessionId);
927
- }
928
- });
929
- // Handle post-initialization setup for roots
930
- server.oninitialized = async () => {
931
- clientCapabilities = server.getClientCapabilities();
932
- if (clientCapabilities?.roots) {
933
- clientSupportsRoots = true;
934
- try {
935
- const response = await server.listRoots();
936
- if (response && 'roots' in response) {
937
- currentRoots = response.roots;
938
- await server.sendLoggingMessage({
939
- level: "info",
940
- logger: "everything-server",
941
- data: `Initial roots received: ${currentRoots.length} root(s) from client`,
942
- }, sessionId);
943
- }
944
- else {
945
- await server.sendLoggingMessage({
946
- level: "warning",
947
- logger: "everything-server",
948
- data: "Client returned no roots set",
949
- }, sessionId);
950
- }
951
- }
952
- catch (error) {
953
- await server.sendLoggingMessage({
954
- level: "error",
955
- logger: "everything-server",
956
- data: `Failed to request initial roots from client: ${error instanceof Error ? error.message : String(error)}`,
957
- }, sessionId);
958
- }
959
- }
960
- else {
961
- await server.sendLoggingMessage({
962
- level: "info",
963
- logger: "everything-server",
964
- data: "Client does not support MCP roots protocol",
965
- }, sessionId);
966
- }
967
- };
968
- const cleanup = async () => {
969
- if (subsUpdateInterval)
970
- clearInterval(subsUpdateInterval);
971
- if (logsUpdateInterval)
972
- clearInterval(logsUpdateInterval);
973
- if (stdErrUpdateInterval)
974
- clearInterval(stdErrUpdateInterval);
975
- };
976
- return { server, cleanup, startNotificationIntervals };
977
- };
978
- const MCP_TINY_IMAGE = "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";