Apache License 2.0

项目介绍

IvanMurzak/Godot-MCP 是一个托管在 GitHub 上的开源项目,主要使用 C# 编写,采用 Apache License 2.0 许可证,目前获得 326 个 Star、31 次 Fork。

仓库全名
IvanMurzak/Godot-MCP
开源许可证
Apache License 2.0
Star 数
326
Fork 数
31
未关闭 Issue
3

README 摘要

✨ AI Game Developer — Godot MCP                                  Godot MCP is an AI-powered game development assistant for the Godot Editor. Connect Claude, Cursor, Copilot, or any MCP-aware agent to Godot and let it inspect and drive your project — create nodes, edit scenes, manage resources and scripts,…

完整内容见 GitHub 原始 README 或本页 。

常见问题

Godot-MCP 用什么语言开发?

主要使用 C# 编写,采用 Apache License 2.0 许可证,目前有 326 个 Star。

Godot-MCP 可以免费商用吗?

仓库采用 Apache License 2.0 许可证,可免费使用与修改,商业使用请遵守许可证条款(例如保留版权声明与许可声明)。

如何获取 Godot-MCP 的源码?

可以直接克隆仓库:git clone https://github.com/IvanMurzak/Godot-MCP.git,默认分支为 main;安装与运行步骤见仓库 README。

Godot-MCP 最近还在维护吗?

仓库最近一次更新为 19 小时前,当前有 3 个未关闭 Issue;Star 数为 326,可作为社区活跃度的参考。

关于

Godot-MCP — Model Context Protocol (MCP) integration for the Godot Engine. AI tools for the Godot Editor in C#, with cloud connection to ai-game.dev. Apache-2.0.

描述取自 GitHub 官方 API,中文内容由 GitRead 中文社区 编辑团队整理。

语言占比

C#
Dockerfile
GDScript
JavaScript
Python
Shell
TypeScript

README

✨ AI Game Developer — Godot MCP

MCP npm Godot Godot Editor Godot Runtime .NET release
Discord Stars Docker Image License Stand With Ukraine

AI Game Developer — Godot MCP

Claude   Codex   Cursor   GitHub Copilot   Gemini   Antigravity   VS Code   Rider   Visual Studio   Open Code   Cline   Kilo Code

Godot MCP is an AI-powered game development assistant for the Godot Editor. Connect Claude, Cursor, Copilot, or any MCP-aware agent to Godot and let it inspect and drive your project — create nodes, edit scenes, manage resources and scripts, capture screenshots, and more.

Godot-MCP is the Godot counterpart of Unity-MCP: a C# editor addon that exposes Godot Editor operations as AI Tools and connects them to an MCP server through the same hosted cloud backend (ai-game.dev) that powers Unity-MCP — or your own self-hosted server. The MCP / reflection stack is not forked: it is shared with Unity-MCP and consumed from nuget.org as PackageReferences.

💬 Join our Discord Server — Ask questions, showcase your work, and connect with other developers!

Features

  • ✔️ AI agents — Use the best agents from Anthropic, OpenAI, Google, or any other provider with no vendor lock-in
  • ✔️ 24 built-in Tools — MCP Tools across 9 families for operating the Godot Editor, led by RQL: one query language for the whole editor
  • ✔️ C# & GDScript — Read, create, and update both .cs and .gd scripts, and attach them to nodes
  • ✔️ Scene & Node control — Query and edit the scene tree, Godot properties (GDScript variables included), .tscn scenes and .tres/.res resources with RQL — bulk, all-or-nothing, undoable
  • ✔️ Visual feedback — Capture viewport, camera, and isolated-node screenshots the LLM can inspect
  • ✔️ Call anything — call CallMethod("name", [args]) reaches any Godot method (GDScript ones too); in a running game, find and call C# methods via ReflectorNet
  • ✔️ Cloud or self-hosted — Connect to ai-game.dev out of the box, or point at your own server
  • ✔️ Natural conversation — Chat with AI like you would with a human

AI Game Developer — Godot MCP

Quick Start

Get up and running from a terminal using the godot-cli (the Godot analog of unity-mcp-cli) — no manual file copying or csproj editing required:

# 1. Install godot-cli
npm install -g godot-cli

# 2. (Optional) Scaffold a fresh Godot C# project — skip if you already have one
godot-cli create-project --dotnet ./MyGodotProject

# 3. Install the godot_mcp addon: downloads addons/godot_mcp/ from the matching
#    GitHub release, adds the required NuGet packages + the extension-catalog
#    EmbeddedResource to your .csproj, and enables the plugin in project.godot —
#    all idempotently
godot-cli install-plugin ./MyGodotProject

# 4. Sign in to the ai-game.dev cloud — OAuth 2.1 device login (opens a browser,
#    saves a machine-wide credential the editor plugin auto-adopts; no token to copy)
godot-cli login

# 5. Pick an AI agent (Claude Code, Cursor, Copilot, …) and write its MCP config —
#    pinned to THIS project's cloud route by default (pass --no-pin for the bare URL)
godot-cli setup-mcp claude-code ./MyGodotProject

# 6. Open the Godot editor — builds the C# assembly first (so the addon loads on
#    the very first open) then auto-connects with the right GODOT_MCP_* env vars
godot-cli open ./MyGodotProject

# 7. Wait until the plugin answers the readiness probe
godot-cli wait-for-ready ./MyGodotProject

That’s it. Ask your AI “Create 3 cubes in a circle with radius 2” and watch it happen. ✨

Offline / dev install: install-plugin --source <path-to>/addons/godot_mcp copies the addon from a local directory instead of downloading it. Prefer the matching release version with install-plugin --version <x.y.z> if you need a specific addon build. The manual route (copy the addon + add the NuGet packages yourself) is still documented under Installation Steps 1–2 for the Asset Library / hand-managed flows.

See the full CLI documentation for every command, editor-resolution order, and connection env vars.

Contents

AI Game Developer — Godot MCP

Tools Reference

Godot-MCP ships 24 built-in tools grouped into 9 families. The editor’s data layer is RQL (Reflection Query Language): rql-query, rql-mutate and rql-schema read and change scene nodes, Godot properties, resources, files, scenes and editor state in one query instead of one tool per operation (they replace the former node-*, scene-*, resource-*, filesystem-* and editor-* tools; in the editor also console-* and reflection-*, which stay available in a running game). With the default toolFormat (Rql) the other tools take RQL values as arguments and return compact text; Json keeps ReflectorNet’s JSON schemas and results. Screenshots return a PNG image. All editor tools are available immediately after the addon is enabled — no extra configuration required. The runtime-errors, console and reflection families serve the running game (the in-game runtime, see Runtime usage); runtime-errors is OFF by default — opt in with builder.WithRuntimeErrorCapture() (see Capturing in-game runtime errors).

