# RimBridgeServer

> RimBridgeServer runs an MCP server inside RimWorld so AI agents and external tools can remotely control and observe a running game.

- **Type:** MCP server
- **Install:** `agentstack add mcp-pardeike-rimbridgeserver`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [pardeike](https://agentstack.voostack.com/s/pardeike)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [pardeike](https://github.com/pardeike)
- **Source:** https://github.com/pardeike/RimBridgeServer

## Install

```sh
agentstack add mcp-pardeike-rimbridgeserver
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# RimBridgeServer

RimBridgeServer is a RimWorld mod that turns the running game into a bridge an external tool can use.

In practice, that means a test harness, developer tool, or AI agent can start RimWorld, inspect live game state, drive built-in UI, manage mods and mod settings, execute debug actions, take targeted screenshots, and verify behavior against the real game instead of a simulation.

This project is aimed at automated mod development and testing:

- integration testing against a real RimWorld session
- UI and UX verification through semantic dialogs, targets, and screenshots
- faster repro loops for debug actions, saves, settings, and load-order changes
- AI-assisted mod development through GABS or direct bridge connections

Architecture and design notes live in [docs/architecture.md](docs/architecture.md), [docs/lua-frontend-design.md](docs/lua-frontend-design.md), [docs/semantic-state-design.md](docs/semantic-state-design.md), and [docs/attention-policy.md](docs/attention-policy.md).

## What It Does

RimBridgeServer runs inside RimWorld and exposes a tool surface for:

- reading game, map, camera, selection, notification, and UI state
- driving high-level game actions such as debug actions, main tabs, Architect designators, and selection changes
- changing mod settings and mod load order
- capturing screenshots, including clipped screenshots for known UI or screen targets
- running small automation scripts through JSON or Lua front-ends
- driving Dubs Performance Analyzer profiling when DPA is installed and active

It is designed to stay as close as possible to RimWorld's own logical seams instead of reimplementing gameplay logic outside the game.

## Installation

### Recommended: Use GABS

GABS is the best way to use RimBridgeServer from an AI or automation harness.

Why this is the recommended mode:

- GABS can start and stop RimWorld for you
- GABS can discover the live bridge tool surface after the game connects
- you do not need to manage ports or tokens manually
- this is the cleanest setup for autonomous mod testing

Basic setup:

1. Install RimBridgeServer into your RimWorld `Mods` folder.
2. Enable `RimBridgeServer` in RimWorld's mod list.
3. Install and configure [GABS](https://github.com/pardeike/GABS).
4. Start RimWorld through GABS and connect to the running game.

Once RimWorld is up, GABS exposes the game-management tools (`games.start`, `games.connect`, `games.call_tool`) and then the live RimBridgeServer tool surface behind them.

RimBridgeServer now also publishes blocking attention when severe async failures happen after a call boundary, such as hard log errors or failed bridge operations. In GABS this surfaces through `games.get_attention` and `games.ack_attention`: ordinary game calls pause until the attention item is reviewed and acknowledged, while tagged bridge diagnostics and lifecycle observation tools such as `rimbridge/get_bridge_status`, `rimbridge/list_operation_events`, `rimbridge/list_logs`, `rimbridge/wait_for_game_loaded`, and `rimbridge/wait_for_long_event_idle` remain available for diagnosis and recovery. The current built-in policy is documented in [docs/attention-policy.md](docs/attention-policy.md).

## RimWorld Mod Debugging Stack

If you want the same stack used for real mod repro-and-fix sessions, use:

1. `Harmony` plus the mod you are testing
2. `RimBridgeServer` inside RimWorld for live game inspection and control
3. [GABS](https://github.com/pardeike/GABS) to launch RimWorld and surface the live tools to your AI client
4. [DecompilerServer](https://github.com/pardeike/DecompilerServer) to inspect `Assembly-CSharp.dll` and related managed code while debugging

When [Dubs Performance Analyzer](https://steamcommunity.com/sharedfiles/filedetails/?id=2038874626) is installed and active, RimBridgeServer also exposes generic DPA profiling tools for repeatable method-level Tick and Update measurements.

There is a short setup order here: [docs/rimworld-mod-debugging-stack.md](docs/rimworld-mod-debugging-stack.md).

### Direct Mode

Direct mode still works if you do not want to use GABS.

Basic setup:

1. Install RimBridgeServer into your RimWorld `Mods` folder.
2. Enable `RimBridgeServer` in RimWorld's mod list.
3. Start RimWorld normally.
4. Read the RimWorld log for the bridge startup lines.

In direct mode, RimBridgeServer logs lines like:

```text
[RimBridge] GABP server running standalone on port 5174
[RimBridge] Bridge token: abc123...
```

Your client then connects to:

- address: `127.0.0.1`
- port: the logged bridge port
- token: the logged bridge token

## Local Package Overrides

For cross-repo development in a sibling workspace, RimBridgeServer supports an opt-in local NuGet source override without switching the project to `ProjectReference`s.

- default local source path: `../.nuget-local`
- enable it with `EnableLocalNuGetOverride=true`
- override package versions with `LibGabPackageVersion` and `RimBridgeServerSdkPackageVersion`

Example:

```bash
dotnet restore Source/RimBridgeServer.csproj \
  -p:EnableLocalNuGetOverride=true \
  -p:LibGabPackageVersion=1.0.3-local.1 \
  -p:RimBridgeServerSdkPackageVersion=2.0.0-local.1
```

Populate the local source by packing the sibling library into `../.nuget-local`, for example:

```bash
dotnet pack ../Lib.GAB/Lib.GAB/Lib.GAB.csproj \
  -o ../.nuget-local \
  -p:PackageVersion=1.0.0-local.1
```

Pack the RimBridgeServer companion SDK into that same local source with:

```bash
scripts/pack-sdk.sh
```

Use `scripts/pack-sdk.sh --out ` when a different local NuGet source should receive the package.

## Release Assets

Release-facing assets are kept in source control so the in-game metadata, GitHub release packaging, and external post copy stay aligned.

- `About/ModIcon.png` is the small in-game mod icon
- `About/Preview.png` is the preview/banner image
- `Source/Originals/Steam-Post.txt` and `Source/Originals/Ludean-Post.txt` hold the maintained workshop/forum copy
- `scripts/render-mod-icon.swift` regenerates `About/ModIcon.png` from the preview art

## Codex Skills

Install or refresh the local Codex skills maintained by this repo with:

```bash
scripts/install-skills.sh
```

That command refreshes the generated `rimbridge-server` live bridge skill from `README.md` and `docs/tool-reference.md`, then installs repo-owned skills from `skills/`, including `rimbridge-companion-tools` for adding `RimBridgeServer.Sdk` companion DLLs to RimWorld mods.

## Local Deploy Targets

`RIMWORLD_MOD_DIR` is a parent directory deploy target: builds copy the mod to `$RIMWORLD_MOD_DIR/RimBridgeServer` and write `$RIMWORLD_MOD_DIR/RimBridgeServer.zip`.

When the enabled RimWorld mod is a specific Steam Workshop item folder or another exact active mod root, use `RIMWORLD_MOD_TARGET_DIR` instead. That deploys directly into the named folder and writes a zip beside it unless `RIMWORLD_MOD_ZIP_PATH` is set.

```bash
scripts/deploy-local-mod.sh \
  --target-dir "$HOME/Library/Application Support/Steam/steamapps/workshop/content/294100/3727949765"
```

Before live smoke testing after a redeploy, confirm the active mod root with `rimworld/get_mod_configuration_status`; the game must load the same directory that the build just updated.

For a source-only build that cannot deploy even when RimWorld deploy environment variables are set, use:

```bash
scripts/build-mod.sh --test
```

## Beginner Start

If you only need the shortest possible mental model, use this:

1. Install the mod and enable it in RimWorld.
2. Prefer GABS if you want AI or harness control.
3. Start RimWorld.
4. Wait until the bridge is connected.
5. Use tools like `rimbridge/get_bridge_status`, `rimworld/start_debug_game`, `rimworld/get_ui_layout`, `rimworld/take_screenshot`, `rimworld/list_mods`, and `rimworld/update_mod_settings` to drive and validate the game.

## UI Layout Targets And Cropped Screenshots

Use `rimworld/get_ui_layout` when visual verification needs something more precise than a full-frame screenshot. The layout response exposes `ui-surface` ids for open windows/main tabs and `ui-element` ids for controls and natural regions such as `scroll_view` elements. Each surface and element includes its local `rect` plus a crop-ready `screenRect`.

Pass those ids to `rimworld/take_screenshot` as `clipTargetId` to crop a screenshot around a dialog, a window surface, a button, a label row, or a scroll viewport. For scroll views, use the element's `scroll` payload to read current offsets and limits, then call `rimworld/scroll_ui_target` with a delta or absolute target offset before capturing the next layout or cropped screenshot.

## Third-Party Extension Tools

Third-party mods can expose bridge tools through companion DLLs that reference the `RimBridgeServer.Sdk` NuGet package. RimBridgeServer starts its bridge services after RimWorld has loaded normal mod assemblies, then loads companion DLLs from explicit `BridgeTools` folders and registers their `[Tool]` methods through the same capability registry and top-level GAB tool surface as built-in tools.

Practical rules:

- use `RimBridgeServer.Sdk` as the only shared bridge dependency
- for normal paired local mod development, deploy the mod into the active RimWorld `Mods` folder and deploy its companion to that same install's sibling global BridgeTools root, for example `$(RIMWORLD_MOD_DIR)/SomeMod/1.6/Assemblies/SomeMod.dll` and `$(RIMWORLD_MOD_DIR)/../BridgeTools/SomeMod/SomeMod.BridgeTools.dll`
- put standalone global tools in `RimWorldRoot/BridgeTools`, either as loose single DLLs or first-level bundle folders
- use a first-level bundle folder when a global companion needs private helper DLLs, for example `BridgeTools/PoseHarness/PoseHarness.dll`
- do not add a separate BridgeTools root or override for normal paired local deployments; derive the companion root from the selected `Mods` folder so the mod DLL and companion DLL are updated as one deployment unit
- treat mod-local companions beside an active load folder's `Assemblies` folder, for example `SomeMod/1.6/BridgeTools`, as a rare packaged-mod edge case only; do not use that layout for ordinary local paired dev deploys unless the packaging model explicitly requires it
- annotate public static methods or public instance methods on a public parameterless tool class
- async tool methods may return `Task`, `ValueTask`, `Task`, or `ValueTask`
- accept `IRimBridgeContext` and/or `CancellationToken` parameters when a tool needs injected SDK access; those parameters are hidden from the public tool schema
- public tool names are global across the bridge surface; collisions are rejected and reported instead of silently choosing one tool
- use `[ToolParameter]` for argument docs, `Tool.ResultDescription` for a short successful-result summary, and `[ToolResponse]` for response field docs when useful
- expect per-mod fault isolation: one broken mod should not block discovery for other mods
- query and call tools dynamically with `ctx.Tools.List(...)`, `ctx.Tools.Get(...)`, `ctx.Tools.CallAsync(...)`, typed `ctx.Tools.CallAsync(...)`, and `ctx.Tools.QueueAsync(...)`
- use `result.Succeeded()`, `result.PayloadSuccess()`, and `result.ReadResult(...)` when a called tool returns dictionary-shaped or anonymous-object payloads
- use `RimBridgeEvidenceManifest` and `RimBridgeEvidence` helpers for repeatable suites that should return screenshots, assertions, errors, and environment details in a stable shape
- let real RimWorld time pass inside structured tools with `ctx.Game.NextFrameAsync()`, `ctx.Game.FramesAsync(...)`, `ctx.Game.StepTicksAsync(...)`, `ctx.Game.RunForTicksAsync(...)`, and `ctx.Game.RunUntilAsync(...)`
- after GABS reports the bridge tool surface, call `rimworld/load_game_ready` for a prepared save or `rimworld/start_debug_game_ready` for a fresh dev colony; those tools queue RimWorld long-event work and wait to the requested readiness target
- if a companion tool is missing or fails with an SDK mismatch, call `rimbridge/get_bridge_status`; the response includes the host SDK version, companion discovery records, local SDK-copy warnings, and companion load/register errors

Minimal example:

```csharp
using RimBridgeServer.Sdk;

public sealed class MyModBridgeTools
{
    [Tool(
        "mymod/ping",
        Description = "Example tool exposed through RimBridgeServer",
        ResultDescription = "A success flag and the resolved label returned to the caller.")]
    public object Ping(
        [ToolParameter(Description = "Optional label")] string label = null)
    {
        return new
        {
            success = true,
            label = label ?? "pong"
        };
    }
}
```

Async orchestration example:

```csharp
using RimBridgeServer.Sdk;

public sealed class MyModHarness
{
    [Tool("mymod/run_particle_test")]
    public async Task RunParticleTest(IRimBridgeContext ctx, string pawnId)
    {
        var spawn = await ctx.Tools.CallAsync("mymod/spawn_test_effect", new { pawnId });
        if (!spawn.Succeeded())
            return new { success = false, stage = "spawn", error = spawn.Error, spawn = spawn.Result };

        await ctx.Game.RunForTicksAsync(120);
        var state = await ctx.Tools.CallAsync("mymod/read_effect_state", new { pawnId });
        return new
        {
            success = state.Succeeded(),
            particleCount = state.TryReadResult(out var count, "particleCount") ? count : 0,
            state = state.Result
        };
    }
}
```

For stable contracts, use a typed DTO instead of a dynamic object payload:

```csharp
var load = await ctx.Tools.CallAsync(
    "rimworld/load_game_ready",
    new { saveName, readiness = "visual", pauseIfNeeded = true });
if (!load.Succeeded())
    return new { success = false, stage = "load", error = load.Error, load = load.Result };
```

Evidence suites can use the SDK's small manifest/assertion helpers without adopting a separate runner:

```csharp
var manifest = RimBridgeEvidence.CreateManifest("mymod/render-sweep", runId);
manifest.saveName = saveName;
manifest.assertions.Add(RimBridgeEvidence.ToolSucceeded("load save", load));
manifest.captures.Add(new RimBridgeEvidenceCapture
{
    label = "north",
    kind = "cell_rect",
    path = shot.TryReadResult(out var path, "path") ? path : string.Empty,
    details = shot.Result
});
RimBridgeEvidence.Complete(manifest);
return manifest;
```

## Tool Surface

The current public tool surface is grouped below by function.
For the generated parameter-level reference pulled straight from the annotated source and kept fresh by CI, see [docs/tool-reference.md](docs/tool-reference.md).

Lua authoring note: `rimbridge/run_lua` is intentionally a lowered Lua subset, not general-purpose Lua. Start with `rimbridge/get_lua_reference` and `rimbridge/compile_lua`; prefer `local` bindings, `rb.call`/`rb.poll`, static field access, and static one-based indexes such as `names[1]`. Dynamic indexing such as `names[i]`, arbitrary global assignment, and most broader Lua features are rejected in v1.

### Bridge Diagnostics

- `rimbridge/ping` - Connectivity test. Returns 'pong'.
- `rimworld/get_game_info` - Get basic information about the current RimWorld game
- `rimbridge/get_operation` - Get the latest retained journal snapshot for a specific operation id, including any bounded retained result payload
- `rimbridge/get_bridge_status` - Get the current bridge and RimWorld state snapshot without mutating game state
- `rimbridge/list_capabilities` - List registered bridge capabilities so an agent can discover the live bridge surface instead of relying on hardcoded tool knowledge
- `rimbridge/get_capability` - Get one registered bridge capability descriptor by capability id or alias
- `rimbridge/list_operations` - List recent bridge operations from the in-memory operation journal, optionally expanding retained result payloads
- `rimbridge/list_operation_events` - List recent bridge operation lifecycle events from the in-memory event journal
-

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [pardeike](https://github.com/pardeike)
- **Source:** [pardeike/RimBridgeServer](https://github.com/pardeike/RimBridgeServer)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-pardeike-rimbridgeserver
- Seller: https://agentstack.voostack.com/s/pardeike
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
