MCP Servers API

Register external MCP servers to extend voice agents with custom tools

MCP Servers API

Register external Model Context Protocol (MCP) servers to make their tools available to voice agents. When users speak naturally, the agent can call your tools automatically.

Base URL:https://api.ferni.ai/api/v2/developers/mcp-servers


Create MCP Server

Register a new MCP server.

POST /mcp-servers

Request Body

{
  "name": "my-crm-tools",
  "description": "CRM integration for customer lookups",
  "transport": "http",
  "endpoint": "https://mcp.yourcompany.com",
  "headers": {
    "X-API-Key": "{{secrets.CRM_API_KEY}}"
  },
  "secrets": {
    "CRM_API_KEY": "your-secret-key-here"
  },
  "autoConnect": true,
  "timeout": 30000
}

Parameters

FieldTypeRequiredDescription
namestringYesUnique identifier (kebab-case, e.g., my-crm-tools)
descriptionstringYesHuman-readable description shown in logs
transportstringYesConnection type: http, websocket, or stdio
endpointstringFor http/wsURL of your MCP server
commandstringFor stdioCommand to execute
argsstring[]For stdioCommand arguments
headersobjectNoHTTP headers (supports {{secrets.X}} interpolation)
secretsobjectNoSecret values (encrypted at rest with AES-256-GCM)
autoConnectbooleanNoConnect on agent startup (default: true)
timeoutnumberNoConnection timeout in ms (default: 30000)
personaIdstringNoLimit to specific persona (omit for all)

Response

{
  "success": true,
  "data": {
    "id": "mcp_lqx7abc_k3m9",
    "name": "my-crm-tools",
    "description": "CRM integration for customer lookups",
    "status": "active",
    "transport": "http",
    "endpoint": "https://mcp.yourcompany.com",
    "autoConnect": true,
    "enabled": true,
    "toolCount": 0,
    "createdAt": "2026-01-11T10:00:00Z",
    "updatedAt": "2026-01-11T10:00:00Z"
  }
}

cURL Example

curl -X POST https://api.ferni.ai/api/v2/developers/mcp-servers \
  -H "Authorization: Bearer pk_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-crm-tools",
    "description": "CRM integration",
    "transport": "http",
    "endpoint": "https://mcp.yourcompany.com"
  }'

List MCP Servers

Retrieve all registered MCP servers.

GET /mcp-servers

Query Parameters

FieldTypeDescription
statusstringFilter by status: active, error, disabled
limitnumberMax results (default: 50, max: 100)
offsetnumberPagination offset

Response