Family Tools What it does
ping ping Lightweight readiness probe — echoes a message back, or returns pong. Verifies the end-to-end MCP path (editor → SignalR → tool dispatch). System tool — reachable over the server’s /api/system-tools/ HTTP surface, not advertised to AI agents in tools/list.
rql rql-query, rql-mutate, rql-schema Query and change the live editor with RQL: nodes, root, selection, scenes, files, folders, classes, console, editor, project, settings, inputActions, autoloads, groups, layers, tools (every MCP tool, hidden ones included) sources; rql-schema "<extension>" prints an installed extension’s guide; godot.find / godot.group / godot.resources / godot.resource / godot.callable; node calls AddChild / InstantiateScene / Duplicate / Reparent / MoveChild / Free / Connect / Disconnect / AddToGroup / RemoveFromGroup; project settings, input map, autoloads, layer names, TileSets, Themes, ShaderMaterial parameters and MeshLibraries; editor calls NewScene / OpenScene / SaveScene / CreateResource / MoveResource / DeleteResource / CreateFolder / DeleteFolder / Reimport. All-or-nothing and undoable. See docs/rql.md and the godot-rql skill.
script script-read, script-create, script-update, script-delete, script-attach-to-node, script-validate, script-build, script-execute CRUD on C# (.cs) and GDScript (.gd) files, attaching a script to a node, validating GDScript, building the project’s C# (the result arrives after Godot’s assembly reload), and running C# in the editor (Code-Exec).
screenshot screenshot-viewport, screenshot-camera, screenshot-isolated Capture the editor viewport, a specific camera, or an isolated node render, returned as a PNG image the LLM can inspect.
console console-get-logs, console-clear-logs In a running game: read and clear the log collector (GD.Print/GD.PushWarning/GD.PushError). In the editor, the RQL console source.
reflection reflection-method-find, reflection-method-call In a running game: find and call C# methods (static/instance, public/private) across every loaded assembly via ReflectorNet. In the editor, RQL call / CallMethod and rql-schema.
skills godot-skill-create, godot-skill-generate Author a new MCP tool as a C# file in the project, and regenerate the SKILL.md files from the tools the editor currently has registered. System tools — reachable over the server’s /api/system-tools/ HTTP surface (like ping), not advertised to AI agents in tools/list.
session session-close Save and quit an editor started by godot-cli exec / open --headless (godot-cli close --owned-only). System tool, and only for that CLI session (its lease nonce).
runtime-errors runtime-errors-get, runtime-errors-clear Poll errors raised inside the running game (NOT the editor) — GDScript runtime errors, push_error/push_warning, shader errors, and C# unhandled / unobserved-Task exceptions, with multi-frame GDScript backtraces on Godot 4.5+. OFF by default — opt in with builder.WithRuntimeErrorCapture().

ping

  • ping — Lightweight readiness probe; echoes a message back, or returns pong. A System tool: call it over /api/system-tools/ping (or godot-cli run-system-tool ping); it is not listed in tools/list.

rql (editor)

  • rql-query — Read-only RQL query, compact rows: nodes | where class == "OmniLight3D" | select name props["light_energy"].
  • rql-mutate — RQL query ending with set / call: nodes | where name starts-with "Enemy" | set Visible = false, root | call AddChild("Node3D", "Props"), nodes | where name == "Button" | call Connect("pressed", godot.find("UI"), "_on_pressed"), project | call AddInputAction("jump", ["Key:Space"]), editor | call SaveScene(). All-or-nothing, undoable (Ctrl+Z), dry_run previews; scene edits mark the scene unsaved, edited resource files and project.godot are saved.
  • rql-schema — The sources, functions and node classes in the edited scene; with a type name its members, methods and Godot properties.

script

  • script-read — Read a .cs / .gd script file.
  • script-create — Create a new script file.
  • script-update — Update an existing script file’s contents.
  • script-delete — Delete a script file.
  • script-attach-to-node — Attach a script to a node.
  • script-validate — Validate GDScript (.gd) files and return structured parse/compile diagnostics.
  • script-build — Build the project’s C# (dotnet build, Debug) so scripts written with script-create / script-update load. The build runs in the background; when it succeeds Godot reloads the C# assembly, the plugin reconnects and the result (the compiler warnings, or the compiler errors) is delivered after the reload through the request’s requestId. See C# assembly reloads.
  • script-execute — Compile and run C# in the editor (Roslyn, via Code-Exec): plain statements with the last expression as the result (own usings, local classes, await), or a class with a static method. The game’s compiled types are visible; include adds helper .cs files from <project>/.ai-game-dev/snippets. Returns the value plus what the code printed (Console; GD.Print / push_warning / push_error when the project builds with Godot.NET.Sdk 4.5+). From a terminal: godot-cli exec '1 + 2'.

screenshot

  • screenshot-viewport — Capture the editor viewport as a PNG.
  • screenshot-camera — Capture from a specific camera.
  • screenshot-isolated — Render a node in isolation from a chosen angle.

console (in-game runtime; in the editor use the RQL console source)

  • console-get-logs — Read the plugin’s collected logs (with filtering). This includes the plugin’s connection lifecycle diagnostics (connect/disconnect, drain-timeout, config save/load, skill-gen, dev-control, dispatcher, and runtime-capture warnings), which route through the same capture sink as its framework logs.
  • console-clear-logs — Clear the collected log cache.

reflection (in-game runtime; in the editor use RQL call / CallMethod and rql-schema)

  • reflection-method-find — Find C# methods (including private) across every loaded assembly.
  • reflection-method-call — Call any C# method with input parameters and get the result.

session (system tool — served on /api/system-tools/, not advertised to AI agents)

  • session-close — Save and quit an editor started by godot-cli (exec, open --headless): open scenes that have a file and the resources they changed. Needs that session’s nonce from .ai-game-dev/session.json, so it never closes a user’s editor; godot-cli close --owned-only calls it.

