Skip to main content
Glama
lumi-fiona

bl2-mcp

by lumi-fiona

bl2-mcp

Let an AI assistant (Claude Code, or any MCP client) look inside a running Borderlands 2 and drive it: read any object, list a function's real arguments, run Python in the game, load a character, fast travel, take screenshots. No keypresses, and the game window never has to be in front.

It has two halves:

Half

What it is

Where it runs

MCP Bridge (mcp_bridge.sdkmod)

A small willow2 mod manager mod. While enabled, every few frames it checks one folder for a request.py, runs it, and writes the output back.

Inside the game

bl2-mcp (bl2_mcp.py)

An MCP server (stdio). It turns tool calls into requests and waits for the answers.

Your machine, started by your MCP client

Why

Modding BL2 from outside means guessing: guess how the game works, restart, walk somewhere, look, guess again. Most of those guesses are facts the running game could tell you: how many arguments a function really takes, which property holds an item's rarity, what the map is called at the moment a character spawns. With the bridge, an assistant can look those up in seconds.

Related MCP server: unity-inspector-mcp

Security: read this first

The bridge runs, with no sandbox, any Python that appears in <game>/sdk_mods/settings/mcp_bridge/request.py. Nothing listens on the network. But any program or person that can write to that folder can run code inside your game process, with your user's rights.

  • The mod is off by default. Enable it in the Mods menu only while you use it. While it is off it has no hooks, so it reads and writes nothing.

  • The mod manager remembers the on/off state between launches. Switch it off when you are done.

  • Don't put the game folder in a synced or shared location (cloud-sync folder, network share) while the bridge is on.

  • The MCP server gives your assistant the same power. Only connect assistants you would trust with a Python prompt on your machine.

Install

Requirements: Windows, Borderlands 2 with the willow2 mod manager v3.8 or newer, and Python 3.10+ with the mcp package for the server.

1. The bridge mod

  1. Download mcp_bridge.sdkmod from the releases page. You can also build it yourself with python tools/build_sdkmod.py, which writes dist/mcp_bridge.sdkmod.

  2. Drop it into <game>/sdk_mods/.

  3. Start the game. Open Mods, select MCP Bridge, read the warning, and enable it.

Optional setting: Check every N frames (default 30). This is how often the bridge looks for a request. Lower numbers answer faster.

2. The MCP server

pip install mcp          # or: pip install .   (from a clone; installs the bl2-mcp command)

Claude Code:

claude mcp add bl2 -- python /path/to/bl2_mcp.py
# or, if the game is not in a Steam library it can find:
claude mcp add bl2 -e BL2_GAME_DIR="C:/Games/Borderlands 2" -- python /path/to/bl2_mcp.py

Any MCP client (JSON config):

{
  "mcpServers": {
    "bl2": {
      "command": "python",
      "args": ["C:/path/to/bl2_mcp.py"],
      "env": { "BL2_GAME_DIR": "C:/Games/Borderlands 2" }
    }
  }
}

Finding the game. It uses the first of these that is set:

  1. --game-dir DIR

  2. the BL2_GAME_DIR environment variable

  3. Steam: it reads the install path from the registry, then steamapps/libraryfolders.vdf, then the app 49520 manifest in each library

The bridge folder is <game>/sdk_mods/settings/mcp_bridge. Override it with --exchange-dir or BL2_MCP_EXCHANGE if your mods folder is somewhere else.

Tools

Tool

What it does

game_status

Running or not (pid), crash message boxes, bridge heartbeat, current map, character, playthrough

game_launch(until, restart)

Starts the game with no input. until="menu" also walks the title screen to the main menu. Refuses if the game is already running, unless restart=True.

game_load_character(playthrough)

From the main menu, loads the most recent character and waits until its backpack can be read

game_quit(force)

Sends the console exit command, then force-kills after 30 s

game_eval(code)

Runs Python in the game and returns stdout/stderr. Globals persist between calls; unrealsdk and get_pc are predefined.

game_find(class_name, contains)

Lists loaded objects of a class

game_object(path, class_name, only)

Shows an object's declared properties and their values

game_function(class_name, function_name)

Shows a function's parameters, in order

game_backpack

Lists the backpack: class, rarity, level, name, balance

game_travel(station)

Fast travels by station name. With no name, lists the stations.

game_log(lines, only)

Tails Binaries/Win32/Plugins/unrealsdk.log

game_screenshot(save_to, max_width)

Captures the game window with PrintWindow without focusing it, and returns the image

An example session walks through a real use.

Limitations

  • Windows only. Process checks, screenshots and launching use Win32 APIs.

  • Borderlands 2 only, for now. The Pre-Sequel and Assault on Dragon Keep use the same SDK and the same WillowPlayerController:PlayerTick, so the bridge may work there. It is untested, and the server is hard-wired to Borderlands2.exe and Steam app 49520.

  • The bridge only answers while PlayerTick runs: on the title screen, in menus and in the world. It is silent during level loads and while a modal dialog is up. Requests wait.

  • Requests run on the game thread, so a slow request freezes the game until it finishes.

  • One request at a time, and one MCP server per game.

  • Launching without focus is a hint (SW_SHOWNOACTIVATE). Windows may still bring the new window to the front.

