Skip to content
forked from Earu/GTerm

About

Garry's Mod external console software with MCP and Websocket support.

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

129 Commits

Folders and files

Repository files navigation

GTerm

Garry's Mod external console software.

This fork develops GTerm with assistance from OpenAI Codex. GTerm was created by Earu and remains available under its original MIT license; see LICENSE. WindowsTerminal_2025-12-21_19-19-37 WindowsTerminal_2025-12-21_19-19-21 WindowsTerminal_2025-12-21_19-19-31

Client Installation

  • Download the latest release.
  • Launch the gterm executable whenever Garry's Mod is running.
  • Restart Garry's Mod to complete the installation.
  • Enjoy!

Server Installation (steamcmd)

  • Download the latest release of gterm.
  • Move the .dll (even on macos/linux!) under srcds/garrysmod/lua/bin (if the bin folder doesnt exist, create it).
  • In srcds/garrysmod/lua/includes/init.lua add at the top of the file require("gterm").
  • Restart the server.
  • Launch the gterm executable.
  • Enjoy!

IMPORTANT NOTE: GTerm communicates with the gmod module over a localhost TCP socket (127.0.0.1:27514), so GTerm must run on the same host as the server. If you run your server inside a docker container or any other sandbox, run GTerm inside that same sandbox (or otherwise share the loopback interface).

For a separate Windows development-server installation using anonymous SteamCMD login, see the isolated SteamCMD helper. Preparing the dedicated server does not establish a GTerm connection or change the owner's installed client.

In case GTerm does NOT detect your Garry's Mod CLIENT installation

  • Download the latest release of gterm.
  • Move the .dll (even on macos/linux!) under GarrysMod/garrysmod/lua/bin (if the bin folder doesnt exist, create it).
  • In GarrysMod/garrysmod/lua/menu/menu.lua add at the bottom of the file require("gterm").
  • Restart Garry's Mod.
  • Voila!

Installation Options

GTerm installs its module on startup. This can be tuned with launch arguments (or the same keys in Config.json):

  • --skipgamefiles - Do not modify the game's Lua files to require("gterm").
  • --skipmodule - Do not drop the module binary into garrysmod/lua/bin.
  • --skipmoduleupdate - Keep an existing module binary instead of replacing it when it differs from the published one.
  • --realm cl|sv - Name the module binary for the client (gmcl_gterm_*.dll) or server (gmsv_gterm_*.dll, default) realm.

WebSocket API

GTerm includes a WebSocket server for console streaming and command execution.

Setup:

  1. Enable API in Config.json: "API": true
  2. Connect WebSocket clients to ws://localhost:27512/ws/

Configuration Options:

{
  "API": true,
  "APIPort": 27512,
  "APISecret": "your_secret_here"
}

Example Payloads:

Sending commands (text message):

status

Receiving console output (JSON):

{
  "Time": 1704123456,
  "Data": [
    {
      "Color": { "R": 255, "G": 255, "B": 255, "A": 255 },
      "Text": "hostname: My Server\n"
    }
  ]
}

MCP Server Integration

GTerm includes an MCP (Model Context Protocol) server for AI agents such as Cursor, Vscode, Zed, Claude Code, etc..

Setup:

  1. Enable MCP in Config.json: "MCP": true
  2. (Optional) Set "MCPSecret" for authentication
  3. Configure your MCP client to connect to http://localhost:27513 (add ?secret=... if using authentication)

