Skip to content

[v2] structuredContent with string wrapped in result: mismatch with specification #2530

Description

@tobiasBora

What happened?

I'm confused, I created a server like

import type { DiagramConfClass } from '$lib/contexts/context.svelte';
import { McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';

export function createServer(diagramConfClass: DiagramConfClass): McpServer {
  const server = new McpServer({ name: 'proofdiag', version: '0.0.1' });

  server.registerTool(
    'ping',
    {
      description: 'Returns pong',
      outputSchema: z.string()
    },
    async () => {
      const str = `Pong at ${new Date()}`
      // content seems to be automatically added by the SDK (needed for backward compatibility)
      return { structuredContent: str };
    }
  );

  return server;
}

The specs specifies that when calling such a tool, we should get back the structured content directly

Structured content is returned as a JSON value in the structuredContent field of a result. This can be any JSON value (object, array, string, number, boolean, or null) that conforms to the tool’s outputSchema if one is defined.

and they provide this valid return:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "resultType": "complete",
    "content": [
      {
        "type": "text",
        "text": "{\"temperature\": 22.5, \"conditions\": \"Partly cloudy\", \"humidity\": 65}"
      }
    ],
    "structuredContent": {
      "temperature": 22.5,
      "conditions": "Partly cloudy",
      "humidity": 65
    }
  }
}

However, when used with strings (and possibly other non-object types), not only typescript complains, but this library nests the structuredContent inside a {result: str}, so I need to access the final content via myjsonrpc.result.structuredContent.result instead of myjsonrpc.result.structuredContent. When considering objects, it works fine.

Screenshot:

Image

What did you expect?

StructuredContent with strings should not be nested inside a result.

Code to reproduce

import type { DiagramConfClass } from '$lib/contexts/context.svelte';
import { McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';

export function createServer(diagramConfClass: DiagramConfClass): McpServer {
  const server = new McpServer({ name: 'proofdiag', version: '0.0.1' });

  server.registerTool(
    'ping',
    {
      description: 'Returns pong',
      outputSchema: z.string()
    },
    async () => {
      const str = `Pong at ${new Date()}`
      // content seems to be automatically added by the SDK (needed for backward compatibility)
      return { structuredContent: str };
    }
  );

  return server;
}

SDK version

@modelcontextprotocol/server@2.0.0-beta.4

Area

Server

Metadata

Metadata

Assignees

No one assigned

    Labels

    v2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions