AI Bot – Bring Your Own MCP Server

:bookmark: This guide explains how to connect external Model Context Protocol (MCP) servers to Discourse AI agents, allowing any MCP-compatible tool provider to be used directly inside the AI bot.

:person_raising_hand: Required user level: Administrator


What is “Bring Your Own MCP”?

Model Context Protocol is an open standard (originally proposed by Anthropic) that lets AI agents communicate with external tool servers over a standard HTTP/JSON-RPC interface. An MCP server exposes a menu of “tools” — functions with typed inputs — that an LLM can call to get things done.

Discourse AI now acts as an MCP client. You register any HTTPS MCP server in the admin panel, Discourse discovers its available tools, and those tools become first-class citizens inside any AI agent you choose. There is no JavaScript to write; the tools are defined by the remote server.

This differs from custom script tools which require writing JavaScript that runs inside Discourse. With MCP you bring an already-running external server.


Summary

  • Register an MCP server (URL + optional auth)
  • Discourse auto-discovers and caches the server’s tools
  • Assign the server to one or more AI agents
  • Optionally limit which tools each agent can use
  • Tools are called by the LLM at runtime, routed through Discourse to the external server

Registering an MCP Server

Navigate to:

Admin → Plugins → Discourse AI → ToolsMCP servers tab → New MCP server

Fill in the following fields:

Field Description
Name A human-readable label (shown in the agent editor and logs)
Description What this server is for (admin reference)
URL The HTTPS endpoint of the MCP server — must be a public HTTPS URL, no private IPs
Authentication One of: No authentication, Header credential, or OAuth
Timeout (seconds) How long Discourse waits per request — default 30, maximum 300
Enabled Toggle to temporarily disable the server without deleting it

:warning: URLs must use HTTPS. localhost and RFC-1918 private addresses are blocked (SSRF protection is enforced server-side).


Authentication Options

No Authentication

The server is publicly reachable. No credentials are sent.

Header Credential

A secret value is injected as an HTTP header on every request.

  1. First create a Credential under Admin → AI → Credentials
  2. Select it as the Credential on the MCP server form
  3. Set the Auth header name (default: Authorization)
  4. Set the optional Auth scheme prefix (default: Bearer)

The request header sent to the MCP server will be:

Authorization: Bearer <your-secret-value>

You can change both the header name and scheme to match any auth style your server requires (e.g., X-Api-Key: <value> by leaving scheme blank).

OAuth

Discourse implements a full OAuth 2.0 + PKCE flow as the MCP client. This supports MCP servers that protect their tools behind OAuth.

Setup steps:

  1. Set Authentication to OAuth
  2. Choose Client registration:
    • Client metadata document (default) — Discourse publishes its own OAuth client metadata at https://your-site.com/discourse-ai/mcp/oauth/client-metadata. If the MCP server supports RFC 7591 Dynamic Client Registration, Discourse will register automatically
    • Manual client credentials — enter your pre-registered OAuth client ID and pick an OAuth client secret credential
  3. Optionally set OAuth scopes (space-separated)
  4. Save the server
  5. Click Connect — Discourse will redirect you through the provider’s authorization page
  6. After authorizing, you are returned to the admin and the status shows Connected

Advanced OAuth options (toggle “Show advanced options”):

Option Purpose
OAuth authorization params JSON object merged into the authorization request (e.g. {"access_type":"offline"})
OAuth token params JSON object merged into token exchange requests
Require refresh token Fail the connection if the provider doesn’t return a refresh token

Discourse automatically refreshes access tokens before expiry and retries on 401 if a refresh token is available.


Testing the Connection

Before assigning a server to an agent, use the Test connection button on the editor form. This immediately initializes an MCP session, calls tools/list, and returns:

  • MCP protocol version negotiated
  • Number of tools discovered
  • Names of all tools

If the test fails, the error message from the server (or a timeout indicator) is shown inline.


How Discourse Discovers Tools

Discourse follows the MCP specification 2025-03-26. The connection sequence is:

Discourse → POST /  { method: "initialize", params: { protocolVersion, capabilities, clientInfo } }
Server    → { result: { protocolVersion, capabilities } } + Mcp-Session-Id header
Discourse → POST /  { method: "notifications/initialized" }   (session handshake complete)
Discourse → POST /  { method: "tools/list", session_id: … }
Server    → { result: { tools: [ { name, description, inputSchema } … ] } }

Tool definitions are cached for 1 hour per server. After the cache expires, a background job transparently refreshes it. The cache key is per-site/per-server, so multi-site installs are isolated.

You can also manually trigger a refresh by clicking Test connection — this always fetches live data.

The health status of the server (healthy / error) is updated on every cache refresh.


Assigning MCP Servers to AI Agents

