Skip to main content
mcp-use helpers Response helpers are utility functions that simplify creating standardized responses for MCP tools, resources, and prompts. Instead of manually constructing CallToolResult objects, these helpers provide a clean, type-safe API with automatic MIME type handling.

Why Use Response Helpers?

Response helpers provide several benefits:
  • Consistency: Standardized response format across your server
  • Type Safety: TypeScript types ensure correct usage
  • Less Boilerplate: No need to manually construct response objects
  • MIME Type Handling: Automatic content type detection and metadata
  • Composability: Easily combine multiple content types with mix()

Basic Text and Content Types

text()

Returns plain text content. The most common response type for tools and resources.
import { text } from 'mcp-use/server';

server.tool({
  name: 'greet',
  schema: z.object({ name: z.string() }),
  async ({ name }) => text(`Hello, ${name}!`)
});

server.resource(
  { name: 'greeting', uri: 'app://greeting' },
  async () => text('Hello World!')
);
Returns: CallToolResult with text/plain MIME type

markdown()

Returns Markdown formatted content.
import { markdown } from 'mcp-use/server';

server.resource(
  { name: 'readme', uri: 'doc://readme' },
  async () => markdown('# Welcome\n\nGetting started with our API...')
);

server.tool({
  name: 'format-docs',
  async () => markdown('## Documentation\n\n- Item 1\n- Item 2')
});
Returns: CallToolResult with text/markdown MIME type

html()

Returns HTML content for web display.
import { html } from 'mcp-use/server';

server.resource(
  { name: 'page', uri: 'ui://dashboard' },
  async () => html('<h1>Dashboard</h1><p>Welcome to your dashboard</p>')
);

server.tool({
  name: 'generate-report',
  async ({ data }) => html(`
    <div class="report">
      <h2>Report</h2>
      <table>
        <tr><td>Total</td><td>${data.total}</td></tr>
      </table>
    </div>
  `)
});
Returns: CallToolResult with text/html MIME type

xml()

Returns XML formatted content.
import { xml } from "mcp-use/server";

server.resource({ name: "sitemap", uri: "data://sitemap" }, async () =>
  xml('<?xml version="1.0"?><urlset>...</urlset>')
);
Returns: CallToolResult with text/xml MIME type

css()

Returns CSS stylesheet content.
import { css } from "mcp-use/server";

server.resource({ name: "styles", uri: "asset://theme.css" }, async () =>
  css("body { margin: 0; padding: 0; font-family: sans-serif; }")
);
Returns: CallToolResult with text/css MIME type

javascript()

Returns JavaScript code content.
import { javascript } from "mcp-use/server";

server.resource({ name: "script", uri: "asset://main.js" }, async () =>
  javascript('console.log("Application started");')
);
Returns: CallToolResult with text/javascript MIME type

Structured Data

object()

Returns JSON object with both text representation and typed structured content.
import { object } from 'mcp-use/server';

server.tool({
  name: 'get-user-info',
  schema: z.object({ userId: z.string() }),
  async ({ userId }) => {
    const user = await fetchUser(userId);
    return object({
      userId: user.id,
      email: user.email,
      name: user.name,
      createdAt: user.createdAt
    });
  }
});

server.resource(
  { name: 'config', uri: 'config://settings' },
  async () => object({ theme: 'dark', version: '1.0', debug: false })
);
Returns: TypedCallToolResult<T> with:
  • Text content: Pretty-printed JSON string
  • Structured content: Typed object data
  • MIME type: application/json
The object() helper includes both stringified JSON for backwards compatibility as specified by the protocol and the new structured data property.

array()

Returns array data wrapped in an object with a data field.
import { array } from 'mcp-use/server';

server.tool({
  name: 'list-items',
  async () => {
    const items = await getItems();
    return array(items);
  }
});
Returns: TypedCallToolResult<{ data: T }> with structured content
Arrays are automatically wrapped in an object with a data field. If you pass an array to object(), it will automatically call array() internally.

Media Content

image()

Returns image content with base64 data or data URL.
import { image } from 'mcp-use/server';

server.tool({
  name: 'generate-chart',
  async ({ data }) => {
    const chartImage = await generateChart(data);
    return image(chartImage, 'image/png');
  }
});

server.resource(
  { name: 'logo', uri: 'asset://logo' },
  async () => image(base64LogoData, 'image/png')
);
Parameters:
  • data: Base64 string or data URL
  • mimeType: Image MIME type (default: 'image/png')
Returns: CallToolResult with image content and metadata