For AI agents

These rules were learned by crashing the game or losing time. Read them before your first game_eval.

Setup and safety

  • One game process. Two copies exhaust the 32-bit memory limit ("Ran out of video memory") and fight over the one request file. game_launch refuses a second copy, so start from game_status.

  • Throwaway characters. Create a new character for experiments and back up the save folder (Documents/My Games/Borderlands 2/WillowGame/SaveData/<id>/) first. Nothing here has undo. Steam Cloud uploads saves when the game closes, so restore the backup before the next upload if you need the old state back.

  • Restart after editing mod files. Python the game has already imported stays imported, so a test against stale code looks exactly like a failing fix. Use game_launch(restart=True).

Reading timeouts

  • A timeout is not a failure. If the error says the bridge picked the request up, your code probably ran, or is still running. Check game_status and the game state before you resend. If it says never picked up, nothing ran and the request was withdrawn. The game is loading, showing a dialog, or the bridge is off.

  • Before you kill the game, look. A long silence during a level load is normal. The game saves on travel, and a kill during that save can corrupt it.

Moving and spawning

  • Move the player with game functions. Assigning pc.Pawn.Location crashed the game. Use game_travel between maps. Within a map, WillowPlayerController.TeleportPlayer(...) is the engine's own teleport; check its parameters with game_function first.

  • Live objects, not archetypes. find_all("WillowAIPawn") also returns archetypes and Default__ objects, and calling native functions on archetypes crashed the game. For live pawns, walk pc.WorldInfo.PawnList.

  • AI pawns refuse Destroy() (it returns False). Suicide() works.

Navigating without input

  • Menus without input. Injected keypresses don't reach the game (InputKey returns False), so every menu step is a function call:

    • Title screen to main menu: WillowGFxMoviePressStart.BeginStartupProcess(). This is what game_launch(until="menu") does.

    • Continue: pc.LoadLastSavedSaveGame(), then FrontendGFxMovie.LaunchSaveGame(n), where n is the playthrough. This skips the difficulty and OP prompts. It is what game_load_character does.

    • New game: FrontendGFxMovie.LaunchNewGame(). This does exactly what the New Game button does and creates a fresh level-1 save. On class select, CharacterSelectionReduxGFxMovie.HandleCharacterClicked(0, i) picks class i, and HandleCustomizationMenuEntryClick(0, 3) confirms. Save a new character explicitly with pc.SaveGame().

  • Wait for a readable backpack. The map name is reported before the map's contents exist. "Loaded" means len(pc.GetPawnInventoryManager().Backpack) works.

  • Fields before functions on freshly spawned items. RarityLevel and DefinitionData.GameStage are right, while GetRarityLevel() and GetGameStage() returned 0.

Calling game functions

  • Look before you call. Use game_function to get the real parameter list. Guessing argument counts costs a round trip per guess.

  • The game hands back its own objects. AddBackpackInventory stores a new object with the same UniqueId, not the one you passed in. Re-read the backpack to get the real object.

  • SetTimer from the bridge does nothing (IsTimerActive stays False). Hooks do fire on functions the bridge calls.

  • from __future__ still works. The server's marker is a comment line, so a request may start with from __future__ import annotations.

How it differs from existing tools

As far as a search in September 2026 found, there was no public MCP server for Borderlands 2 or pyunrealsdk. The nearest tools:

  • pyunrealsdk's pyexec console command runs a Python file in the game, but someone has to type it into the console.

  • The mod manager's debugpy and ipykernel hooks (see pyunrealsdk) are for a human with a debugger or Jupyter. They open a local TCP port. They are powerful, but they are not a tool an assistant can call, and they don't launch, load, screenshot or diagnose a crashed game.

bl2-mcp adds a file-based bridge with no network listener, and an off switch in the Mods menu. On top of that it has task-shaped tools that know BL2's quirks: menus without input, readiness checks, crash-box detection, and screenshots without focus.

Credits

Built on pyunrealsdk / unrealsdk and the willow2 mod manager by apple1417 and the bl-sdk contributors. Without them none of this could reach the game. It uses the MCP Python SDK.

Development

python -m unittest discover -s tests -v    # offline: no game needed
python tools/build_sdkmod.py               # -> dist/mcp_bridge.sdkmod

The tests start the real server over stdio, and run the real bridge protocol (mod/mcp_bridge/exchange.py) in a stand-in process that plays the game's side.

License: MIT.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables an agent to drive a running Unreal Engine game via UE4SS by reading/writing UObject properties and calling UFunction, with verdicts that verify whether the requested state change actually happened.
    MIT
  • A
    license
    B
    quality
    A
    maintenance
    Enables AI agents and scripts to inspect objects, call functions, and run Lua in a running UE4SS game via MCP, with no sockets or admin rights required.
    26
    MIT