VoltAgent MCP Server
Follow these steps to expose your VoltAgent project over MCP so you can browse tools, prompts, and resources from VoltOps Console (https://console.voltagent.dev/mcp) or an MCP-compatible IDE.
1. Install the MCP server package
- pnpm
- npm
- yarn
pnpm add @voltagent/mcp-server
npm install @voltagent/mcp-server
yarn add @voltagent/mcp-server
2. Create an MCP server instance
import { MCPServer } from "@voltagent/mcp-server";
export const mcpServer = new MCPServer({
name: "voltagent-example",
version: "0.1.0",
description: "VoltAgent MCP example",
});
📘 Tip: When you expose agents through MCP, their
purposefield becomes the tool description shown in clients. Keep it short and user-facing (fallback is the agent instructions ifpurposeis empty).
This minimal configuration:
- Names the server
voltagent-example(used in URLs and IDE listings). - Registers server metadata so clients can discover it even before you add tools/agents.
- Enables all transports (
stdio,http,sse) by default. Overrideprotocolsto disable transports you do not need.
export const mcpServer = new MCPServer({
name: "voltagent-example",
version: "0.1.0",
description: "VoltAgent MCP stdio example",
protocols: {
stdio: true,
http: false,
sse: false,
},
});
The snippet above shows how to run in stdio-only mode (ideal for IDE integrations or command-line tooling).
3. Register the server with VoltAgent
import { VoltAgent } from "@voltagent/core";
import { honoServer } from "@voltagent/server-hono";
import { mcpServer } from "./mcp/server";
import { assistant } from "./agents/assistant";
import { expenseApprovalWorkflow } from "./workflows/expense";
import { logger } from "./logger";
export const voltAgent = new VoltAgent({
agents: {
assistant,
},
workflows: {
expenseApprovalWorkflow,
},
mcpServers: {
mcpServer,
},
server: honoServer({ port: 3141 }),
logger,
});
mcpServersregisters your MCP server alongside the agent/workflow registries.- Passing
server: honoServer(...)makes VoltAgent expose MCP HTTP and SSE routes automatically. With the server running, visithttps://console.voltagent.dev/mcpto browse, invoke, and debug tools.
4. Find the MCP endpoint (HTTP + SSE)
When you start the VoltAgent server, MCP transport endpoints are exposed per server ID:
- Streamable HTTP:
POST /mcp/{serverId}/mcp - SSE (if enabled):
GET /mcp/{serverId}/sseandPOST /mcp/{serverId}/messages
The {serverId} is a normalized version of the name (lowercased, spaces replaced) and may get a numeric suffix if there are duplicates. You can always discover it via the registry endpoint:
curl http://localhost:3141/mcp/servers
Example response (trimmed):
{
"servers": [
{
"id": "voltagent-example",
"name": "voltagent-example",
"version": "0.1.0"
}
]
}
Once you have the id, the HTTP MCP URL becomes:
http://localhost:3141/mcp/voltagent-example/mcp
5. Connect via stdio (local process)
STDIO does not use an HTTP URL. The MCP client spawns your server process and communicates over stdin/stdout. In the startup log you should see a line like:
STDIO uses stdin/stdout. Example client: { type: "stdio", command: "node", args: ["dist/index.js"] }
Client example (MCPClient):
import { MCPClient } from "@voltagent/core";
const client = new MCPClient({
clientInfo: { name: "local-client", version: "0.1.0" },
server: {
type: "stdio",
command: "node",
args: ["dist/index.js"],
cwd: process.cwd(),
env: { ...process.env },
},
});
await client.connect();
const tools = await client.listTools();
Replace command/args with the entry that starts your VoltAgent + MCP server (for example pnpm start -- --stdio or node dist/index.js after build).
6. Connect via HTTP
Use the MCP URL in MCPConfiguration:
import { MCPConfiguration } from "@voltagent/core";
const mcpConfig = new MCPConfiguration({
servers: {
local: {
type: "http",
url: "http://localhost:3141/mcp/voltagent-example/mcp",
},
},
});
const tools = await mcpConfig.getTools();
7. Optional: add MCP-only entries
Sometimes you want MCP clients to see helpers that are not (yet) registered with VoltAgent. Provide them as keyed objects (just like the main VoltAgent config) via the agents, workflows, or tools fields to append entries that live only on the MCP side:
import { openai } from "@ai-sdk/openai";
import { Agent, createTool, createWorkflowChain } from "@voltagent/core";
import { MCPServer } from "@voltagent/mcp-server";
import { z } from "zod";
const statusTool = createTool({
name: "status",
description: "Return the current time",
parameters: z.object({}),
async execute() {
return { status: "ok", time: new Date().toISOString() };
},
});
const supportAgent = new Agent({
name: "Support Agent",
purpose: "Route customer tickets to the correct queue.",
instructions:
"Use internal knowledge to triage customer tickets and respond with routing guidance.",
model: openai("gpt-4o-mini"),
tools: [statusTool],
});
const incidentWorkflow = createWorkflowChain({
id: "incident-triage",
name: "Incident Triage",
purpose: "Placeholder entry for an external workflow.",
input: z.object({ ticketId: z.string() }),
}).andThen({
id: "acknowledge",
execute: async ({ data }) => ({ ...data, acknowledged: true }),
});
export const mcpServer = new MCPServer({
name: "voltagent-example",
version: "0.1.0",
description: "VoltAgent MCP stdio example",
tools: {
statusTool,
},
agents: {
supportAgent,
},
workflows: {
incidentWorkflow,
},
});
These configured entries behave like regular VoltAgent components for MCP clients, they appear in listings and can be invoked-yet they are not registered with the main VoltAgent instance.
8. Optional: filter exposed agents/workflows/tools
By default, every agent, workflow, and tool registered with VoltAgent is visible to MCP clients. Provide filter functions when you need to hide or reorder the registry output for a specific transport:
export const mcpServer = new MCPServer({
name: "voltagent-example",
version: "0.1.0",
description: "VoltAgent MCP stdio example",
filterAgents: ({ items }) => items.filter((agent) => agent.id !== "internal"),
filterWorkflows: ({ items }) => items,
filterTools: ({ items }) => items,
});
Filters receive the list of components sourced from the VoltAgent registries (plus any configured additions) and must return the array you want to expose. They are intended for pruning or sorting, use the agents/workflows/tools fields when you need to introduce brand-new entries.
9. Optional: stream prompts and resources
MCP clients can ask a server for structured prompt templates (prompts/list, prompts/get) and arbitrary resources (resources/list, resources/read). VoltAgent lets you seed static content and/or forward to a dynamic source via the new adapters field:
import { MCPServer } from "@voltagent/mcp-server";
// Replace these placeholders with your own services or data sources
const voltOps = {
prompts: {
list: async () => [
{
name: "triage",
description: "Short ticket triage message",
arguments: [],
},
],
get: async (name: string, version?: string) => ({
description: `Prompt ${name}`,
messages: [{ role: "user", content: { type: "text", text: "Summarise ticket {{id}}" } }],
version,
}),
},
};
const knowledgeBase = {
list: async () => [
{
uri: "volt://docs/runbook",
name: "On-call runbook",
description: "Operational checklist",
mimeType: "text/markdown",
},
],
read: async (uri: string) => ({
uri,
mimeType: "text/markdown",
text: "# On-call runbook\n...",
}),
};
export const mcpServer = new MCPServer({
name: "voltagent-example",
version: "0.1.0",
description: "VoltAgent MCP with prompts/resources",
adapters: {
prompts: {
listPrompts: async () => voltOps.prompts.list(),
getPrompt: async (params) => voltOps.prompts.get(params.name, params.version),
},
resources: {
listResources: async () => knowledgeBase.list(),
readResource: async (uri) => knowledgeBase.read(uri),
},
},
});
- The
adaptersblock forwards MCP requests to any backend (VoltOps Prompt Manager, a documentation service, your own REST API). - When you change external data, call
await mcpServer.notifyPromptListChanged()orawait mcpServer.notifyResourceListChanged()so connected IDEs receive the standardlist_changednotifications. If you update a specific resource at runtime, invokeawait mcpServer.notifyResourceUpdated("volt://docs/runbook")to push an incremental update only to subscribers. - If an adapter provides a
sendRequestmethod, MCP clients can makeelicitation/createcalls. VoltAgent forwards these requests to the adapter so you can collect data from the user and return anElicitResult. Tools can consume the bridge viaoperationContext.elicitation:
const confirmAction = createTool({
name: "confirm-action",
description: "Ask the operator to approve a risky step",
parameters: z.object({ description: z.string() }),
async execute(args, operationContext) {
const handler = operationContext?.elicitation;
if (!handler) {
throw new Error("Elicitation bridge unavailable");
}
return handler({
schema: {
type: "object",
properties: {
confirmed: { type: "boolean" },
},
required: ["confirmed"],
},
message: `Approve the following action: ${args.description}`,
});
},
});
That’s it! Your VoltAgent stack now speaks MCP. Start the agent, open VoltOps Console (or your preferred MCP client), and you’ll see the server listed with its tools, prompts, resources, and workflows ready to debug.