Available Tools:

  • get_game_status - Report whether GMod is connected, in a session, and which Lua realms can run code right now (map, gamemode, players). Works even while GMod is closed. Agents should call this first.

  • run_gmod_command - Execute a console command and capture its output

  • execute_lua_code - Execute Lua in a required realm (server or client).

  • validate_lua_syntax - Compile-check Lua with the game's own CompileString without executing it

  • check_game_file - Ask the running game whether a path exists in its virtual filesystem (mounted addons/GMAs included), not just on disk

  • capture_console_output - Monitor console output for a duration

  • list_gmod_directory - Browse the Garry's Mod file structure on disk

  • read_gmod_file - Read a text file from the installation on disk

  • read_game_file - Read a file's contents from the running game's virtual filesystem (mounted addons, Workshop GMAs), which the on-disk reader can't see

  • take_screenshot_region - Capture one rectangle of the screen and return it enlarged, so a HUD element, viewmodel or panel is actually legible. Preferred over the full-screen shot for anything specific

  • take_screenshot - Capture the whole screen. Last resort: prove things with Lua state and arithmetic first

  • read_gmod_wiki - Fetch a page from the Garry's Mod wiki (wiki.facepunch.com/gmod) to check a function's real signature before using it

  • list_tool_packages - Lists all the third party tools provided by addons in lua/gterm_packages/*.lua (see below)

  • request_tool_packages - Ask the user, in GTerm's own console, which packages to enable. The agent cannot choose by itself

  • call_package_tool - Run one tool from an enabled package with a JSON args object

Screenshot relay files are restricted to JPEG, 64 MiB encoded data and 67,108,864 pixels, with each dimension at most 16384 pixels. Reported capture dimensions must match the JPEG header. These checks limit input to the capture workflow's expected format; they are not a substitute for updating vulnerable image libraries. A whole-frame JPEG is returned without full pixel decoding.

GTerm logs MCP response sizes but omits their contents, including screenshot data and tool results. This does not make the log private: MCP request bodies, commands, game console output and diagnostic errors may still contain sensitive data, and MCP clients may retain the responses they receive.

Every tool result is prefixed with a [GTerm] status line so the agent always knows the connection and realm state. When a precondition is not met (disconnected, wrong realm, no session), the tool returns an error explaining what to do rather than failing silently; pass force: true to attempt the call anyway.

Seeing what an agent is doing. MCP clients show the tool name but usually not the arguments, so GTerm surfaces them itself: every tool call prints a magenta [agent] line in GTerm's console before it runs. Lua is shown in full on its own lines with Monokai syntax highlighting, and console commands are highlighted inline.

MCP Tool packages (opt-in)

Addons and servers can provide their own tools to the agent as Lua files at lua/gterm_packages/<package>.lua. GTerm normally discovers packages with client-realm Lua (sv_allowcslua must be 1). When connected directly to a local dedicated server, it discovers server-owned packages in the server realm and offers only their server-realm tools. That server uses a separate local-dedicated consent scope.

Enabling is done manually in GTerm's console using packages in GTerm, or when the agent calls request_tool_packages. Consent is stored in Config.json under ToolPackageConsent per scope (server IPv4, or local for listen servers and singleplayer).

The file returns a table: optional description, optional server (IPv4; only usable on that server), and tools. Each tool has name ([a-z][a-z0-9_]*), description, inputSchema (JSON schema, type = "object"), optional realm ("client", the default, or "server"), and run(args). Its return value (string or table) comes back as the result, capped at 4096 characters by print. Limits: 32 tools, 512-character descriptions, 8 KB input schema, 256 KB definition. Package names: [a-z0-9][a-z0-9_-]{0,63}.

Example lua/gterm_packages/my_addon.lua:

return {
    description = "Helpers for my addon.",
    tools = {
        {
            name = "find_entities",
            description = "Lists entities of a class near the local player.",
            inputSchema = {
                type = "object",
                properties = {
                    class = { type = "string", description = "Entity class, e.g. prop_physics" },
                    radius = { type = "number", description = "Search radius in units (default 512)" },
                },
                required = { "class" },
            },
            run = function(args)
                local out = {}
                for _, e in ipairs(ents.FindInSphere(LocalPlayer():GetPos(), args.radius or 512)) do
                    if e:GetClass() == args.class then out[#out + 1] = { id = e:EntIndex(), pos = tostring(e:GetPos()) } end
                end
                return out
            end,
        },
        {
            name = "count_props",
            description = "Counts props on the server (listen server or singleplayer only).",
            inputSchema = { type = "object" },
            realm = "server",
            run = function() return #ents.FindByClass("prop_physics") end,
        },
    },
}

Configuration Options:

{
  "MCP": true,
  "MCPPort": 27513,
  "MCPCollectionWindowMs": 1000,
  "MCPSecret": "your_secret_here"
}

MCP Client Example (with secret):

{
  "mcpServers": {
    "gterm": {
      "url": "http://localhost:27513?secret=your_secret_here"
    }
  }
}
image image

About

Garry's Mod external console software with MCP and Websocket support.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages