Clean up and add more comments (#2)

This commit is contained in:
Peder Holdgaard Pedersen 2025-01-02 19:02:24 +01:00 • committed by GitHub
commit 9a244f5770
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 349 additions and 653 deletions

View file

@ -5,6 +5,8 @@ using McpDotNet.Protocol.Messages;
/// <summary>
/// Represents an instance of the MCP client connecting to a specific server.
/// Use PingAsync, ListToolsAsync and CallToolAsync instead of SendRequestAsync for common operations.
/// SendRequestAsync is provided for custom request and those not yet covered explicitly by the client.
/// </summary>
public interface IMcpClient : IAsyncDisposable
{
@ -14,44 +16,58 @@ public interface IMcpClient : IAsyncDisposable
bool IsInitialized { get; }
/// <summary>
/// Gets the capabilities that the server supports.
/// Gets the capabilities supported by the server.
/// </summary>
ServerCapabilities? ServerCapabilities { get; }
/// <summary>
/// Gets the version information of the server.
/// Gets the version and implementation information of the server.
/// </summary>
Implementation? ServerInfo { get; }
/// <summary>
/// Connects to the server.
/// Establishes a connection to the server.
/// </summary>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task ConnectAsync(CancellationToken cancellationToken = default);
/// <summary>
/// A simple ping to the server to check if it is alive. Task completes when the ping is successful.
/// Sends a ping request to verify server connectivity.
/// </summary>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task that completes when the ping is successful.</returns>
Task PingAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Queries the server for a list of tools that are available (if any)
/// Retrieves a list of available tools from the server.
/// </summary>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task containing the server's response with tool information.</returns>
Task<ListToolsResponse> ListToolsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Calls a tool on the server.
/// Invokes a tool on the server with optional arguments.
/// </summary>
/// <param name="toolName">The name of the tool as given when listing tool definitions.</param>
/// <param name="arguments">Arguments for the tool (if any)</param>
/// <param name="toolName">The name of the tool to call.</param>
/// <param name="arguments">Optional arguments for the tool.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task containing the tool's response.</returns>
Task<CallToolResponse> CallToolAsync(string toolName, Dictionary<string, object>? arguments = null, CancellationToken cancellationToken = default);
/// <summary>
/// A generic method to send a request to the server and get a response.
/// Sends a generic JSON-RPC request to the server.
/// </summary>
/// <typeparam name="T">The expected response type.</typeparam>
/// <param name="request">The JSON-RPC request to send.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task containing the server's response.</returns>
Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class;
/// <summary>
/// Registers a handler for a specific notification method.
/// Registers a handler for server notifications of a specific method.
/// </summary>
/// <param name="method">The notification method to handle.</param>
/// <param name="handler">The async handler function to process notifications.</param>
void OnNotification(string method, Func<JsonRpcNotification, Task> handler);
}
}

View file

