Basic MCP Server
Create a simple MCP server with stdio transport:mcp-server.ts
import { MCPServer } from '@mastra/mcp';
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
const weatherTool = createTool({
id: 'getWeather',
description: 'Gets the current weather for a location',
inputSchema: z.object({
location: z.string()
}),
execute: async (input) => {
const response = await fetch(
`https://api.weather.com/v1/weather?q=${input.location}`
);
return response.json();
},
});
const server = new MCPServer({
name: 'Weather Server',
version: '1.0.0',
tools: {
weatherTool,
},
});
await server.startStdio();
node mcp-server.js
HTTP Server with Express
Create an HTTP-based MCP server:import http from 'node:http';
import { MCPServer } from '@mastra/mcp';
const server = new MCPServer({
name: 'My MCP Server',
version: '1.0.0',
tools: { /* tools */ },
});
const httpServer = http.createServer(async (req, res) => {
const url = new URL(req.url || '', `http://${req.headers.host}`);
await server.startSSE({
url,
ssePath: '/sse',
messagePath: '/message',
req,
res,
});
});
httpServer.listen(3000, () => {
console.log('MCP server running on http://localhost:3000/sse');
});
HTTP Server with Hono
Use Hono framework for modern HTTP handling:import { Hono } from 'hono';
import { MCPServer } from '@mastra/mcp';
const app = new Hono();
const server = new MCPServer({
name: 'Hono MCP Server',
version: '1.0.0',
tools: { /* tools */ },
});
app.all('*', async (c) => {
const url = new URL(c.req.url);
return await server.startHonoSSE({
url,
ssePath: '/hono-sse',
messagePath: '/message',
context: c,
});
});
export default app;
Streamable HTTP Transport
Use modern HTTP transport for better performance:import http from 'node:http';
import { MCPServer } from '@mastra/mcp';
import { randomUUID } from 'node:crypto';
const server = new MCPServer({
name: 'Streamable Server',
version: '1.0.0',
tools: { /* tools */ },
});
const httpServer = http.createServer(async (req, res) => {
await server.startHTTP({
url: new URL(req.url || '', 'http://localhost:3000'),
httpPath: '/mcp',
req,
res,
options: {
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (sessionId) => {
console.log(`New session: ${sessionId}`);
},
},
});
});
httpServer.listen(3000);
Serverless Mode
Deploy to serverless environments:export default {
async fetch(request: Request) {
const url = new URL(request.url);
if (url.pathname === '/mcp') {
await server.startHTTP({
url,
httpPath: '/mcp',
req: request,
res: response,
options: {
serverless: true // Stateless mode
},
});
}
return new Response('Not found', { status: 404 });
},
};
Converting Agents to Tools
Automatically expose agents as MCP tools:import { Agent } from '@mastra/core/agent';
import { MCPServer } from '@mastra/mcp';
const myAgent = new Agent({
id: 'helper',
name: 'Helper Agent',
description: 'A helpful assistant that answers questions',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-4o-mini',
});
const server = new MCPServer({
name: 'Agent Server',
version: '1.0.0',
tools: { /* regular tools */ },
agents: { myAgent }, // Becomes 'ask_myAgent' tool
});
Converting Workflows to Tools
Expose workflows as executable tools:import { Workflow } from '@mastra/core/workflows';
import { MCPServer } from '@mastra/mcp';
import { z } from 'zod';
const dataProcessingWorkflow = new Workflow({
id: 'process-data',
description: 'Process and transform data',
inputSchema: z.object({
data: z.array(z.any()),
}),
});
const server = new MCPServer({
name: 'Workflow Server',
version: '1.0.0',
workflows: {
dataProcessingWorkflow // Becomes 'run_dataProcessingWorkflow' tool
},
});
Exposing Resources
Provide access to data and content:const server = new MCPServer({
name: 'Data Server',
version: '1.0.0',
tools: { /* tools */ },
resources: {
// List available resources
listResources: async ({ extra }) => {
// Access MCP protocol context
const userId = extra?.meta?.userId;
return [
{
uri: 'file:///data/users.json',
name: 'User Database',
description: 'List of all users',
mimeType: 'application/json',
},
{
uri: 'file:///data/products.json',
name: 'Product Catalog',
description: 'Product information',
mimeType: 'application/json',
},
];
},
// Get resource content
getResourceContent: async ({ uri, extra }) => {
const content = await readFile(uri);
return {
text: content,
};
},
// Optional: Resource templates
resourceTemplates: async ({ extra }) => {
return [
{
uriTemplate: 'file:///data/{collection}.json',
name: 'Data Collection',
description: 'Access any data collection',
mimeType: 'application/json',
},
];
},
},
});
Resource Notifications
Notify clients about resource changes:const server = new MCPServer({
name: 'Live Data Server',
version: '1.0.0',
resources: {
listResources: async () => resources,
getResourceContent: async ({ uri }) => content,
},
});
// Notify about updated resource
await server.resources.notifyUpdated({
uri: 'file:///data/users.json'
});
// Notify that resource list changed
await server.resources.notifyListChanged();
// Example: Watch file changes
fs.watch('/data', async (event, filename) => {
await server.resources.notifyUpdated({
uri: `file:///data/${filename}`
});
});
Exposing Prompts
Share reusable prompt templates:const server = new MCPServer({
name: 'Prompt Server',
version: '1.0.0',
prompts: {
// List available prompts
listPrompts: async ({ extra }) => {
return [
{
name: 'code-review',
version: 'v1',
description: 'Review code for best practices',
arguments: [
{
name: 'code',
description: 'Code to review',
required: true
},
{
name: 'language',
description: 'Programming language',
required: true
},
],
},
{
name: 'summarize',
version: 'v1',
description: 'Summarize text content',
arguments: [
{
name: 'text',
description: 'Text to summarize',
required: true
},
],
},
];
},
// Get prompt messages
getPromptMessages: async ({ name, version, args, extra }) => {
if (name === 'code-review') {
return [
{
role: 'user',
content: {
type: 'text',
text: `Review this ${args.language} code for best practices:\n\n${args.code}`,
},
},
];
}
if (name === 'summarize') {
return [
{
role: 'user',
content: {
type: 'text',
text: `Summarize the following text:\n\n${args.text}`,
},
},
];
}
throw new Error(`Prompt not found: ${name}`);
},
},
});
Elicitation (Interactive Input)
Request user input during tool execution:const interactiveTool = createTool({
id: 'configure-service',
description: 'Configure a service with user input',
execute: async (input, context) => {
// Request input from user via MCP client
const result = await context?.mcp?.elicitation.sendRequest({
message: 'Please provide your email address',
requestedSchema: {
type: 'object',
properties: {
email: {
type: 'string',
format: 'email'
},
},
required: ['email'],
},
});
const email = result?.data?.email;
return { configured: true, email };
},
});
Error Handling
Handle errors gracefully in MCP servers:const resilientTool = createTool({
id: 'api-call',
description: 'Call external API',
execute: async (input) => {
try {
const response = await fetch(input.url);
return await response.json();
} catch (error) {
// Return error as MCP result
return {
content: [{
type: 'text',
text: `Error: ${error.message}`,
}],
isError: true,
};
}
},
});
Graceful Shutdown
Handle server shutdown properly:const server = new MCPServer({
name: 'My Server',
version: '1.0.0',
tools: { /* tools */ },
});
const httpServer = http.createServer(/* ... */);
process.on('SIGINT', async () => {
console.log('Shutting down server...');
await server.close();
httpServer.close(() => {
console.log('Server shutdown complete');
process.exit(0);
});
});
Testing MCP Servers
Test your MCP server:import { MCPClient } from '@mastra/mcp';
// Start server in test
const server = new MCPServer({ /* ... */ });
await server.startStdio();
// Connect client
const client = new MCPClient({
name: 'test-client',
version: '1.0.0',
server: {
command: 'node',
args: ['./mcp-server.js'],
},
});
await client.connect();
// Test tools
const tools = await client.tools();
const result = await tools.weatherTool?.execute?.({ location: 'NYC' });
expect(result).toHaveProperty('temperature');
await client.disconnect();
Next Steps
MCP Overview
Learn more about Model Context Protocol
Creating Tools
Build tools for your MCP server