MCP Integration
Model Context Protocol (MCP) lets VoiceRail call tools in your systems. This is completely optional - VoiceRail works great without it.
MCP is Optional
Most use cases don't need MCP. VoiceRail's built-in AI handles conversations well, and you can use webhooks for custom reasoning. MCP is best when you need to integrate with external systems (CRMs, databases, APIs) during calls.
What is MCP?
The Model Context Protocol is an open standard for connecting AI models to external tools and data sources. With VoiceRail + MCP:
- Your MCP server defines available tools
- VoiceRail decides when to call tools based on conversation
- Tool results are woven naturally into the dialogue
- Hold music plays automatically during long tool calls
Organization-Level Configuration
MCP servers are configured at the organization level, making tools available to all assistants in your organization:
# Configure MCP servers at the organization level
curl -X PATCH https://api.voicerail.ai/v1/organizations/{org_id} \
-H "Authorization: Bearer $VOICERAIL_KEY" \
-H "X-Organization-Id: $ORG_ID" \
-H "Content-Type: application/json" \
-d '{
"mcpServers": [
{
"id": "crm-tools",
"name": "CRM Tools",
"transportType": "Http",
"httpEndpoint": "https://your-mcp-server.com",
"authentication": {
"type": "Bearer",
"bearerToken": "your-secret-token"
},
"isEnabled": true,
"timeoutSeconds": 30
}
]
}'Server Configuration Fields
id- Unique identifier for this servername- Human-readable nametransportType-HttporStdiohttpEndpoint- Server URL (for HTTP transport)authentication- Auth config (Bearer or OAuth2)isEnabled- Toggle server on/offtimeoutSeconds- Operation timeout (default: 30)
Transport Types
MCP supports two transport mechanisms:
| Transport | Use Case | Configuration |
|---|---|---|
| Http | Production - remote MCP servers | Set httpEndpoint + authentication |
| Stdio | Development - local processes | Set command + arguments |
Stdio Example (Local Development)
{
"mcpServers": [
{
"id": "local-tools",
"name": "Local Development Tools",
"transportType": "Stdio",
"command": "npx",
"arguments": ["-y", "@your-org/mcp-server"],
"isEnabled": true,
"timeoutSeconds": 30
}
]
}Authentication
HTTP transport supports multiple authentication methods:
| Type | Fields |
|---|---|
| None | No additional fields (local/trusted only) |
| Bearer | bearerToken |
| OAuth2 | tokenEndpoint, clientId, clientSecret, scopes |
Building an MCP Server
Use the official MCP SDK to create a server that exposes your tools:
import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
const server = new Server({
name: "customer-service-tools",
version: "1.0.0"
});
// Define available tools
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "lookup_customer",
description: "Look up customer information by phone number or account ID",
inputSchema: {
type: "object",
properties: {
phone: { type: "string", description: "Customer phone number" },
account_id: { type: "string", description: "Customer account ID" }
}
}
},
{
name: "check_order_status",
description: "Check the status of an order",
inputSchema: {
type: "object",
properties: {
order_id: { type: "string", description: "Order ID to look up" }
},
required: ["order_id"]
}
}
]
}));
// Handle tool calls
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "lookup_customer":
const customer = await db.customers.findOne({
$or: [{ phone: args.phone }, { accountId: args.account_id }]
});
return { content: [{ type: "text", text: JSON.stringify(customer) }] };
case "check_order_status":
const order = await db.orders.findOne({ orderId: args.order_id });
return { content: [{ type: "text", text: JSON.stringify(order) }] };
default:
throw new Error(`Unknown tool: ${name}`);
}
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);Tool Call Flow
Here's how a tool call flows through the system:
// 1. User says: "Where's my order 12345?"
// 2. VoiceRail recognizes tool need, calls your MCP server:
{
"method": "tools/call",
"params": {
"name": "check_order_status",
"arguments": { "order_id": "12345" }
}
}
// 3. Your server returns:
{
"content": [{
"type": "text",
"text": "{ \"status\": \"shipped\", \"carrier\": \"UPS\", \"tracking\": \"1Z999...\" }"
}]
}
// 4. VoiceRail speaks: "Your order 12345 has shipped via UPS.
// Would you like the tracking number?"MCP vs Webhooks
Both are optional. Choose based on your needs:
| Aspect | Webhook | MCP |
|---|---|---|
| Control | You decide what to do with each utterance | VoiceRail decides when to call tools |
| Best for | Complex business logic, custom LLMs | Simple tool calls, integrations |
| Scope | Per-assistant configuration | Organization-wide configuration |
| Hold music | Plays during webhook calls >3s | Plays during tool calls >3s |
Tool Design Guidelines
Clear Names
Use descriptive names like check_order_status notcos. The model uses names to decide when to call tools.
Good Descriptions
Tool descriptions help the model understand when to use each tool. Be specific about what the tool does and what inputs it needs.
Simple Inputs
Keep input schemas simple. Prefer strings and numbers over complex nested objects. The model extracts these from conversation.
Fast Response
Keep tool calls under 3 seconds when possible. Longer calls trigger hold music, which is fine but feels slower to callers.
Next steps
- • Compare with webhook integration
- • Configure hold music for long tool calls
- • Create your first assistant