@ -1,5 +1,4 @@
// Client/McpClientOptions.cs
namespace McpDotNet.Client;
namespace McpDotNet.Client;
using McpDotNet.Protocol.Types;
using McpDotNet.Protocol.Transport;
@ -9,10 +8,8 @@ using System.Diagnostics;
using System.Text.Json;
using McpDotNet.Utils.Json;
/// <summary>
/// Main MCP client implementation that handles protocol lifecycle and message routing.
/// </summary>
public class McpClient : IMcpClient
/// </inheritdoc>
internal class McpClient : IMcpClient
{
private readonly IMcpTransport _transport;
private readonly McpClientOptions _options;
@ -24,21 +21,20 @@ public class McpClient : IMcpClient
private CancellationTokenSource? _cts;
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions().ConfigureForMcp();
/// <summary>
/// Gets whether the client is connected and initialized.
/// </summary>
/// </inheritdoc>
public bool IsInitialized => _isInitialized;
/// <summary>
/// Gets the server's capabilities after initialization.
/// </summary>
/// </inheritdoc>
public ServerCapabilities? ServerCapabilities { get; private set; }
/// <summary>
/// Gets information about the server implementation after initialization.
/// </summary>
/// </inheritdoc>
public Implementation? ServerInfo { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="McpClient"/> class.
/// </summary>
/// <param name="transport">An MCP transport implementation.</param>
/// <param name="options">Options for the client, defining protocol version and capabilities.</param>
public McpClient(IMcpTransport transport, McpClientOptions options)
{
_transport = transport;
@ -48,9 +44,7 @@ public class McpClient : IMcpClient
_nextRequestId = 1;
}
/// <summary>
/// Connects to the server and performs the initialization sequence.
/// </summary>
/// </inheritdoc>
public async Task ConnectAsync(CancellationToken cancellationToken = default)
{
if (_isInitialized)
@ -128,6 +122,7 @@ public class McpClient : IMcpClient
}
}
/// </inheritdoc>
public async Task PingAsync(CancellationToken cancellationToken)
{
await SendRequestAsync<dynamic>(
@ -139,6 +134,7 @@ public class McpClient : IMcpClient
).ConfigureAwait(false);
}
/// </inheritdoc>
public async Task<ListToolsResponse> ListToolsAsync(CancellationToken cancellationToken)
{
return await SendRequestAsync<ListToolsResponse>(
@ -151,6 +147,7 @@ public class McpClient : IMcpClient
).ConfigureAwait(false);
}
/// </inheritdoc>
public async Task<CallToolResponse> CallToolAsync(string toolName, Dictionary<string, object>? arguments = null,
CancellationToken cancellationToken = default)
{
@ -218,6 +215,7 @@ public class McpClient : IMcpClient
}
}
/// </inheritdoc>
public async Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class
{
if (!_transport.IsConnected)
@ -275,9 +273,7 @@ public class McpClient : IMcpClient
await _transport.SendMessageAsync(notification, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Registers a handler for notifications of a specific method.
/// </summary>
/// </inheritdoc>
public void OnNotification(string method, Func<JsonRpcNotification,Task> handler)
{
var handlers = _notificationHandlers.GetOrAdd(method, _ => new());

View file

@ -1,5 +1,4 @@
// Client/McpClientOptions.cs
namespace McpDotNet.Client;
namespace McpDotNet.Client;
/// <summary>
/// Represents errors that occur in the MCP client.
@ -11,15 +10,29 @@ public class McpClientException : Exception
/// </summary>
public int? ErrorCode { get; }
/// <summary>
/// Initializes a new instance of the <see cref="McpClientException"/> class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public McpClientException(string message) : base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="McpClientException"/> class with a specified error message and error code.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="errorCode">The error code associated with the JSON-RPC error response.</param>
public McpClientException(string message, int errorCode) : base(message)
{
ErrorCode = errorCode;
}
/// <summary>
/// Initializes a new instance of the <see cref="McpClientException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
public McpClientException(string message, Exception innerException) : base(message, innerException)
{
}

View file

@ -1,11 +1,13 @@
// Client/McpClientFactory.cs
namespace McpDotNet.Client;
namespace McpDotNet.Client;
using McpDotNet.Configuration;
using McpDotNet.Protocol.Transport;
/// <summary>
/// Factory for creating MCP clients based on configuration.
/// Factory for creating MCP clients based on configuration. It caches clients for reuse, so it is safe to call GetClientAsync multiple times.
/// Call GetClientAsync to get a client for a specific server (by ID), which will create a new client and connect if it doesn't already exist.
/// All server configurations must be passed in the constructor.
/// Capabilities (as defined in client options) are shared across all clients, as the client host can always decide not to use certain capabilities.
/// </summary>
public class McpClientFactory
{
@ -15,6 +17,15 @@ public class McpClientFactory
private readonly Func<McpServerConfig, IMcpTransport> _transportFactoryMethod;
private readonly Func<IMcpTransport, McpClientOptions, IMcpClient> _clientFactoryMethod;
/// <summary>
/// Initializes a new instance of the <see cref="McpClientFactory"/> class.
/// It is not necessary to pass factory methods for creating transports and clients, as default implementations are provided.
/// Custom factory methods can be provided for mocking or to use custom transport or client implementations.
/// </summary>
/// <param name="serverConfigs">Configuration objects for each server the factory should support.</param>
/// <param name="clientOptions">A configuration object which specifies client capabilities and protocol version.</param>
/// <param name="transportFactoryMethod">An optional factory method which returns transport implementations based on a server configuration.</param>
/// <param name="clientFactoryMethod">An optional factory method which creates a client based on client options and transport implementation. </param>
public McpClientFactory(
IEnumerable<McpServerConfig> serverConfigs,
McpClientOptions clientOptions,
@ -28,8 +39,12 @@ public class McpClientFactory
}
/// <summary>
/// Gets or creates a client for the specified server.
/// Gets or creates a client for the specified server. The first time a server is requested, a new client is created and connected.
/// Note that this will often spawn the server process during connection, so in some cases you want to call this method only when needed.
/// In other cases, you may want to call it ahead of time to ensure the server is ready when needed, as it may take some time to start up.
/// </summary>
/// <param name="serverId">The ID of the server to connect to. It must have been passed in the serverConfigs when constructing the factory.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
public async Task<IMcpClient> GetClientAsync(string serverId, CancellationToken cancellationToken = default)
{
if (!_serverConfigs.TryGetValue(serverId, out var config))

View file

@ -1,10 +1,11 @@
// Client/McpClientOptions.cs
using McpDotNet.Protocol.Types;
namespace McpDotNet.Client;
using global::McpDotNet.Protocol.Types;
/// <summary>
/// Configuration options for the MCP client.
/// Configuration options for the MCP client. This is passed to servers during the initialization sequence, letting them know about the client's capabilities and
/// protocol version.
/// <see href="https://spec.modelcontextprotocol.io/specification/basic/lifecycle/">See the protocol specification for details on capability negotiation</see>
/// </summary>
public record McpClientOptions
{

View file

@ -1,5 +1,4 @@
// Configuration/McpServerConfig.cs
namespace McpDotNet.Configuration;
namespace McpDotNet.Configuration;
/// <summary>
/// Configuration for an MCP server connection.

View file

@ -1,188 +0,0 @@
// Features/LlmIntegration/DefaultMcpToolProvider.cs
namespace McpDotNet.Features.LlmIntegration;
using System.Text.Json;
using mcpdotnet.Features.Tools;
using McpDotNet.Client;
using McpDotNet.Features.Tools;
/// <summary>
/// Default implementation of IMcpToolProvider that handles conversion between MCP and LLM-friendly formats.
/// </summary>
public class DefaultMcpToolProvider : IMcpToolProvider
{
private readonly McpClient _client;
private readonly JsonSerializerOptions _jsonOptions;
public DefaultMcpToolProvider(McpClient client, JsonSerializerOptions? jsonOptions = null)
{
_client = client;
_jsonOptions = jsonOptions ?? new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
}
/// <inheritdoc/>
public async Task<List<ToolDefinition>> GetToolsAsync(CancellationToken cancellationToken = default)
{
return await _client.ListToolDefsAsync(cancellationToken);
}
/// <inheritdoc/>
public async Task<ToolResult> ExecuteToolCallAsync(
string toolName,
Dictionary<string, object> arguments,
CancellationToken cancellationToken = default)
{
try
{
// Execute tool call
var result = await _client.CallToolAsync(toolName, arguments, cancellationToken);
if (result != null)
{
return new ToolResult()
{
Succeeded = !result.IsError,
Content = result.Content.Select(c => new ToolContent()
{
Type = c.Type,
Value = (c.Data ?? c.Text) ?? "",
MimeType = c.MimeType
}).ToList()
};
}
else
{
return new ToolResult
{
Succeeded = false,
Content = [new ToolContent
{
Type = "error",
Value = "Tool execution failed with no error message"
}],
};
}
}
catch (Exception ex)
{
return new ToolResult
{
Succeeded = false,
Content = [new ToolContent
{
Type = "error",
Value = ex.Message
}],
};
}
}
//private static (Dictionary<string, ToolArgument> Arguments, List<string> Required) ParseInputSchema(ToolInputSchema schema)
//{
// var arguments = new Dictionary<string, ToolArgument>();
// var required = new List<string>();
// if (schema.Properties == null)
// {
// return (arguments, required);
// }
// foreach (var (name, propObj) in schema.Properties)
// {
// // Convert property to JsonElement for easier parsing
// var prop = (propObj as JsonElement?) ?? JsonSerializer.SerializeToElement(propObj);
// if (prop.TryGetProperty("type", out var typeElement))
// {
// var type = typeElement.GetString() ?? "unknown";
// var description = prop.TryGetProperty("description", out var descElement)
// ? descElement.GetString()
// : string.Empty;
// var isRequired = prop.TryGetProperty("required", out var reqElement) && reqElement.GetBoolean();
// if (isRequired)
// {
// required.Add(name);
// }
// string[]? enumValues = null;
// if (type == "string" && prop.TryGetProperty("enum", out var enumElement))
// {
// enumValues = enumElement.EnumerateArray()
// .Select(e => e.GetString())
// .Where(s => s != null)
// .Cast<string>()
// .ToArray();
// }
// arguments[name] = new ToolArgument
// {
// Name = name,
// Type = type,
// Description = description ?? string.Empty,
// Required = isRequired,
// EnumValues = enumValues
// };
// }
// }
// // Also check for required array at schema root
// if (schema.Properties.TryGetValue("required", out var rootRequired))
// {
// var requiredArray = rootRequired as JsonElement?;
// if (requiredArray?.ValueKind == JsonValueKind.Array)
// {
// foreach (var item in requiredArray.Value.EnumerateArray())
// {
// var name = item.GetString();
// if (name != null && !required.Contains(name))
// {
// required.Add(name);
// // Update the argument's required flag if it exists
// if (arguments.TryGetValue(name, out var arg))
// {
// arguments[name] = arg with { Required = true };
// }
// }
// }
// }
// }
// return (arguments, required);
//}
//private static ToolResultContent ConvertContent(IContent content)
//{
// return content switch
// {
// TextContent text => new ToolResultContent
// {
// Type = "text",
// Value = text.Text,
// },
// ImageContent image => new ToolResultContent
// {
// Type = "image",
// Value = image.Data,
// MimeType = image.MimeType
// },
// _ => new ToolResultContent
// {
// Type = "unknown",
// Value = content.ToString() ?? string.Empty
// }
// };
//}
//private static string ExtractErrorMessage(IReadOnlyList<IContent> content)
//{
// // Try to extract error message from content, defaulting to first text content if available
// var textContent = content.OfType<TextContent>().FirstOrDefault();
// return textContent?.Text ?? "Tool execution failed with no error message";
//}
}

View file

@ -1,23 +0,0 @@
// Features/LlmIntegration/IMcpToolProvider.cs
using mcpdotnet.Features.Tools;
namespace McpDotNet.Features.LlmIntegration;
/// <summary>
/// Provides MCP tool information and execution capabilities to an LLM.
/// </summary>
public interface IMcpToolProvider
{
/// <summary>
/// Gets the available tools and their descriptions.
/// </summary>
Task<List<ToolDefinition>> GetToolsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Executes a tool call.
/// </summary>
Task<ToolResult> ExecuteToolCallAsync(
string toolName,
Dictionary<string, object> arguments,
CancellationToken cancellationToken = default);
}

View file

@ -1,115 +0,0 @@
using System.Text.Json;
using mcpdotnet.Features.Tools;
using McpDotNet.Protocol.Types;
namespace McpDotNet.Features.Tools;
internal static class ToolMapper
{
public static ToolDefinition ToToolDefinition(Tool protocolTool)
{
ArgumentNullException.ThrowIfNull(protocolTool);
ArgumentNullException.ThrowIfNull(protocolTool.InputSchema);
var parameters = new Dictionary<string, ToolParameter>();
if (protocolTool.InputSchema.Properties != null)
{
foreach (var property in protocolTool.InputSchema.Properties)
{
// Convert the dynamic property value to a JsonElement to access its properties
var propertySchema = property.Value;
parameters[property.Key] = new ToolParameter
{
Name = property.Key,
Type = propertySchema.Type,
Description = propertySchema.Description,
Required = IsPropertyRequired(protocolTool.InputSchema, property.Key),
AllowedValues = GetEnumValues(propertySchema)
};
}
}
return new ToolDefinition
{
Name = protocolTool.Name,
Description = protocolTool.Description ?? string.Empty,
Parameters = parameters
};
}
public static ToolResult ToToolResult(CallToolResponse protocolResult)
{
ArgumentNullException.ThrowIfNull(protocolResult);
return new ToolResult
{
Succeeded = protocolResult.IsError,
Content = protocolResult.Content?.Select(ToToolContent).ToList(),
ErrorMessage = protocolResult.IsError == true ?
GetErrorMessage(protocolResult.Content) : null
};
}
private static mcpdotnet.Features.Tools.ToolContent ToToolContent(Protocol.Types.ToolContent c)
{
return new mcpdotnet.Features.Tools.ToolContent()
{
Type = c.Type,
Value = (c.Data ?? c.Text) ?? "",
MimeType = c.MimeType
};
}
private static string GetSchemaType(JsonElement schema)
{
if (!schema.TryGetProperty("type", out var typeElement))
{
return "object";
}
return typeElement.GetString() ?? "object";
}
private static string GetSchemaDescription(JsonElement schema)
{
if (!schema.TryGetProperty("description", out var descElement))
{
return string.Empty;
}
return descElement.GetString() ?? string.Empty;
}
private static bool IsPropertyRequired(JsonSchema? schema, string propertyName)
{
if (schema?.Required != null && schema.Required.Contains(propertyName))
{
return true;
}
return false;
}
private static string[]? GetEnumValues(JsonSchemaProperty? schema)
{
// TODO
return null;
}
private static string GetErrorMessage(IReadOnlyList<Protocol.Types.ToolContent>? contents)
{
if (contents == null || contents.Count == 0)
{
return "Unknown error";
}
// Concatenate all text content as the error message
var errorMessages = contents
.Where(c => !string.IsNullOrEmpty(c.Text))
.Select(c => c.Text);
return string.Join(" ", errorMessages);
}
}

View file

@ -1,61 +0,0 @@
using mcpdotnet.Features.Tools;
using McpDotNet.Client;
using McpDotNet.Protocol.Messages;
using McpDotNet.Protocol.Types;
namespace McpDotNet.Features.Tools;
/// <summary>
/// Extension methods for working with MCP tools.
/// </summary>
public static class ToolsExtensions
{
/// <summary>
/// Lists all available tools from the server.
/// </summary>
public static async Task<List<ToolDefinition>> ListToolDefsAsync(
this McpClient client,
CancellationToken cancellationToken = default)
{
if (client.ServerCapabilities?.Tools == null)
{
throw new McpClientException("Server does not support tools");
}
var response = await client.ListToolsAsync(cancellationToken);
return response.Tools
.Select(ToolMapper.ToToolDefinition)
.ToList();
}
/// <summary>
/// Calls a tool with the specified arguments.
/// </summary>
public static async Task<ToolResult> CallToolAsync(
this McpClient client,
string toolName,
object? arguments = null,
CancellationToken cancellationToken = default)
{
if (client.ServerCapabilities?.Tools == null)
{
throw new McpClientException("Server does not support tools");
}
var response = await client.SendRequestAsync<CallToolResponse>(
new JsonRpcRequest
{
Method = "tools/call",
Params = new
{
name = toolName,
arguments = arguments
}
},
cancellationToken
);
return ToolMapper.ToToolResult(response);
}
}

View file

@ -1,74 +0,0 @@
// Features/Tools/ToolTypes.cs
namespace mcpdotnet.Features.Tools;
/// <summary>
/// Represents a tool available from an MCP server.
/// </summary>
public record ToolDefinition
{
public required string Name { get; init; }
public required string Description { get; init; }
public required Dictionary<string, ToolParameter> Parameters { get; init; }
}
/// <summary>
/// Represents a tool parameter.
/// </summary>
public record ToolParameter
{
public required string Name { get; init; }
public required string Type { get; init; }
public required string Description { get; init; }
public bool Required { get; init; }
public string[]? AllowedValues { get; init; }
}
/// <summary>
/// Result of a tool execution, from server to client
public record McpToolCallResponse
{
// TODO
}
/// <summary>
/// Result of a tool execution, from client to host.
/// </summary>
public record ToolResult
{
public required bool Succeeded { get; init; }
public List<ToolContent>? Content { get; init; }
public string? ErrorMessage { get; init; }
}
/// <summary>
/// Content returned by a tool execution.
/// </summary>
public record ToolContent
{
/// <summary>
/// The type of content.
/// </summary>
public required string Type { get; init; }
/// <summary>
/// The content value.
/// </summary>
public required object Value { get; init; }
/// <summary>
/// Optional MIME type for binary content.
/// </summary>
public string? MimeType { get; init; }
}
/// <summary>
/// A list of tools available from an MCP server.
/// </summary>
public record ToolDefinitionList
{
/// <summary>
/// The list of tools.
/// </summary>
public required List<ToolDefinition> Tools { get; init; }
}

View file

@ -0,0 +1,21 @@
namespace McpDotNet.Protocol.Types;
using System.Text.Json.Serialization;
/// <summary>
/// Represents binary resource contents.
/// </summary>
public record BlobResourceContents : IResourceContents
{
[JsonPropertyName("uri")]
public required string Uri { get; init; }
[JsonPropertyName("mimeType")]
public string? MimeType { get; init; }
/// <summary>
/// The base64-encoded binary content of the resource.
/// </summary>
[JsonPropertyName("blob")]
public required string Blob { get; init; }
}

View file

@ -0,0 +1,18 @@
namespace McpDotNet.Protocol.Types;
/// <summary>
/// A response to a request to call a tool on the server.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/schema.json">See the schema for details</see>
/// </summary>
public class CallToolResponse
{
/// <summary>
/// The server's response to a tools/call request from the client.
/// </summary>
public List<ToolContent> Content { get; set; } = new();
/// <summary>
/// Whether the tool call was unsuccessful. If true, the call was unsuccessful.
/// </summary>
public bool IsError { get; set; }
}

View file

@ -26,42 +26,6 @@ public record ClientCapabilities
public SamplingCapability? Sampling { get; init; }
}
/// <summary>
/// Represents the capabilities that a server may support.
/// </summary>
public record ServerCapabilities
{
/// <summary>
/// Experimental, non-standard capabilities that the server supports.
/// </summary>
[JsonPropertyName("experimental")]
public Dictionary<string, object>? Experimental { get; init; }
/// <summary>
/// Present if the server supports sending log messages to the client.
/// </summary>
[JsonPropertyName("logging")]
public LoggingCapability? Logging { get; init; }
/// <summary>
/// Present if the server offers any prompt templates.
/// </summary>
[JsonPropertyName("prompts")]
public PromptsCapability? Prompts { get; init; }
/// <summary>
/// Present if the server offers any resources to read.
/// </summary>
[JsonPropertyName("resources")]
public ResourcesCapability? Resources { get; init; }
/// <summary>
/// Present if the server offers any tools to call.
/// </summary>
[JsonPropertyName("tools")]
public ToolsCapability? Tools { get; init; }
}
/// <summary>
/// Represents the roots capability configuration.
/// </summary>

View file

@ -0,0 +1,10 @@
namespace McpDotNet.Protocol.Types;
/// <summary>
/// Interface for resource contents.
/// </summary>
public interface IResourceContents
{
string Uri { get; }
string? MimeType { get; }
}

View file

@ -1,5 +1,4 @@
// Protocol/Types/Implementation.cs
namespace McpDotNet.Protocol.Types;
namespace McpDotNet.Protocol.Types;
using System.Text.Json.Serialization;

View file

@ -0,0 +1,23 @@
namespace McpDotNet.Protocol.Types;
/// <summary>
/// Represents a JSON schema for a tool's input arguments.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/schema.json">See the schema for details</see>
/// </summary>
public class JsonSchema
{
/// <summary>
/// The type of the schema, should be "object".
/// </summary>
public string Type { get; set; } = string.Empty;
/// <summary>
/// Map of property names to property definitions.
/// </summary>
public Dictionary<string, JsonSchemaProperty>? Properties { get; set; }
/// <summary>
/// List of required property names.
/// </summary>
public List<string>? Required { get; set; }
}

View file

@ -0,0 +1,18 @@
namespace McpDotNet.Protocol.Types;
/// <summary>
/// Represents a property in a JSON schema.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/schema.json">See the schema for details</see>
/// </summary>
public class JsonSchemaProperty
{
/// <summary>
/// The type of the property. Should be a JSON Schema type and is required.
/// </summary>
public string Type { get; set; } = string.Empty;
/// <summary>
/// A human-readable description of the property.
/// </summary>
public string? Description { get; set; }
}

View file

@ -0,0 +1,13 @@
namespace McpDotNet.Protocol.Types;
/// <summary>
/// A response to a request to list the tools available on the server.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/schema.json">See the schema for details</see>
/// </summary>
public class ListToolsResponse
{
/// <summary>
/// The server's response to a tools/list request from the client.
/// </summary>
public List<Tool> Tools { get; set; } = new();
}

View file

@ -37,48 +37,3 @@ public record Resource
[JsonPropertyName("annotations")]
public Annotations? Annotations { get; init; }
}
/// <summary>
/// Interface for resource contents.
/// </summary>
public interface IResourceContents
{
string Uri { get; }
string? MimeType { get; }
}
/// <summary>
/// Represents text-based resource contents.
/// </summary>
public record TextResourceContents : IResourceContents
{
[JsonPropertyName("uri")]
public required string Uri { get; init; }
[JsonPropertyName("mimeType")]
public string? MimeType { get; init; }
/// <summary>
/// The text content of the resource.
/// </summary>
[JsonPropertyName("text")]
public required string Text { get; init; }
}
/// <summary>
/// Represents binary resource contents.
/// </summary>
public record BlobResourceContents : IResourceContents
{
[JsonPropertyName("uri")]
public required string Uri { get; init; }
[JsonPropertyName("mimeType")]
public string? MimeType { get; init; }
/// <summary>
/// The base64-encoded binary content of the resource.
/// </summary>
[JsonPropertyName("blob")]
public required string Blob { get; init; }
}

Some files were not shown because too many files have changed in this diff Show more