pob-mcp
Allows loading Path of Exile 2 builds from Pastebin links.
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., "@pob-mcpload my current build and show me the DPS breakdown"
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.
pob-mcp
pob-mcp is an MCP server. It lets an LLM load, inspect, change, and improve Path of Exile 2 builds. It uses the real calculation engine from Path of Building Community (PoE2 fork). It does not reimplement that engine.
pob-mcp runs a real, headless copy of PoB (a Lua program) as a background process. It talks to that process over a small JSON-RPC protocol. Every stat you get back is a number PoB itself calculated.
How it works
MCP client (Claude Desktop, Cursor, ...)
| MCP over stdio
v
pob-mcp (Python) -- tools_*.py, optimizer/
| JSON-RPC over stdio
v
lua/pob_bridge.lua (running under `luajit`)
| dofile()
v
Path of Building - PoE2's own Lua source (Launch.lua, Main.lua, ...)lua/pob_bridge.lua is a fork of PoB's own src/HeadlessWrapper.lua, which
PoB uses for its test suite. pob-mcp does not depend on that file directly.
Installed copies of PoB leave HeadlessWrapper.lua out (see
manifest.cfg), so pob-mcp brings its own version instead. This means
pob-mcp works the same way against a git checkout of PathOfBuilding-PoE2 and
against an installed release build.
Before you start
You need four things:
uv. Use it to install and run pob-mcp.
LuaJIT, a 5.1-compatible build. Put it on your
PATHasluajit, or point to it withPOB_MCP_LUAJIT. You need this separately from PoB itself: PoB's own runtime only shipslua51.dll/SimpleGraphic.dllfor its graphical app. It does not ship a command-line interpreter you can run on its own.Windows: install it with Scoop (
scoop install luajit), Chocolatey (choco install luajit), or a portable build.macOS:
brew install luajit.Linux:
apt install luajit, the equivalent for your distribution, or build it from source.
A Path of Building - PoE2 install. This can be a git checkout (this repo, or your own clone) or an installed release build. See "Point pob-mcp at a PoB install" below.
zlib. pob-mcp needs this to read and write build codes, and to calculate Timeless Jewel data. On Windows, you already have this: PoB bundles
zlib1.dll(inruntime/for a checkout, or alongside everything else for an installed release). On Linux and macOS, install your system'szlib/libzpackage if you don't have it already (most systems do). If pob-mcp can't find zlib, everything still works except pasted or shared build codes and Timeless Jewel calculations. Load and export builds as.xmlfiles instead.
Point pob-mcp at a PoB install
pob-mcp needs to know where your Path of Building - PoE2 install keeps its Lua source, because that's what the bridge process runs against. There are two ways to point it there. Note that the two have different layouts on disk — pob-mcp detects which one you're using automatically.
Dev checkout mode. Set
POB_MCP_SOURCE_DIRto a PathOfBuilding-PoE2 git checkout — either its root folder, or itssrcfolder directly. This layout keeps the Lua source undersrc/, and keeps the native runtime (LuaJIT DLLs, zlib, the bundled Lua libraries) in a separateruntime/folder next to it.Release mode. Set
POB_MCP_INSTALL_DIRto the root folder of an installed release. On Windows, this is usually%APPDATA%\Path of Building Community (PoE2). An installed release puts everything in one folder —Launch.lua,Modules/,zlib1.dll, the bundledlua/libraries — instead of splitting it up. (We checked this against a real install. We didn't just guess from the repo's packaging config.)
If you don't set either variable, pob-mcp checks a few common install locations for your operating system, and gives you a clear error if it can't find one. On Windows, this already finds a normal installer-installed copy without any setup on your part.
Install pob-mcp
git clone <this repo, or wherever you put pob-mcp> pob-mcp
cd pob-mcp
uv syncRun it on its own (for testing)
POB_MCP_SOURCE_DIR=/path/to/PathOfBuilding-PoE2 uv run pob-mcp
# or, against an installed release:
POB_MCP_INSTALL_DIR="C:\Users\you\AppData\Roaming\Path of Building Community (PoE2)" uv run pob-mcpThis starts the MCP server over stdio. You won't see much happen — MCP servers talk to MCP clients, not directly to you. See "Check that it works," below, for a way to try it out without a full client.
Use it with Claude Desktop, Cursor, or another MCP client
Add an entry to your client's MCP server config. For Claude Desktop, this
is claude_desktop_config.json. For Cursor, it's mcp.json.
{
"mcpServers": {
"pob-mcp": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/pob-mcp", "run", "pob-mcp"],
"env": {
"POB_MCP_SOURCE_DIR": "/absolute/path/to/PathOfBuilding-PoE2"
}
}
}
}For release mode, use POB_MCP_INSTALL_DIR instead. Point it to the root
folder of your installed release — on Windows, usually
%APPDATA%\Path of Building Community (PoE2):
{
"mcpServers": {
"pob-mcp": {
"command": "uv",
"args": ["--directory", "C:\\path\\to\\pob-mcp", "run", "pob-mcp"],
"env": {
"POB_MCP_INSTALL_DIR": "C:\\Users\\you\\AppData\\Roaming\\Path of Building Community (PoE2)"
}
}
}
}Restart your client after you edit its config. You don't need to close Path of Building itself. pob-mcp only reads game data from the install folder. It never writes to it, so it runs fine alongside the app.
Environment variables
Variable | What it does |
| Path to a PathOfBuilding-PoE2 git checkout (its root folder or |
| Path to the root folder of an installed release |
| Path to a |
| Path or name to load zlib from, if pob-mcp can't find it on its own |
| Path to your PoB Builds folder, for |
| Log level for the Python side (default |
What you can do with it
Once your client is connected, start with load_build. Then use the other
tools to inspect, change, and improve the build:
Load a build:
load_build(takes a PoB export code, a pobb.in/Maxroll/poe.ninja pob-link/poe2db.tw/Pastebin.com/Rentry.co link, a local.xmlfile path, or raw XML text),new_build,list_local_builds.Inspect a build:
get_stats,list_stat_keys,get_character,list_classes,get_tree_state,node_info,search_tree,get_items,get_skills,list_gems,get_config,list_config_options,sanity_check.Change a build:
alloc_node/dealloc_node,node_path_cost,select_class,equip_item_raw/unequip_item,add_socket_group,set_main_skill,add_gem/remove_gem/set_gem,list_valid_supports,set_config.A note on gems: each gem has an internal id, and that id is not the same as its display name. Fireball's id, for example, is
"Metadata/Items/Gems/SkillGemFireball". Uselist_gemsto look up the right id — don't guess it. A wrong guess doesn't raise an error. It just silently fails to resolve, so the gem does nothing. The same goes for classes:select_classtakes an internal class id, not a simple 0-based index. Uselist_classesto find it.Improve a build:
optimize_build(goal="damage"|"defence"|"balanced", scope=[...])runs a goal-directed search over the passive tree, support gems, and local unique items. It checks every candidate change against PoB's real engine. See its own description in your MCP client for the full details, including what it deliberately leaves alone.Compare or export:
compare_builds,export_build.
Every tool that changes the build also returns its updated stats. You
don't need a separate get_stats call to see the effect of a change.
What this doesn't do (on purpose)
These are choices, not bugs:
The optimizer never changes configuration options (buffs, curses, enemy stats, map mods). If it could, it could raise its own score by assuming an unrealistic scenario. Call
set_configyourself first if you want to optimize for one specific scenario.Item and jewel search only uses PoB's local database. The
itemsscope ofoptimize_buildtries items from PoB's own bundled unique database, for the same slot. It doesn't check trade-site prices, and it doesn't search rare-item crafting options.The optimizer doesn't search jewels on its own. Matching a jewel to the right socket isn't reliable enough yet. You can still try a specific jewel by hand: use
list_uniques_for_slot, thenequip_item_raw.The optimizer is a greedy search, not a perfect solver. It only adds tree nodes — it never removes or replaces existing ones — and it only swaps one gem or item at a time. It can get stuck on a good-but-not-best answer that a wider search might beat.
pob-mcp can't import a live poe.ninja character profile. It can import a poe.ninja pob-link just like any other supported site, but a live character profile is different: it needs the official character API, and this version doesn't talk to that API yet. Export the character to a PoB code or link first, and use that instead.
pob-mcp doesn't watch your Builds folder for changes.
list_local_buildslists what's there when you call it. It doesn't push updates when something changes. For an LLM-driven session, calling the tool again is simpler, and works just as well.
Check that it works
Automated tests (run with uv run pytest) come in two groups:
Tests that don't touch PoB at all (
test_importers.py,test_optimizer_goals.py,test_optimizer_moves.py,test_locate.py). These run anywhere — you don't need LuaJIT or a PoB install.test_bridge_protocol.pyruns a real bridge process from start to finish: it starts a new build, searches the tree, allocates and deallocates nodes, saves and reloads, lists config options, and runs a sanity check. If it can't findPOB_MCP_SOURCE_DIR,POB_MCP_INSTALL_DIR, or aluajitexecutable, it skips itself and tells you why. Set those environment variables to actually run it.
To try the bridge by hand, without a full MCP client:
cd /path/to/PathOfBuilding-PoE2/src
luajit /absolute/path/to/pob-mcp/lua/pob_bridge.luaThen type (or pipe in) JSON-RPC requests, one per line:
{"id": 1, "method": "new_build", "params": {}}
{"id": 2, "method": "get_stats", "params": {}}Each one should print back a {"id": ..., "result": {...}} line.
Where things live
pob-mcp/
lua/
json.lua # self-contained JSON codec for the bridge protocol
pob_bridge.lua # the headless PoB bridge + JSON-RPC loop
src/pob_mcp/
server.py # MCP server entrypoint, tool registration
bridge.py # subprocess + JSON-RPC client for pob_bridge.lua
locate.py # finds a PoB install + luajit
sites.py # pobb.in/Maxroll/poe.ninja/etc. URL -> build code
importers.py # unifies code/URL/file/XML into one load_build path
tools_*.py # MCP tool definitions, grouped by area
optimizer/ # goal-directed build search
tests/This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Provides cloud browser automation capabilities using Stagehand and Browserbase, enabling LLMs to i…
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
GW1 build compiler: skill data, template code encode/decode, validation, hero roster. Read-only.
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/juddisjudd/pob-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server