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.
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