com.IvanMurzak.Brutal.MCP
0.2.1
dotnet add package com.IvanMurzak.Brutal.MCP --version 0.2.1
NuGet\Install-Package com.IvanMurzak.Brutal.MCP -Version 0.2.1
<PackageReference Include="com.IvanMurzak.Brutal.MCP" Version="0.2.1" />
<PackageVersion Include="com.IvanMurzak.Brutal.MCP" Version="0.2.1" />
<PackageReference Include="com.IvanMurzak.Brutal.MCP" />
paket add com.IvanMurzak.Brutal.MCP --version 0.2.1
#r "nuget: com.IvanMurzak.Brutal.MCP, 0.2.1"
#:package com.IvanMurzak.Brutal.MCP@0.2.1
#addin nuget:?package=com.IvanMurzak.Brutal.MCP&version=0.2.1
#tool nuget:?package=com.IvanMurzak.Brutal.MCP&version=0.2.1
Brutal-MCP
AI Game Developer integration for games built on the BRUTAL C# framework.
Brutal-MCP is a NuGet package (com.IvanMurzak.Brutal.MCP) that runs inside your game process and connects it to
AI agents (Claude Code, Codex, Cursor …) through the AI Game Developer App and the shared MCP server. Agents can then
inspect and change the running game with RQL — one query language instead of
hundreds of tools — read its logs, and learn how to write BRUTAL code from generated skills.
BRUTAL has no editor, no scene graph and no renderer, so there is no in-game UI either: the plugin starts itself in Debug builds and is configured through the App or environment variables.
Install
With the AI Game Developer App (recommended). Open your BRUTAL game project in the App and enable the BRUTAL
integration: the App adds the package to your .csproj, writes .ai-game-dev/brutal-mcp.json, generates the agent
skills and launches the game with the right BRUTAL_MCP_* environment variables. Sign-in is shared with the App.
Manually.
dotnet add package com.IvanMurzak.Brutal.MCP
That is all for Debug builds: the package's build targets add a module initializer that calls
BrutalMcp.AutoStart(...) before Main. Release builds do not include it unless you opt in:
<PropertyGroup>
<BrutalMcpAutoStart>true</BrutalMcpAutoStart>
</PropertyGroup>
Two lines in your game
using com.IvanMurzak.Brutal.MCP;
BrutalMcp.Register(world, "World"); // make objects visible to agents (any C# object)
BrutalMcp.Register(scheduler, "Simulation");
while (!window.ShouldClose && !BrutalMcp.QuitRequested)
{
Glfw.PollEvents();
Update();
BrutalMcp.Tick(); // once per frame: agents' main-thread work runs here
}
BrutalMcp.Tick(TimeSpan? budget = null)drains the main-thread queue within a small time budget (default 4 ms). Changes made by agents (rql-mutate) run there, between your frames. WithoutTick, reads still work and writes fail after 5 s with an explanation.BrutalMcp.Register(obj, name)/Unregister(obj)choose what agents see. Static fields and properties of your game assembly are visible without registration. Value types (BRUTAL handle structs such as a JoltPhysicsSystem) are compared by value: registering a copy again renames the one registration instead of adding another.BrutalMcp.QuitRequested/BrutalMcp.QuitRequestedEvent: an agent asked the game to quit (game-quit). The plugin never kills your process.- Mark methods agents may invoke with
[Rql.RqlCallable("what it does")]. - Manual control:
BrutalMcp.Start(new BrutalMcpOptions { ProjectRoot = ..., GameAssembly = ... }),BrutalMcp.Stop(),BrutalMcp.IsRunning,BrutalMcp.IsConnected.
No Brutal-MCP call throws into your game; problems are written to stderr as [Brutal-MCP] … (level:
BRUTAL_MCP_LOG_LEVEL).
Configuration
Precedence: environment variables → code options (BrutalMcpOptions) → <project>/.ai-game-dev/brutal-mcp.json →
defaults.
| Env var | json key | Default | Meaning |
|---|---|---|---|
BRUTAL_MCP_ENABLED |
enabled |
true |
false disables the plugin |
BRUTAL_MCP_CONNECTION_MODE |
connectionMode |
Cloud |
Cloud (ai-game.dev) or Custom (your own server) |
BRUTAL_MCP_CLOUD_URL |
cloudUrl |
https://ai-game.dev |
cloud base URL (/mcp is appended) |
BRUTAL_MCP_HOST |
host |
http://localhost:<project port> |
Custom server URL (port derived from the project path, like the App) |
BRUTAL_MCP_AUTH_OPTION |
authOption |
none |
Custom mode: none, oauth (signed-in account; sent to a localhost server only) or token |
BRUTAL_MCP_TOKEN |
— | — | bearer token for token mode (and for oauth to a non-localhost server); kept in memory, never written to disk |
BRUTAL_MCP_LOG_LEVEL |
logLevel |
Warning |
the plugin's own diagnostics |
BRUTAL_MCP_SKILLS_PATH |
skillsPath |
.claude/skills |
where generated skills are written |
| — | generateSkillFiles, logBufferSize, mainThreadTimeoutMs |
true, 2000, 5000 |
Cloud mode signs in with the machine credentials shared by the App, the CLIs and the other engine plugins
(~/.ai-game-dev/credentials.json): sign in once with the App.
What agents get
RQL tools — rql-query (read), rql-mutate (set / call, with dry_run), rql-schema (sources and types).
| RQL source | Content |
|---|---|
game |
process, uptime, frame counter, main-thread pump, OS / .NET, connection, BRUTAL packages + versions, extensions |
registered |
objects passed to BrutalMcp.Register |
statics |
static fields / properties of your game types (read and write) |
types |
your game types (with their statics and known instances) |
console |
log lines captured from BRUTAL LogSystem (ring buffer) |
logCategories |
BRUTAL LogCategory registry (mute a category with set IsCategoryEnabled = false) |
jobSchedulers |
JobSchedulers with per-runner timings |
localization |
LStrings (localize with call Localize("…")) |
monitor |
BRUTAL Monitor log files, stats, recovered crash tails, dumps |
Functions: brutal.registered("Name"), brutal.find("Type"), brutal.type("Type"). BRUTAL value types read and
write naturally: float3 as "(1, 2, 3)", floatQuat, float4x4, int*, double*, colors as "#ff8800".
registered | select Name Type
brutal.registered("World") | get Entities | where Health < 50 | select $ref Name Position
console | where Level == "Error" | sort Sequence desc | first 5 | select Category Message
brutal.registered("World") | get Entities | where Name == "Boss" | set Health = 100, Position = "(0, 1, 0)"
Other tools — game-logs-tail (Monitor log files on disk), game-quit (graceful quit request), ping and
brutal-skill-generate (system tools).
script-execute (Debug builds of the game only) — compiles and runs C# inside the game, on its main thread: plain
statements whose last expression is the result, or a class with a static method. Usings for System, LINQ,
Brutal.Numerics, Brutal.Logging and com.IvanMurzak.Brutal.MCP are already there, game types are imported
automatically, compile errors point at the agent's own lines, and Console / LogSystem output written meanwhile comes
back with the result. In a Release build the tool does not exist.
var world = (World)BrutalMcp.Registry.Get("World")!;
world.Entities.Count(e => e.Health < 50)
Skills (written to .claude/skills): brutal-rql (RQL for this game, generated from the live engine and installed
extensions) and brutal-framework (how to write BRUTAL code, plus the BRUTAL packages your game loads and a table of
every Brutal-MCP extension: package, required BRUTAL package, registration line, RQL sources, loaded / recommended),
plus one skill per tool.
Extensions
Feature packages (ImGui, Jolt, Glfw, Fmod, Box2D, RakNet, Vulkan.Vma, RenderDoc, Sdl) get optional extension packages
com.IvanMurzak.Brutal.MCP.<Feature> (catalog: extensions/manifest.json, embedded into the
core and rendered into the brutal-framework skill). Each depends only on the core and its BRUTAL package. An extension
is a class library that references the core and adds a public Rql.Execution.IRqlModule (sources, functions, adapters,
guide); its assembly is picked up automatically when it sits next to the game. Core API for extensions:
| API | Use |
|---|---|
BrutalMcp.Registry.Find<T>(InstanceSources) |
live instances of T (class or struct) with display names: registrations, discoverers, statics (incl. T?, collections, dictionaries), fields of registered objects; distinct by reference / value |
BrutalMcp.Registry.OfType<T>(), NameOf(obj) |
instances without names (no struct constraint); the registration name of an instance |
BrutalMcp.AddInstanceDiscoverer(name, func) |
expose instances the plugin cannot find itself |
BrutalMcp.Log.For("Feature") |
Debug/Info/Warn/Error, WarnOnce(key, msg): [Brutal-MCP] warn: [Feature] … on stderr, filtered by BRUTAL_MCP_LOG_LEVEL |
BrutalMcp.Ticked |
event raised on the main thread at the end of every BrutalMcp.Tick(); handler exceptions are caught and logged |
BrutalLogging.GetProviders() / CurrentFactory() |
the ILoggerProviders of BRUTAL LogSystem's factory (e.g. ImGui ConsoleWindow, Monitor) |
BrutalMainThread.Current.Run(...) |
run non-thread-safe native calls on the game's main thread |
BrutalPackages.Catalog / CatalogState() |
the extension catalog and what is loaded / recommended in this process |
Extension test projects (Brutal.Mcp.<Feature>.Tests) see the core's internals: BrutalMcp.ResetForTests() clears
registrations, discoverers, game assemblies, Ticked handlers and once-only log keys; RqlBrutal.Reset() rebuilds the
engine.
Releasing
Maintainers: packages are published to nuget.org by a manual dispatch of the release workflow, see
docs/RELEASING.md.
Licence
Brutal-MCP is licensed under the Apache License 2.0. It depends on com.IvanMurzak.Rql, licensed under the
PolyForm Shield License 1.0.0, and on McpPlugin / ReflectorNet (Apache-2.0).
BRUTAL itself is licensed by Ahwoo Limited under the BRUTAL License (MIT + attribution). Its attribution duties —
credits line, BRUTAL logo before gameplay, shipping NOTICE.txt, third-party notices — apply to your game, as a
product built with BRUTAL, not to this package. Brutal-MCP is an independent project, not affiliated with Ahwoo.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Ahwoo.BRUTAL.Collections (>= 2026.10.1)
- Ahwoo.BRUTAL.Concurrency (>= 2026.10.1)
- Ahwoo.BRUTAL.Core (>= 2026.10.1)
- Ahwoo.BRUTAL.Localization (>= 2026.10.2)
- Ahwoo.BRUTAL.Logging (>= 2026.10.2)
- Ahwoo.BRUTAL.Numerics (>= 2026.10.1)
- com.IvanMurzak.CodeExec (= 0.2.1)
- com.IvanMurzak.McpPlugin (>= 8.11.1)
- com.IvanMurzak.ReflectorNet (>= 5.5.0)
- com.IvanMurzak.Rql (>= 0.1.1)
- Microsoft.AspNetCore.SignalR.Client (>= 8.0.32)
- Microsoft.AspNetCore.SignalR.Common (>= 8.0.32)
- Microsoft.CodeAnalysis.CSharp (>= 5.9.0)
NuGet packages (9)
Showing the top 5 NuGet packages that depend on com.IvanMurzak.Brutal.MCP:
| Package | Downloads |
|---|---|
|
com.IvanMurzak.Brutal.MCP.Jolt
Brutal-MCP extension for Ahwoo.BRUTAL.Jolt: exposes live Jolt physics to AI agents through RQL. |
|
|
com.IvanMurzak.Brutal.MCP.RenderDoc
Brutal-MCP extension for Ahwoo.BRUTAL.RenderDoc: RenderDoc in-application API (captures, trigger capture, replay UI), exposed to AI agents through RQL. |
|
|
com.IvanMurzak.Brutal.MCP.Vma
Brutal-MCP extension for Ahwoo.BRUTAL.Vulkan.Vma: Vulkan Memory Allocator (device, heap budgets, statistics; read-only), exposed to AI agents through RQL. |
|
|
com.IvanMurzak.Brutal.MCP.ImGui
Brutal-MCP extension for Ahwoo.BRUTAL.ImGui: pumps BrutalMcp.Tick() from an ImGui NewFramePre hook, exposes the ImGui context (io, style, windows), ini settings and the ConsoleWindow terminal commands to AI agents through RQL, and discovers the GLFW window behind the main viewport. |
|
|
com.IvanMurzak.Brutal.MCP.Sdl
Brutal-MCP extension for Ahwoo.BRUTAL.Sdl: exposes the SDL windows of the game (title, position, size, flags) to AI agents through RQL. |
GitHub repositories
This package is not used by any popular GitHub repositories.