runtime-errors (in-game; OFF by default — enable with builder.WithRuntimeErrorCapture())

  • runtime-errors-get — Read captured in-game runtime errors (oldest-first, newest-kept page); poll only new errors via sinceSequence. Returns available:false when capture was never enabled, so an empty list is never mistaken for health.
  • runtime-errors-clear — Clear the captured in-game runtime-error buffer (a no-op when capture is not enabled); the monotonic sequence counter is preserved.

skills (system tools — served on /api/system-tools/, not advertised to AI agents)

  • godot-skill-create — Write a new C# (.cs) MCP tool file into the project. The tool becomes callable once the project is rebuilt (Godot builds C# out-of-band).
  • godot-skill-generate — Regenerate every SKILL.md from the tools currently registered in the editor, into the selected AI agent’s skills folder.

Install Additional Skills and Tools

Install extensions when you need more or create your own tools. Each extension is an RQL module: it adds no MCP tools of its own, it extends the core rql-query / rql-mutate / rql-schema tools and the godot-rql skill.

godot-cli install-extension com.IvanMurzak.Godot.MCP.CSG ./MyGodotProject
godot-cli build ./MyGodotProject
Extension Description Requires
AI Animation AnimationPlayer libraries, animations, tracks and keys
AI Beehave Beehave addon: list behaviour trees and their nodes Beehave addon
AI CSG Constructive solid geometry: validated primitive dimensions
AI Dialogic Dialogic addon: list and create timelines and characters, append timeline text Dialogic addon, Godot 4.4+
AI GridMap GridMap 3D tile maps: validated settings, cell rows and cell editing
AI Navigation 2D and 3D navigation: agents, regions, links and region baking
AI Particles GPU particles in 2D and 3D: validated emitter settings and restart
AI PhantomCamera Phantom Camera addon: list virtual cameras and hosts, set follow and look-at targets Phantom Camera addon, Godot 4.4+
AI Terrain3D Terrain3D addon: terrain source, region size changes and material creation Terrain3D addon, Godot 4.4+
AI Tilemap TileMapLayer: used-cell rows and cell editing

The installer adds only the extension package; install a required third-party addon into the project yourself.

AI Game Developer — Godot MCP

Requirements

  • Godot 4.3+ — the C# / .NET (mono) edition. The addon csproj pins Godot.NET.Sdk/4.3.0 as its minimum floor; newer 4.x editors (4.4, 4.5) work.
  • .NET 8 SDK (net8.0).

