Discourse Mcp Server
About
A Model Context Protocol (MCP) stdio server that exposes Discourse forum capabilities as tools for AI agents. Works with all deployments of discourse.org, self hosted or cloud hosted. just generate an API key to connect.
Explore
- Read‑only by default; writes are opt‑in and guarded.
- Built‑in tools: search, read topics/posts, list categories/tags, filter topics.
- Write tools: create posts, topics, categories, and users (when enabled).
- Supports Admin API Keys and User API Keys for authentication.
- Rate‑limited writes (~1 req/sec) with retries on 429/5xx.
- Remote Tool Execution API for additional dynamic tools.
Setting up with Highlight
This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:
- Download and install Highlight from highlightai.com/download
- Navigate to the plugins tab and select "Add Custom Plugin"
-
Configure the plugin with the settings below
Plugin Name
Discourse Mcp ServerCommand (node, npx, python, etc.)Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.
- Enable "Start Automatically" if you want the plugin to start when Highlight launches
From the repository
The server registers tools under the MCP server name @discourse/mcp. Choose a target Discourse site either by:
- Using the discourse_select_site tool at runtime (validates via /about.json), or
- Supplying --site <url> to tether the server to a single site at startup (validates via /about.json and hides discourse_select_site).
- Auth
- None by default.
- Admin API Keys (require admin permissions): --auth_pairs '[{"site":"https://example.com","api_key":"...","api_username":"system"}]'
- User API Keys (any user can generate): --auth_pairs '[{"site":"https://example.com","user_api_key":"...","user_api_client_id":"..."}]'
- You can include multiple entries in auth_pairs; the matching entry is used for the selected site. If both user_api_key and api_key are provided for the same site, user_api_key takes precedence.
- Write safety
- Writes are disabled by default.
- The tools discourse_create_post, discourse_create_topic, discourse_create_category, and discourse_create_user are only registered when all are true:
- --allow_writes AND not --read_only AND some auth is configured (either default flags or a matching auth_pairs entry).
- A ~1 req/sec rate limit is enforced for write actions.
- Flags & defaults
- --read_only (default: true)
- --allow_writes (default: false)
- --timeout_ms <number> (default: 15000)
- --concurrency <number> (default: 4)
- --log_level <silent|error|info|debug> (default: info)
- debug: Shows all HTTP requests, responses, and detailed error information
- info: Shows retry attempts and general operational messages
- error: Shows only errors
- silent: No logging output
- --tools_mode <auto|discourse_api_only|tool_exec_api> (default: auto)
- --site <url>: Tether MCP to a single site and hide discourse_select_site.
- --default-search <prefix>: Unconditionally prefix every search query (e.g., tag:ai order:latest-post).
- --max-read-length <number>: Maximum characters returned for post content (default 50000). Applies to discourse_read_post and per-post content in discourse_read_topic. The tools prefer raw content by requesting include_raw=true.
- --transport <stdio|http> (default: stdio): Transport type. Use stdio for standard input/output (default), or http for Streamable HTTP transport (stateless mode with JSON responses).
- --port <number> (default: 3000): Port to listen on when using HTTP transport.
- --cache_dir <path> (reserved)
- --profile <path.json> (see below)
- Profile file (keep secrets off the command line)
{
"auth_pairs": [
{ "site": "https://try.discourse.org", "api_key": "<redacted>", "api_username": "system" },
{ "site": "https://example.com", "user_api_key": "<user_api_key>", "user_api_client_id": "<client_id>" }
],
"read_only": false,
"allow_writes": true,
"log_level": "info",
"tools_mode": "auto",
"site": "https://try.discourse.org",
"default_search": "tag:ai order:latest-post",
"max_read_length": 50000,
"transport": "stdio",
"port": 3000
}
Run with:
node dist/index.js --profile /absolute/path/to/profile.json
Flags still override values from the profile.
- Remote Tool Execution API (optional)
- With tools_mode=auto (default) or tool_exec_api, the server discovers remote tools via GET /ai/tools after you select a site (or immediately at startup if --site is provided) and registers them dynamically. Set --tools_mode=discourse_api_only to disable remote tool discovery.
- Networking & resilience
- Retries on 429/5xx with backoff (3 attempts).
- Lightweight in‑memory GET cache for selected endpoints.
- Privacy
- Secrets are redacted in logs. Errors are returned as human‑readable messages to MCP clients.
- Run (read‑only, recommended to start)
npx -y @discourse/mcp@latest
Then, in your MCP client, either:
- Call the
discourse_select_site tool with { "site": "https://try.discourse.org" } to choose a site, or- Start the server tethered to a site using
--site https://try.discourse.org (in which case discourse_select_site is hidden).
- Enable writes (opt‑in, safe‑guarded)
npx -y @discourse/mcp@latest --allow_writes --read_only=false --auth_pairs '[{"site":"https://try.discourse.org","api_key":"'$DISCOURSE_API_KEY'","api_username":"system"}]'
- Use in an MCP client (example: Claude Desktop) — via npx
{
"mcpServers": {
"discourse": {
"command": "npx",
"args": ["-y", "@discourse/mcp@latest"],
"env": {}
}
}
}
> Alternative: if you prefer a global binary after install, the package exposes discourse-mcp.
>
> {
> "mcpServers": {
> "discourse": { "command": "discourse-mcp", "args": [] }
> }
> }
>
```bash
discourse_select_site
Validate and select a Discourse site. Returns JSON with site URL and title.
discourse_search
Search site content. Returns JSON object with results array of matching topics (id, slug, title) and meta (total, has_more).
discourse_filter_topics
Filter topics with a concise query language. Returns JSON object with results array (id, slug, title) and meta (page, limit, has_more). Query syntax: category/categories (comma=OR, '=category'=without subcats, '-'=exclude), tag/tags (comma=OR, '+'=AND), status:(open|closed|archived|listed|unlisted|public), in:(bookmarked|watching|tracking|muted|pinned), dates: created/activity-(before|after) YYYY-MM-DD or N days, order: activity|created|latest-post|likes|views with optional -asc.
discourse_read_topic
Read topic metadata and posts. Returns JSON with id, title, slug, category_id, tags, and posts array.
discourse_read_post
Read a specific post. Returns JSON with id, topic_id, post_number, username, created_at, and raw content.
discourse_get_user
Get user info. Returns JSON with id, username, name, trust_level, created_at, bio, admin, and moderator.
discourse_list_user_posts
Get paginated list of user posts/replies. Returns JSON object with posts array (id, topic_id, post_number, slug, title, created_at, excerpt, category_id) and meta (page, limit, has_more).
discourse_list_users
List users via admin API. Requires admin API key. Returns ~100 users per page (Discourse's fixed page size). Returns JSON with users array and pagination meta.
discourse_get_chat_messages
Get messages from a chat channel. Returns JSON object with channel_id, messages array (id, username, created_at, message, edited, thread_id, in_reply_to_id), and meta.
discourse_get_draft
Retrieve a specific draft by key. Returns JSON with draft_key, sequence, and parsed data (title, reply, categoryId, tags, action).
discourse_get_query
Get full details of a Data Explorer query including SQL and parameters. Requires admin API key.
discourse_run_query
Execute a Data Explorer query with parameters. Returns columns, rows, result_count, duration_ms. Queries run in read-only transactions with 10-second timeout. Requires admin API key.
Built‑in tools (always present unless noted):
- discourse_search
- Input: { query: string; with_private?: boolean; max_results?: number (1–50, default 10) }
- Output: text summary plus a compact footer like:
{ "results": [{ "id": 123, "url": "https://…", "title": "…" }] }
-
discourse_read_topic- Input:
{ topic_id: number; post_limit?: number (1–20, default 5) }-
discourse_read_post- Input:
{ post_id: number }-
discourse_list_categories- Input:
{}-
discourse_list_tags- Input:
{}-
discourse_get_user- Input:
{ username: string }-
discourse_filter_topics- Input:
{ filter: string; page?: number (default 1); per_page?: number (1–50) }- Query language (succinct): key:value tokens separated by spaces; category/categories (comma = OR,
=category = without subcats, - prefix = exclude); tag/tags (comma = OR, + = AND) and tag_group; status:(open|closed|archived|listed|unlisted|public); personal in: (bookmarked|watching|tracking|muted|pinned); dates: created/activity/latest-post-(before|after) with YYYY-MM-DD or relative days N; numeric: likes[-op]-(min|max), posts-(min|max), posters-(min|max), views-(min|max); order: activity|created|latest-post|likes|likes-op|posters|title|views|category with optional -asc; free text terms are matched.-
discourse_create_post (only when writes enabled; see Write safety)- Input:
{ topic_id: number; raw: string (≤ 30k chars) }
- discourse_create_topic (only when writes enabled; see Write safety)
- Input: { title: string; raw: string (≤ 30k chars); category_id?: number; tags?: string[] }
- discourse_create_user (only when writes enabled; see Write safety)
- Input: { username: string (1-20 chars); email: string; name: string; password: string; active?: boolean; approved?: boolean }
- discourse_create_category (only when writes enabled; see Write safety)
- Input: { name: string; color?: hex; text_color?: hex; parent_category_id?: number; description?: string }
Notes:
- Outputs are human‑readable first. Where applicable, a compact JSON is embedded in fenced code blocks to ease structured extraction by agents.
Claude Desktop / Cursor
Paste into your MCP client config file to install this server.
{
"mcpServers": {
"discourse mcp server": {
"discourse": {
"command": "npx",
"args": [
"-y",
"@discourse/mcp@latest"
],
"env": []
}
}
}
}
McpServers
{
"discourse": {
"command": "npx",
"args": [
"-y",
"@discourse/mcp@latest"
],
"env": []
}
}
Step 3: Run the MCP server with your new key
npx @discourse/mcp@latest --profile profile.json --allow_writes --read_only=false
Other Examples
- Read‑only session against try.discourse.org:
bashnpx -y @discourse/mcp@latest --log_level debug
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.