Once a server is registered, assign it to an agent:

  1. Go to Admin → Plugins → Discourse AI → Agents and edit or create an agent
  2. Scroll to the MCP servers section (below the regular Tools section)
  3. The list shows all enabled MCP servers with their tool count and estimated token cost
  4. Toggle a server on — it’s now available to that agent

Tip: By default, all tools from a server are made available to the agent. The locale string says it well: “Selected MCP servers expose all of their tools by default. Narrow them per agent to reduce token usage and keep tool choice focused.”


Selecting Specific Tools per Agent

Having dozens of tools available increases the token cost of every message (each tool definition is sent to the model in the system prompt). To keep things lean:

  1. In the agent editor, next to an assigned MCP server, click Choose tools
  2. A modal shows every tool the server currently exposes, with its description and parameter list
  3. Check only the tools this agent needs
  4. Click Save — the agent will now only see the selected subset

The ai_agent_mcp_servers join table stores selected_tool_names as a JSONB array. An empty array means “all tools enabled”.


Tool Naming and Conflict Resolution

MCP tool names must be unique within a single agent’s tool list (including the agent’s built-in and custom script tools). Discourse handles conflicts automatically:

  • If two different MCP servers expose a tool with the same name, Discourse namespaces them: servername__toolname
  • If a built-in Discourse tool and an MCP tool share a name, the MCP tool is also namespaced
  • If there are still collisions after namespacing, a numeric suffix is appended (_2, _3, …)

The function_name used in the LLM call may therefore differ from the raw tool_name on the MCP server. This is handled transparently — the MCP tool class always stores the original tool_name_value separately and uses it when calling the server.


How Tool Calls Work at Runtime

When the LLM decides to use an MCP tool:

  1. Session reuse: Discourse looks up a cached MCP session ID for this server in the current bot context (context.mcp_state). Sessions are created per bot reply chain and reused across tool calls to the same server.
  2. Initialize if needed: If no session exists, a fresh initialize + notifications/initialized handshake runs.
  3. Call: POST / with { method: "tools/call", params: { name: tool_name, arguments: params } }
  4. Session expiry: If the server returns 404 (expired session), Discourse automatically re-initializes and retries once.
  5. Response normalization: MCP content items of type text are concatenated. Non-text items are JSON-serialized. structuredContent is pretty-printed JSON.
  6. Error result: If the server returns isError: true, the bot receives an error message rather than a result.

The server response can be plain JSON or an SSE stream — Discourse handles both.


Token Cost Display

In the agent editor, each assigned MCP server shows an estimated token count. This is calculated using the OpenAI cl100k_base tokenizer applied to each tool’s full JSON signature (name + description + input schema). This is an approximation — actual cost depends on your LLM’s tokenizer.

The token cost breakdown is shown to help you make informed decisions about which servers and tools to assign to a given agent.


Troubleshooting

Symptom What to check
Test connection fails with timeout Increase Timeout (seconds). Default is 30. If the server is slow to initialize, try 60–120.
Test succeeds but tools don’t appear in agent Make sure the server is Enabled and that the agent has it toggled on in its MCP servers section.
OAuth status shows “Needs attention” The last OAuth error is shown on the editor form. Common causes: refresh token expired (click Reconnect), server returned unexpected scopes, or the client metadata URL is not accessible from your server.
Tool names look like myserver__sometool Normal — another tool (built-in or from another server) had the same name. The LLM sees and uses this namespaced name automatically.
Health shows “error” after a period The background refresh job couldn’t reach the server. Check /logs on your site and verify the MCP server is reachable from Discourse’s host.
Tools stopped working mid-conversation Session expiry. Discourse auto-retries once per tool call, but if the server is consistently restarting, shorten its session TTL or investigate the server-side logs.

For deeper debugging, enable access to AI transcripts via ai_bot_debugging_allowed_groups and inspect the full conversation log.


Technical Reference

MCP Protocol Details

Property Value
Protocol version 2025-03-26
Transport HTTP POST (JSON-RPC 2.0)
SSE support Yes (for streaming tools/call responses)
Session management Mcp-Session-Id HTTP header
Max response body 5 MB
Client User-Agent Discourse AI MCP Client / <version>

JSON Schema Support

Discourse resolves the following JSON Schema constructs in tool inputSchema definitions before passing them to the LLM:

  • $ref — resolved against the root schema’s $defs / definitions
  • allOf — merged (properties and required arrays are union-merged)
  • anyOf / oneOf — the first non-null variant is used

Relevant Source Files


Related Topics

:bulb: The Discourse-as-MCP-server feature (discourse/discourse-mcp) is the complement to this: it lets external AI clients (Claude Code, Cursor, etc.) read and write your Discourse site. This guide is the inverse — it lets your Discourse AI agents call external MCP servers.

2 Likes