[!IMPORTANT] Godot-MCP requires the mono (C#/.NET) build of Godot — the standard (GDScript-only) build cannot compile the addon.

[!NOTE] C# scripts in a game run from the editor need <EnableDynamicLoading>true</EnableDynamicLoading>. If a game started from the editor (Play) fails to create every C# script (“Cannot instantiate C# script because the associated class could not be found”, after a TypeLoadException ... Could not resolve type '<an EditorPlugin class>'), the project’s .csproj lacks that property: without it the build does not copy the NuGet package assemblies (Godot-MCP’s packages, and the Debug configuration’s GodotSharpEditor reference) into .godot/mono/temp/bin/Debug/. Godot’s own C# project template always has it, and godot-cli install-plugin / create-project set it. Add it to the project’s <PropertyGroup> (next to <TargetFramework>) and rebuild.

Installation

There are two things to install: the addon (the plugin files) and the two NuGet packages the addon’s C# depends on. Godot compiles every .cs under your project into one assembly, so your project’s .csproj must declare the same NuGet references the addon needs — otherwise the addon’s C# will not compile.

Step 1: Add the addon

Pick one of the following ways to get the addons/godot_mcp/ folder into your Godot C# project.

Fully automated (recommended for terminal workflows): godot-cli install-plugin ./MyGodotProject does all of Step 1 and Step 2 in one command — it downloads addons/godot_mcp/ from the matching GitHub release, adds the two NuGet packages and the extension-catalog <EmbeddedResource> to your .csproj, and enables the plugin in project.godot, idempotently. Use --source <path>/addons/godot_mcp to install from a local copy offline. The manual Options A–C below remain for in-editor (Asset Library) and hand-managed installs.

The easiest path: install directly from inside the editor.

  1. Open the AssetLib tab at the top of the Godot editor.
  2. Search for Godot-MCP and open the asset.
  3. Click Download, then Install — Godot unpacks the addon into your project’s res://addons/godot_mcp/.

The Asset Library entry is published per release and always points at a tagged version, so an in-editor install gives you a known-good snapshot of the addon. (See note below if the entry is not visible yet.)

Option B — GitHub Release zip

Grab the latest godot-mcp-addon-<version>.zip from the Releases page and extract it into your project’s root — the archive already contains addons/godot_mcp/..., so the files land at res://addons/godot_mcp/.

Option C — copy from source

Copy the addons/godot_mcp/ folder from this repository (or your clone) into your project’s addons/ directory by hand.


After the files are in place (Options A–C), enable the plugin: Project → Project Settings → Plugins → Godot-MCP → Enable. (If you used the fully-automated godot-cli install-plugin above, the plugin is already enabled and the NuGet packages + extension-catalog embed are already added — skip straight to Step 3.) On a successful load the editor Output panel prints:

[Godot-MCP] plugin loaded

Asset Library availability. The in-editor AssetLib entry (Option A) appears after the maintainer’s first submission is approved by the Godot Asset Library moderators. Until then, use Option B (GitHub Release zip) or Option C.

Step 2: Add the NuGet packages + the extension catalog embed

Add the six PackageReferences and the extension-catalog <EmbeddedResource> to your project’s .csproj (use these exact pinned versions — they must match the addon’s Godot-MCP.csproj), and keep <EnableDynamicLoading>true</EnableDynamicLoading> in its <PropertyGroup> (Godot’s C# template has it; without it the package assemblies are not copied next to the game assembly):

<ItemGroup>
  <PackageReference Include="com.IvanMurzak.ReflectorNet" Version="5.5.1" />
  <PackageReference Include="com.IvanMurzak.McpPlugin"   Version="8.19.0" />
</ItemGroup>

<!-- Editor-only: exported games (ExportDebug / ExportRelease) ship no RQL and no Roslyn. -->
<ItemGroup>
  <PackageReference Include="com.IvanMurzak.Rql"         Version="0.3.0" Condition="'$(Configuration)' != 'ExportDebug' and '$(Configuration)' != 'ExportRelease'" />
  <PackageReference Include="com.IvanMurzak.CodeExec"        Version="0.4.1" Condition="'$(Configuration)' != 'ExportDebug' and '$(Configuration)' != 'ExportRelease'" />
  <PackageReference Include="com.IvanMurzak.CodeExec.Roslyn" Version="0.4.1" Condition="'$(Configuration)' != 'ExportDebug' and '$(Configuration)' != 'ExportRelease'" />
  <PackageReference Include="Microsoft.CodeAnalysis.CSharp"  Version="4.12.0" Condition="'$(Configuration)' != 'ExportDebug' and '$(Configuration)' != 'ExportRelease'" />
</ItemGroup>

<!-- Embed the extension catalog so the Extensions panel populates (else it is EMPTY). -->
<ItemGroup>
  <EmbeddedResource Include="addons/godot_mcp/extensions.catalog.json" LogicalName="Godot-MCP.extensions.catalog.json" />
</ItemGroup>
Package Version Role
com.IvanMurzak.ReflectorNet 5.5.1 Reflection / serialization core
com.IvanMurzak.McpPlugin 8.19.0 MCP plugin client (transitively pulls McpPlugin.Common + ReflectorNet; carries the shared AgentConfig module)
com.IvanMurzak.Rql 0.3.0 RQL, the editor tools’ data layer (licensed separately under PolyForm Shield — see License)
com.IvanMurzak.CodeExec 0.4.1 Code-Exec runtime behind script-execute (PolyForm Shield)
com.IvanMurzak.CodeExec.Roslyn 0.4.1 Code-Exec’s Roslyn adapter, shipped as source (PolyForm Shield)
Microsoft.CodeAnalysis.CSharp 4.12.0 Roslyn, the C# compiler script-execute runs (its dependencies match .NET 8)

The four editor-only packages carry a Condition that leaves them out of Godot’s export builds: only editor code (#if TOOLS) uses them, so your exported game ships neither RQL nor Roslyn (godot-cli install-plugin writes the same condition; see docs/ARCHITECTURE.md).

The <EmbeddedResource> is as required as the NuGet pins: the addon’s pure-managed extension registry reads the catalog at editor runtime via GetManifestResourceStream (no res:// / filesystem fallback), and because the addon ships as source its own <EmbeddedResource> does not carry into your project — so without this line your Extensions panel is empty. The LogicalName must be exactly Godot-MCP.extensions.catalog.json so the resource resolves identically to the addon’s own assembly.

Run dotnet restore so the packages land in your NuGet cache, then build. No manual DLL copying is required — at editor runtime the addon’s assembly resolver locates the DLLs in your NuGet global-packages folder by reading the build’s *.deps.json. (If you prefer self-contained output, set <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> so the DLLs are copied beside your project assembly instead.)

Step 3: Install an AI agent

Choose a single AI agent you prefer — you don’t need to install all of them. This is your main chat window to communicate with the LLM.

Write the agent’s MCP-client config with godot-cli setup-mcp <agent> ./MyGodotProject. By default it points the client at the project-pinned cloud URL <host>/mcp/p/<pin>, so an agent session launched in this project folder routes to this project’s editor even when your account has several editors connected; pass --no-pin for the bare <host>/mcp URL. In Cloud mode the config carries this project’s project key (Authorization: Bearer agd_pk_…) — a non-expiring credential bound to this project only, created with your machine sign-in; without a sign-in (or with --oauth) the config is URL-only and the agent signs in with its own OAuth. The editor’s Configure button writes the same config. See the CLI documentation for the full list of supported agents.

AI Game Developer — Godot MCP

Connect

The plugin connects to an MCP server in one of two modes. The mode and its URL / token can be set in the serialized config or overridden at process start with environment variables (handy for CI, headless runs, and local dev). All variable names are the Godot analog of Unity-MCP’s UNITY_MCP_*. The active mode always recomputes from the environment, so a process-level override wins over the serialized config without editing any file.

Cloud mode (default) — ai-game.dev

In Cloud mode the plugin connects to the hosted backend at https://ai-game.dev (the /mcp hub path is appended automatically). This is the default connectionMode.

Sign in once with godot-cli login. Cloud authentication uses the OAuth 2.1 device-authorization flow (RFC 8628): godot-cli login prints a short user code, opens your browser, and — on approval — saves a cloud credential to the shared machine store (~/.ai-game-dev/credentials.json) that the editor plugin auto-adopts, so godot-cli open connects with no token to copy or paste. No personal access token (PAT) is minted. GODOT_MCP_TOKEN (below) remains available as a manual override for CI / headless runs.

Environment variable Purpose Default
GODOT_MCP_CONNECTION_MODE Force the mode: Cloud or Custom (case-insensitive). Cloud
GODOT_MCP_CLOUD_URL Override the cloud base URL. A trailing /mcp is stripped if present; a non-http(s) value falls back to the default. https://ai-game.dev
GODOT_MCP_CREDENTIALS_DIR Absolute credential-store directory for isolated development/testing. Also accepted in the project’s .env; process environment wins. Omit for the regular machine store. Platform user profile’s .ai-game-dev
GODOT_MCP_TOKEN Bearer token, routed to the active mode’s token. Surrounding quotes are trimmed. (none)

Custom mode — your own server

In Custom mode the plugin connects to a server URL you supply (a local dev server, a self-hosted instance, etc.).

Environment variable Purpose Default
GODOT_MCP_CONNECTION_MODE Set to Custom to select this mode. Cloud
GODOT_MCP_HOST The custom server URL. Must be an absolute http(s) URL or it falls back to the default. http://localhost:8080
GODOT_MCP_TOKEN Bearer token (only needed if the server requires authorization). (none)

With authorization oauth, your signed-in ai-game.dev account token is sent only to a localhost server (localhost, 127.0.0.0/8, ::1). For any other host set GODOT_MCP_TOKEN; without it the connection fails with Refusing to send your ai-game.dev account token to <host>; set GODOT_MCP_TOKEN or use a localhost server.

Example — boot the editor pointed at a local server:

export GODOT_MCP_CONNECTION_MODE=Custom
export GODOT_MCP_HOST=http://localhost:5300
# export GODOT_MCP_TOKEN=...   # only if the server enforces auth

The godot-cli open command forwards these env vars for you via --mode, --url, --cloud-url, and --token flags.

AI Game Developer — Godot MCP

Godot MCP Server setup

In Cloud mode you don’t run a server at all — the plugin talks to ai-game.dev. If you want to host the server yourself (local dev, CI, or your own cloud), you have two options: let the addon download and run the matched server binary for you (recommended), or run it manually (advanced).

The server itself is the shared, engine-agnostic GameDev-MCP-Server — one server binary (gamedev-mcp-server) serving Unity-MCP, Godot-MCP, and Unreal-MCP. It is released from its own repo on its own version line; this addon pins the server version it consumes (the ServerVersion constant in addons/godot_mcp/Runtime/Connection/GodotMcpServerView.cs).

Local server — let the addon download & run it for you

In Custom mode the plugin can host its own MCP server — you don’t have to build or launch anything by hand. Open the addon dock’s Server card while Custom mode is selected and use the Local server row:

  • Start Server — downloads the server build for the pinned server version, caches it, launches it, and the plugin connects to it. Stop Server terminates it (it is also stopped automatically when you close the editor).
  • The download is the per-platform release asset gamedev-mcp-server-<rid>.zip — pulled over HTTPS from github.com only, from the GameDev-MCP-Server release tagged v<ServerVersion>, so the asset URL is: https://github.com/IvanMurzak/GameDev-MCP-Server/releases/download/v<ServerVersion>/gamedev-mcp-server-<rid>.zip. The <rid> (platform runtime identifier — e.g. win-x64, osx-arm64, linux-x64) is resolved automatically for your machine; all seven published RIDs are supported (win-x64/x86/arm64, linux-x64/arm64, osx-x64/arm64).
  • The binary is cached under your project’s .godot/mcp-server/<rid>/ folder (gitignored) and re-used on later launches; it is only re-downloaded when the pinned server version changes (an exact version match, so the editor plugin and the server it talks to never drift). The server is launched on the port from your Server URL (default http://localhost:8080), over the streamableHttp transport, with plugin-timeout=10000 (the connection timeout) and tool-timeout=300000. A server built on McpPlugin 8.11.0+ sends a tool call to the editor once and lets it run up to 5 minutes (script-execute stops a snippet itself when its timeout argument runs out: 30 s by default, at most 4 minutes, the tool timeout minus a minute; an endless loop returns a Timeout error and runaway recursion a “Recursion too deep” error, the editor keeps running). Older servers ignore tool-timeout: they re-send a call every 10 s and give up after about 110 s; the addon runs each re-sent call only once.

Version pinning & security. The download URL is derived solely from the addon’s pinned ServerVersion constant and your platform RID — there is no arbitrary-URL binary execution. The addon version and the server version are decoupled: bumping the consumed server is an explicit addon change (a new ServerVersion), and the pinned v<ServerVersion> release must already exist on GameDev-MCP-Server before an addon release that pins it. If the release asset can’t be fetched (you’re offline), the addon logs a warning and the local server simply doesn’t start — fall back to the manual run below, or use Cloud mode. The download is skipped entirely under CI (the CI / GITHUB_ACTIONS environment), where no local server is hosted.

This mirrors Unity-MCP’s self-hosted server flow: the editor plugin manages the pinned server binary for you instead of requiring a manual build.

Run the server manually (advanced)

To run the server as a standalone / cloud process, download a GameDev-MCP-Server release binary (or use the aigamedeveloper/mcp-server Docker image). Both transports are supported: streamableHttp (HTTP) and stdio.

# HTTP transport on port 8080
./gamedev-mcp-server --client-transport streamableHttp --port 8080

# stdio transport — for local MCP clients that launch the server directly
./gamedev-mcp-server --client-transport stdio

Then point the plugin at it in Custom mode (GODOT_MCP_HOST=http://localhost:8080).

Choosing a transport: use stdio when the MCP client launches the server binary directly (local use — the most common setup); use streamableHttp when running the server as a standalone process or in the cloud and connecting over HTTP.

See the GameDev-MCP-Server README for the full argument / environment-variable table, the Docker image, and the cross-platform build matrix.

AI Game Developer — Godot MCP

Customize Tools

Godot-MCP supports custom MCP Tool development directly in your project code. A tool family is a partial class decorated [AiToolType]; each tool method is decorated [AiTool("tool-name", …)] with a [Description] on the method and on each parameter to help the LLM understand it.

Any Godot API call (Node, Resource, EditorInterface, …) must run on the editor main thread — marshal it through MainThread.Instance.Run(...) (ReflectorNet’s MainThread is backed by the Godot main-thread dispatcher on plugin boot). Never touch engine objects off-thread.

[AiToolType]
public partial class Tool_MyFeature
{
    [AiTool("my-custom-task", Title = "Do a custom task")]
    [Description("Explain to the LLM what this does and when to call it.")]
    public string CustomTask
    (
        [Description("Explain to the LLM what this parameter is.")]
        string inputData
    )
    {
        // ... work that does not touch the Godot API can run on this background thread ...

        return MainThread.Instance.Run(() =>
        {
            // ... touch EditorInterface / Node / Resource here, on the main thread ...
            return "[Success] Operation completed.";
        });
    }
}

Return a structured data model (ReflectorNet-serialized) or void for side-effect-only ops — never ad-hoc string formatting for parseable output. Use string? optional = null parameters (nullable + default) to mark them as optional for the LLM.

C# assembly reloads

Godot reloads the project’s C# assembly about half a second after the built DLL changes (script-build, the editor’s Build button, or a dotnet build in a terminal), whatever the plugin is doing. The plugin is part of that assembly, so it is torn down, rebuilt and reconnects (a few seconds). A tool call still running at that moment would keep the old assembly alive and Godot’s unload would fail, so the plugin gates tool calls around a reload:

  • once the rebuilt DLL is on disk, new tool calls are refused with a retryable error (“Godot is about to reload the project’s C# assembly … Retry in a few seconds”); calls already running finish first, and Godot’s reload waits for them (at most 10 s);
  • when the unload starts, the plugin stops receiving calls, refuses main-thread work still queued for a call instead of running it, and waits for those calls to finish (a call caught there is reported by the server as lost with the connection: retry it too);
  • after the reload the plugin reconnects by itself, and script-build delivers its result.

Known issue: crash or hang on reload with .NET 10

On .NET 10, the editor can crash or hang shortly after a C# assembly reload. This is a .NET runtime bug, dotnet/runtime#135441: when an idle thread-pool thread exits after a reload, the runtime can free a handle in the wrong collectible load context and corrupt a static of the newly loaded assemblies (the addon’s dependencies use thread-static fields, which trigger it). It is fixed on the runtime’s main branch (dotnet/runtime#134983); the .NET 10 servicing fix is dotnet/runtime#136481.

Until that servicing release ships, keep idle thread-pool threads alive by setting this environment variable for the editor process:

DOTNET_ThreadPool_ThreadsToKeepAlive=-1

Editors started by godot-cli (open, open --headless, exec) get it automatically. If you open the editor yourself, set it system-wide (Windows: System Properties → Environment Variables, or setx DOTNET_ThreadPool_ThreadsToKeepAlive -1; macOS / Linux: export it in the shell or launcher that starts Godot) and restart the editor. Remove it once your .NET 10 runtime includes the fix.

AI Game Developer — Godot MCP

Runtime usage (in-game)

Everything above runs the MCP connection inside the Godot editor (the [Tool] EditorPlugin boots it for you). Godot-MCP can also run inside a running / exported game build (debug or release) — the Godot analog of Unity-MCP’s runtime mode. This lets an LLM read and drive your live game state: imagine a Chess game whose bot logic you outsource to an LLM by exposing a couple of tools.

Two things make runtime mode different from editor mode, and both are deliberate:

  • It never auto-connects. The editor plugin connects on boot; a game build does not. You write the opt-in code and decide when (if ever) to call Connect().
  • There are no tools, prompts, or resources by default — strictly manual. The runtime ships zero MCP tools, prompts, and resources. You register every [AiToolType] tool, [AiPromptType] prompt, and [AiResourceType] resource yourself, in your own code — and each kind is independently optional (register prompts without any tools, or vice versa). (The addon’s editor tool families are gated by #if TOOLS and don’t even compile into a game build, so they can never leak in.)

The entry point is GodotMcpRuntime.Initialize(...) (namespace com.IvanMurzak.Godot.MCP.Runtime). Write it once — e.g. from a Godot autoload’s _Ready() so a SceneTree exists:

using System.Reflection;
using com.IvanMurzak.Godot.MCP.Connection;   // GodotMcpConnectionMode
using com.IvanMurzak.Godot.MCP.Runtime;      // GodotMcpRuntime
using McpServerConsts = com.IvanMurzak.McpPlugin.Common.Consts.MCP.Server;   // AuthOption (none/oauth/token)
using Godot;

public partial class GameMcp : Node
{
    private GodotMcpRuntimeHandle? _mcp;

    public override async void _Ready()
    {
        // 1) Build the connection (default OFF — nothing connects yet).
        _mcp = GodotMcpRuntime.Initialize(builder =>
        {
            builder.WithConfig(config =>
            {
                config.ConnectionMode = GodotMcpConnectionMode.Custom;         // your own server
                config.Host           = "http://localhost:8080";               // prefer loopback
                config.AuthOption     = McpServerConsts.AuthOption.token;      // offline bearer-token auth
                config.Token          = "your-secret-token";
            });

            // 2) Opt YOUR tools / prompts / resources in. Zero of each by default — this is the only way
            //    they get registered, and each kind is independently optional.
            builder.WithToolsFromAssembly(Assembly.GetExecutingAssembly());     // [AiToolType] classes
            builder.WithPromptsFromAssembly(Assembly.GetExecutingAssembly());   // [AiPromptType] classes
            builder.WithResourcesFromAssembly(Assembly.GetExecutingAssembly()); // [AiResourceType] classes
            //   …or register specific families:
            //   builder.WithTools(typeof(GameMcpTools));
            //   builder.WithPrompts(typeof(GameMcpPrompts));
            //   builder.WithResources(typeof(GameMcpResources));
        }).Build();

        // 3) Connect — explicit, the security-required opt-in. Retries in the background while
        //    KeepConnected is true (the default).
        await _mcp.Connect();
    }

    public override async void _ExitTree()
    {
        // 4) Disconnect on shutdown (or whenever you want to stop exposing tools).
        if (_mcp is not null)
            await _mcp.Disconnect();
    }
}

Builder surface (all fluent / chainable):

Call What it does
GodotMcpRuntime.Initialize(configure) Begin configuring; returns a GodotMcpRuntimeBuilder. configure may be null for the zero-tool, env-configured default.
builder.WithConfig(Action<GodotMcpConfig>) Set Host / Token / ConnectionMode / AuthOption in code. Multiple calls compose in order.
builder.WithToolsFromAssembly(Assembly) Register every [AiToolType] class in an assembly (usually Assembly.GetExecutingAssembly()).
builder.WithTools(params Type[]) Register specific [AiToolType] classes when a whole-assembly scan is too broad.
builder.WithPromptsFromAssembly(Assembly) Register every [AiPromptType] class in an assembly. Independent of tools/resources.
builder.WithPrompts(params Type[]) Register specific [AiPromptType] classes.
builder.WithResourcesFromAssembly(Assembly) Register every [AiResourceType] class in an assembly. Independent of tools/prompts.
builder.WithResources(params Type[]) Register specific [AiResourceType] classes.
builder.WithoutMainThreadDispatcher() Skip the automatic main-thread-dispatcher bootstrap (only if you install your own autoload dispatcher).
builder.ConnectWhenRunFromEditor() Let handle.Connect() connect in a game started from the Godot editor (Play) too. OFF by default: see “Games run from the editor” below.
builder.WithRuntimeErrorCapture() Capture errors raised in the running game (GDScript runtime errors, push_error/push_warning, shader errors via the Godot 4.5+ engine hook; C# unhandled / unobserved-Task exceptions with full stack traces) and register the runtime-errors-* tool so an agent can poll them. OFF by default. See “Capturing in-game runtime errors” below.
builder.WithScriptExecute() Register script-execute in the game: the agent’s C# is compiled with Roslyn and run on the game’s main thread. OFF by default, needs the csproj opt-in, arbitrary code execution. See “Running C# in the game” below.
builder.Build() Finalize; returns a default-OFF GodotMcpRuntimeHandle.
handle.Connect() / handle.Disconnect() Open / close the connection. handle.Dispose() tears it down on shutdown.

Initialize().Build() also guarantees a main-thread dispatcher Node in the running SceneTree (so tool handlers can marshal Godot API calls onto the engine main thread), unless you opt out with WithoutMainThreadDispatcher(). Call it once a SceneTree is live (e.g. from an autoload _Ready).

Games run from the editor

A game started from the Godot editor (Play, F5) inherits the editor’s environment, GODOT_MCP_HOST and GODOT_MCP_TOKEN included, so its in-game runtime would join the server the editor is connected to. By default handle.Connect() therefore does nothing in such a game and returns false (it logs why); the editor stays the one plugin the agent talks to. Exported games and games started outside the editor connect as before. To connect a game run from the editor too, opt in with builder.ConnectWhenRunFromEditor() or the process environment variable GODOT_MCP_RUNTIME_FROM_EDITOR=1. A GameDev-MCP-Server with plugin roles then keeps both connections (the game connects with the runtime role, the editor with the editor role) and routes tool calls to the editor while it is connected. The editor plugin sets GODOT_MCP_EDITOR_PID in its process, so every process it starts inherits it; it counts only while that editor runs, and the plugin clears it when it unloads.

Capturing in-game runtime errors

In editor mode, console-get-logs and script-validate surface the plugin’s own logs and GDScript parse errors. But errors raised inside a running game — a GDScript runtime error (a null dereference, a bad index), a push_error/push_warning, a shader error, or a C# unhandled exception — are not visible to an agent through those editor tools. Without this, an agent can launch the game, poll for logs, see silence, and wrongly conclude the game is healthy. This is the gap that blocks an unattended “keep fixing until no errors” loop for real gameplay/runtime bugs.

Opt in with WithRuntimeErrorCapture():

_mcp = GodotMcpRuntime.Initialize(builder =>
{
    builder.WithConfig(cfg => { /* host / token … */ });
    builder.WithRuntimeErrorCapture();   // capture in-game runtime errors + expose the runtime-errors-* tool
}).Build();

await _mcp.Connect();

That single call installs three best-effort capture channels and registers the runtime-errors-* tool:

  1. Engine error stream (Godot 4.5+) — registers a Godot.Logger via OS.AddLogger, so GDScript runtime errors, push_error/push_warning, and shader errors raised in the running game are captured with their origin (file / line / function).
  2. C# unhandled exceptions — AppDomain.CurrentDomain.UnhandledException, with the full managed stack trace.
  3. C# unobserved Task exceptions — TaskScheduler.UnobservedTaskException, with the full managed stack trace. (It only observes for logging — it does not call SetObserved(), so your game’s own escalation behavior is unchanged.)

An MCP client polls the captured errors with the runtime-errors-get tool (and clears the buffer with runtime-errors-clear):

Tool What it returns / does
runtime-errors-get A bounded, newest-kept list of { sequence, message, type, source, file, line, function, stackTrace, frames, timestamp }. Pass the previous result’s highestSequence as sinceSequence to poll only new errors — the “did anything break since I last looked?” loop. Returns available:false when capture was never enabled (so an empty list is never mistaken for health).
runtime-errors-clear Clears the captured buffer (the monotonic sequence counter is preserved, so a pre-clear sinceSequence poll still behaves).

Stack-trace fidelity (read this). The two error sources differ in depth:

  • Engine errors (source: Engine) carry the error’s origin — file:line and the originating function — plus the message and a type (Error / Warning / Script / Shader). On Godot 4.5+, a GDScript runtime error also carries the deep multi-frame call stack: frames is the ordered (innermost-first) backtrace — each { function, file, line } — and stackTrace is the engine’s formatted rendering of it. On Godot < 4.5 (or a release build without call-stack tracking) frames is null and stackTrace is null (origin only). The frames are materialized off the engine’s non-thread-safe ScriptBacktrace inside the logger callback on the originating thread — only plain managed values ever cross into the collector, never a live engine object.
  • C# faults (source: UnhandledException / UnobservedTaskException) carry the full managed stack trace (inner exceptions inlined) in stackTrace, plus the CLR exception type name in type. (frames is null — the managed stack lives in the stackTrace string.)

Graceful degradation. On Godot < 4.5 there is no OS.AddLogger managed hook, so the engine channel is silently unavailable — the C# exception channels still work, and runtime-errors-get still functions (it just won’t see GDScript runtime errors). And like the rest of runtime mode, capture is strictly opt-in — without WithRuntimeErrorCapture() nothing is hooked and there is no behavior change. Disposing the handle (handle.Dispose()) uninstalls the hooks.

⚠️ Security — information disclosure. Captured errors forward the full message and (for C# faults) the full managed stack trace to the connected agent through runtime-errors-get. Those strings can embed sensitive runtime data — absolute filesystem paths, machine/user names, query strings, or a secret/token that happened to appear in an exception message or argument. That is the intended diagnostic value, but it widens what is exposed over the connection. Enable WithRuntimeErrorCapture() only on a trusted connection: a loopback host (http://localhost:… / 127.0.0.1) with AuthOption = Consts.MCP.Server.AuthOption.token and a real token — never an unauthenticated public interface in a release build. See Security and docs/runtime-security.md.

Running C# in the game

script-execute normally runs in the editor. A game can offer it too: the agent sends C#, the running game compiles it with Roslyn and runs it on its main thread, with the game’s own types, autoloads and scene tree (((SceneTree)Engine.GetMainLoop()).Root). There is no editor there, so no EditorInterface.

Godot’s export builds leave Roslyn out, so the game’s .csproj opts in:

<PropertyGroup>
  <GodotMcpCodeExecInGame>true</GodotMcpCodeExecInGame>
  <DefineConstants>$(DefineConstants);GODOT_MCP_CODE_EXEC_IN_GAME</DefineConstants>
</PropertyGroup>

(godot-cli install-plugin of this release or later writes the Code-Exec / Roslyn PackageReferences with a Condition that honours GodotMcpCodeExecInGame; an older one writes them editor-only, and the opted-in export then fails to compile until you re-run a current install-plugin. RQL is never shipped.) Then register the tool:

_mcp = GodotMcpRuntime.Initialize(builder =>
{
    builder.WithConfig(cfg => { /* loopback host + token */ });
    builder.WithScriptExecute();
}).Build();

Without the opt-in, WithScriptExecute() logs a warning and registers nothing, so the same code builds either way. A game started from the editor always has it (and there a WithToolsFromAssembly scan of the game assembly also brings the addon’s editor tools, see docs/runtime-security.md).

⚠️ Security — arbitrary code execution. Anyone who can call tools on this connection can run any code in the game process. Use it in debug/dev builds only, on a loopback host with a token, and never ship it enabled in a public release build. Desktop CoreCLR builds only: NativeAOT and iOS cannot run code emitted at run time; mobile is untested. See docs/runtime-security.md.

Sample: a live game-state tool

A runtime tool is written exactly like an editor tool — a partial class decorated [AiToolType], each method decorated [AiTool("tool-name", …)] with a [Description] on the method and each parameter. Any Godot API call (Node, SceneTree, …) must run on the engine main thread — marshal it through MainThread.Instance.Run(...) (ReflectorNet’s MainThread, backed by the dispatcher Initialize() bootstrapped for you).

This Godot analog of Unity-MCP’s “Chess bot” sample exposes the live running SceneTree to the LLM — a pure-managed game-ping round-trip plus a game-scene-tree-summary that reads real Node state:

using System.ComponentModel;
using com.IvanMurzak.McpPlugin;              // [AiToolType], [AiTool]
using com.IvanMurzak.McpPlugin.Common;       // ToolTarget
using com.IvanMurzak.ReflectorNet.Utils;     // MainThread
using Godot;

// Target = ToolTarget.Runtime: a game-only tool. A game run from the editor compiles the same assembly, but only the
// game's connection registers it; while the editor is connected too, the server sends its calls to the game.
[AiToolType(Target = ToolTarget.Runtime)]
public partial class GameMcpTools
{
    [AiTool("game-ping", Title = "Game Ping", ReadOnlyHint = true, IdempotentHint = true)]
    [Description("Runtime readiness probe. Echoes 'message' back, or returns 'pong-from-game' when omitted.")]
    public string GamePing(
        [Description("Optional message to echo back. When null/empty, returns 'pong-from-game'.")]
        string? message = null)
    {
        return string.IsNullOrEmpty(message) ? "pong-from-game" : message;
    }

    [AiTool("game-scene-tree-summary", Title = "Game Scene-Tree Summary", ReadOnlyHint = true)]
    [Description("Summary of the LIVE running game's SceneTree (current scene + root child node names).")]
    public SceneTreeSummary GameSceneTreeSummary()
    {
        // Touch the live SceneTree on the engine main thread — MainThread.Instance was installed by
        // GodotMcpRuntime.Initialize(...). Touching Node APIs off the main thread would fault.
        return MainThread.Instance.Run(() =>
        {
            var summary = new SceneTreeSummary();
            if (Engine.GetMainLoop() is not SceneTree tree || tree.Root == null)
            {
                summary.CurrentSceneName = "<no-scene-tree>";
                return summary;
            }

            summary.CurrentSceneName = tree.CurrentScene?.Name ?? "<none>";
            summary.RootChildCount   = tree.Root.GetChildCount();
            foreach (var child in tree.Root.GetChildren())
                summary.RootChildNames.Add(child.Name);
            return summary;
        });
    }
}

// Structured result (ReflectorNet-serialized — never ad-hoc string formatting for parseable output).
public sealed class SceneTreeSummary
{
    public string CurrentSceneName { get; set; } = string.Empty;
    public int RootChildCount { get; set; }
    public System.Collections.Generic.List<string> RootChildNames { get; set; } = new();
}

Register it from the Initialize(...) block above (WithToolsFromAssembly(Assembly.GetExecutingAssembly()) picks it up automatically), connect, and the LLM can now call game-ping / game-scene-tree-summary against your live game. Real example outsourcing bot logic: a chess-do-turn tool that calls into your game controller on the main thread, plus a chess-get-board tool returning a structured board model.

Same [AiToolType]/[AiTool]/MainThread.Instance.Run(...) contract as the editor Customize Tools section — the only differences are that in a game build you register the tools and you call Connect(), and that game tools are marked [AiToolType(Target = ToolTarget.Runtime)] (or per tool [AiTool("x", Target = ToolTarget.Runtime)]) so the editor does not register them and the agent reaches the game even while the editor is connected. ToolTarget.Editor marks an editor-only tool; the default, Both, registers it everywhere (the editor answers it while connected).

Sample: a prompt and a resource

Tools are not the only thing you can expose — MCP also has prompts (reusable instruction templates an LLM can request by name) and resources (addressable, read-only content the LLM can fetch by URI). They register exactly like tools: a partial class decorated [AiPromptType] / [AiResourceType], with each member decorated [AiPrompt(...)] / [AiResource(...)] and a [Description]. Register your prompt and resource classes the same way you register tools — WithPromptsFromAssembly(...) / WithResourcesFromAssembly(...) (or the by-type WithPrompts(...) / WithResources(...)) from the Initialize(...) block above. Each kind is independently optional — a game can expose prompts and/or resources with no tools at all.

using System.ComponentModel;
using com.IvanMurzak.McpPlugin;               // [AiPromptType], [AiPrompt], [AiResourceType], [AiResource]
using com.IvanMurzak.McpPlugin.Common.Model;  // Role, ResponseResourceContent
using com.IvanMurzak.ReflectorNet.Utils;      // MainThread
using Godot;

// A PROMPT — a named, reusable instruction the LLM can request. Returns the prompt text; Role marks who
// the message is from. Set Enabled = false to ship a prompt registered-but-off until you flip it on.
[AiPromptType]
public partial class GameMcpPrompts
{
    [AiPrompt(Name = "explain-game-state", Role = Role.User)]
    [Description("Ask the assistant to summarize the current game state for the player.")]
    public string ExplainGameState()
    {
        return "Read the live SceneTree via the game tools and explain the current game state in one paragraph.";
    }
}

// A RESOURCE — addressable read-only content fetched by URI. Route is the URI template; the method
// returns ResponseResourceContent[]. Any Godot API access marshals onto the main thread, exactly like a tool.
[AiResourceType]
public partial class GameMcpResources
{
    [AiResource(
        Name = "Live SceneTree node names",
        Route = "game://scene-tree/nodes",
        MimeType = "application/json",
        Description = "The root child node names of the live running game's SceneTree.")]
    public ResponseResourceContent[] SceneTreeNodes(string uri)
    {
        return MainThread.Instance.Run(() =>
        {
            var names = new System.Collections.Generic.List<string>();
            if (Engine.GetMainLoop() is SceneTree tree && tree.Root != null)
            {
                foreach (var child in tree.Root.GetChildren())
                    names.Add(child.Name);
            }

            var json = System.Text.Json.JsonSerializer.Serialize(names);
            return new[] { ResponseResourceContent.CreateText(uri, json, "application/json") };
        });
    }
}

Same independently-optiona

README 内容过长,已截取前 64 KB。完整内容请前往 GitHub 仓库查看。

评论

暂无评论