MCP Servers | Rasa Documentation

Build your first agent in just a few minutes with Rasa Copilot.

New Beta Feature in 3.14

Rasa supports native integration of MCP servers.

This feature is in a beta (experimental) stage and may change in future Rasa versions. We welcome your feedback on this feature.

MCP servers allow your Rasa agent to connect to external services and APIs through the Model Context Protocol. These servers expose tools that your agent can use directly in flows or provide to autonomous sub agents for dynamic decision-making.

Basic Configuration

MCP servers are configured in your endpoints.yml file.

mcp_servers:
  - name: trade_server
    url: http://localhost:8080
    type: http

The following fields are required:

Multiple MCP Servers

You can configure multiple MCP servers to connect to different services:

mcp_servers:
  - name: inventory_server
    url: http://localhost:8080
    type: http
  - name: payment_server
    url: https://api.payment-service.com
    type: https
  - name: customer_database
    url: http://localhost:9000
    type: http

Each server can expose different tools and be used independently in your flows or by different sub agents. Server names must be unique across all MCP servers. If you attempt to configure multiple servers with the same name, Rasa will raise a validation error during startup.

Authentication

MCP servers support multiple authentication methods for connecting to external services:

Authentication settings are specified using additional parameters in your MCP server configuration.

mcp_servers:
  - name: secure_api_server
    url: https://api.example.com
    type: https
    api_key: "${API_KEY}"
mcp_servers:
  - name: custom_header_server
    url: https://api.example.com
    type: https
    api_key: "${API_KEY}"
    header_name: "X-API-Key"
    header_format: "{key}"
mcp_servers:
  - name: oauth_server
    url: https://api.example.com
    type: https
    oauth:
      client_id: "${CLIENT_ID}"
      client_secret: "${CLIENT_SECRET}"
      token_url: "https://auth.example.com/oauth/token"
      scope: "read:data write:data"
mcp_servers:
  - name: token_server
    url: https://api.example.com
    type: https
    token: "${ACCESS_TOKEN}"

The $ syntax is required for the following sensitive parameters:

This ensures that they are not stored in plain text in your configuration files. For other parameters like client_id, using the $ syntax is optional — you can either reference an environment variable using the $ syntax or provide the value directly in the configuration.

Advanced Configuration

Custom Headers

You can specify custom headers for API key authentication:

mcp_servers:
  - name: custom_auth_server
    url: https://api.example.com
    type: https
    api_key: "${API_KEY}"
    header_name: "X-Custom-Auth"
    header_format: "Bearer {key}"

OAuth 2.0 Scopes

For OAuth 2.0 authentication, you can optionally pass in scope, audience, and timeout:

mcp_servers:
  - name: oauth_server_with_scopes
    url: https://api.example.com
    type: https
    oauth:
      client_id: "${CLIENT_ID}"
      client_secret: "${CLIENT_SECRET}"
      token_url: "https://auth.example.com/oauth/token"
      scope: "read:users write:orders admin:settings" # Optional: scopes for the OAuth 2.0 token
      audience: "https://api.example.com" # Optional: audience for the OAuth 2.0 token
      timeout: 10 # Optional: timeout for the OAuth 2.0 token

Complete Example

Here's a comprehensive example showing multiple MCP servers with different authentication methods:

mcp_servers:
  # Public API with API key
  - name: weather_service
    url: https://api.weather.com
    type: https
    api_key: "${WEATHER_API_KEY}"

# Internal service with OAuth
  - name: internal_database
    url: https://db.internal.com
    type: https
    oauth:
      client_id: "${DB_CLIENT_ID}"
      client_secret: "${DB_CLIENT_SECRET}"
      token_url: "https://auth.internal.com/oauth/token"
      scope: "database:read database:write"

# Local development server
  - name: local_tools
    url: http://localhost:8080
    type: http

# Service with custom header authentication
  - name: custom_auth_server
    url: https://api.example.com
    type: https
    api_key: "${API_KEY}"
    header_name: "X-API-Key"
    header_format: "{key}"

Call-time credential hooks (pre_call_hook)

Call-time credential hooks resolve per-conversation secrets only when an outbound MCP tool call is about to be made. Rasa invokes your hook, merges the returned metadata into MCP _meta, and never writes secret values to slots, the tracker, Kafka, or the Inspector.

Use pre_call_hook when credentials are:

The hook applies to:

Flows and sub agents reference MCP servers by name only. There is no pre_call_hook on individual flow steps or per sub-agent connection entries — configure the hook in each MCP server entry in endpoints.yml.

mcp_servers:
  - name: appointment_booking
    url: http://appointment-booking:8000/mcp/
    type: http
    pre_call_hook: custom.call_time_credentials.resolve_appointment_booking_meta
    meta_map:
      static:
        api_version: "v2"

When both meta_map and pre_call_hook are set, static meta_map is merged first; hook metadata wins on key collision.

Hook contract

Add pre_call_hook as a dotted import path to a module-level sync or async function. Use async def when the hook performs I/O (for example fetching from a secret store). Import types from rasa.shared.agents.outbound_call_hook:

from rasa.shared.agents.outbound_call_hook import (
    MCPOutboundCallContext,
    OutboundCallResult,
)

Rasa calls the hook as hook(context) and passes a frozen, read-only MCPOutboundCallContext:

Field Description
sender_id Conversation id — use as your secret-store lookup key
tool_name Tool being called (flow call step, MCP tool name, or custom tool name)
server_name MCP server name for flow / ReAct MCP calls; None for custom tools
flow_id, step_id Set for direct MCP tool calls in flows; otherwise None
agent_id Sub-agent id for ReAct MCP calls; otherwise None

The hook must return an OutboundCallResult with a metadata dict. OutboundCallResult has a single metadata field; Rasa merges it onto the wire. For convenience, a plain dict is accepted and normalized to OutboundCallResult(metadata=...). Never put secrets in flow mapping.input or tool argument mappings.

Passing metadata to tools (meta_map)

Remote MCP tool calls can include a protocol-level _meta object (when supported by your MCP client SDK) so the server receives context that does not appear in the tool arguments the LLM fills. In Rasa, this is configured per server with optional meta_map in endpoints.yml:

When both meta_map and pre_call_hook are set, static meta_map is merged first; hook metadata wins on key collision.

mcp_servers:
  - name: internal_api
    url: http://internal-api:8000/mcp/
    meta_map:
      from_slots:
        - slot: user_id
          param: user_id
        - slot: role
          param: user_role
      static:
        api_version: "v2"
        source: "rasa_agent"

If meta_map is omitted or has no from_slots entries, Rasa still sends any static entries. Slot values are read from the same agent input used for the ReAct turn; ensure the slot is set before the tool runs if you map it in from_slots.

Older MCP Python SDK releases that do not support a meta parameter on call_tool are still supported: Rasa detects this and falls back to calling without metadata so tools keep working; once the SDK supports meta, metadata is sent automatically.

Validation

Rasa validates MCP server configurations to ensure:

If validation fails, Rasa will provide specific error messages to help you fix the configuration.