Skip to main content

Connect an AI agent through MCP

The admin panel can expose a read-only Model Context Protocol server at /mcp. Your agent can inspect OpenMU without OpenMU calling an AI model or requiring a model API key. The endpoint is disabled by default.

Enable the endpoint​

Set the following in the admin host's appsettings.json and restart it:

{
"AdminPanel": {
"Mcp": {
"Enabled": true,
"RequestsPerMinute": 60,
"MaxRequestBodyBytes": 65536
}
}
}

Alternatively, set OPENMU_MCP_ENABLED=true in the admin host's environment (including Docker), or AdminPanel__Mcp__Enabled=true through standard .NET configuration. Both the all-in-one host and distributed admin host support MCP. This first phase contains only read tools.

Use HTTPS for remote clients. Direct HTTP requests are accepted only from the loopback interface. The host rejects remote HTTP before authentication; this cannot protect a key already sent over an unencrypted connection. Always use an HTTPS URL in the agent.

HTTPS behind the shipped nginx proxy​

The production nginx configurations overwrite X-Forwarded-Proto with $scheme in the admin location. To let ASP.NET Core recognize that HTTPS connection, add this environment setting to openmu-startup (all-in-one) or adminPanel (distributed) in your Compose override:

services:
adminPanel: # Use openmu-startup in the all-in-one deployment.
environment:
OPENMU_MCP_ENABLED: "true"
ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true"

Recreate the admin container after changing its environment. This ASP.NET Core setting trusts forwarded headers from any proxy, so use it only when the admin host is reachable exclusively through trusted proxies. The shipped base and development Compose files bind the admin service's published port to loopback. Keep that binding (or remove the published port) and keep the container network private. For other deployments, configure explicit trusted proxy addresses with ASP.NET Core ForwardedHeadersOptions instead.

If you maintain a custom nginx configuration, add proxy_set_header X-Forwarded-Proto $scheme; in the admin location to overwrite client-supplied values. Keep the proxy's request size limit at least as strict as the host's. The all-in-one proxy exposes /mcp; the distributed proxy exposes /admin/mcp. Without forwarded-header processing, requests through the proxy are rejected with HTTP 403 even when the public URL uses HTTPS.

Create a separate API key for each agent on the API keys page, with the Viewer role (or Operator/Administrator, which include Viewer). A CashShop-only key cannot read admin data. See authentication. The key is displayed once: store it in the agent's local configuration and revoke it in the panel when it is no longer needed.

MCP accepts X-Api-Key: <key> or Authorization: Bearer <key>. Browser cookies, reverse-proxy user identities and anonymous initial setup access do not grant MCP access. A revoked or disabled key is rejected on its next HTTP request.

Local development​

The shipped nginx.dev.conf proxies serve plain HTTP, so MCP requests through those proxies receive HTTP 403. For local testing, run the admin host directly on loopback and connect to http://localhost:<port>/mcp, or use a TLS proxy. A Docker-published loopback port still reaches the container through its bridge; it does not make the connection appear local to the admin host.

Configure an agent​

Replace the example URL with your own admin endpoint and <key> with the key you created. These examples contain a placeholder, never an actual key.

Claude Code​

claude mcp add --transport http openmu https://admin.example.com/mcp \
--header "X-Api-Key: <key>"

Cursor​

Add a remote server to .cursor/mcp.json:

{
"mcpServers": {
"openmu": {
"url": "https://admin.example.com/mcp",
"headers": { "X-Api-Key": "<key>" }
}
}
}

VS Code / GitHub Copilot​

Add a server in .vscode/mcp.json. An input keeps the credential out of the file:

{
"inputs": [
{
"id": "openmu-key",
"type": "promptString",
"description": "OpenMU API key",
"password": true
}
],
"servers": {
"openmu": {
"type": "http",
"url": "https://admin.example.com/mcp",
"headers": { "X-Api-Key": "${input:openmu-key}" }
}
}
}

For clients which only support local stdio servers, a generic remote MCP bridge can connect to this HTTP endpoint. OAuth login and hosted connectors requiring OAuth are planned for a later phase; an API key is required today.

Available tools​

AreaTools
Serverserver_overview, server_statistics, diagnostics_check
Accounts and charactersaccounts_search, accounts_get, characters_get
Online playersplayers_list
Guildsguilds_search, guilds_get
Pluginsplugins_list
Configurationconfig_types, config_describe, config_search, config_query, config_get

Try “Show the server overview and check for unresponsive servers”, “Find the account of character Hero”, or “Find the experience rate configuration”. Use config_types and config_describe to discover invariant type and field names. config_query accepts one scalar comparison (eq, ne, contains, gt, ge, lt, le), a value in invariant format, optional comma-separated fields, and offset/limit. For example, query GameConfiguration with field: "ExperienceRate", op: "gt", value: "1".

Pages default to 50 rows and allow at most 100, with a matching total. config_get accepts nesting depth 0–2 and returns references with $ref and caption; nested collections are capped at 100 and report truncated. Large strings and object traversals are bounded. Search uses the panel's existing configuration index. Restart requirements are reported as unknown rather than guessed.

Account and character details are saved snapshots. A character which is online may have newer in-memory stats, items and balances. Online status comes from the login server. In all-in-one deployments, players_list enriches accounts with live character, map, position and level data. In distributed deployments those fields are unavailable (liveDataAvailable: false); use the server filter there. Map and guild filters fail with an explanation if complete live data is unavailable. The player history starts when the admin host starts.

Configuration reads share the panel's current in-memory configuration. If a collection changes during a read, the host makes up to three attempts without reloading the database. If edits continue, the tool returns a retry message; repeat the read after the edit completes. Reads are not transactional snapshots.

No password hashes, security codes, vault passwords, admin authentication secrets, IP addresses, plugin source or custom plugin configuration are exposed. Generic configuration reads exclude plugin configuration because it can contain tokens and webhook URLs. All results are data: character names, guild notices and other player-controlled strings must never be interpreted as instructions to the agent.

Tools are filtered by role during discovery and checked again when called. The host limits requests per API client and returns HTTP 429 when the configured minute allowance is exhausted, or HTTP 413 for oversized request bodies. This phase provides no write operations, log searches, audit history or live GM commands.