Agentic Data Plane
Preview

Exa Managed MCP Server

Give your AI agents web search, page contents, and research through the Exa managed MCP server. Connect each caller’s Exa account through an OAuth provider to use those tools without distributing a shared API key.

After reading this page, you will be able to:

  • Register an Exa public OAuth client with your gateway’s callback URL

  • Configure the Exa managed MCP server with per-user OAuth

  • Run web searches and research with an explicit per-run budget

Prerequisites

Exa tool calls can incur charges. Review Exa pricing before testing. The research budget on this page applies to each research run, not to searches, content retrieval, or total account spending.

Register an Exa public client

Obtain the OAuth client ID through Exa’s dynamic client registration endpoint. You do not need an Exa API key or a client secret for this registration. The client ID identifies your application. Each caller authorizes their own account separately.

Exa publishes its endpoints and supported OAuth settings in its authorization-server metadata.

  1. Open Integrations setup in the sidebar, select Outbound providers, and click Add provider.

  2. Select Custom Provider and copy the Authorization callback URL. Use the complete value, including /oauth/v1/callback. Do not substitute the Agentic Data Plane browser address or an Exa URL. Close the form without saving. You create the provider with the CLI in Create the OAuth provider.

  3. Set the callback URL in your shell:

    export EXA_REDIRECT_URI='<gateway-callback-url>'

    Replace <gateway-callback-url> with the exact Authorization callback URL you copied. Register the callback for the same gateway your CLI targets.

  4. Register the public client and capture its client ID:

    EXA_CLIENT_ID=$(
      jq -n --arg redirect "$EXA_REDIRECT_URI" '{
        client_name: "Redpanda Exa",
        redirect_uris: [$redirect],
        grant_types: ["authorization_code", "refresh_token"],
        response_types: ["code"],
        token_endpoint_auth_method: "none",
        scope: "mcp:tools"
      }' |
      curl --fail-with-body -sS https://auth.exa.ai/api/oauth/register \
        -H 'Content-Type: application/json' --data-binary @- |
      jq -er '.client_id'
    )
    export EXA_CLIENT_ID

    A successful response contains client_id, which the command stores in EXA_CLIENT_ID. Save this value for the provider configuration. If registration fails, resolve the error before continuing. Do not use an API key, a user access token, or an Agentic Data Plane inbound OAuth client ID in its place.

Create the OAuth provider

Create a manually configured OAuth provider for the managed Exa integration. This server calls Exa’s REST API. It does not proxy Exa’s hosted MCP server.

Do not choose Discover from MCP server URL or use --register-from-url for this managed server. A provider discovered from Exa’s hosted MCP URL is bound to that remote server’s origin. Tool calls through the managed Exa integration fail when they use that provider.

Run this command in the shell that holds EXA_CLIENT_ID:

rpk ai oauth-provider create exa \
  --display-name Exa \
  --authorization-endpoint https://auth.exa.ai/oauth/authorize \
  --token-endpoint https://auth.exa.ai/api/oauth/token \
  --revocation-endpoint https://auth.exa.ai/api/oauth/revoke \
  --client-id "$EXA_CLIENT_ID" \
  --scopes mcp:tools \
  --grant-types oauth-grant-type-browser-consent \
  --pkce-required \
  --token-endpoint-auth-method oauth-token-endpoint-auth-method-none \
  --extra-auth-params resource=https://mcp.exa.ai/mcp \
  --extra-token-params resource=https://mcp.exa.ai/mcp \
  --enabled

This configuration uses browser consent with Proof Key for Code Exchange (PKCE), the mcp:tools scope, and no client secret. Leave Client secret reference empty. Keep the resource parameter in both authorization and token requests. The value https://mcp.exa.ai/mcp is the OAuth resource, not the callback URL or the managed server’s address.

Create the managed server

Attach the exa provider and explicitly set a research budget of $1 per run:

rpk ai mcp-server create exa \
  --enabled \
  --description 'Exa web search and research as the connected user' \
  --managed.config '{
    "@type": "type.googleapis.com/redpanda.mcps.exa.v1.ExaMCPConfig",
    "user_oauth": {
      "provider_name": "exa",
      "required_scopes": ["mcp:tools"]
    },
    "research": {
      "enabled": true,
      "max_cost_dollars_per_run": 1
    }
  }'

The provider name in user_oauth.provider_name must match the provider you created. The server’s required_scopes matches the provider’s mcp:tools scope.

