GW2 MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@GW2 MCP ServerWhat are today's daily fractals?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
gw2mcp — GW2 Wiki Answers
An agentic AI assistant that answers Guild Wars 2 questions from authoritative
sources: the official wiki and the
official GW2 API, with citations back to the
wiki. Spec: specs/gw2-agentic-ai-spec.md.
Two components, one repo:
MCP tool server (
gw2mcp-server) — a FastMCP server exposing wiki search/fetch and GW2 API tools (items, skills, live trading-post prices, daily fractals, event timers, waypoint/POI chat codes) to any MCP client: Claude Desktop/Code, ChatGPT, Gemini, or our own agent.Agent core + adapters (
gw2mcp-repl,gw2mcp-discord) — the provider-pluggable tool-use loop (Anthropic, OpenAI, or OpenRouter) that turns "question in" into "grounded answer + citations out". Transport-agnostic: a terminal REPL and a Discord bot share the same core.
REPL / Discord bot any MCP client (Claude, ChatGPT, Gemini)
│ │
Agent core (Anthropic/OpenAI/OpenRouter) │
│ MCP: in-memory (default) or HTTP │ MCP: stdio or HTTP
└────────────────┬───────────────────────┘
FastMCP server (gw2mcp)
wiki_search · wiki_get_page · get_event_timer · search_items
get_item · get_item_prices · search_skills · get_skill
get_build_id · get_daily_fractals · search_waypoints
│
Supabase Postgres (TTL cache · name index · run traces)Setup
Prereqs: uv, Supabase CLI, Docker (for local Supabase).
supabase start # local Postgres on 127.0.0.1:54322
supabase migration up # create cache/name-index/run-trace tables
uv sync --all-groups
cp .env.example .env # then fill in ANTHROPIC_API_KEYEvery config variable the code reads is documented in
.env.example (optional tunables are listed commented-out with
their defaults). Secrets live only in .env (gitignored) — never commit them.
Related MCP server: OSRS MCP Server
Run
uv run gw2mcp-repl # terminal REPL (agent + in-process server)
uv run gw2mcp-server # MCP server over stdio (Claude Desktop/Code)
uv run gw2mcp-server --transport http # MCP server over streamable HTTP :8720To point an external MCP client at the server, use stdio config
(command: uv, args: [run, gw2mcp-server], cwd this repo) or the HTTP URL
http://127.0.0.1:8720/mcp.
To run the agent against a separately running server instead of in-process,
set MCP_SERVER_URL in .env.
Authentication (optional)
By default, the HTTP MCP server is unauthenticated — any client can call tools.
Setting MCP_AUTH_ENABLED=true requires all HTTP clients to authenticate via OAuth
(WorkOS AuthKit) before accessing tools.
Local transports are unaffected: stdio (Claude Desktop) and the in-memory transport
(REPL, tests) never see the HTTP auth layer. Pointing the REPL at a remote authed
server via MCP_SERVER_URL is not supported (it sends no bearer token).
Discord /link flow
Users can link their Discord account to a WorkOS identity (for higher rate limits) and optionally store an encrypted GW2 API key through Discord slash commands:
/linkopens a temporary login URL to your AuthKit application.User completes sign-up or login at the AuthKit domain.
Authorization redirects back to the MCP server with an authorization code (which the server exchanges with WorkOS).
The bot stores the linked identity (person and tier); future
/gw2calls run at the linked tier with higher rate limits.Optionally,
/setkeyopens a modal to securely store an encrypted GW2 API key./whoamishows the current link status;/unlinkrevokes the authorization.
/account — GW2 API key for MCP clients
MCP users (Claude Desktop, etc.) manage their GW2 API key in the browser at
{PUBLIC_BASE_URL}/account — sign in with the same WorkOS account the MCP
OAuth uses, then save, replace, or clear the key. Keys are validated against the
GW2 API before storing and encrypted at rest; the key never appears in the
agent conversation. The account_info MCP tool returns this URL plus
non-secret status (key stored, tier, Discord linked).
The key is stored on the person, not the surface: set it via Discord
/setkey or via /account and it is available to both — provided you sign
into the same WorkOS account in both places. /link now asks for an explicit
confirmation in the browser before attaching a Discord account.
New env var: ACCOUNT_SESSION_TTL_S (optional, default 1800) — browser
session lifetime for /account.
Upgrade note: when /link (WorkOS) settings are configured, GW2_KEY_ENCRYPTION_KEY
is now REQUIRED at startup — a server with link settings but a missing or invalid
Fernet key refuses to boot.
WorkOS dashboard setup
To enable the /link flow and OAuth on the HTTP server:
Create an AuthKit application in your WorkOS organization; note the AuthKit domain, Client ID, and API key.
In AuthKit → Configuration → Dynamic Client Registration: enable it (required so Claude/ChatGPT can self-register with the MCP server).
In the Redirects tab, add both redirect URIs:
Add
<PUBLIC_BASE_URL>/link/callback(e.g.,https://your-host.example.com/link/callback).Add
<PUBLIC_BASE_URL>/account/callbackto the allowed Redirect URIs (exact byte match —127.0.0.1vslocalhostmatters).
Recommended: In OAuth → Resource Indicators (RFC 8707): enable it and register the MCP resource URL (e.g.,
https://your-host.example.com/mcp). This ensures tokens carry the correctaud(audience) claim.
Fill in the corresponding .env variables:
WORKOS_CLIENT_ID, WORKOS_API_KEY, AUTHKIT_DOMAIN, PUBLIC_BASE_URL.
Generate LINK_SIGNING_KEY and GW2_KEY_ENCRYPTION_KEY as random cryptographic
values (see comments in .env.example).
Smoke-testing account tools
The REPL has no person identity, so account tools answer with setup guidance there — that itself is the no-identity smoke test. Real-data smoke tests (do NOT commit keys):
Discord path:
/setkeywith a real API key (all permissions), then/ask what's in my material storage?— expect real counts, ephemeral.Hosted OAuth path: connect Claude to the hosted server, store a key at /account, then ask the same question.
Ask with a key lacking
inventories— expect a message naming the missing permission, not an error.
Discord bot
The Discord adapter (spec §6.5–6.6) runs the same agent core behind two slash
commands: /gw2 question:<text> (defers ephemerally, then edits the answer
in, splitting across follow-ups past Discord's 2000-char limit) and /about.
Per-user (5/10 min) and per-guild (30/hour) rate limits plus a global monthly
budget kill-switch ($50 default, summed across all runs including REPL and
eval) are enforced as aggregate queries over run_traces — fail-closed: if
Postgres is unreachable, the bot declines to answer rather than run unmetered.
Discord application setup (once per environment)
Dev and prod are separate Discord applications so guild-scoped dev commands never collide with global prod ones.
Create an application at the Discord Developer Portal → Bot tab → Reset Token → put it in
.envasDISCORD_TOKEN. No privileged intents are needed (slash commands only — leave presence, server members, and message content off).For dev: enable Developer Mode in your Discord client, right-click your test server → Copy Server ID → set
DISCORD_DEV_GUILD_IDin.env. Commands sync instantly to that guild. For prod: leave it unset — commands register globally (first propagation can take up to an hour).Invite the bot with (replace
<APP_ID>from the portal's General Information page):https://discord.com/api/oauth2/authorize?client_id=<APP_ID>&scope=bot%20applications.commands&permissions=2048permissions=2048is just Send Messages; interaction replies work even without it, keeping the permission footprint minimal.
Run
uv run gw2mcp-discord # requires DISCORD_TOKEN in .env, local Supabase runningRate-limit and budget knobs (RATE_LIMIT_*, MONTHLY_BUDGET_USD) are
documented in .env.example.
Eval
uv run python eval/run_eval.py # full 25-question set, manual scoring
uv run python eval/run_eval.py --category live --limit 2The question set (eval/questions.yaml) is versioned; re-run it on every
significant prompt/tool change. Results land in eval/results/*.jsonl.
Baseline (2026-07-22, claude-sonnet-5, prompt v1): 21/25 pass (84%),
3 partial, 1 fail · median latency 12.0s (target ≤15s ✓) · avg cost
$0.0621/question (target ≤$0.06, marginal). The fail + 2 partials traced to a
wikitext-cleaner bug that stripped inline cost templates ({{gold|…}},
{{item icon|…}}); fixed after this run — re-run the eval to record a v2
baseline against the ≥90% target.
Model
LLM_PROVIDER env var picks the backend — anthropic (default), openai, or
openrouter — and MODEL_ID names the model in that provider's naming
(default claude-sonnet-5, $3/M input, $15/M output — the best
price/quality Sonnet-class model per the spec's cost target of
≤ $0.06/question; OpenRouter ids are vendor-prefixed, e.g.
anthropic/claude-sonnet-5). The agent loop is provider-agnostic
(src/gw2mcp/agent/providers/); pricing for cost accounting lives in
src/gw2mcp/agent/costs.py and is keyed by (provider, model) — a pair
without a pricing entry refuses to start (fail-closed, so nothing can spend
invisibly to the monthly budget cap).
Tests
uv run pytest # fully offline: respx-mocked HTTP, in-memory MCP, fake cacheObservability
Every run writes one JSON line to logs/runs.jsonl (every tool call, tokens,
cost, latency) and a queryable row to the run_traces table in Postgres —
the table the Discord adapter's rate limits and budget kill-switch aggregate
over (src/gw2mcp/agent/gating.py).
Politeness & attribution
Wiki requests carry a descriptive User-Agent and are limited to ≤ 2 req/s.
Wiki content is cached (pages 24h, search 1h); GW2 API static data is cached keyed to the game build; prices for 5 minutes.
Wiki content is GFDL; this project is not affiliated with ArenaNet.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Guild-Wars-MCP/GW2_MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server