A Python client for The Mana World, exposed as an MCP server so an AI agent can play the game.
Project description
tmw-mcp
A Python client for The Mana World (a tmwAthena-based MMORPG) exposed as an MCP server. Point any MCP-capable AI agent at it and the agent can log in, walk around, fight, trade, and talk to NPCs.
The bot also runs as an interactive CLI for humans, and ships with an optional browser dashboard.
Please follow the server rules
The Mana World's game rules explicitly forbid AFK botting. Treat this MCP server as an attended assistant: stay at the keyboard while your character is logged in, prompt the bot to respond to chat and GMs in a timely way, and disconnect before stepping away. Running it unattended may get your account banned.
Install
pip install tmw-mcp
The only third-party dependency is mcp. Game data (maps, items, monsters, sprites) is fetched on first login from the server's update host and cached under ~/.cache/tmw-mcp/; nothing to clone or unpack.
Register an account
tmw-mcp-register --user MyAccount --char-name MyCharacter
This writes a credentials.json (chmod 600, owner read/write only) in the current directory. Treat it like any other secret. tmw-mcp looks for it in its own current working directory by default, so the simplest setup is to run the host from this same directory; otherwise point at the file explicitly with TMW_CREDENTIALS_FILE (covered below).
Using an existing account
If you already have a TMW account and character, you can skip tmw-mcp-register and write credentials.json by hand. The full shape is:
{
"server": "server.themanaworld.org",
"port": 6901,
"username": "MyAccount",
"password": "hunter2",
"char_name": "MyCharacter"
}
Only username and password are required; the rest fall back to the defaults shown above. char_name picks which character on the account to log in as; omit it to use the account's first character. Remember to chmod 600 credentials.json so it's owner-only, and keep it out of git.
Use it from an MCP client
Recommended: Claude Code
Claude Code is the only MCP host today that wakes the agent on notifications/claude/channel messages, which is how the bot surfaces chat, NPC dialog, combat damage, death, map changes, and the ferry-bell effect in real time. Without that, the bot only acts when you prompt it, which is fine for short tasks but turns the game into "ask the bot what's happening" instead of "the bot tells you." If you have a choice, use this one.
claude mcp add tmw -- tmw-mcp # writes .mcp.json in the current project
# (or add -s user for ~/.claude.json)
Equivalent in JSON, drop into .mcp.json at your project root by hand:
{
"mcpServers": {
"tmw": {
"command": "tmw-mcp"
}
}
}
Verify with claude mcp list; remove with claude mcp remove tmw.
The reactive-wakeup channel is gated behind a Claude Code dev flag. Launch claude with --dangerously-load-development-channels server:tmw so the host actually subscribes to notifications/claude/channel from this server; without the flag every other tool still works, you just don't get the wake-up on in-game events.
Other hosts (no wake-ups)
The tool surface is identical across hosts; what you lose without Claude Code is just the wake-up channel, every tmw tool itself works the same. Pick whichever fits your workflow.
Claude Desktop, Cursor, Cline. Same mcpServers shape as Claude Code, just in a different config file:
{ "mcpServers": { "tmw": { "command": "tmw-mcp" } } }
| Host | Config path |
|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (macOS), %APPDATA%\Claude\claude_desktop_config.json (Windows) |
| Cursor | ~/.cursor/mcp.json (user) or .cursor/mcp.json (workspace) |
| Cline | cline_mcp_settings.json (open via "Cline: MCP Servers" command in VS Code, or under ~/.cline/data/settings/ for the Cline CLI) |
VS Code Copilot extension. Different schema (servers not mcpServers, explicit type: "stdio"). Drop into .vscode/mcp.json at the workspace root (or use "MCP: Open User Configuration"):
{ "servers": { "tmw": { "type": "stdio", "command": "tmw-mcp" } } }
Switch Copilot Chat from "Ask" to "Agent" mode; MCP tools only show up there.
Copilot CLI and Codex CLI. Same mcp add shape as Claude Code's:
copilot mcp add tmw -- tmw-mcp # writes ~/.copilot/mcp-config.json
codex mcp add tmw -- tmw-mcp # writes a block into ~/.codex/config.toml
Verify with <host> mcp list; remove with <host> mcp remove tmw. If tmw-mcp isn't on PATH (e.g. it's only in a specific venv), use the absolute path after the --.
When credentials.json isn't in the host's cwd
Claude Code, Cursor, Cline, and VS Code Copilot launch tmw-mcp with the workspace as cwd, so a credentials.json at the workspace root is found automatically. The CLI hosts (Claude Code CLI, Copilot CLI, Codex CLI) inherit your terminal's cwd. If neither lines up with where credentials.json lives (Claude Desktop on macOS, for instance), pass an absolute path via TMW_CREDENTIALS_FILE:
{
"mcpServers": {
"tmw": {
"command": "tmw-mcp",
"env": {
"TMW_CREDENTIALS_FILE": "/home/you/credentials.json"
}
}
}
}
For the CLI hosts: claude mcp add -e TMW_CREDENTIALS_FILE=/home/you/credentials.json tmw -- tmw-mcp (and --env instead of -e for copilot / codex).
Without a credentials file
If you'd rather not have a credentials.json on disk at all, pass TMW_USERNAME, TMW_PASSWORD, and TMW_CHAR_NAME in the host's env block directly. Mind that those secrets then live inside each host's config file, which is usually plaintext and sometimes inside a workspace dir that's easy to commit by accident.
Self-restart via restart
tmw-mcp is fronted by a thin stdio shim that owns the actual game-client daemon as a subprocess. Calling the restart tool sends a clean quit to the map server, waits for the server's account-online entry to clear, and respawns the daemon, all without dropping the MCP session. The standard MCP tools/listChanged notification fires after the restart so any host re-syncs. It pairs especially well with Claude Code, where the conversation context survives the restart and you get a tight "fix bug, restart, verify" loop in one session.
Configuration
| Variable | Meaning |
|---|---|
TMW_USERNAME |
Account name |
TMW_PASSWORD |
Account password |
TMW_CHAR_NAME |
Character name. If omitted, the account's first character is used. |
TMW_SERVER |
Login server. Accepts host or host:port. Default server.themanaworld.org:6901. |
TMW_PORT |
Override port only. Default 6901. |
TMW_WORLD |
World name (blank for default). |
TMW_DASHBOARD_PORT |
Bind the browser dashboard on 127.0.0.1:PORT. Off by default. |
TMW_CLIENT_DATA |
Skip the update-host download and read game data from this directory instead. Dev-only convenience for iterating on local TMX / item XML edits. |
TMW_CREDENTIALS_FILE |
Absolute path to a credentials.json. Useful when your MCP host runs tmw-mcp from a cwd that doesn't contain one. |
Precedence: explicit CLI flags > env vars > credentials.json > built-in defaults. TMW_CREDENTIALS_FILE, if set, picks which credentials.json gets read; per-field env vars (TMW_USERNAME etc.) still override whatever's in the file.
Browser dashboard
Set TMW_DASHBOARD_PORT=8765 (or pass --dashboard-port 8765 to any CLI entry) and open http://127.0.0.1:8765/. The dashboard shows a live tile map (collision grid, beings, floor items, walk path, hunt zone, aggro discs), HP/SP/EXP bars, hunt status, NPC dialog state, inventory, and a chat tail. Localhost-only, no auth, no extra dependencies (stdlib HTTP + SSE + vanilla JS).
Where things live
| Kind | Path |
|---|---|
| Downloaded game data | ${XDG_CACHE_HOME:-~/.cache}/tmw-mcp/ |
| Logs and session state | ${XDG_STATE_HOME:-~/.local/state}/tmw-mcp/ |
| Credentials file | ./credentials.json in your cwd (chmod 600, gitignored) |
Console scripts
pip install creates four entry points:
| Command | What it runs |
|---|---|
tmw-mcp |
Self-restartable MCP stdio entry point. This is what MCP clients should call. |
tmw-mcp-server |
The daemon itself, useful for standalone testing. |
tmw-mcp-cli |
Interactive REPL for humans. |
tmw-mcp-register |
Create an account on the server. |
The same modules also work via python -m tmw_mcp.mcp_shim etc, so you don't need to install to try them.
Running from source
git clone https://git.sr.ht/~thorbjorn/tmw-mcp
cd tmw-mcp
python3 -m venv .venv
.venv/bin/pip install -e .
.venv/bin/python -m unittest discover # from repo root; 66 tests
Game data (maps, items, monsters) is fetched from the server's update host on first login and cached under ~/.cache/tmw-mcp/, so a checkout is all you need to run the tests and the CLI. If you want to iterate on local TMX or item XML changes, point TMW_CLIENT_DATA at a directory that mirrors the same layout and the downloader is bypassed.
How it works
The TMW protocol is binary, little-endian, over TCP. Three servers in sequence: login (default 6901), character (6122), map (5122). After a successful login the server emits a SMSG_UPDATE_HOST (0x0063) packet pointing at a small resources.xml manifest of ZIP files; the client downloads, hash-verifies (adler32), and presents them as a read-only overlay used for map collision, item names, and monster names.
The active code path is tmw_mcp.mcp_shim (the console-script tmw-mcp), a thin stdio proxy that owns a daemon subprocess running tmw_mcp.mcp_server. The shim survives daemon restarts; the daemon owns the actual game connection. Inside the daemon, a single GameClient (tmw_mcp.game) walks the login handshake and dispatches packets, while a thin MCP layer exposes every action as an MCP tool under the tmw namespace.
Game data layout, packet definitions, and the NPC dialog state machine are documented in CLAUDE.md.
License
MIT. See LICENSE.
The Mana World itself is GPL'd content maintained by its community; this client is independent original work that speaks the same wire protocol.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tmw_mcp-0.1.2.tar.gz.
File metadata
- Download URL: tmw_mcp-0.1.2.tar.gz
- Upload date:
- Size: 126.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70a2a3092e43ca83db53e21bb4a23a93ea83043cb940b513f0b28cdf3d25d03d
|
|
| MD5 |
2d47f4e035b6214183ab6e1aff9b838c
|
|
| BLAKE2b-256 |
aa3c43b958b3573ac51b653e56e0ee50b9c450791a0d5b79e8ac463b55d47c56
|
File details
Details for the file tmw_mcp-0.1.2-py3-none-any.whl.
File metadata
- Download URL: tmw_mcp-0.1.2-py3-none-any.whl
- Upload date:
- Size: 104.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68a3b9e76b971b06d648ab3792d6ab060411c6b3fe5fd065edc5e790f67c9054
|
|
| MD5 |
5334c663462f23bae21461f1f6ba0877
|
|
| BLAKE2b-256 |
637293e03b693e87b4c58dd840097f09b05c79282b6dd7cd8cb2c412151a7af5
|