Editor/Commands/ResourceCommands.cs
using System.Threading.Tasks;
using System.Text.Json;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;
using Sandbox;
using Editor;
using FileSystem = Editor.FileSystem;

namespace Braxnet.Commands;

[MCPCommand( "resources/list" )]
public class ListResourcesCommand : IMCPCommand
{
	public string Name => "resources/list";

	public async Task<object> ExecuteAsync( JsonRpcRequest request, string sessionId, string protocolVersion )
	{
		var resources = new List<Resource>();

		try
		{
			var projectDir = Path.Combine( FileSystem.Mounted.GetFullPath( "." ), ".." );
			projectDir = Path.GetFullPath( projectDir );

			var files = Directory.GetFiles( projectDir, "*.*", SearchOption.AllDirectories )
				.Where( f => !f.Contains( ".git" ) && !f.Contains( ".vscode" ) && !f.Contains( ".idea" ) )
				.Take( 100 );

			foreach ( var file in files )
			{
				var relativePath = Path.GetRelativePath( projectDir, file );
				var fileInfo = new FileInfo( file );

				resources.Add( new Resource
				{
					Uri = $"file://{file.Replace( '\\', '/' )}",
					Name = relativePath.Replace( '\\', '/' ),
					Title = Path.GetFileName( file ),
					Description = $"Project file: {relativePath}",
					MimeType = MCPServer.GetMimeType( file ),
					Size = fileInfo.Length
				} );
			}
		}
		catch ( Exception ex )
		{
			Log.Error( $"Error listing resources: {ex.Message}" );
		}

		return new ListResourcesResult { Resources = resources };
	}
}

[MCPCommand( "resources/read" )]
public class ReadResourceCommand : IMCPCommand
{
	public string Name => "resources/read";

	public async Task<object> ExecuteAsync( JsonRpcRequest request, string sessionId, string protocolVersion )
	{
		var contents = new List<ResourceContents>();

		if ( request.Params.HasValue )
		{
			var paramsObj = JsonSerializer.Deserialize<Dictionary<string, object>>(
				request.Params.Value.GetRawText(), MCPServer.JsonOptions );

			if ( paramsObj?.ContainsKey( "uri" ) == true )
			{
				var uriStr = paramsObj["uri"]?.ToString();
				if ( !string.IsNullOrEmpty( uriStr ) && uriStr.StartsWith( "file://" ) )
				{
					var filePath = uriStr.Substring( 7 );
					try
					{
						if ( File.Exists( filePath ) )
						{
							var text = await File.ReadAllTextAsync( filePath );
							contents.Add( new ResourceContents
							{
								Uri = uriStr, Text = text, MimeType = MCPServer.GetMimeType( filePath )
							} );
						}
					}
					catch ( Exception ex )
					{
						Log.Error( $"Error reading file {filePath}: {ex.Message}" );
						throw new Exception( $"Could not read file: {ex.Message}" );
					}
				}
			}
		}

		return new ReadResourceResult { Contents = contents };
	}
}