Research uses Exa Agent Ultra and sends an explicit budget with every run. The server limit defaults to $1 and accepts $1 to $100. A caller’s max_cost_dollars defaults to $1, even if the server permits more, and cannot exceed the server limit. This is a per-run budget, not an aggregate or monthly cap. Concurrent or repeated runs each have their own budget. See Exa Agent Ultra budgets.

Research defaults to enabled. To remove all three research tools, set research.enabled to false. Configuring either allowed_domains or blocked_domains also removes research and answer from the tool list.

Before disabling research or adding a domain restriction, stop any in-flight runs and retrieve any output you need. Changing the server configuration does not stop Exa’s work, but it removes this server’s tools for reading and stopping those runs.

Connect your account and verify access

Each caller connects their own Exa account before invoking a tool. The public client registration alone does not authorize tool calls.

  1. Open Connections in Agentic Data Plane, select the Exa provider, and click Connect.

  2. Complete Exa’s consent flow, then confirm that the connection shows Connected. See Manage your connections.

  3. Open the exa server’s Inspector and confirm that it lists these five tools:

    Tool Purpose

    search

    Search the web and return results with source URLs.

    get_contents

    Retrieve text, highlights, or summaries for supplied URLs.

    start_research

    Start a billable asynchronous research run with an explicit budget.

    get_research

    Read a run’s status and available output.

    stop_research

    Stop a running research job while retaining available partial output.

The answer tool requires API-key authentication and is unavailable when the managed server uses OAuth. To generate answers with citations, create a separate server using an API key. The managed server does not fall back to a shared credential.

Listing tools does not verify the Exa connection. Call a tool to verify access, as in Examples.

Examples

Use the Inspector to test these inputs before attaching the server to an agent. Each call uses your connected Exa account.

Search the web

Call search with this input:

{
  "query": "Redpanda tiered storage architecture",
  "num_results": 5,
  "include_domains": ["docs.redpanda.com"]
}

Confirm that the response contains search results with source URLs. To read a result, call get_contents with its URL in the urls array.

Run research with a budget

Start a run, retain its ID, and poll that same run rather than creating a new one:

  1. Call start_research with this input:

    {
      "query": "Summarize how tiered storage separates compute and storage, with source citations.",
      "max_cost_dollars": 1
    }
  2. Copy run.run_id from the response.

  3. Call get_research with that value as run_id and wait_seconds set to 20. If run.status is RESEARCH_STATUS_QUEUED or RESEARCH_STATUS_RUNNING, poll again. Inspect the available output and the final status when the run finishes.

  4. To end the run early, call stop_research with the same run_id. Exa retains available partial output and bills usage accrued before stopping.

Do not automatically retry start_research after an ambiguous network failure. A second call can create a second billable run.

Use a shared API key instead

If you need answer or a shared Exa identity, create a separate server with an API key instead of user_oauth. Every caller shares the key’s permissions, billing identity, and access to research runs. Restrict access to the server accordingly.

  1. Create a key in the Exa API key dashboard. Store it in Agentic Data Plane’s Secrets store with AI Gateway scope and the name EXA_API_KEY.

  2. Create an API-key server. This example disables research and leaves search, content retrieval, and answer available:

    rpk ai mcp-server create exa-api-key \
      --enabled \
      --managed.config '{
        "@type": "type.googleapis.com/redpanda.mcps.exa.v1.ExaMCPConfig",
        "api_key": {"key_secret_ref": "EXA_API_KEY"},
        "research": {"enabled": false}
      }'

The key_secret_ref value is the secret’s name, not the API key itself. Leave api_key.header_name unset. The server sends the key in x-api-key.

Open exa-api-key in the Inspector and confirm that it lists search, get_contents, and answer. Call answer with {"query":"What is Redpanda Data? One sentence."} and confirm that the response contains an answer and source citations. This verifies the separate API-key server, not the OAuth connection.

Troubleshooting

Check the configuration and the caller’s connection when setup or tool calls fail:

Symptom Action

Consent rejects the redirect URI

Register the exact Authorization callback URL for the gateway your CLI targets, including /oauth/v1/callback. Do not use the browser address or Exa’s hosted MCP URL.

Tool calls fail with a discovered OAuth provider

Use the manually configured provider on this page, not a provider created with Discover from MCP server URL or --register-from-url.

A tool returns connection_required or scope_upgrade_required

Connect or reconnect your Exa account through Connections, then retry the call. Confirm that the provider and server both request mcp:tools.

The tool list omits answer

Expected for OAuth. Use a separate API-key server if you need this tool.

The tool list omits research tools

Check research.enabled, allowed_domains, and blocked_domains. Domain restrictions disable research even when research.enabled is true.