Skip to content

Commit 6b3ef73

Browse files
committed
feat: enhance MCP server with new agent capabilities and documentation updates
1 parent 275149e commit 6b3ef73

File tree

10 files changed

+64
-44
lines changed

10 files changed

+64
-44
lines changed

examples/with-mcp-server/src/index.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,26 @@ const approvalTool = createTool({
7777
},
7878
});
7979

80+
const storyWriter = new Agent({
81+
name: "StoryWriterAgent",
82+
instructions: "You are a creative story writer.",
83+
model: openai("gpt-4o-mini"),
84+
});
85+
86+
const translatorAgent = new Agent({
87+
name: "TranslatorAgent",
88+
instructions: "You are a skilled translator.",
89+
model: openai("gpt-4o-mini"),
90+
});
91+
92+
const supervisorAgent = new Agent({
93+
name: "SupervisorAgent",
94+
instructions:
95+
"You are a supervisor agent that delegates tasks to specialized agents. Use the `StoryWriterAgent` agent for creative writing tasks and the `TranslatorAgent` agent for translation tasks. Always choose the most appropriate agent for the given task.",
96+
model: openai("gpt-4o-mini"),
97+
subAgents: [storyWriter, translatorAgent],
98+
});
99+
80100
const assistant = new Agent({
81101
name: "AssistantAgent",
82102
instructions:
@@ -171,7 +191,7 @@ const mcpServer = new MCPServer({
171191
protocols: {
172192
stdio: true,
173193
http: true,
174-
sse: false,
194+
sse: true,
175195
},
176196
filterTools: ({ items }) => {
177197
return items;
@@ -248,6 +268,9 @@ const mcpServer = new MCPServer({
248268

249269
new VoltAgent({
250270
agents: {
271+
supervisorAgent,
272+
translatorAgent,
273+
storyWriter,
251274
assistant,
252275
},
253276
mcpServers: {

examples/with-mcp/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const mcpConfig = new MCPConfiguration({
1616
filesystem: {
1717
type: "stdio",
1818
command: "npx",
19-
args: ["-y", "@modelcontextprotocol/server-filesystem", path.resolve("./data")],
19+
args: ["-y", "mcp-remote", "http://localhost:3141/mcp/voltagent-example/mcp"],
2020
},
2121
},
2222
});

packages/core/src/voltagent.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import type { Agent } from "./agent/agent";
88
import { getGlobalLogger } from "./logger";
99
import { VoltAgentObservability } from "./observability/voltagent-observability";
1010
import { AgentRegistry } from "./registries/agent-registry";
11-
import type { Tool } from "./tool";
1211
import type { IServerProvider, VoltAgentOptions } from "./types";
1312
import { checkForUpdates } from "./utils/update";
1413
import { isValidVoltOpsKeys } from "./utils/voltops-validation";
@@ -463,6 +462,7 @@ export class VoltAgent {
463462
getAllAgents: () => this.registry.getAllAgents() as any,
464463
getAgent: (id: string) => this.registry.getAgent(id) as any,
465464
},
465+
getParentAgentIds: (agentId: string) => this.registry.getParentAgentIds(agentId),
466466
workflowRegistry: {
467467
getWorkflow: (id: string) => this.workflowRegistry.getWorkflow(id) as any,
468468
getAllWorkflows: () => this.workflowRegistry.getAllWorkflows() as any,
@@ -480,7 +480,6 @@ export class VoltAgent {
480480
resumeStepId,
481481
),
482482
},
483-
getTools: () => this.collectAllTools() as any,
484483
} as MCPServerDeps;
485484
}
486485

@@ -524,12 +523,4 @@ export class VoltAgent {
524523
this.a2aServers.delete(server);
525524
}
526525
}
527-
528-
private collectAllTools(): Tool[] {
529-
const tools: Tool[] = [];
530-
for (const agent of this.registry.getAllAgents()) {
531-
tools.push(...agent.getTools());
532-
}
533-
return tools;
534-
}
535526
}

packages/internal/src/mcp/registry.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import type { MCPServerDeps, MCPServerLike, MCPServerMetadata } from "./types";
22

3+
export interface RegisterOptions {
4+
startTransports?: boolean;
5+
transportOptions?: Record<string, unknown>;
6+
}
7+
38
export class MCPServerRegistry<TServer extends MCPServerLike = MCPServerLike> {
49
private readonly servers = new Set<TServer>();
510
private readonly idByServer = new Map<TServer, string>();

packages/internal/src/mcp/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface MCPServerDeps {
1515
getAllAgents(): unknown[];
1616
};
1717
workflowRegistry?: Record<string, unknown>;
18-
getTools?: () => unknown[];
18+
getParentAgentIds?: (agentId: string) => string[];
1919
logging?: unknown;
2020
prompts?: unknown;
2121
resources?: unknown;

packages/mcp-server/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ pnpm install
1616
pnpm build --filter @voltagent/mcp-server
1717
```
1818

19+
## Agent metadata
20+
21+
When an agent is exposed through MCP, its `purpose` field is used as the MCP tool description. Provide a concise, user-facing explanation in `purpose` so MCP clients display helpful copy. If `purpose` is empty, the adapter falls back to the agent instructions.
22+
1923
## License
2024

2125
MIT

packages/mcp-server/src/adapters/agent.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ interface AgentCallArgs {
1717
}
1818

1919
function toMcpTool(agent: Agent, name: string): MCPTool {
20+
const purpose = typeof agent.purpose === "string" ? agent.purpose.trim() : undefined;
21+
const instructions =
22+
typeof agent.instructions === "string" ? agent.instructions.trim() : undefined;
23+
const description =
24+
purpose && purpose.length > 0
25+
? purpose
26+
: instructions && instructions.length > 0
27+
? instructions
28+
: `VoltAgent agent ${agent.name}`;
29+
2030
const inputSchema = {
2131
type: "object",
2232
properties: {
@@ -49,7 +59,7 @@ function toMcpTool(agent: Agent, name: string): MCPTool {
4959
return {
5060
name,
5161
title: agent.name,
52-
description: agent.purpose ?? `VoltAgent agent ${agent.name}`,
62+
description,
5363
inputSchema: inputSchema as MCPTool["inputSchema"],
5464
annotations: {
5565
title: agent.name,

packages/mcp-server/src/server.ts

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -739,14 +739,6 @@ export class MCPServer {
739739
return this.deps;
740740
}
741741

742-
private collectToolsFromAgents(agents: Agent[]): Tool[] {
743-
const tools: Tool[] = [];
744-
for (const agent of agents) {
745-
tools.push(...agent.getTools());
746-
}
747-
return tools;
748-
}
749-
750742
private normalizeConfiguredAgents(agents: Record<string, Agent>): Agent[] {
751743
const map = new Map<string, Agent>();
752744
for (const agent of Object.values(agents)) {
@@ -886,7 +878,15 @@ export class MCPServer {
886878
}
887879
}
888880
const combinedAgents = Array.from(agentMap.values());
889-
const filteredAgents = this.getAgentFilter()({ items: combinedAgents, context });
881+
const topLevelAgents = combinedAgents.filter((agent) => {
882+
if (!agent.id || !deps.getParentAgentIds) {
883+
return true;
884+
}
885+
const parents = deps.getParentAgentIds(agent.id);
886+
return !parents || parents.length === 0;
887+
});
888+
889+
const filteredAgents = this.getAgentFilter()({ items: topLevelAgents, context });
890890

891891
const registeredWorkflows = deps.workflowRegistry.getAllWorkflows();
892892
const workflowSource = new Map<string, RegisteredWorkflow>();
@@ -930,25 +930,8 @@ export class MCPServer {
930930
}
931931
}
932932

933-
const collectedTools = this.collectToolsFromAgents(filteredAgents);
934933
const toolById = new Map<string, Tool>();
935934

936-
for (const tool of collectedTools) {
937-
const key = tool.id ?? tool.name;
938-
if (key && !toolById.has(key)) {
939-
toolById.set(key, tool);
940-
}
941-
}
942-
943-
if (deps.getTools) {
944-
for (const tool of deps.getTools()) {
945-
const key = tool.id ?? tool.name;
946-
if (key && !toolById.has(key)) {
947-
toolById.set(key, tool);
948-
}
949-
}
950-
}
951-
952935
for (const tool of this.configuredTools) {
953936
const key = tool.id ?? tool.name;
954937
if (key && !toolById.has(key)) {

packages/mcp-server/src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,13 @@ export interface MCPServerConfig {
121121
version: string;
122122
description?: string;
123123
protocols?: ProtocolConfig;
124-
filterTools?: FilterFunction<VoltTool>;
124+
filterTools?: FilterFunction<VoltTool<any, any>>;
125125
filterAgents?: FilterFunction<Agent>;
126126
filterWorkflows?: FilterFunction<WorkflowSummary>;
127127
capabilities?: MCPServerCapabilitiesConfig;
128128
agents?: Record<string, Agent>;
129129
workflows?: Record<string, MCPWorkflowConfigEntry>;
130-
tools?: Record<string, VoltTool>;
130+
tools?: Record<string, VoltTool<any, any>>;
131131
releaseDate?: string;
132132
packages?: MCPServerPackageInfo[];
133133
remotes?: MCPServerRemoteInfo[];
@@ -208,7 +208,7 @@ export interface MCPServerDeps extends BaseMCPServerDeps {
208208
error?: unknown;
209209
} | null>;
210210
};
211-
getTools?: () => VoltTool[];
211+
getParentAgentIds?: (agentId: string) => string[];
212212
logging?: MCPLoggingAdapter;
213213
prompts?: MCPPromptsAdapter;
214214
resources?: MCPResourcesAdapter;

website/docs/agents/mcp/mcp-server.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export const mcpServer = new MCPServer({
4242
});
4343
```
4444

45+
> 📘 **Tip:** When you expose agents through MCP, their `purpose` field becomes the tool description shown in clients. Keep it short and user-facing (fallback is the agent instructions if `purpose` is empty).
46+
4547
This minimal configuration:
4648

4749
- Names the server `voltagent-example` (used in URLs and IDE listings).
@@ -112,7 +114,9 @@ const statusTool = createTool({
112114

113115
const supportAgent = new Agent({
114116
name: "Support Agent",
115-
instructions: "Route customer tickets to the correct queue.",
117+
purpose: "Route customer tickets to the correct queue.",
118+
instructions:
119+
"Use internal knowledge to triage customer tickets and respond with routing guidance.",
116120
model: openai("gpt-4o-mini"),
117121
tools: [statusTool],
118122
});

0 commit comments

Comments
 (0)