Releases: VoltAgent/voltagent
@voltagent/[email protected]
Patch Changes
-
#883
9320326Thanks @omeraplak! - feat: add authNext and deprecate legacy authAdd a new
authNextpolicy that splits routes into public, console, and user access. All routes are protected by default; usepublicRoutesto opt out.AuthNext example:
import { jwtAuth } from "@voltagent/server-core"; import { honoServer } from "@voltagent/server-hono"; const server = honoServer({ authNext: { provider: jwtAuth({ secret: process.env.JWT_SECRET! }), publicRoutes: ["GET /health"], }, });
Behavior summary:
- When
authNextis set, all routes are private by default. - Console endpoints (agents, workflows, tools, docs, observability, updates) require a Console Access Key.
- Execution endpoints require a user token (JWT).
Console access uses
VOLTAGENT_CONSOLE_ACCESS_KEY:VOLTAGENT_CONSOLE_ACCESS_KEY=your-console-key
curl http://localhost:3141/agents \ -H "x-console-access-key: your-console-key"Legacy
authremains supported but is deprecated. UseauthNextfor new integrations. - When
-
Updated dependencies [
9320326]:- @voltagent/[email protected]
@voltagent/[email protected]
Patch Changes
-
#883
9320326Thanks @omeraplak! - feat: add authNext and deprecate legacy authAdd a new
authNextpolicy that splits routes into public, console, and user access. All routes are protected by default; usepublicRoutesto opt out.AuthNext example:
import { jwtAuth } from "@voltagent/server-core"; import { honoServer } from "@voltagent/server-hono"; const server = honoServer({ authNext: { provider: jwtAuth({ secret: process.env.JWT_SECRET! }), publicRoutes: ["GET /health"], }, });
Behavior summary:
- When
authNextis set, all routes are private by default. - Console endpoints (agents, workflows, tools, docs, observability, updates) require a Console Access Key.
- Execution endpoints require a user token (JWT).
Console access uses
VOLTAGENT_CONSOLE_ACCESS_KEY:VOLTAGENT_CONSOLE_ACCESS_KEY=your-console-key
curl http://localhost:3141/agents \ -H "x-console-access-key: your-console-key"Legacy
authremains supported but is deprecated. UseauthNextfor new integrations. - When
@voltagent/[email protected]
Patch Changes
-
b663dceThanks @omeraplak! - fix: dedupe MCP endpoints in server startup output and include MCP transport paths (streamable HTTP/SSE) so the actual server endpoint is visible. -
Updated dependencies [
b663dce]:- @voltagent/[email protected]
- @voltagent/[email protected]
@voltagent/[email protected]
Patch Changes
-
b663dceThanks @omeraplak! - fix: dedupe MCP endpoints in server startup output and include MCP transport paths (streamable HTTP/SSE) so the actual server endpoint is visible. -
Updated dependencies [
b663dce]:- @voltagent/[email protected]
@voltagent/[email protected]
Patch Changes
b663dceThanks @omeraplak! - fix: dedupe MCP endpoints in server startup output and include MCP transport paths (streamable HTTP/SSE) so the actual server endpoint is visible.
@voltagent/[email protected]
Minor Changes
-
#879
2f81e6dThanks @omeraplak! - feat: add VoltAgentRagRetriever to @voltagent/coreAdded
VoltAgentRagRetriever- a built-in retriever that connects to VoltAgent Knowledge Bases for fully managed RAG. No infrastructure setup required - just upload documents to the Console and start searching.Features
- Automatic context injection: Searches before each response and injects relevant context
- Tool-based retrieval: Use as a tool that the agent calls when needed
- Tag filtering: Filter results by custom document tags
- Source tracking: Access retrieved chunk references via
rag.referencescontext
Usage
import { Agent, VoltAgentRagRetriever } from "@voltagent/core"; import { openai } from "@ai-sdk/openai"; const retriever = new VoltAgentRagRetriever({ knowledgeBaseName: "my-docs", topK: 8, includeSources: true, }); // Option 1: Automatic context injection const agent = new Agent({ name: "RAG Assistant", model: openai("gpt-4o-mini"), retriever, }); // Option 2: Tool-based retrieval const agentWithTool = new Agent({ name: "RAG Assistant", model: openai("gpt-4o-mini"), tools: [retriever.tool], });
Configuration
Option Default Description knowledgeBaseNamerequired Name of your knowledge base topK8 Number of chunks to retrieve tagFiltersnull Filter by document tags includeSourcestrue Include document metadata includeSimilarityfalse Include similarity scores Environment Variables
VOLTAGENT_PUBLIC_KEY=pk_... VOLTAGENT_SECRET_KEY=sk_... # Optional VOLTAGENT_API_BASE_URL=https://api.voltagent.dev
@voltagent/[email protected]
Patch Changes
37be1edThanks @omeraplak! - fix: bump @voltagent/server-core dep
@voltagent/[email protected]
Minor Changes
-
#875
93c52ccThanks @omeraplak! - feat: add MCP client elicitation support for user input handlingAdded support for handling elicitation requests from MCP servers. When an MCP server needs user input during tool execution (e.g., confirmation dialogs, credentials, or form data), you can now dynamically register handlers to process these requests.
New API
Access the elicitation bridge via
mcpClient.elicitation:const clients = await mcpConfig.getClients(); // Set a persistent handler clients.myServer.elicitation.setHandler(async (request) => { console.log("Server asks:", request.message); console.log("Expected schema:", request.requestedSchema); const userConfirmed = await promptUser(request.message); return { action: userConfirmed ? "accept" : "decline", content: userConfirmed ? { confirmed: true } : undefined, }; }); // One-time handler (auto-removes after first call) clients.myServer.elicitation.once(async (request) => { return { action: "accept", content: { approved: true } }; }); // Remove handler clients.myServer.elicitation.removeHandler(); // Check if handler exists if (clients.myServer.elicitation.hasHandler) { console.log("Handler registered"); }
Agent-Level Elicitation
Pass elicitation handler directly to
generateTextorstreamText:const response = await agent.generateText("Do something with MCP", { userId: "user123", elicitation: async (request) => { // Handler receives elicitation request from any MCP tool const confirmed = await askUser(request.message); return { action: confirmed ? "accept" : "decline", content: confirmed ? { confirmed: true } : undefined, }; }, });
This handler is automatically applied to all MCP tools during the request.
Key Features
- Dynamic handler management: Add, replace, or remove handlers at runtime
- One-time handlers: Use
.once()for handlers that auto-remove after first invocation - Method chaining: All methods return
thisfor fluent API usage - Auto-cancellation: Requests without handlers are automatically cancelled
- Agent-level integration: Pass handler via
generateText/streamTextoptions - Full MCP SDK compatibility: Uses
ElicitRequestandElicitResulttypes from@modelcontextprotocol/sdk
Exports
New exports from
@voltagent/core:MCPClient- MCP client with elicitation supportUserInputBridge- Bridge class for handler managementUserInputHandler- Handler function type
@voltagent/[email protected]
Minor Changes
-
#870
63cade8Thanks @omeraplak! - feat: add authorization layer for MCP toolsAdd a
canfunction toMCPConfigurationthat lets you control which MCP tools users can discover and execute. Supports both tool discovery filtering and execution-time checks.Usage
import { MCPConfiguration, type MCPCanParams } from "@voltagent/core"; const mcp = new MCPConfiguration({ servers: { expenses: { type: "http", url: "http://localhost:3142/mcp" }, }, authorization: { can: async ({ toolName, action, userId, context }: MCPCanParams) => { const roles = (context?.get("roles") as string[]) ?? []; // action is "discovery" (getTools) or "execution" (tool call) if (toolName === "delete_expense" && !roles.includes("admin")) { return { allowed: false, reason: "Admin only" }; } return true; }, filterOnDiscovery: true, // Hide unauthorized tools from tool list checkOnExecution: true, // Verify on each tool call }, }); // Get tools filtered by user's permissions const tools = await mcp.getTools({ userId: "user-123", context: { roles: ["manager"] }, });
MCPCanParamsinterface MCPCanParams { toolName: string; // Tool name (without server prefix) serverName: string; // MCP server identifier action: "discovery" | "execution"; // When the check is happening arguments?: Record<string, unknown>; // Tool arguments (execution only) userId?: string; context?: Map<string | symbol, unknown>; }
Cerbos Integration
For production use with policy-based authorization:
import { GRPC } from "@cerbos/grpc"; const cerbos = new GRPC("localhost:3593", { tls: false }); const mcp = new MCPConfiguration({ servers: { expenses: { type: "http", url: "..." } }, authorization: { can: async ({ toolName, serverName, userId, context }) => { const roles = (context?.get("roles") as string[]) ?? ["user"]; const result = await cerbos.checkResource({ principal: { id: userId ?? "anonymous", roles }, resource: { kind: `mcp::${serverName}`, id: serverName }, actions: [toolName], }); return { allowed: result.isAllowed(toolName) ?? false }; }, filterOnDiscovery: true, checkOnExecution: true, }, });
See the full Cerbos example: examples/with-cerbos
@voltagent/[email protected]
Patch Changes
-
#865
77833b8Thanks @omeraplak! - fix: make GET /tools endpoint public when auth is enabledPreviously,
GET /toolswas listed inPROTECTED_ROUTES, requiring authentication even though it only returns tool metadata (name, description, parameters). This was inconsistent withGET /agentsandGET /workflowswhich are publicly accessible for discovery.Changes
- Moved
GET /toolsfromPROTECTED_ROUTEStoDEFAULT_PUBLIC_ROUTES - Tool execution (
POST /tools/:name/execute) remains protected and requires authentication
This allows VoltOps Console and other clients to discover available tools without authentication, while still requiring auth to actually execute them.
- Moved