audio()

Returns audio content. Supports both base64 data and file paths.
import { audio } from 'mcp-use/server';

// With base64 data (synchronous)
server.tool({
  name: 'generate-audio',
  async () => audio(base64AudioData, 'audio/wav')
});

// With file path (asynchronous)
server.resource(
  { name: 'notification', uri: 'audio://notification' },
  async () => await audio('./sounds/notification.wav')
);
Parameters:
  • dataOrPath: Base64 audio data or file path
  • mimeType: Audio MIME type (optional, inferred from extension for files)
Returns: CallToolResult (sync) or Promise<CallToolResult> (async for files) Supported formats: WAV, MP3, OGG, M4A, WebM, FLAC, AAC
When using file paths, make sure to await the result as the file is read asynchronously.

binary()

Returns arbitrary binary content as base64.
import { binary } from "mcp-use/server";

server.resource({ name: "document", uri: "file://document.pdf" }, async () => {
  const pdfData = await readFile("./document.pdf");
  const base64 = pdfData.toString("base64");
  return binary(base64, "application/pdf");
});
Parameters:
  • base64Data: Base64-encoded binary data
  • mimeType: Content MIME type
Returns: CallToolResult with binary metadata

Resource Embedding

resource()

Creates embedded resource content. Supports two patterns: Pattern 1: Three arguments (uri, mimeType, text)
import { resource } from 'mcp-use/server';

server.tool({
  name: 'get-config',
  async () => resource(
    'config://app',
    'application/json',
    JSON.stringify({ api: 'v2', timeout: 30 })
  )
});
Pattern 2: Two arguments (uri, content helper result)
import { resource, text, object } from 'mcp-use/server';

// With text helper
server.tool({
  name: 'get-greeting',
  async () => resource('test://greeting', text('Hello'))
});

// With object helper
server.tool({
  name: 'get-data',
  async () => resource('data://user', object({ id: 1, name: 'Alice' }))
});
Returns: CallToolResult with embedded resource content

Error Handling

error()

Returns an error response with the isError flag set.
import { error, text } from 'mcp-use/server';

server.tool({
  name: 'divide',
  schema: z.object({
    a: z.number(),
    b: z.number()
  }),
  async ({ a, b }) => {
    if (b === 0) {
      return error('Division by zero is not allowed');
    }
    return text(`Result: ${a / b}`);
  }
});

server.tool({
  name: 'fetch-data',
  async ({ url }) => {
    try {
      const data = await fetch(url);
      return object(data);
    } catch (err) {
      return error(`Failed to fetch data: ${err.message}`);
    }
  }
});
Returns: CallToolResult with isError: true
Using error() provides a standardized way to communicate failures to clients while maintaining consistent response structure.

Mixed Content

mix()

Combines multiple content types into a single response. Perfect for returning text with images, resources, or multiple content items together.
import { mix, text, image, resource, object } from 'mcp-use/server';

// Text + Image
server.tool({
  name: 'generate-report',
  async ({ data }) => {
    const chart = await generateChart(data);
    return mix(
      text('Analysis complete. See chart below:'),
      image(chart, 'image/png')
    );
  }
});

// Text + Image + Resource
server.tool({
  name: 'test_multiple_content_types',
  async () => mix(
    text('Multiple content types test:'),
    image(RED_PIXEL_PNG, 'image/png'),
    resource(
      'test://mixed-content-resource',
      object({ test: 'data', value: 123 })
    )
  )
});

// Multiple text messages
server.tool({
  name: 'batch-process',
  async ({ items }) => {
    const results = [];
    for (const item of items) {
      const result = await processItem(item);
      results.push(text(`Processed ${item}: ${result}`));
    }
    return mix(...results);
  }
});
Returns: CallToolResult with merged content array and combined metadata
The mix() helper merges content arrays and combines structuredContent and _meta objects from all inputs, allowing complex multi-part responses.

Widget Responses

widget()

Creates a response that returns runtime data for an OpenAI Apps SDK widget. Used in conjunction with the widget config on your tool definition.
The widget() helper only handles runtime data. Widget configuration (name, invoking status, etc.) must be set on the tool’s widget config property at registration time.
import { widget, text } from "mcp-use/server";
import z from "zod";

