Architecture
How a request travels from the AI app through the server, the permission gate and the game.
The path of a tool call
McpServer(XivMcp/Mcp) implements MCP's Streamable HTTP transport with JSON responses, directly onHttpListener, because Dalamud does not ship ASP.NET Core. It only listens on localhost, checks the bearer token, and refuses browser requests from other origins.ToolRegistry(XivMcp.Core/Mcp) holds every tool: the core ones, the maintained integrations and those third-party plugins register at runtime. It is thread-safe and raisesChangedwhen tools come or go, which becomesnotifications/tools/list_changedfor the apps.ToolGate(XivMcp.Core/Permissions) decides each call from the tool's provider and the player's settings: Allow, Ask (an approval window in the game) or Deny.- The handler runs. Game memory is only read on the framework thread; static data sheet lookups run on a background thread.
- For third-party tools,
SideEffectscompares a snapshot from before and after the call, and the audit log records it.
Providers and trust
Every tool has a ToolProvider with a trust level, which decides how its calls are gated:
| Trust | Who | Gated by |
|---|---|---|
Core | XIV MCP's own tools | The modules in PermissionCatalog |
Maintained | The integrations in IntegrationCatalog, named after the plugin they drive | Their own module; only offered while that plugin is loaded |
| Third-party | Tools registered over IPC | The plugin's PluginPolicy: consent, capabilities, per-tool settings and suspension |
RegistrationReview decides when a third-party plugin needs the player's decision again: only when its registration grows.
The plugin API
PluginApi (XivMcp/Api) exposes the IPC gates. Plugins cannot share types, so everything crossing the boundary is a JSON string. ToolDefinition (XivMcp.Core/Api) validates registrations. The contract is described in Raw IPC.
Background jobs
Jobs (XivMcp/Util) runs a queue of tool calls one after another, independent of any app connection. A failed or stopped step puts the job into pending, waiting for the agent. While an acting step runs, other changing calls are refused; passive steps such as wait and wait_until_arrived do not block. Placeholders between steps are resolved by Placeholders in the core.
Pausing other plugins
While XIV MCP drives game windows, it pauses YesAlready and TextAdvance by adding itself to their StopRequests sets, and holds AutoRetainer back at a bell through AutoRetainer's public IPC. See Compatibility for what players see.
Caches as resources
Each cache (see Caches) is also an MCP resource (xiv://cache/<id>) that apps can subscribe to with resources/subscribe. Apps that open the event stream (GET /mcp with their Mcp-Session-Id) receive notifications/resources/updated when a cache changes.
Where things live
| Folder | What is in it |
|---|---|
XivMcp/Tools | One class per area of tools (MapTools, RetainerTools, MarketTools, …). |
XivMcp/Util | Game access and helpers: navigation, retainers, lobby login, caches, client setup, bridges to other plugins. |
XivMcp/Windows | The /xivmcp window, the Modules and Third-party panels, the consent and approval windows. |
XivMcp.Core/Connect | What each AI app needs to connect, and reading whether it is set up. |
XivMcp.Core/Permissions | Capabilities, the catalog, policies, the gate, side effects, the audit log, module search. |
XivMcp.Core/Maps | Map and world coordinates, and route plans. |
XivMcp.Core/Diagnostics | The self-test runner. |