GMod
FreeNot checkedModel Context Protocol bridge for Garry's Mod — lets an AI assistant run Lua and inspect state inside a live game session.
About
Model Context Protocol bridge for Garry's Mod — lets an AI assistant run Lua and inspect state inside a live game session.
README
A Model Context Protocol (MCP) bridge between an AI coding assistant and a running Garry's Mod session. Lets the assistant invoke tools (e.g. run Lua, inspect state) inside the live game, instead of relying on static analysis and copy-pasted console output.
The repo is the GMod addon: clone it directly into garrysmod/addons/. The .NET MCP server lives in server/ and is ignored by the GMod engine.
Quick start
- Install the addon
cd garrysmod/addons git clone https://github.com/AmyJeanes/GMod-MCP-Server.git - Build the MCP server
cd GMod-MCP-Server/server/GModMcpServer dotnet build - Register the MCP server with your client (e.g. Claude Code):
claude mcp add gmod -- dotnet run --project /absolute/path/to/server/GModMcpServer - Launch GMod via the
host_launchtool, or start it yourself. The bridge runs regardless, but tool dispatch requires opting in: in the GMod developer console, runmcp_enable 1. Sensitive tools additionally need their capability granted — see Capabilities. - Verify: the host and game tools (see Tools) appear in your assistant's tool list, and
host_statusreportsbridge.reachable: trueonce GMod is running and responsive.
How it works
GMod cannot run a listening socket from pure Lua, and http.Fetch/HTTP() block private-IP destinations on listen and singleplayer servers. This addon uses file-based IPC via garrysmod/data/mcp/ — the server-realm and client-realm bridges run independent poll loops, the .NET host polls the response files, and big payloads like screenshots never traverse net.WriteString. No binary modules required.
Each .NET MCP host generates a per-process session GUID and prefixes its request IDs with it, so multiple MCP clients (Claude Code + MCP Inspector + …) can share the same GMod instance without stealing each other's responses.
See docs/protocol.md for the wire format.
Tools
These are the built-in tools, grouped by where they run. This is not an exhaustive list of what a live game exposes: any addon can register its own tools (MCP:AddFunction) and capabilities (MCP:AddCapability), which then appear alongside the built-ins — the TARDIS addon does exactly this to add its tardis_* tools.
Host tools
Implemented by the .NET MCP server itself — available even when GMod isn't running.
| Tool | Description |
|---|---|
host_launch |
Launch Garry's Mod and wait until the MCP bridge is fully ready before returning. |
host_close |
Close the running GMod process (located by name, regardless of who launched it). |
host_status |
Report whether GMod is running, whether the MCP bridge is reachable (a live ping is sent when GMod is detected), and the current tool count and capability state. |
host_changelevel |
Change the map of the already-running GMod server and block until the new map is ready before returning (the in-game sibling of host_launch's readiness wait). |
mcp_reload |
Reload the in-game MCP addon (re-run its Lua and restart the bridge) and block until the bridge is back and ready before returning — the host-managed equivalent of running mcp_reload in the GMod console, but without the timeout a bare reload causes (the reload tears the bridge down mid-call). |
engine_log |
Read the tail of GMod's engine console log (console.log) — the raw, unfiltered console: engine-native C++ output (Bad SetLocalOrigin, Crazy origin, asset/mount spew, engine errors) plus both realms' Lua output, interleaved. |
Game tools
Dispatched into the running game over the file bridge. The framework appends _sv (server realm) or _cl (client realm) to each name, so the realm is always visible.
| Tool | Realm | Requires | Description |
|---|---|---|---|
bot_remove_sv |
server | world_control |
Remove (kick) bots from the server. |
bot_spawn_sv |
server | world_control |
Spawn one or more bots on the server (needs a listen server -- maxplayers>1). |
console_cmd_cl |
client | unsafe |
Run a raw console command in this realm (server: game.ConsoleCommand; client: the local console). |
console_cmd_sv |
server | unsafe |
Run a raw console command in this realm (server: game.ConsoleCommand; client: the local console). |
console_read_cl |
client | — | Read recently captured console output and Lua errors that fired outside a tool call (background hooks, timers, autorefresh, other addons) in this realm. |
console_read_sv |
server | — | Read recently captured console output and Lua errors that fired outside a tool call (background hooks, timers, autorefresh, other addons) in this realm. |
constraint_find_sv |
server | — | List an entity's physics constraints and its whole constraint network -- the structured answer to "what is this welded/no-collided/roped to?" and "why does this prop fall through or not collide?". |
cvar_set_cl |
client | unsafe |
Set a console variable, wait for it to settle, and report the actual stabilized value. |
cvar_set_sv |
server | unsafe |
Set a console variable, wait for it to settle, and report the actual stabilized value. |
cvar_state_cl |
client | — | Structured snapshot of one or more console variables -- current value (as string/int/float/bool), default, decoded FCVAR_* flags, help text and min/max bounds, in a single read. |
cvar_state_sv |
server | — | Structured snapshot of one or more console variables -- current value (as string/int/float/bool), default, decoded FCVAR_* flags, help text and min/max bounds, in a single read. |
debug_clear_cl |
client | — | Remove every hook the debug_* tools installed in this realm -- debug_record sampling hooks and (later) debug_draw render hooks, all under the mcp_debug_ id namespace. |
debug_clear_sv |
server | — | Remove every hook the debug_* tools installed in this realm -- debug_record sampling hooks and (later) debug_draw render hooks, all under the mcp_debug_ id namespace. |
debug_draw_cl |
client | unsafe |
Install a persistent client-side render hook that runs your draw Lua every frame, for visual debugging you can then screenshot -- mark an entity, outline a volume, draw a path, label something on the HUD. |
debug_hooks_cl |
client | — | Inspect the hook registry -- answer "did my hook register, and where is it defined?" without hand-dumping hook.GetTable(). |
debug_hooks_sv |
server | — | Inspect the hook registry -- answer "did my hook register, and where is it defined?" without hand-dumping hook.GetTable(). |
debug_record_cl |
client | unsafe |
Record a value each time a hook fires, for a bounded window, then return the time series -- a managed sampling probe that owns the hook lifecycle (unique namespaced hook, duration cap, auto-remove on end/stop/error) so you never hand-roll hook.Add/poll/hook.Remove. |
debug_record_interactive_cl |
client | unsafe |
ARM an on-screen, player-driven recorder for a repro the user must physically perform (walk a path, time a portal crossing, mash a seam) -- the interactive sibling of debug_record. |
debug_record_interactive_sv |
server | unsafe |
Arm the paired SERVER-realm capture for an interactive recording -- the server half of debug_record_interactive_cl (which owns the on-screen UI and human timing). |
debug_record_read_cl |
client | — | Collect the series from a debug_record_interactive recorder. |
debug_record_read_sv |
server | — | Collect the SERVER-realm series from a debug_record_interactive (server) recorder, by link_id. |
debug_record_sv |
server | unsafe |
Record a value each time a hook fires, for a bounded window, then return the time series -- a managed sampling probe that owns the hook lifecycle (unique namespaced hook, duration cap, auto-remove on end/stop/error) so you never hand-roll hook.Add/poll/hook.Remove. |
entity_create_sv |
server | world_control |
Spawn one entity server-side -- Create, SetModel, SetPos, Spawn, Activate -- optionally frozen and coloured, and tagged for later cleanup by entity_remove. |
entity_find_cl |
client | — | Find entities and return compact rows -- index, class, model, pos and distance -- instead of a raw dump. |
entity_find_sv |
server | — | Find entities and return compact rows -- index, class, model, pos and distance -- instead of a raw dump. |
entity_remove_sv |
server | world_control |
Remove entities server-side and wait until they are actually gone before reporting (:Remove is deferred, so a same-call count would be stale). |
entity_set_sv |
server | world_control |
Mutate one entity's transform, render and physics state by index, then confirm. |
entity_state_cl |
client | — | Nil-safe structured snapshot of one entity by index -- identity, transform, render (incl. |
entity_state_sv |
server | — | Nil-safe structured snapshot of one entity by index -- identity, transform, render (incl. |
file_exists_cl |
client | — | Check whether a single path exists in the GMod virtual filesystem, and report whether it's a file or folder plus its size and modified time -- file.Exists/IsDir/Size/Time. |
file_exists_sv |
server | — | Check whether a single path exists in the GMod virtual filesystem, and report whether it's a file or folder plus its size and modified time -- file.Exists/IsDir/Size/Time. |
file_find_cl |
client | — | List files and folders in the GMod virtual filesystem matching a glob -- file.Find(pattern, path). |
file_find_sv |
server | — | List files and folders in the GMod virtual filesystem matching a glob -- file.Find(pattern, path). |
game_set_cl |
client | world_control |
Set curated client-only game knobs, then confirm. |
game_set_sv |
server | world_control |
Set one or more curated, safe server-tuning knobs, wait for them to settle, and report the actual values. |
game_state_sv |
server | — | Structured snapshot of server-wide game state in one read -- current map, gamemode, hostname, singleplayer/dedicated flags, max player slots, player/bot/human counts, a lean roster of every player (name/userid/entindex/is_bot/is_host/team -- drill into one with player_state or entity_state), a tuning block with the live values of game_set's knobs (gravity, timescale, phys_timescale, fakelag), and cheats_enabled (sv_cheats) -- which gates whether game_set's timescale/fakelag will take. |
hook_call_cl |
client | unsafe |
Fire a GMod hook and report the result -- the dispatch companion to debug_hooks (which only reads the registry). |
hook_call_sv |
server | unsafe |
Fire a GMod hook and report the result -- the dispatch companion to debug_hooks (which only reads the registry). |
job_cancel_cl |
client | — | Abort a background job started with async=true, tearing down its hooks and side effects immediately (e.g. |
job_cancel_sv |
server | — | Abort a background job started with async=true, tearing down its hooks and side effects immediately (e.g. |
job_collect_cl |
client | — | Fetch the result of a background job started by calling a tool with async=true, identified by the job_id the arm returned. |
job_collect_sv |
server | — | Fetch the result of a background job started by calling a tool with async=true, identified by the job_id the arm returned. |
job_list_cl |
client | — | List background jobs (from async=true arms) in this realm: job_id, the tool, status (armed / finished / cancelled), seconds elapsed since arming, and whether it's collectable now. |
job_list_sv |
server | — | List background jobs (from async=true arms) in this realm: job_id, the tool, status (armed / finished / cancelled), seconds elapsed since arming, and whether it's collectable now. |
light_projected_cl |
client | — | Create, update, or remove a clientside ProjectedTexture -- a spotlight test-light rig, the projected-light sibling of debug_draw. |
lua_run_cl |
client | unsafe |
Compile and execute Lua source in this realm. |
lua_run_sv |
server | unsafe |
Compile and execute Lua source in this realm. |
model_info_cl |
client | — | Structured info about a model ASSET without spawning a prop -- read straight from the model file via util.GetModelInfo (no entity, no spawn), so it is synchronous and realm-identical. |
model_info_sv |
server | — | Structured info about a model ASSET without spawning a prop -- read straight from the model file via util.GetModelInfo (no entity, no spawn), so it is synchronous and realm-identical. |
player_lua_run_sv |
server | unsafe |
Compile and execute Lua source on a target player's client realm and return the result. |
player_set_sv |
server | player_control |
Set a player or bot's pose and state, then wait for it to settle and confirm it stuck. |
player_state_cl |
client | — | Structured snapshot of a player (or all players) -- identity, vitals, eye position/aim, velocity, movement state (movetype, on_ground, crouching, ducking, frozen, godmode, water_level), view offset and collision hull, model/animation sequence, playermodel and weapon colours, and active weapon, in one read. |
player_state_sv |
server | — | Structured snapshot of a player (or all players) -- identity, vitals, eye position/aim, velocity, movement state (movetype, on_ground, crouching, ducking, frozen, godmode, water_level), view offset and collision hull, model/animation sequence, playermodel and weapon colours, and active weapon, in one read. |
player_trace_cl |
client | — | Raycast from a player's eyes along their view and report what they're looking at -- the hit entity (index and class; drill in with entity_state), hit position, distance from the eye, surface normal, and surface material/texture. |
player_trace_sv |
server | — | Raycast from a player's eyes along their view and report what they're looking at -- the hit entity (index and class; drill in with entity_state), hit position, distance from the eye, surface normal, and surface material/texture. |
player_walk_cl |
client | player_control |
Walk the local (host) player naturally by driving the real movement code (CUserCmd each tick) via CreateMove, so grounded-locomotion bugs reproduce -- unlike teleport or +forward. |
player_walk_sv |
server | player_control |
Walk a target player or bot naturally by driving its CUserCmd each tick via StartCommand -- the canonical way to control bots. |
reload_file_cl |
client | — | Hot-reload one on-disk Lua source file by re-running it in this realm -- a targeted alternative to mcp_reload (which rebuilds the whole MCP addon) and the engine's autorefresh (which only fires for some edits), for iterating on a single file in any addon. |
reload_file_sv |
server | — | Hot-reload one on-disk Lua source file by re-running it in this realm -- a targeted alternative to mcp_reload (which rebuilds the whole MCP addon) and the engine's autorefresh (which only fires for some edits), for iterating on a single file in any addon. |
screenshot_cl |
client | — | Capture a JPEG of what the player actually sees on screen - the genuine rendered frame (HUD, portals, post-processing all as-live), not a re-render, so the image matches the game exactly. |
world_trace_cl |
client | — | Raycast from an arbitrary origin and report what the ray hits -- the hit entity (index and class; drill in with entity_state), hit position, distance, surface normal and material, plus the origin's point-contents and the trace's solid flags. |
world_trace_sv |
server | — | Raycast from an arbitrary origin and report what the ray hits -- the hit entity (index and class; drill in with entity_state), hit position, distance, surface normal and material, plus the origin's point-contents and the trace's solid flags. |
Capabilities
Security gates a tool can require (requires = { ... }). Each derives an archived mcp_allow_<id> convar; grant it in the GMod developer console (e.g. mcp_allow_unsafe 1) to enable the tools that depend on it. Only the built-in unsafe is listed here — addons can declare their own.
| Capability | ConVar | Default | Description |
|---|---|---|---|
player_control |
mcp_allow_player_control |
off | Player control: let MCP drive and reposition the local player — teleport/pose/health/loadout (player_set) and movement/aim (player_walk). |
unsafe |
mcp_allow_unsafe |
off | Unsafe: arbitrary code execution via MCP — Lua source (lua_run) and raw console commands (console_cmd). |
world_control |
mcp_allow_world_control |
off | World control: let MCP mutate world state via structured tools — spawn/remove/modify entities (entity_create/remove/set), curated game knobs (game_set), and test bots (bot_spawn/remove). |
Console & error capture
Output and errors that happen during a tool call are already returned on that call's response (console / warnings). Anything that fires outside a tool call — a hook the assistant registered firing later, a timer, an autorefresh re-run, another addon erroring — would otherwise be invisible. Passive capture records these into a small per-realm ring buffer and surfaces them to the model two ways, both over the existing bridge (MCP has no way to push unsolicited messages into the model's context, so there's no notification channel — it rides tool results):
- Attached to the next tool response as an
eventsarray (per-session cursor, so it isn't re-sent). - On demand via the
console_read_sv/console_read_cltools (pass back the returnedcursorassinceto get only newer events).
It's realm-local — _sv shows server-side errors/prints, _cl shows client-side. Controlled by mcp_capture (only active while mcp_enable is 1):
mcp_capture 2 # default: Lua errors + console (print/Msg)
mcp_capture 1 # Lua errors only
mcp_capture 0 # off
Extending
Drop a Lua file in lua/mcp/functions/ with the conventional sh_/cl_/sv_ prefix; the realm is implicit from the prefix and the framework appends _sv/_cl to the tool name automatically. Saving the file is enough — GMod's autorefresh re-runs it, the registry updates in place, and a debounced manifest write propagates the change to the .NET host (which emits notifications/tools/list_changed). mcp_reload forces a rebuild when a tool file is deleted (autorefresh has nothing to fire on for removals).
Adding a tool
MCP:AddFunction({
id = "list_players",
description = "List all connected players.",
schema = { type = "object", properties = {}, required = {} },
handler = function(args, ctx)
local names = {}
for _, ply in ipairs(player.GetAll()) do
names[#names + 1] = ply:Nick()
end
return { ok = true, result = names }
end,
})
Adding a capability
Gate a sensitive tool behind a capability. MCP:AddCapability auto-derives a mcp_allow_<id> convar (default off), and the bridge refuses to dispatch a tool whose required capability is off — so a buggy or compromised handler can't bypass the gate.
MCP:AddCapability({
id = "dangerous",
description = "What this unlocks, and why it's risky.",
default = false,
})
MCP:AddFunction({
id = "my_tool",
requires = { "dangerous" },
-- ...
})
License
MIT — see LICENSE.
Installing GMod
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/AmyJeanes/GMod-MCP-ServerFAQ
Is GMod MCP free?
Yes, GMod MCP is free — one-click install via Unyly at no cost.
Does GMod need an API key?
No, GMod runs without API keys or environment variables.
Is GMod hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install GMod in Claude Desktop, Claude Code or Cursor?
Open GMod on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
by modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
by xuzexin-hzMCP-Agent
A simple, composable framework to build agents using Model Context Protocol by [LastMile AI](https://www.lastmileai.dev)
by lastmile-aiSpring AI MCP Client
Provides auto-configuration for MCP client functionality in Spring Boot applications.
mcp.natoma.ai
A Hosted MCP Platform to discover, install, manage and deploy MCP servers by [Natoma Labs](https://www.natoma.ai)
MCPHub
Website to list high quality MCP servers and reviews by real users. Also provide online chatbot for popular LLM models with MCP server support.
MCP Servers Rating and User Reviews
Website to rate MCP servers, write authentic user reviews, and [search engine for agent & mcp](http://www.deepnlp.org/search/agent)
mkinf
An Open Source registry of hosted MCP Servers to accelerate AI agent workflows.
Compare GMod with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All ai MCPs