server.tool(
  {
    name: "show-weather",
    schema: z.object({ city: z.string() }),
    // Widget configuration goes here (registration-time)
    widget: {
      name: "weather-display", // Must match widget in resources/
      invoking: "Fetching weather data...",
      invoked: "Weather data loaded",
      widgetAccessible: true,
      resultCanProduceWidget: true,
    },
  },
  async ({ city }) => {
    const weatherData = await fetchWeather(city);

    // widget() helper returns runtime data only
    return widget({
      props: {
        city,
        temperature: weatherData.temp,
        conditions: weatherData.conditions,
        humidity: weatherData.humidity,
      },
      output: text(
        `Weather in ${city}: ${weatherData.temp}°C, ${weatherData.conditions}`
      ),
      message: `Showing weather for ${city}`,
    });
  }
);
Parameters:
  • props - Widget-only data passed to useWidget().props in your widget component (hidden from the model)
  • output - Optional response helper (text(), object(), etc.) that defines what the model sees
  • message - Optional text message override (used if no output provided)
Returns: CallToolResult with widget props in _meta["mcp-use/props"] and tool output in content
The widget name must match a .tsx file or folder in your resources/ directory. The widget will receive the props data via the useWidget() hook, while the model sees the output or message in the conversation.

Using Response Helpers in Prompts and Resources

Response helpers aren’t just for tools - they work seamlessly with prompts and resources too. The server automatically converts CallToolResult to the appropriate format (GetPromptResult for prompts, ReadResourceResult for resources), allowing you to use the same familiar API across all MCP primitives.

Prompts with Response Helpers

Instead of manually constructing message objects, you can use the same helpers you use in tools. The server automatically converts them to the required GetPromptResult format:
import { text, object, mix, image } from "mcp-use/server";
import { z } from "zod";

// Simple text prompt
server.prompt(
  {
    name: "greeting",
    description: "Generate a greeting message",
    schema: z.object({ name: z.string() }),
  },
  async ({ name }) => {
    return text(`Hello, ${name}! How can I help you today?`);
  }
);

// Structured data prompt
server.prompt(
  {
    name: "user_context",
    description: "Provide user context data",
    schema: z.object({ userId: z.string() }),
  },
  async ({ userId }) => {
    const userData = await fetchUser(userId);
    return object({
      userId: userData.id,
      email: userData.email,
      preferences: userData.preferences,
    });
  }
);

// Mixed content prompt
server.prompt(
  {
    name: "analysis_report",
    description: "Generate analysis report with visualization",
    schema: z.object({ dataId: z.string() }),
  },
  async ({ dataId }) => {
    const data = await fetchData(dataId);
    const chart = await generateChart(data);

    return mix(
      text("Analysis Report"),
      object({ summary: data.summary, metrics: data.metrics }),
      image(chart, "image/png")
    );
  }
);
How it works: When you return a response helper from a prompt handler, the server automatically converts it to a GetPromptResult with properly formatted messages. The content becomes message content, and any structured data is preserved.

Resources with Response Helpers

Resources fully support response helpers (you’ve seen examples throughout this guide). The automatic conversion ensures consistent behavior:
import { text, object, markdown } from "mcp-use/server";

// Text resource
server.resource(
  {
    name: "readme",
    uri: "doc://readme",
  },
  async () => markdown("# Welcome\n\nGetting started...")
);

// Structured resource
server.resource(
  {
    name: "config",
    uri: "config://app",
  },
  async () => object({ version: "1.0.0", features: ["auth", "api"] })
);

// Resource template with helpers
server.resourceTemplate(
  {
    name: "user_profile",
    uriTemplate: "user://{userId}/profile",
  },
  async (uri, { userId }) => {
    const profile = await fetchProfile(userId);
    return object(profile);
  }
);
Automatic Conversion: The server converts CallToolResult to ReadResourceResult format, extracting content and metadata appropriately. This means you can use the same response helpers for tools, prompts, and resources without worrying about format differences.
This unified API makes it easy to share response-building logic across tools, prompts, and resources. For example, a helper function that returns object() can be used in all three contexts.

Type Safety

Response helpers are fully typed for TypeScript users:
import { object, TypedCallToolResult } from "mcp-use/server";

// Type inference
const response = object({ userId: "123", name: "Alice" });
// response type: TypedCallToolResult<{ userId: string; name: string }>

// Explicit typing
interface UserData {
  userId: string;
  email: string;
  role: "admin" | "user";
}

function getUserResponse(user: UserData): TypedCallToolResult<UserData> {
  return object(user);
}

Next Steps

  • Tools - Learn about creating MCP tools
  • Resources - Managing static and dynamic content
  • Prompts - Building interactive prompts
  • UI Widgets - Creating OpenAI Apps SDK widgets