gmod-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GMOD_MCP_REPO | No | The root directory of the Garry's Mod addon project. If not set, the daemon walks up from the cwd looking for tools/lint.sh and CLAUDE.md, or uses .gmod-mcp/config.json. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| healthA | gmod-mcp daemon status: version, detected repo root, presence of the tools/ scripts, state directory. Also probes the addon (3s) and reports the transport state -- whether this daemon owns the shared directory (a second Claude Code session starts a second daemon, which breaks every bridge tool), what is in flight, and any server handler the daemon declares but the game has not registered. |
| lintA | Runs tools/lint.sh on an addon (name or path). Returns structured findings (file, line, rule) and the exit code. Exit 0 means clean. |
| start_serverB | Starts the dedicated server through tools/start-server.sh [map] [gamemode] [tickrate] and records the log's boot boundary. Script defaults: rp_nycity_day/darkrp/33. |
| stop_serverB | Stops the dedicated server through tools/stop-server.sh. |
| sync_configA | Reapplies server-config/ and (re)creates the symlinks through tools/sync-server-config.sh. check:true compares without writing (--check). |
| read_logsA | Reads the server logs. source=game (Lua errors, -condebug) or stdout (the wrapper). sinceBoot:true bounds output to the current boot. errorsOnly:true returns structured runtime findings. |
| packageA | Builds an addon's .gma through tools/package-gma.sh, linting first and refusing on failure. Output lands in dist/. |
| read_runtimeA | Snapshot of server state: map, gamemode, CurTime, player and entity counts, uptime. |
| read_playersA | Lists players: name, SteamID, team/job, ping, position, health. |
| read_entitiesA | Lists entities, filterable by class. Returns index, class, model and position. |
| inspect_entityC | Details of one entity by index: class, model, health, owner, key-values. |
| read_hooksB | Registered hooks (hook.GetTable), filterable by event. Returns event -> identifiers. |
| read_convarsB | Server convar values. Without |
| read_net_messagesB | Registered net messages (util.AddNetworkString) and whether a net.Receive exists. |
| read_timersA | State of named timers: exists, time left, repetitions left. GMod cannot enumerate timers, so |
| run_console_commandA | Runs a server console command (game.ConsoleCommand -- queued, around 0.25s of latency). |
| send_debugA | Prints a message server-side, useful for marking the log or tracing. |
| run_testA | Runs a GLua test file server-side and returns {passed, failed, results}. path is relative to lua/, e.g. 'myaddon/tests/x.lua'. The file returns a table { [name] = function(t) end }. |
| run_luaA | GUARDED. Runs arbitrary Lua server-side (RunString) and returns the resulting value. Requires confirm:true. Audited. |
| read_panelsB | Derma/VGUI panel tree: class, name, visibility, size, position both parent-relative (x/y) and absolute (screen_x/screen_y), whether mouse input is enabled, and on_screen. Filter on on_screen: |
| inspect_panelA | Finds a panel by NAME, class and/or displayed text, and returns its screen rectangle, its text, whether it holds keyboard focus, and the other matches. NAME is the registered vgui name (R_CharCreate, R_UI_Button, echat.textentry) and is what you want: |
| read_panel_textA | Dumps what the interface DISPLAYS, as text: name, class, screen rectangle and text content of each panel under a named root. Use this instead of capture_screen to assert a value -- a capture travels in 7KB chunks paced one per frame, and a number read off a compressed JPEG is not an assertion. Text comes from GetText, GetValue, or a .label/.text/.title field (kit buttons paint their label and answer '' to GetText). The list is depth-first with depth relative to the root, so the parent chain is recoverable from the ordering: the DTextEntry that follows the DLabel 'Prénom' is that field. capture_screen remains the tool for anything visual -- z-order, overlap, a missing glyph. |
| capture_screenA | Captures the client's screen on the next frame and returns it as a viewable image. Every byte travels in 7KB chunks paced by frame, so a full-resolution capture takes seconds and dominates any act-then-look loop: the default half scale at quality 60 is 4-6x cheaper and still legible for a Derma layout. Pass region (from read_panels' screen_x/screen_y) to capture just one panel. A capture that would exceed the client's channel budget is refused with its size rather than sent: a full-screen quality-80 capture measured 424KB and timed the client out of the server. Requires an active GMod client. |
| read_consoleB | CLIENT Lua errors captured since load. GMod does not expose the console buffer itself. |
| read_viewA | What the client sees and is pointed at: eye position and angles, aim trace (class, index, distance, hit position), health, weapon, cursor position and visibility, the hovered panel, the panel holding keyboard focus, and the current scripted-input mode. This is the cheap half of an act-then-look loop -- one chunk, no image -- and answers 'am I aimed at the door' without a screenshot. |
| client_inputA | Drives the connected GMod client: movement, aim, keys, Derma clicks, typing, chat. Modal -- 'world' drives movement through CreateMove, 'ui' hands input to the panel system, and the two are mutually exclusive; the action switches mode for you. Durations are SECONDS (CreateMove runs at the client's cmdrate, so tick counts are not a duration), clamped to 5s, and everything resets after 30s or on |
| read_client_convarsC | Client-side convar values. Without names, returns a common subset. |
| patch_fileA | Replaces a file's contents (inside the repo) after backing it up. Returns a patch id for restore_patch, plus the unified diff. rationale explains the change. |
| restore_patchC | Reverts a patch by id, restoring the previous state. |
| reload_fileA | Triggers GMod's Lua autorefresh for a file by bumping its mtime. Best-effort: it covers edits, while new files and autoruns still need a restart. |
| reload_addonA | Touches every .lua file of an addon to trigger autorefresh. Best-effort; structural changes still need a restart. |
| validateC | Verdict for the loop: the addon's lint plus the current boot's runtime errors. ok=true when lint is clean AND no runtime error was seen. |
| run_iterationA | One full iteration: optional patch -> reload (or a restart note) -> validate. Returns the applied patch and the verdict. This is the core of the edit/observe/fix loop. |
| batchA | Runs up to 32 server tools in ONE bridge round trip instead of one per call. A round trip costs about 0.4s, so any act-then-look sequence is dominated by transport unless it is batched. Each step reports its own ok/data/error; a step failing is data, not a transport error. IMPORTANT: with settleMs 0 every step runs in the SAME server tick, and some engine effects only land at the end of a frame -- a removed entity still reads as valid. Set settleMs (100 is usually enough) whenever a step must observe what an earlier one did. Any arg value may be {"__step": 1, "get": "index"} to read a field from an earlier step's result, so spawn-then-act still costs one round trip. |
| spawn_entityA | GUARDED. Creates and spawns an entity at a position. Returns its EntIndex, which the other world tools take as a target. Requires confirm:true. |
| world_editA | GUARDED. Acts on one entity or player: remove, teleport, set_ang, freeze, unfreeze, set_health, set_armor, give, strip. target is an entity index or a player's SteamID/name. Requires confirm:true. |
| set_player_stateA | GUARDED, DarkRP. Sets a player's money, job, salary or RP name. Money is in INTEGER CENTS (1.50$ is 150) and goes through the r-capitalism ledger when it is loaded, so the audited invariant stays intact. Fails with a named error when DarkRP is absent. Requires confirm:true. |
| force_hookA | GUARDED. Runs hook.Run(name, ...) to exercise a gamemode path without reproducing the situation. JSON cannot carry an Entity, so arguments may be tagged: {"__ent": 3}, {"__ply": "STEAM_0:1:2"}, {"__vec": [x,y,z]}, {"__ang": [p,y,r]}. Requires confirm:true. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
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/ProjectSocietyStudio/gmod-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server