Give your AI assistant full context on your EverQuest Emulator server — source code, quest API, database schema, documentation, and live game data — so it can write accurate queries, debug issues, and manage content without guessing.
A Model Context Protocol (MCP) server for EverQuest Emulator servers. Works with Windsurf, VS Code, Cursor, OpenAI Codex, Claude Desktop, and any MCP-compatible AI client.
Your AI assistant gets access to everything it needs to understand and operate your EQEmu server:
| Data Source | What Your AI Can Access |
|---|---|
| 📚 EQEmu Documentation | Full-text search across all 638 pages of docs.eqemu.io — server operation guides, configuration references, quest tutorials, and more |
| 🗄️ Database Schema Docs | Detailed documentation for all 261 tables across 48 categories — column names, types, descriptions, and ER relationship diagrams |
| 🔍 Live Database | Read-only SQL queries against your actual game database — NPCs, items, spawns, loot, characters, accounts, zones, spells, factions, tasks, tradeskills |
| 💻 C++ Source Code | Full-text search across the EQEmu C++ codebase — find how mechanics work, trace calculations, understand game systems |
| 📜 Quest Scripts | Browse and search all Perl/Lua quest scripts across every zone — read quest logic, find event handlers, trace quest flows |
| 🔧 Quest API Reference | Complete Lua and Perl quest API documentation — method signatures, event lists, and examples for all 30+ method classes |
| ⚙️ Server Configuration | Server rules, content flags, expansion settings, eqemu_config.json (with passwords auto-redacted) |
| 📋 Server Logs | Recent server logs and crash logs for debugging |
| 👤 Characters & Accounts | Character inspection (stats, AAs, inventory, guild), account details, IP history, alt/multibox detection |
| 🗺️ Zone Details | Zone information with spawn counts, NPC lists, doors/portals, ground spawns, forage/fishing tables, patrol grids |
No guessing. Your AI looks up the exact schema, follows the correct relationships, and writes accurate queries on the first try.
When you ask an AI assistant to write a query, inspect spawn data, or debug a quest issue, it has to guess table names, column names, relationships, and valid values. It gets things wrong. You end up copy-pasting schema docs and correcting hallucinated SQL.
This MCP server eliminates that. Your AI assistant can:
- Look up exact schema —
get_schema_doc("npc_types")returns all 80+ columns with types and descriptions - Follow relationships —
table_relationships("spawn2")shows FK links through the entire spawn chain - Search documentation —
search_docs("loottable_id")finds every doc page referencing that column - Query live data —
run_query("SELECT * FROM npc_types WHERE name LIKE '%Nagafen%'")hits your actual database - Inspect full chains — NPC → faction → loot → spawn group → grid path, all from structured tools
The result: correct queries on the first try, accurate quest scripts, and faster debugging.
| Category | Tools | Description |
|---|---|---|
| C++ Source | search_source get_source_file list_source_files |
Search and browse the EQEmu C++ codebase |
| Quest API | list_quest_api_classes get_quest_api_methods |
Browse Lua/Perl quest API method signatures |
| Quest Scripts | list_quest_zones list_quest_files read_quest_file search_quests |
Browse and search quest scripts across all zones |
| Server Files | list_server_files read_server_file get_server_config |
Server files, plugins, config (passwords redacted) |
| Server Info | get_server_rules get_server_logs get_crash_logs get_content_flags get_expansion_info |
Rules, logs, crash analysis, content flags |
| Database | list_tables describe_table run_query table_relationships |
Schema inspection and read-only SQL |
| NPCs | search_npcs get_npc |
NPC search by name/zone/level with spawn locations |
| Items | search_items get_item search_items_by_stat |
Item search by name/type/level or stat thresholds |
| Spawns | get_zone_spawns get_spawngroup |
Spawn points, spawn groups, placeholder/named setups |
| Loot | get_npc_loot |
Full loot chain: NPC → loottable → lootdrop → items |
| Merchants | get_merchant_items |
Merchant inventories |
| Zones | search_zones get_zone_info |
Zone lookup with spawn/NPC/door counts |
| Spells | search_spells get_spell |
Spell search and full effect/class breakdown |
| Factions | search_factions get_npc_faction |
Faction search and NPC faction kill-hit details |
| Tasks | search_tasks get_task |
Task search and full activity/reward breakdown |
| Characters | list_characters get_character get_online_characters |
Character inspection, stats, AAs, inventory, online players |
| Accounts | get_account_info find_associated_accounts |
Account investigation, IP history, alt detection |
| Tradeskills | search_recipes get_recipe |
Recipe search and component/result breakdown |
| Grids | get_npc_grid |
NPC patrol paths with waypoint coordinates |
| Doors | get_zone_doors |
Zone doors/portals with destinations, keys, lockpick |
| Ground Spawns | get_ground_spawns |
Clickable ground items in a zone |
| Forage/Fishing | get_zone_forage_fishing |
Zone forage and fishing loot tables |
| Documentation | search_docs read_doc list_doc_sections |
Full-text search across docs.eqemu.io |
| Schema Docs | get_schema_doc list_schema_tables |
Table docs with column descriptions and ER relationships |
| Quest API Docs | get_quest_api_doc |
Official quest API docs with signatures and examples |
| Server Docs | get_server_doc |
Server operation guides and command references |
Enable with EQEMU_ACCESS_MODE=readwrite:
| Category | Tools | Description |
|---|---|---|
| Quest Editing | write_quest_file delete_quest_file |
Create, edit, or delete quest scripts |
| Server Rules | set_server_rule |
Change server rule values |
| Content Flags | set_content_flag |
Enable/disable content flags |
| NPC Management | create_npc update_npc |
Create or modify NPCs |
| Spawn Management | create_spawn delete_spawn |
Add/remove spawn points |
| Loot Management | add_loot_to_npc |
Add items to NPC loot tables |
| Merchants | add_merchant_item remove_merchant_item |
Manage merchant inventories |
| Data Buckets | get_data_buckets set_data_bucket |
Read/write data buckets |
| Database | run_write_query |
Execute INSERT/UPDATE/DELETE queries |
- Python 3.10+
- Access to an EQEmu server (akk-stack recommended)
- ripgrep (optional — for fast source code search, falls back to grep)
git clone https://github.com/straps-eq/eqemu-mcp-server.git
cd eqemu-mcp-server
cp .env.example .env
# Edit .env with your database credentials and paths
docker compose up -dThe server starts on port 8888. Connect your AI client to http://YOUR_SERVER_IP:8888/sse.
If you're running akk-stack, the MCP server can join your existing Docker network and talk to MariaDB directly. No separate .env file is needed — the compose overlay reads credentials from your akk-stack .env automatically.
Step 1: Clone into your akk-stack directory
cd /opt/akk-stack
git clone https://github.com/straps-eq/eqemu-mcp-server.gitStep 2 (optional): Add token authentication
To require a token for connections, add this to your akk-stack .env:
echo "EQEMU_MCP_TOKEN=$(openssl rand -hex 32)" >> /opt/akk-stack/.env
# View the generated token:
grep EQEMU_MCP_TOKEN /opt/akk-stack/.envStep 3: Build and start the MCP container
cd /opt/akk-stack
# Build the image
docker compose -f docker-compose.yml \
-f eqemu-mcp-server/docker-compose.akk-stack.yml \
build eqemu-mcp
# Start (only the MCP container — does NOT restart your game server)
docker compose -f docker-compose.yml \
-f eqemu-mcp-server/docker-compose.akk-stack.yml \
up -d --no-deps eqemu-mcp
⚠️ Important: Always use--no-deps eqemu-mcpto start only the MCP container. Without--no-deps, Docker Compose may recreate your MariaDB and EQEmu server containers, causing a server restart.
Step 4: Open the firewall
sudo ufw allow 8888/tcpStep 5: Verify
docker logs akk-stack-eqemu-mcp-1 --tail 5
# Should show: "Uvicorn running on http://0.0.0.0:8888"The MCP server is read-only by default. It automatically:
- Connects to MariaDB via the
backendnetwork (no external IP needed) - Mounts your
code/andserver/directories read-only - Uses your existing
MARIADB_PASSWORDfrom the akk-stack.env
Configuration: All settings go in your akk-stack .env (/opt/akk-stack/.env) — you do not create a separate .env inside the eqemu-mcp-server/ folder. Available variables:
| Variable | Default | Description |
|---|---|---|
MARIADB_PASSWORD |
(from akk-stack) | Database password — already in your .env |
IP_ADDRESS |
0.0.0.0 |
Bind address — already in your .env |
EQEMU_DB_NAME |
peq |
Database name — set this if your DB isn't named peq |
EQEMU_DB_USER |
eqemu |
Database user — set to a read-only user for extra safety (see Read-Only DB User) |
EQEMU_DB_PASSWORD |
${MARIADB_PASSWORD} |
Database password — override if using a separate read-only user |
EQEMU_MCP_TOKEN |
(empty) | Set to require token auth on connections |
MCP_ACCESS_MODE |
read |
Set to readwrite to enable write tools |
git clone https://github.com/straps-eq/eqemu-mcp-server.git
cd eqemu-mcp-server
python3 -m venv venv
source venv/bin/activate
pip install -e .
cp .env.example .env
# Edit .env with your server paths and database credentials
# Start SSE server
./start.sh --sse 8888akk-stack users:
cd /opt/akk-stack && make infoOr read eqemu_config.json:
cat /opt/akk-stack/server/eqemu_config.json | python3 -m json.toolNote: If running the MCP server outside Docker (directly on the host), use the host's external IP for
EQEMU_DB_HOST, not127.0.0.1ormariadb.
Start the server:
./start.sh --sse 8888Then configure your AI client:
Windsurf
Edit ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"eqemu": {
"serverUrl": "http://YOUR_SERVER_IP:8888/sse"
}
}
}With token authentication enabled:
{
"mcpServers": {
"eqemu": {
"serverUrl": "http://YOUR_SERVER_IP:8888/sse",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
}Cursor
In Settings → MCP Servers, add:
{
"mcpServers": {
"eqemu": {
"url": "http://YOUR_SERVER_IP:8888/sse"
}
}
}VS Code (GitHub Copilot)
Open Command Palette → "MCP: Open User Configuration" (or edit .vscode/mcp.json in your workspace):
{
"servers": {
"eqemu": {
"type": "sse",
"url": "http://YOUR_SERVER_IP:8888/sse"
}
}
}With token authentication:
{
"servers": {
"eqemu": {
"type": "sse",
"url": "http://YOUR_SERVER_IP:8888/sse",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
}OpenAI Codex CLI
Run codex mcp add or edit ~/.codex/config.toml:
[mcp_servers.eqemu]
url = "http://YOUR_SERVER_IP:8888/sse"
enabled = true
[mcp_servers.eqemu.env]
MCP_TOKEN = "YOUR_TOKEN"Or with token via environment variable:
[mcp_servers.eqemu]
url = "http://YOUR_SERVER_IP:8888/sse"
bearer_token_env_var = "MCP_TOKEN"
enabled = trueThen set export MCP_TOKEN=YOUR_TOKEN in your shell.
Claude Desktop
Claude Desktop doesn't natively support SSE. Use stdio mode instead (Option 2), or use mcp-proxy to bridge SSE to stdio.
If the MCP server is on the same machine as your AI client:
{
"mcpServers": {
"eqemu": {
"command": "/path/to/venv/bin/python",
"args": ["/path/to/eqemu-mcp-server/server.py"],
"env": {
"EQEMU_SOURCE_PATH": "/opt/akk-stack/code",
"EQEMU_QUESTS_PATH": "/opt/akk-stack/server/quests",
"EQEMU_SERVER_PATH": "/opt/akk-stack/server",
"EQEMU_DB_HOST": "YOUR_SERVER_IP",
"EQEMU_DB_PORT": "3306",
"EQEMU_DB_USER": "eqemu",
"EQEMU_DB_PASSWORD": "YOUR_DB_PASSWORD",
"EQEMU_DB_NAME": "peq",
"RG_PATH": "/path/to/rg",
"EQEMU_ACCESS_MODE": "read"
}
}
}
}| Mode | EQEMU_ACCESS_MODE |
Tools | Use Case |
|---|---|---|---|
| Read-Only | read (default) |
50+ read-only | Safe for sharing — SQL restricted to SELECT, passwords redacted |
| Read-Write | readwrite |
All 60+ | Server admins actively managing content |
# In .env
EQEMU_ACCESS_MODE=read # safe default
EQEMU_ACCESS_MODE=readwrite # full accessBy default, the MCP server accepts connections from anyone who can reach the port. Use one or both of these methods to restrict access.
Use UFW to only allow specific IP addresses to connect:
# Remove any existing open rule
sudo ufw delete allow 8888/tcp
# Allow only your IP
sudo ufw allow from YOUR_HOME_IP to any port 8888 proto tcp
# Allow additional users
sudo ufw allow from FRIEND_IP to any port 8888 proto tcp
# Verify
sudo ufw status | grep 8888This is the simplest approach — no code changes needed. To find your IP, visit https://whatismyip.com.
Require a secret token for all SSE connections. Set EQEMU_MCP_TOKEN in your .env:
# Generate a random token
EQEMU_MCP_TOKEN=$(openssl rand -hex 32)
echo "EQEMU_MCP_TOKEN=$EQEMU_MCP_TOKEN" >> .env
echo "Your token: $EQEMU_MCP_TOKEN"Then restart the server. Clients must include the token in the URL:
Windsurf:
{
"mcpServers": {
"eqemu": {
"serverUrl": "http://YOUR_SERVER_IP:8888/sse",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
}The token can also be passed as a query parameter (?token=YOUR_TOKEN) for clients that don't support custom headers. Without a valid token, the server returns 401 Unauthorized.
By default, the MCP server connects to MariaDB using the eqemu user, which has full read/write access. For production or shared deployments, create a dedicated read-only MySQL user so that no database writes are possible, even if a bug or prompt injection bypasses the application-level SQL validation.
Step 1: Create the read-only user
# For akk-stack (Docker):
docker exec -it akk-stack-mariadb-1 mysql -u root -p${MARIADB_PASSWORD} -e "
CREATE USER 'eqemu_readonly'@'%' IDENTIFIED BY 'PICK_A_STRONG_PASSWORD';
GRANT SELECT, SHOW DATABASES, SHOW VIEW ON \`YOUR_DB_NAME\`.* TO 'eqemu_readonly'@'%';
FLUSH PRIVILEGES;
"Replace YOUR_DB_NAME with your database name (e.g. peq, e9profusion_production) and PICK_A_STRONG_PASSWORD with a password of your choice.
Step 2: Add to your .env
EQEMU_DB_USER=eqemu_readonly
EQEMU_DB_PASSWORD=PICK_A_STRONG_PASSWORDStep 3: Restart the MCP container
cd /opt/akk-stack
docker compose -f docker-compose.yml \
-f eqemu-mcp-server/docker-compose.akk-stack.yml \
up -d --no-deps --force-recreate eqemu-mcpThe MCP server now connects with SELECT-only permissions. Any write attempt — whether from the application, an AI, or a crafted query — will be rejected by MySQL itself.
For maximum security, use all three layers:
- Firewall — restricts which IPs can connect
- Token auth — ensures only authorized clients can use the tools
- Read-only DB user — guarantees no database writes at the MySQL level, regardless of application behavior
Once connected, your AI assistant can handle requests like:
Querying & Inspecting:
"Write me a query to find all NPCs in crushbone that drop cloth items"
"What's in Lord Nagafen's loot table?"
"Show me all items with haste >= 30"
"Who's online right now?"
Debugging & Investigation:
"Find all accounts that share IPs with the character Soandso"
"Show me the patrol path for the guard NPCs in Qeynos"
"What faction hits do you get for killing a Freeport Militia member?"
"Show me the most recent crash logs"
Quest Development:
"What Lua quest methods are available on the Client object?"
"Search the source for how spell resistance is calculated"
"Find all quest scripts that use
eq.spawn2"
Content Management (write mode):
"Create a new NPC named Test_Merchant at level 30"
"Add a Cloth Cap to merchant 123's inventory"
"Set the AA:ExpPerPoint rule to 50000000"
cd /opt/akk-stack
# Create venv
python3 -m venv eqemu-mcp-venv
source eqemu-mcp-venv/bin/activate
pip install mcp[cli] mysql-connector-python
# Install ripgrep (optional but recommended)
apt-get install -y ripgrep
# Clone documentation (for docs tools)
git clone --depth 1 https://github.com/EQEmu/eqemu-docs-v2.git eqemu-docs
# Clone and configure
git clone https://github.com/straps-eq/eqemu-mcp-server.git
cd eqemu-mcp-server
cp .env.example .env
# Edit .env with: DB host/password (from `make info`), paths, access mode
# Test
python server.py # Ctrl+C to stop
# Run SSE
./start.sh --sse 8888
# Open the firewall port
sudo ufw allow 8888/tcpsudo tee /etc/systemd/system/eqemu-mcp.service > /dev/null << 'EOF'
[Unit]
Description=EQEmu MCP Server
After=docker.service
[Service]
Type=simple
WorkingDirectory=/opt/akk-stack/eqemu-mcp-server
ExecStart=/opt/akk-stack/eqemu-mcp-server/start.sh --sse 8888
Restart=always
User=root
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable eqemu-mcp
sudo systemctl start eqemu-mcpeqemu-mcp-server/
server.py # Entry point — registers tools based on access mode
start.sh # Startup script (loads .env, activates venv)
Dockerfile # Docker image for containerized deployment
docker-compose.yml # Standalone Docker Compose
docker-compose.akk-stack.yml # akk-stack integration overlay
eqemu_mcp/
config.py # Centralized configuration from env vars
helpers.py # Shared utilities (DB connections, ripgrep, file I/O)
tools_source.py # C++ source code search and browsing
tools_quest_api.py # Lua/Perl quest API method parsing
tools_quests.py # Quest script browsing + editing (write)
tools_server.py # Server config, rules, logs, content flags
tools_database.py # Schema inspection and SQL queries
tools_entities.py # NPC, item, spawn, loot, zone, spell lookups
tools_entities_write.py # NPC, spawn, loot, merchant write operations
tools_docs.py # EQEmu documentation search (docs.eqemu.io)
tools_lookup.py # Characters, accounts, recipes, doors, grids, factions
Each EQEmu server operator runs their own instance:
- Clone this repo on the server
- Configure
.envwith their paths and DB credentials - Set
EQEMU_ACCESS_MODE=read(safe default) - Run via stdio or SSE
- Connect their AI client
The server is completely self-contained — no external services, no cloud dependencies, no API keys. All data stays on your machine.
MIT