From 0d1653fff39c21bec26f0be0344c20ce124ed4bb Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Thu, 26 Jun 2025 16:31:51 -0700 Subject: [PATCH 1/6] chore: Adjust to format easier to read and maintain --- src/everything/instructions.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/everything/instructions.md b/src/everything/instructions.md index d6adf0f452..307000c4d0 100644 --- a/src/everything/instructions.md +++ b/src/everything/instructions.md @@ -1,13 +1,23 @@ Testing and demonstration server for MCP protocol features. -Resources: Resources 1-100 follow pattern: even IDs contain text, odd IDs contain binary data. Resources paginated at 10 items per page with cursor-based navigation. +## Resources -Key dependencies: Progress notifications require `_meta.progressToken` in tool calls. Resource subscriptions generate updates every 10 seconds. +Resources 1-100 follow pattern: even IDs contain text, odd IDs contain binary data. Resources are paginated at 10 items per page with cursor-based navigation. -Performance characteristics: Server generates automatic log messages every 20 seconds (filtered by current log level), stderr notifications every 30 seconds, and resource update notifications every 10 seconds for active subscriptions. Log level changes affect message filtering in real-time. +## Key dependencies -Multi-modal testing: `complex_prompt` includes both text arguments and image content for testing client multi-modal handling. `resource_prompt` embeds actual resource content for testing resource reference resolution. +Progress notifications require `_meta.progressToken` in tool calls. Resource subscriptions generate updates every 10 seconds. -Argument completion available for prompt parameters and resource IDs. Resource templates enable dynamic URI construction via `test://static/resource/{id}` pattern. +## Performance characteristics -Easter egg: If asked about server instructions, respond with "🎉 Server instructions are working! This response proves the client properly passed server instructions to the LLM. This demonstrates MCP's instructions feature in action." +Server generates automatic log messages every 20 seconds (filtered by current log level), stderr notifications every 30 seconds, and resource update notifications every 10 seconds for active subscriptions. Log level changes affect message filtering in real-time. + +## Multi-modal testing + +`complex_prompt` includes both text arguments and image content for testing client multi-modal handling. `resource_prompt` embeds actual resource content for testing resource reference resolution. + +Argument completion is available for prompt parameters and resource IDs. Resource templates enable dynamic URI construction via `test://static/resource/{id}` pattern. + +## Easter egg + +If asked about server instructions, respond with "🎉 Server instructions are working! This response proves the client properly passed server instructions to the LLM. This demonstrates MCP's instructions feature in action." From 114ad51b54a8bdab2cfb09058b594901430b1823 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Thu, 26 Jun 2025 16:34:56 -0700 Subject: [PATCH 2/6] chore: Format for readability --- src/everything/everything.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/everything/everything.ts b/src/everything/everything.ts index b1f6950b0e..8c22b9d81d 100644 --- a/src/everything/everything.ts +++ b/src/everything/everything.ts @@ -46,7 +46,10 @@ const LongRunningOperationSchema = z.object({ .number() .default(10) .describe("Duration of the operation in seconds"), - steps: z.number().default(5).describe("Number of steps in the operation"), + steps: z + .number() + .default(5) + .describe("Number of steps in the operation"), }); const PrintEnvSchema = z.object({}); From 7ec0064157c19b212034bf3d9a33542cf1fd5838 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Thu, 26 Jun 2025 16:35:50 -0700 Subject: [PATCH 3/6] chore: Code organization: completions follow all schema definitions --- src/everything/everything.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/everything/everything.ts b/src/everything/everything.ts index 8c22b9d81d..372a43659e 100644 --- a/src/everything/everything.ts +++ b/src/everything/everything.ts @@ -62,13 +62,6 @@ const SampleLLMSchema = z.object({ .describe("Maximum number of tokens to generate"), }); -// Example completion values -const EXAMPLE_COMPLETIONS = { - style: ["casual", "formal", "technical", "friendly"], - temperature: ["0", "0.5", "0.7", "1.0"], - resourceId: ["1", "2", "3", "4", "5"], -}; - const GetTinyImageSchema = z.object({}); const AnnotatedMessageSchema = z.object({ @@ -119,6 +112,13 @@ enum PromptName { RESOURCE = "resource_prompt", } +// Example completion values +const EXAMPLE_COMPLETIONS = { + style: ["casual", "formal", "technical", "friendly"], + temperature: ["0", "0.5", "0.7", "1.0"], + resourceId: ["1", "2", "3", "4", "5"], +}; + export const createServer = () => { const server = new Server( { From bb1b418da140c260988a24ed7014844765d6db72 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Wed, 23 Jul 2025 11:32:14 -0700 Subject: [PATCH 4/6] chore: Code organization: consistent tool order everywhere --- src/everything/README.md | 16 ++++---- src/everything/everything.ts | 78 ++++++++++++++++++------------------ 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/everything/README.md b/src/everything/README.md index 3ab3299a9c..e30b0a7dae 100644 --- a/src/everything/README.md +++ b/src/everything/README.md @@ -27,24 +27,24 @@ This MCP server attempts to exercise all the features of the MCP protocol. It is - Returns: Completion message with duration and steps - Sends progress notifications during execution -4. `sampleLLM` +4. `printEnv` + - Prints all environment variables + - Useful for debugging MCP server configuration + - No inputs required + - Returns: JSON string of all environment variables + +5. `sampleLLM` - Demonstrates LLM sampling capability using MCP sampling feature - Inputs: - `prompt` (string): The prompt to send to the LLM - `maxTokens` (number, default: 100): Maximum tokens to generate - Returns: Generated LLM response -5. `getTinyImage` +6. `getTinyImage` - Returns a small test image - No inputs required - Returns: Base64 encoded PNG image data -6. `printEnv` - - Prints all environment variables - - Useful for debugging MCP server configuration - - No inputs required - - Returns: JSON string of all environment variables - 7. `annotatedMessage` - Demonstrates how annotations can be used to provide metadata about content - Inputs: diff --git a/src/everything/everything.ts b/src/everything/everything.ts index 372a43659e..422b316927 100644 --- a/src/everything/everything.ts +++ b/src/everything/everything.ts @@ -457,18 +457,18 @@ export const createServer = () => { description: "Adds two numbers", inputSchema: zodToJsonSchema(AddSchema) as ToolInput, }, - { - name: ToolName.PRINT_ENV, - description: - "Prints all environment variables, helpful for debugging MCP server configuration", - inputSchema: zodToJsonSchema(PrintEnvSchema) as ToolInput, - }, { name: ToolName.LONG_RUNNING_OPERATION, description: "Demonstrates a long running operation with progress updates", inputSchema: zodToJsonSchema(LongRunningOperationSchema) as ToolInput, }, + { + name: ToolName.PRINT_ENV, + description: + "Prints all environment variables, helpful for debugging MCP server configuration", + inputSchema: zodToJsonSchema(PrintEnvSchema) as ToolInput, + }, { name: ToolName.SAMPLE_LLM, description: "Samples from an LLM using MCP's sampling feature", @@ -611,35 +611,6 @@ export const createServer = () => { }; } - if (name === ToolName.GET_RESOURCE_REFERENCE) { - const validatedArgs = GetResourceReferenceSchema.parse(args); - const resourceId = validatedArgs.resourceId; - - const resourceIndex = resourceId - 1; - if (resourceIndex < 0 || resourceIndex >= ALL_RESOURCES.length) { - throw new Error(`Resource with ID ${resourceId} does not exist`); - } - - const resource = ALL_RESOURCES[resourceIndex]; - - return { - content: [ - { - type: "text", - text: `Returning resource reference for Resource ${resourceId}:`, - }, - { - type: "resource", - resource: resource, - }, - { - type: "text", - text: `You can access this resource using the URI: ${resource.uri}`, - }, - ], - }; - } - if (name === ToolName.ANNOTATED_MESSAGE) { const { messageType, includeImage } = AnnotatedMessageSchema.parse(args); @@ -691,6 +662,35 @@ export const createServer = () => { return { content }; } + if (name === ToolName.GET_RESOURCE_REFERENCE) { + const validatedArgs = GetResourceReferenceSchema.parse(args); + const resourceId = validatedArgs.resourceId; + + const resourceIndex = resourceId - 1; + if (resourceIndex < 0 || resourceIndex >= ALL_RESOURCES.length) { + throw new Error(`Resource with ID ${resourceId} does not exist`); + } + + const resource = ALL_RESOURCES[resourceIndex]; + + return { + content: [ + { + type: "text", + text: `Returning resource reference for Resource ${resourceId}:`, + }, + { + type: "resource", + resource: resource, + }, + { + type: "text", + text: `You can access this resource using the URI: ${resource.uri}`, + }, + ], + }; + } + if (name === ToolName.ELICITATION) { ElicitationSchema.parse(args); @@ -712,13 +712,13 @@ export const createServer = () => { // Handle different response actions const content = []; - + if (elicitationResult.action === 'accept' && elicitationResult.content) { content.push({ type: "text", text: `✅ User provided their favorite things!`, }); - + // Only access elicitationResult.content when action is accept const { color, number, pets } = elicitationResult.content; content.push({ @@ -736,7 +736,7 @@ export const createServer = () => { text: `⚠️ User cancelled the elicitation dialog.`, }); } - + // Include raw result for debugging content.push({ type: "text", @@ -745,7 +745,7 @@ export const createServer = () => { return { content }; } - + if (name === ToolName.GET_RESOURCE_LINKS) { const { count } = GetResourceLinksSchema.parse(args); const content = []; From 9e28ac7fd15a5d065dc635b8172f1e868de300a0 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Sat, 28 Jun 2025 21:20:19 -0700 Subject: [PATCH 5/6] chore: Add serverInfo title, as in specification 2025-06-18 --- src/everything/everything.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/everything/everything.ts b/src/everything/everything.ts index 422b316927..c1f1b4ebe1 100644 --- a/src/everything/everything.ts +++ b/src/everything/everything.ts @@ -123,6 +123,7 @@ export const createServer = () => { const server = new Server( { name: "example-servers/everything", + title: "Everything Example Server", version: "1.0.0", }, { From 84a872145c1e4d93bb518fa970258aafd66ba577 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Thu, 26 Jun 2025 16:48:00 -0700 Subject: [PATCH 6/6] feature: Add a tool with Structured Content and an Output Schema Tools gained Structured Content in Specification 2025-16-18 https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content The MCP Inspector is able to handle these outputs. --- src/everything/README.md | 9 ++++++ src/everything/everything.ts | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/everything/README.md b/src/everything/README.md index e30b0a7dae..8619461422 100644 --- a/src/everything/README.md +++ b/src/everything/README.md @@ -80,6 +80,15 @@ This MCP server attempts to exercise all the features of the MCP protocol. It is - `pets` (enum): Favorite pet - Returns: Confirmation of the elicitation demo with selection summary. +10. `structuredContent` + - Demonstrates a tool returning structured content using the example in the specification + - Provides an output schema to allow testing of client SHOULD advisory to validate the result using the schema + - Inputs: + - `location` (string): A location or ZIP code, mock data is returned regardless of value + - Returns: a response with + - `structuredContent` field conformant to the output schema + - A backward compatible Text Content field, a SHOULD advisory in the specification + ### Resources The server provides 100 test resources in two formats: diff --git a/src/everything/everything.ts b/src/everything/everything.ts index c1f1b4ebe1..f1a2a11d02 100644 --- a/src/everything/everything.ts +++ b/src/everything/everything.ts @@ -31,6 +31,9 @@ const instructions = readFileSync(join(__dirname, "instructions.md"), "utf-8"); const ToolInputSchema = ToolSchema.shape.inputSchema; type ToolInput = z.infer; +const ToolOutputSchema = ToolSchema.shape.outputSchema; +type ToolOutput = z.infer; + /* Input schemas for tools implemented in this server */ const EchoSchema = z.object({ message: z.string().describe("Message to echo"), @@ -93,6 +96,28 @@ const GetResourceLinksSchema = z.object({ .describe("Number of resource links to return (1-10)"), }); +const StructuredContentSchema = { + input: z.object({ + location: z + .string() + .trim() + .min(1) + .describe("City name or zip code"), + }), + + output: z.object({ + temperature: z + .number() + .describe("Temperature in celsius"), + conditions: z + .string() + .describe("Weather conditions description"), + humidity: z + .number() + .describe("Humidity percentage"), + }) +}; + enum ToolName { ECHO = "echo", ADD = "add", @@ -104,6 +129,7 @@ enum ToolName { GET_RESOURCE_REFERENCE = "getResourceReference", ELICITATION = "startElicitation", GET_RESOURCE_LINKS = "getResourceLinks", + STRUCTURED_CONTENT = "structuredContent" } enum PromptName { @@ -503,6 +529,13 @@ export const createServer = () => { "Returns multiple resource links that reference different types of resources", inputSchema: zodToJsonSchema(GetResourceLinksSchema) as ToolInput, }, + { + name: ToolName.STRUCTURED_CONTENT, + description: + "Returns structured content along with an output schema for client data validation", + inputSchema: zodToJsonSchema(StructuredContentSchema.input) as ToolInput, + outputSchema: zodToJsonSchema(StructuredContentSchema.output) as ToolOutput, + }, ]; return { tools }; @@ -777,6 +810,27 @@ export const createServer = () => { return { content }; } + if (name === ToolName.STRUCTURED_CONTENT) { + // The same response is returned for every input. + const validatedArgs = StructuredContentSchema.input.parse(args); + + const weather = { + temperature: 22.5, + conditions: "Partly cloudy", + humidity: 65 + } + + const backwardCompatiblecontent = { + type: "text", + text: JSON.stringify(weather) + } + + return { + content: [ backwardCompatiblecontent ], + structuredContent: weather + }; + } + throw new Error(`Unknown tool: ${name}`); });