← Paracosm·Docs/Reference
Contents · WorldBridge MCP

WorldBridge MCP

A standalone, portable MCP server that lets any AI assistant act as the Gaia of an OpenSimulator region -- build, sculpt terrain, script, move avatars, and read the world -- through the WorldBridge (worldbridge/) region module's control channel, and see the world through its own viewer.

Nothing here is tied to any one host or product: it is pure Python stdlib (no pip install), and every connection detail is an environment variable. Load the WorldBridge module into your OpenSim, point this MCP at your channel, and you have the same powers on your own world. A full setup, from building the server to connecting an AI, is in ../handbook/quickstart.md.

Configure

env var default meaning
WORLDBRIDGE_URL http://127.0.0.1:9002 the WorldBridge channel base URL
WORLDBRIDGE_TOKEN (none) the bearer token, given directly
WORLDBRIDGE_TOKEN_FILE (none) a file holding the token (read when WORLDBRIDGE_TOKEN is unset). With no AuthToken in its config, WorldBridge generates a token on its first start into WorldBridge.token beside OpenSim: point this at that file
VIEWER_URL http://127.0.0.1:9004 the viewer bridge (tools/leap_bridge.py), for the viewer_* tools
PARACOSM_VIEWER_TOKEN (none) the viewer bridge's bearer token, when it is set explicitly. Normally leave it unset: tools/run_viewer.py makes a fresh random token on every launch and the bridge writes it to the token file below, which this MCP reads on every call
PARACOSM_VIEWER_TOKEN_FILE %LOCALAPPDATA%/ParacosmViewer_x64/leap_bridge/bridge.token (Windows), ~/Library/Application Support/... (macOS), $XDG_CONFIG_HOME or ~/.config/... (Linux) where the bridge writes its token
VIEWER_TOKEN (none) legacy name, read only when neither of the above gives a token

viewer_look asks the bridge for a snapshot by bare file name; the bridge writes it inside its own snapshot folder (PARACOSM_SNAPSHOT_DIR, see tools/PORTABILITY.md) and answers with the full path, which the MCP reads and deletes.

This server does not read the Paracosm .env; give it its variables in the MCP client's configuration. It reads the WorldBridge token once, when it starts (start OpenSim once first, so the token file exists); the viewer bridge's token is read on every call, so a relaunched viewer is picked up.

Add to an MCP client

{
  "mcpServers": {
    "worldbridge": {
      "command": "python",
      "args": ["/path/to/paracosm/mcp/worldbridge_mcp.py"],
      "env": {
        "WORLDBRIDGE_URL": "http://127.0.0.1:9002",
        "WORLDBRIDGE_TOKEN_FILE": "/path/to/opensim/bin/WorldBridge.token"
      }
    }
  }
}

Speaks MCP over stdio (newline-delimited JSON-RPC 2.0). Quick smoke test without a client (the second call needs the server running):

printf '%s\n%s\n' \
 '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
 '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"world_state","arguments":{}}}' \
 | WORLDBRIDGE_TOKEN_FILE=/path/to/opensim/bin/WorldBridge.token python worldbridge_mcp.py

Tools (version 0.2): 26

tool args does
world_state -- region name, size, avatar count, object count
world_list -- every object: uuid, name, shape, pos, size, colour
world_heightmap -- downsampled terrain height grid (64 x 64)
world_avatars -- every avatar: name, position, heading, camera look-at
world_chat limit recent local chat typed by avatars
world_raycast x,y,z, dx,dy,dz, length, land cast a physics ray; the hits and the objects that own them
world_spawn x,y,z (req); shape box/cylinder/sphere; sx,sy,sz; r,g,b,a; name create a prim
world_spawn_mesh file, x,y,z (req); size, name, texture a mesh from a meshdata JSON file on the region's disk (inside WorldBridge's FileRoots)
world_upload_texture file (req), name store a J2C texture from the region's disk; returns its uuid
world_set_script uuid, script (req), name put an LSL script into an object and run it
world_move uuid, x,y,z (req) move an object
world_recolor uuid (req); r,g,b,a repaint an object
world_despawn uuid (req) delete an object
world_terrain cx,cy,radius (req); amount; op raise/lower/set/flatten sculpt a circular area (smooth falloff)
world_teleport x,y,z (req); lx,ly,lz; avatar teleport an avatar within the region
world_save -- back the scene up to the region's database
world_contents uuid (req) what an object holds: each item's name, type (object, notecard, script, ...), item and asset ids, description, whether it can be copied
world_rez_item box, item, x,y,z (req); rx,ry,rz, count, spacing, atRoot, param rez a copy of an object item from a box anywhere in the region; the item stays in the box and the copy's scripts start
world_put_notecard uuid, name, text (req); description write a notecard (up to 64 KB) into an object; one of the same name is replaced
world_roam uuid, walk_anim, pauses, speed, cx,cy, radius, leader, ...; or status; or uuid + off a rigged creature's nomadic wander over the ground
world_call command (req), body any other WorldBridge command by name (the handbook's worldbridge.md lists them all)
viewer_look focus, camera or distance/azimuth/elevation; width, height, settle place the AI viewer's camera and return a snapshot as an image
viewer_camera_reset -- the camera follows the avatar again
viewer_walk x,y (req), z walk the viewer's avatar there (autopilot)
viewer_say text (req), channel say something in local chat as the viewer's avatar
viewer_call pump, op (req), ... any LEAP operation in the viewer

The viewer_* tools need the AI's own viewer running with its bridge: build and start it as described in ../handbook/viewer.md.

Security

The WorldBridge module binds 127.0.0.1 only and requires the bearer token; this MCP runs on the same host and talks to that loopback channel, so there is no public attack surface by default.

RBAC (built in): the module supports role-scoped tokens -- observer (read-only: state, list, heightmap, avatars, chat, inspect, worn, contents, roam_notecard), builder (+ spawn, recolor, rez_item, put_notecard), gaia (everything else) -- configured as TokenObserver/TokenBuilder/TokenGaia (16 characters or more) in the module's [WorldBridge] ini section (in Paracosm, from the .env keys WORLDBRIDGE_OBSERVER_TOKEN/_BUILDER_TOKEN/_GAIA_TOKEN through tools/make_config.py). The generated token file holds a gaia token. Whichever token you give this MCP determines what it can do: a builder token gets a 403 forbidden (naming the role needed) if it calls world_terrain. Give an assistant the lowest role it needs. A leaked low token cannot wreck the world.

world_call can reach every command the token's role allows, including console when the module's AllowConsole is true (it is false by default).

If you ever expose the channel beyond localhost, do NOT do so without also adding TLS + rate-limiting on top of the token/RBAC (see PLAN.md "SECURITY OF THE CONTROL CHANNEL").

Not yet here

Driving a LibreMetaverse avatar (walking the world as a player) is a separate process today (see bot/); folding it into this MCP is a planned addition. The viewer_* tools drive a real viewer instead.