{
  "success": true,
  "data": [
    {
      "id": "mcp_lqx7abc_k3m9",
      "name": "my-crm-tools",
      "description": "CRM integration",
      "status": "active",
      "transport": "http",
      "endpoint": "https://mcp.yourcompany.com",
      "autoConnect": true,
      "enabled": true,
      "toolCount": 3,
      "lastConnected": "2026-01-11T10:05:00Z",
      "createdAt": "2026-01-11T10:00:00Z",
      "updatedAt": "2026-01-11T10:00:00Z"
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 50,
    "offset": 0
  }
}

Get MCP Server

Retrieve a specific MCP server by ID.

GET /mcp-servers/:id

Response

{
  "success": true,
  "data": {
    "id": "mcp_lqx7abc_k3m9",
    "name": "my-crm-tools",
    "description": "CRM integration",
    "status": "active",
    "transport": "http",
    "endpoint": "https://mcp.yourcompany.com",
    "headers": {
      "X-API-Key": "{{secrets.CRM_API_KEY}}"
    },
    "autoConnect": true,
    "enabled": true,
    "timeout": 30000,
    "toolCount": 3,
    "lastConnected": "2026-01-11T10:05:00Z",
    "lastError": null,
    "createdAt": "2026-01-11T10:00:00Z",
    "updatedAt": "2026-01-11T10:00:00Z"
  }
}

Note: Secret values are never returned in responses.


Update MCP Server

Update an existing MCP server. Only include fields you want to change.

PUT /mcp-servers/:id

Request Body

{
  "description": "Updated description",
  "timeout": 60000,
  "secrets": {
    "CRM_API_KEY": "new-secret-value"
  }
}

Secrets are merged, not replaced. To remove a secret, set it to null.

Response

{
  "success": true,
  "data": {
    "id": "mcp_lqx7abc_k3m9",
    "name": "my-crm-tools",
    "description": "Updated description",
    "timeout": 60000,
    "updatedAt": "2026-01-11T11:00:00Z"
  }
}

Delete MCP Server

Permanently remove an MCP server.

DELETE /mcp-servers/:id

Response

{
  "success": true,
  "data": {
    "deleted": true,
    "id": "mcp_lqx7abc_k3m9"
  }
}

Test Connection

Test connectivity to your MCP server and discover available tools.

POST /mcp-servers/:id/test

Successful Response

{
  "success": true,
  "data": {
    "connected": true,
    "latencyMs": 145,
    "serverInfo": {
      "name": "my-crm-tools",
      "version": "1.0.0"
    },
    "toolCount": 3,
    "tools": [
      {
        "name": "lookup_customer",
        "description": "Look up a customer by name or ID"
      },
      {
        "name": "create_ticket",
        "description": "Create a support ticket"
      },
      {
        "name": "list_orders",
        "description": "List recent orders for a customer"
      }
    ],
    "testedAt": "2026-01-11T10:05:00Z"
  }
}

Failed Response

{
  "success": true,
  "data": {
    "connected": false,
    "error": "Connection timeout after 30000ms",
    "testedAt": "2026-01-11T10:05:00Z"
  }
}

List Discovered Tools

Get the cached list of tools from an MCP server. Tools are discovered during the test operation.

GET /mcp-servers/:id/tools

Response

{
  "success": true,
  "data": [
    {
      "name": "lookup_customer",
      "description": "Look up a customer by name or ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Customer name or ID"
          }
        },
        "required": ["query"]
      }
    },
    {
      "name": "create_ticket",
      "description": "Create a support ticket",
      "inputSchema": {
        "type": "object",
        "properties": {
          "subject": { "type": "string" },
          "description": { "type": "string" },
          "priority": { "type": "string", "enum": ["low", "medium", "high"] }
        },
        "required": ["subject", "description"]
      }
    }
  ]
}

Transport Types

HTTP Transport

Most common for production. Your server must expose MCP protocol over HTTP.

{
  "transport": "http",
  "endpoint": "https://mcp.yourcompany.com",
  "headers": {
    "Authorization": "Bearer {{secrets.API_TOKEN}}"
  }
}

WebSocket Transport

For real-time bidirectional communication.

{
  "transport": "websocket",
  "endpoint": "wss://mcp.yourcompany.com/ws"
}

Stdio Transport

For local development or sidecar containers.

{
  "transport": "stdio",
  "command": "node",
  "args": ["./mcp-server.js"]
}

Secret Management

Secrets are stored encrypted and referenced using {{secrets.KEY}} syntax.

Storing Secrets

{
  "headers": {
    "X-API-Key": "{{secrets.MY_API_KEY}}"
  },
  "secrets": {
    "MY_API_KEY": "actual-secret-value"
  }
}

Security

  • Encrypted at rest using AES-256-GCM
  • Never returned in API responses
  • Decrypted only when connecting to your server
  • Rotatable without server restart

Status Values

StatusDescription
activeServer connected and healthy
errorLast connection attempt failed
disabledManually disabled by developer

Error Codes

CodeDescription
MCP_NAME_EXISTSServer name already registered
MCP_INVALID_ENDPOINTEndpoint URL is malformed
MCP_CONNECTION_FAILEDCould not connect to server
MCP_TIMEOUTConnection timed out
MCP_INVALID_RESPONSEServer didn't return valid MCP protocol

Best Practices

  1. Use meaningful names — acme-crm-tools not mcp-1
  2. Store secrets properly — Never hardcode in headers
  3. Test before enabling — Run /test to verify connectivity
  4. Set appropriate timeouts — Increase for slow servers
  5. Monitor tool count — If 0, tools weren't discovered

Related