Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,4 @@ code/Properties/*
*idea

# Exported / standalone games
Exports/

# Exclude the Server project
!Server/modelcontextprotocol.csproj
Exports/
22 changes: 0 additions & 22 deletions Assets/Materials/library_material.vmat

This file was deleted.

4 changes: 4 additions & 0 deletions Code/Assembly.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global using Sandbox;
global using Editor;
global using System.Collections.Generic;
global using System.Linq;
4 changes: 4 additions & 0 deletions Editor/Assembly.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global using Sandbox;
global using Editor;
global using System.Collections.Generic;
global using System.Linq;
29 changes: 24 additions & 5 deletions Editor/Connection/MCPConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Editor;
using Sandbox;
using SandboxModelContextProtocol.Editor.Connection.Models;
using SandboxModelContextProtocol.Editor.Tools;
using SandboxModelContextProtocol.Editor.Tools.Models;
Expand Down Expand Up @@ -110,14 +108,35 @@ public static void Disconnect()

try
{
CallEditorToolRequest? request = JsonSerializer.Deserialize<CallEditorToolRequest>( message );
CallRequest? request = JsonSerializer.Deserialize<CallRequest>( message );
if ( request == null )
{
return;
}

CallEditorToolResponse? response = await McpToolExecutor.CallEditorTool( request );
await Send( JsonSerializer.Serialize( response ) );
if ( request.Type == "tool" )
{
CallToolRequest? toolRequest = JsonSerializer.Deserialize<CallToolRequest>( message );
if ( toolRequest == null )
{
return;
}

CallToolResponse? response = await McpToolExecutor.CallTool( toolRequest );
await Send( JsonSerializer.Serialize( response ) );
}

if ( request.Type == "tool" )
{
CallToolRequest? toolRequest = JsonSerializer.Deserialize<CallToolRequest>( message );
if ( toolRequest == null )
{
return;
}

CallToolResponse? response = await McpToolExecutor.CallTool( toolRequest );
await Send( JsonSerializer.Serialize( response ) );
}
}
catch ( Exception ex )
{
Expand Down
1 change: 0 additions & 1 deletion Editor/Connection/MCPConnectionStatus.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using SandboxModelContextProtocol.Editor.Connection.Models;

namespace SandboxModelContextProtocol.Editor.Connection;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace SandboxModelContextProtocol.Server.Services.Models;
namespace SandboxModelContextProtocol.Editor.Connection.Models;

public class CallEditorToolRequest
public class CallRequest
{
[JsonPropertyName( "id" )]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Id { get; init; } = Guid.NewGuid().ToString();

[JsonPropertyName( "type" )]
public virtual string? Type { get; init; }

[JsonPropertyName( "name" )]
public required string Name { get; init; }

[JsonPropertyName( "arguments" )]
public IReadOnlyDictionary<string, JsonElement>? Arguments { get; init; }
}
}
22 changes: 22 additions & 0 deletions Editor/Connection/Models/CallResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace SandboxModelContextProtocol.Editor.Connection.Models;

public class CallResponse
{
[JsonPropertyName( "id" )]
public required string Id { get; init; }

[JsonPropertyName( "type" )]
public virtual string? Type { get; init; }

[JsonPropertyName( "name" )]
public required string Name { get; init; }

[JsonPropertyName( "content" )]
public List<JsonElement> Content { get; init; } = [];

[JsonPropertyName( "isError" )]
public bool IsError { get; init; }
}
2 changes: 1 addition & 1 deletion Editor/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ public static void Trace( string message, params object[] args )
{
_logger.Trace( message );
}
}
}
61 changes: 61 additions & 0 deletions Editor/Resources/Attributes/McpResourceAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;

namespace SandboxModelContextProtocol.Editor.Resources.Attributes;

/// <summary>
/// Attribute that marks a method as an MCP resource.
/// The method name is automatically used as the resource name unless overridden.
/// </summary>
[AttributeUsage( AttributeTargets.Method )]
public class McpResourceAttribute : Attribute
{
/// <summary>
/// Gets the resource name. If not specified, the method name will be used.
/// </summary>
public string? ResourceName { get; }

/// <summary>
/// Gets the resource description.
/// </summary>
public string? Description { get; }

/// <summary>
/// Initializes a new instance of the McpResourceAttribute with automatic resource name from method name.
/// </summary>
public McpResourceAttribute()
{
ResourceName = null;
Description = null;
}

/// <summary>
/// Initializes a new instance of the McpResourceAttribute with a custom resource name.
/// </summary>
/// <param name="resourceName">The custom resource name to use instead of the method name</param>
public McpResourceAttribute( string resourceName )
{
ResourceName = resourceName;
Description = null;
}

/// <summary>
/// Initializes a new instance of the McpResourceAttribute with a custom resource name and description.
/// </summary>
/// <param name="resourceName">The custom resource name to use instead of the method name</param>
/// <param name="description">The description of the resource</param>
public McpResourceAttribute( string resourceName, string description )
{
ResourceName = resourceName;
Description = description;
}

/// <summary>
/// Gets the effective resource name, using the method name if no custom name was specified.
/// </summary>
/// <param name="methodName">The name of the method this attribute is applied to</param>
/// <returns>The resource name to use</returns>
public string GetResourceName( string methodName )
{
return ResourceName ?? methodName;
}
}
60 changes: 60 additions & 0 deletions Editor/Resources/Attributes/McpResourceTypeAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;

namespace SandboxModelContextProtocol.Editor.Resources.Attributes;

/// <summary>
/// Attribute that marks a class as an MCP resource type.
/// </summary>
[AttributeUsage( AttributeTargets.Class )]
public class McpResourceTypeAttribute : Attribute
{
/// <summary>
/// Gets the resource type name. If not specified, the class name will be used.
/// </summary>
public string? ResourceTypeName { get; }

/// <summary>
/// Gets the resource type description.
/// </summary>
public string? ResourceTypeDescription { get; }

/// <summary>
/// Initializes a new instance of the McpResourceTypeAttribute with automatic resource type name from class name.
/// </summary>
public McpResourceTypeAttribute()
{
ResourceTypeName = null;
ResourceTypeDescription = null;
}

/// <summary>
/// Initializes a new instance of the McpResourceTypeAttribute with a custom resource type name.
/// </summary>
/// <param name="resourceTypeName">The custom resource type name to use instead of the class name</param>
public McpResourceTypeAttribute( string resourceTypeName )
{
ResourceTypeName = resourceTypeName;
ResourceTypeDescription = null;
}

/// <summary>
/// Initializes a new instance of the McpResourceTypeAttribute with a custom resource type name and description.
/// </summary>
/// <param name="resourceTypeName">The custom resource type name to use instead of the class name</param>
/// <param name="resourceTypeDescription">The description of the resource type</param>
public McpResourceTypeAttribute( string resourceTypeName, string resourceTypeDescription )
{
ResourceTypeName = resourceTypeName;
ResourceTypeDescription = resourceTypeDescription;
}

/// <summary>
/// Gets the effective resource type name, using the class name if no custom name was specified.
/// </summary>
/// <param name="className">The name of the class this attribute is applied to</param>
/// <returns>The resource type name to use</returns>
public string GetResourceTypeName( string className )
{
return ResourceTypeName ?? className;
}
}
14 changes: 14 additions & 0 deletions Editor/Resources/GameObjectResource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Text.Json.Nodes;
using SandboxModelContextProtocol.Editor.Resources.Attributes;

namespace SandboxModelContextProtocol.Editor.Resources;

[McpResourceType()]
public class GameObjectResource
{
[McpResource()]
public static JsonObject GetGameObject( string id )
{
return new JsonObject();
}
}
Loading
Loading