사용자 지정 도구
C#로 나만의 Godot MCP 도구를 작성하고, 메인 스레드에서 Godot API를 호출하며, 실행 중인 Godot 게임에서 도구와 프롬프트, 리소스를 노출하세요.
프로젝트 안에서 순수 C#으로 Godot MCP에 자신만의 MCP 도구를 추가할 수 있습니다. 사용자 지정 도구는 AI 에이전트가 호출할 수 있는 메서드이며, 설명을 통해 모델이 그 도구가 무엇을 하는지 알 수 있습니다. 이 페이지에서는 에디터 도구, 메인 스레드 규칙, 그리고 에이전트가 실행 중인 게임과 대화할 수 있게 해주는 옵트인 런타임을 다룹니다.
에디터 도구 작성하기
도구 패밀리는 [AiToolType]이 붙은 partial class입니다. 각 도구는 [AiTool("tool-name")]이 붙은 메서드이며, 메서드와 모든 매개변수에 [Description]을 붙여 모델이 언제 어떻게 호출해야 하는지 알 수 있게 합니다.
using System.ComponentModel;
using com.IvanMurzak.McpPlugin; // [AiToolType], [AiTool]
using com.IvanMurzak.ReflectorNet.Utils; // MainThread
[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 here, on a background thread.
return MainThread.Instance.Run(() =>
{
// Touch EditorInterface, Node or Resource here, on the main thread.
return "[Success] Operation completed.";
});
}
}C# 프로젝트를 빌드하세요(에디터의 Build 버튼, godot-cli build, 또는 에이전트에게 script-build 실행 요청). Godot이 어셈블리를 다시 로드하고 애드온이 재연결되면, 새 도구가 에이전트의 도구 목록과 독의 Tools 창에 나타납니다.
도구를 안정적으로 유지하는 규칙
- Godot 객체는 메인 스레드에서만. 도구 메서드는 메인 스레드 밖에서 호출됩니다.
Node,Resource,SceneTree,EditorInterface에 대한 모든 호출은MainThread.Instance.Run(...)을 거쳐야 합니다. 백그라운드 스레드에서 이들에 접근하면 에디터가 충돌할 수 있습니다. - 포맷된 텍스트가 아니라 데이터를 반환하세요. 속성이 있는 클래스를 반환하거나(모델을 위해 직렬화됩니다), 부수 효과만 있는 도구라면
void를 반환하세요. 에이전트가 파싱해야 하는 값에는 직접 만든 문자열을 쓰지 마세요. - 선택적 매개변수를 표시하세요. 기본값이 있는 널 허용 타입을 사용하세요. 예를 들어
string? filter = null처럼 쓰면 모델이 해당 매개변수를 선택 사항으로 취급합니다. - 모든 것을 설명하세요. 모델이 읽는 것은 바로 이 설명입니다. 도구가 무엇을 하는지, 언제 사용해야 하는지, 각 매개변수가 무엇을 의미하는지 적으세요.
- 에디터 전용 코드는
#if TOOLS뒤에 두세요. 에디터 API를 사용하는 코드는 내보낸 게임에 컴파일되어서는 안 됩니다.
힌트와 대상
[AiTool]은 ReadOnlyHint = true, IdempotentHint = true 같은 선택적 힌트를 받으며, 이는 클라이언트에게 해당 도구가 아무것도 변경하지 않거나 안전하게 반복 호출할 수 있음을 알려줍니다. Target은 도구가 등록되는 위치를 결정합니다: ToolTarget.Editor(에디터 전용), ToolTarget.Runtime(게임 전용), 또는 기본값인 양쪽 모두입니다.
에이전트가 도구를 작성하게 하기
시스템 도구 godot-skill-create는 프로젝트에 새 C# 도구 파일을 작성하며, 해당 도구는 다음 빌드 후에 호출 가능해집니다. 새 도구를 작성하기 전에 RQL이 이미 그 작업을 처리하는지 확인하세요. 대부분의 에디터 데이터 접근(노드, 리소스, 파일, 프로젝트 설정)은 rql-query나 rql-mutate 한 번이면 됩니다. Tools를 참고하세요.
실행 중인 게임 속 도구
Godot MCP는 실행 중이거나 내보낸 게임 안에서도 동작할 수 있습니다(디버그 또는 릴리스). 이를 통해 에이전트는 실시간 게임 상태를 읽고 제어할 수 있습니다. 예를 들어 봇의 수가 LLM에서 나오는 체스 게임이 그렇습니다. 두 가지는 의도된 설계입니다:
- 스스로 연결하지 않습니다. 연결 여부와 시점은
Connect()호출로 여러분의 코드가 결정합니다. - 기본적으로 아무것도 노출하지 않습니다. 모든 도구, 프롬프트, 리소스는 직접 등록해야 합니다. 애드온의 에디터 도구는 게임 빌드에 컴파일되지 않습니다.
SceneTree가 존재한 뒤에 시작하세요. 예를 들어 오토로드의 _Ready()에서 시작할 수 있습니다:
using System.Reflection;
using com.IvanMurzak.Godot.MCP.Connection;
using com.IvanMurzak.Godot.MCP.Runtime;
using McpServerConsts = com.IvanMurzak.McpPlugin.Common.Consts.MCP.Server;
using Godot;
public partial class GameMcp : Node
{
private GodotMcpRuntimeHandle? _mcp;
public override async void _Ready()
{
_mcp = GodotMcpRuntime.Initialize(builder =>
{
builder.WithConfig(config =>
{
config.ConnectionMode = GodotMcpConnectionMode.Custom;
config.Host = "http://localhost:8080";
config.AuthOption = McpServerConsts.AuthOption.token;
config.Token = "your-secret-token";
});
builder.WithToolsFromAssembly(Assembly.GetExecutingAssembly());
}).Build();
await _mcp.Connect();
}
public override async void _ExitTree()
{
if (_mcp is not null)
await _mcp.Disconnect();
}
}게임 전용 도구 클래스에는 [AiToolType(Target = ToolTarget.Runtime)]을 붙이세요(com.IvanMurzak.McpPlugin.Common에서 제공). 그러면 에디터가 해당 도구를 등록하지 않으며, 에디터가 연결되어 있는 동안에도 에이전트가 게임에 접근할 수 있습니다.
빌더 옵션
| 호출 | 동작 내용 |
|---|---|
WithConfig(...) | 코드에서 Host, Token, ConnectionMode, AuthOption을 설정합니다. |
WithToolsFromAssembly(...) / WithTools(...) | 어셈블리에서 [AiToolType] 클래스를 등록하거나 특정 타입을 등록합니다. |
WithPromptsFromAssembly(...) / WithPrompts(...) | [AiPromptType] 프롬프트 클래스를 등록합니다. |
WithResourcesFromAssembly(...) / WithResources(...) | [AiResourceType] 리소스 클래스를 등록합니다. |
WithRuntimeErrorCapture() | 게임 내 오류를 캡처하고 runtime-errors-get / runtime-errors-clear를 등록합니다. 기본값은 꺼짐입니다. |
WithScriptExecute() | 게임에 script-execute를 등록합니다. 기본값은 꺼짐이며 .csproj 옵트인이 필요합니다. |
ConnectWhenRunFromEditor() | 에디터에서 Play로 게임을 시작한 경우에도 연결합니다. 기본값은 꺼짐입니다. |
WithoutMainThreadDispatcher() | 자동 메인 스레드 디스패처를 건너뜁니다(직접 설치한 경우에만). |
Host와 토큰은 GODOT_MCP_* 환경 변수나 .env 파일에서도 가져올 수 있으며, 이 값이 코드보다 우선합니다. 게임은 에디터에 저장된 설정을 절대 읽지 않습니다.
프롬프트와 리소스
도구 외에도, 게임은 MCP 프롬프트(이름이 붙은 지시 템플릿, [AiPrompt] 메서드가 있는 [AiPromptType])와 리소스(URI로 가져오는 읽기 전용 콘텐츠, [AiResource] 메서드가 있는 [AiResourceType])를 노출할 수 있습니다. 각 종류는 선택 사항이며 도구와 동일한 방식으로 등록됩니다.
게임 내부에서 C# 실행하기
에이전트가 게임에서 C#을 실행하도록 하려면 게임의 .csproj에서 옵트인하고 WithScriptExecute()를 호출하세요:
<PropertyGroup>
<GodotMcpCodeExecInGame>true</GodotMcpCodeExecInGame>
<DefineConstants>$(DefineConstants);GODOT_MCP_CODE_EXEC_IN_GAME</DefineConstants>
</PropertyGroup>이 기능은 데스크톱 CoreCLR 빌드에서만 동작하며, NativeAOT나 iOS에서는 동작하지 않습니다.
게임 빌드를 위한 보안 체크리스트
localhost또는127.0.0.1에서AuthOption.token과 실제 토큰을 사용하는 Custom 모드를 선호하세요.- 필요한 도구만 등록하세요. 공격 표면은 정확히 여러분이 등록한 도구입니다.
- 그렇게 하도록 설계하고 보안을 갖추지 않은 한, 릴리스 빌드에서 공용 네트워크 인터페이스에 연결을 노출하지 마세요.
전체 도구 목록은 Tools를, 패키징된 도구 세트는 Extensions를 참고하세요.