Clean up and add more comments (#2)
This commit is contained in:
parent
79af38cf21
commit
9a244f5770
30 changed files with 349 additions and 653 deletions
|
|
@ -5,6 +5,8 @@ using McpDotNet.Protocol.Messages;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an instance of the MCP client connecting to a specific server.
|
/// 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>
|
/// </summary>
|
||||||
public interface IMcpClient : IAsyncDisposable
|
public interface IMcpClient : IAsyncDisposable
|
||||||
{
|
{
|
||||||
|
|
@ -14,44 +16,58 @@ public interface IMcpClient : IAsyncDisposable
|
||||||
bool IsInitialized { get; }
|
bool IsInitialized { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the capabilities that the server supports.
|
/// Gets the capabilities supported by the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ServerCapabilities? ServerCapabilities { get; }
|
ServerCapabilities? ServerCapabilities { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the version information of the server.
|
/// Gets the version and implementation information of the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Implementation? ServerInfo { get; }
|
Implementation? ServerInfo { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connects to the server.
|
/// Establishes a connection to the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||||
|
/// <returns>A task representing the asynchronous operation.</returns>
|
||||||
Task ConnectAsync(CancellationToken cancellationToken = default);
|
Task ConnectAsync(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </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);
|
Task PingAsync(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries the server for a list of tools that are available (if any)
|
/// Retrieves a list of available tools from the server.
|
||||||
/// </summary>
|
/// </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);
|
Task<ListToolsResponse> ListToolsAsync(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calls a tool on the server.
|
/// Invokes a tool on the server with optional arguments.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="toolName">The name of the tool as given when listing tool definitions.</param>
|
/// <param name="toolName">The name of the tool to call.</param>
|
||||||
/// <param name="arguments">Arguments for the tool (if any)</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);
|
Task<CallToolResponse> CallToolAsync(string toolName, Dictionary<string, object>? arguments = null, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </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;
|
Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a handler for a specific notification method.
|
/// Registers a handler for server notifications of a specific method.
|
||||||
/// </summary>
|
/// </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);
|
void OnNotification(string method, Func<JsonRpcNotification, Task> handler);
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// Client/McpClientOptions.cs
|
namespace McpDotNet.Client;
|
||||||
namespace McpDotNet.Client;
|
|
||||||
|
|
||||||
using McpDotNet.Protocol.Types;
|
using McpDotNet.Protocol.Types;
|
||||||
using McpDotNet.Protocol.Transport;
|
using McpDotNet.Protocol.Transport;
|
||||||
|
|
@ -9,10 +8,8 @@ using System.Diagnostics;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using McpDotNet.Utils.Json;
|
using McpDotNet.Utils.Json;
|
||||||
|
|
||||||
/// <summary>
|
/// </inheritdoc>
|
||||||
/// Main MCP client implementation that handles protocol lifecycle and message routing.
|
internal class McpClient : IMcpClient
|
||||||
/// </summary>
|
|
||||||
public class McpClient : IMcpClient
|
|
||||||
{
|
{
|
||||||
private readonly IMcpTransport _transport;
|
private readonly IMcpTransport _transport;
|
||||||
private readonly McpClientOptions _options;
|
private readonly McpClientOptions _options;
|
||||||
|
|
@ -24,21 +21,20 @@ public class McpClient : IMcpClient
|
||||||
private CancellationTokenSource? _cts;
|
private CancellationTokenSource? _cts;
|
||||||
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions().ConfigureForMcp();
|
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions().ConfigureForMcp();
|
||||||
|
|
||||||
/// <summary>
|
/// </inheritdoc>
|
||||||
/// Gets whether the client is connected and initialized.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsInitialized => _isInitialized;
|
public bool IsInitialized => _isInitialized;
|
||||||
|
|
||||||
/// <summary>
|
/// </inheritdoc>
|
||||||
/// Gets the server's capabilities after initialization.
|
|
||||||
/// </summary>
|
|
||||||
public ServerCapabilities? ServerCapabilities { get; private set; }
|
public ServerCapabilities? ServerCapabilities { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// </inheritdoc>
|
||||||
/// Gets information about the server implementation after initialization.
|
|
||||||
/// </summary>
|
|
||||||
public Implementation? ServerInfo { get; private set; }
|
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)
|
public McpClient(IMcpTransport transport, McpClientOptions options)
|
||||||
{
|
{
|
||||||
_transport = transport;
|
_transport = transport;
|
||||||
|
|
@ -48,9 +44,7 @@ public class McpClient : IMcpClient
|
||||||
_nextRequestId = 1;
|
_nextRequestId = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// </inheritdoc>
|
||||||
/// Connects to the server and performs the initialization sequence.
|
|
||||||
/// </summary>
|
|
||||||
public async Task ConnectAsync(CancellationToken cancellationToken = default)
|
public async Task ConnectAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (_isInitialized)
|
if (_isInitialized)
|
||||||
|
|
@ -128,6 +122,7 @@ public class McpClient : IMcpClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// </inheritdoc>
|
||||||
public async Task PingAsync(CancellationToken cancellationToken)
|
public async Task PingAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await SendRequestAsync<dynamic>(
|
await SendRequestAsync<dynamic>(
|
||||||
|
|
@ -139,6 +134,7 @@ public class McpClient : IMcpClient
|
||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// </inheritdoc>
|
||||||
public async Task<ListToolsResponse> ListToolsAsync(CancellationToken cancellationToken)
|
public async Task<ListToolsResponse> ListToolsAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return await SendRequestAsync<ListToolsResponse>(
|
return await SendRequestAsync<ListToolsResponse>(
|
||||||
|
|
@ -151,6 +147,7 @@ public class McpClient : IMcpClient
|
||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// </inheritdoc>
|
||||||
public async Task<CallToolResponse> CallToolAsync(string toolName, Dictionary<string, object>? arguments = null,
|
public async Task<CallToolResponse> CallToolAsync(string toolName, Dictionary<string, object>? arguments = null,
|
||||||
CancellationToken cancellationToken = default)
|
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
|
public async Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class
|
||||||
{
|
{
|
||||||
if (!_transport.IsConnected)
|
if (!_transport.IsConnected)
|
||||||
|
|
@ -275,9 +273,7 @@ public class McpClient : IMcpClient
|
||||||
await _transport.SendMessageAsync(notification, cancellationToken).ConfigureAwait(false);
|
await _transport.SendMessageAsync(notification, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// </inheritdoc>
|
||||||
/// Registers a handler for notifications of a specific method.
|
|
||||||
/// </summary>
|
|
||||||
public void OnNotification(string method, Func<JsonRpcNotification,Task> handler)
|
public void OnNotification(string method, Func<JsonRpcNotification,Task> handler)
|
||||||
{
|
{
|
||||||
var handlers = _notificationHandlers.GetOrAdd(method, _ => new());
|
var handlers = _notificationHandlers.GetOrAdd(method, _ => new());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// Client/McpClientOptions.cs
|
namespace McpDotNet.Client;
|
||||||
namespace McpDotNet.Client;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents errors that occur in the MCP client.
|
/// Represents errors that occur in the MCP client.
|
||||||
|
|
@ -11,15 +10,29 @@ public class McpClientException : Exception
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? ErrorCode { get; }
|
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)
|
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)
|
public McpClientException(string message, int errorCode) : base(message)
|
||||||
{
|
{
|
||||||
ErrorCode = errorCode;
|
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)
|
public McpClientException(string message, Exception innerException) : base(message, innerException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
// Client/McpClientFactory.cs
|
namespace McpDotNet.Client;
|
||||||
namespace McpDotNet.Client;
|
|
||||||
|
|
||||||
using McpDotNet.Configuration;
|
using McpDotNet.Configuration;
|
||||||
using McpDotNet.Protocol.Transport;
|
using McpDotNet.Protocol.Transport;
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public class McpClientFactory
|
public class McpClientFactory
|
||||||
{
|
{
|
||||||
|
|
@ -15,6 +17,15 @@ public class McpClientFactory
|
||||||
private readonly Func<McpServerConfig, IMcpTransport> _transportFactoryMethod;
|
private readonly Func<McpServerConfig, IMcpTransport> _transportFactoryMethod;
|
||||||
private readonly Func<IMcpTransport, McpClientOptions, IMcpClient> _clientFactoryMethod;
|
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(
|
public McpClientFactory(
|
||||||
IEnumerable<McpServerConfig> serverConfigs,
|
IEnumerable<McpServerConfig> serverConfigs,
|
||||||
McpClientOptions clientOptions,
|
McpClientOptions clientOptions,
|
||||||
|
|
@ -28,8 +39,12 @@ public class McpClientFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </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)
|
public async Task<IMcpClient> GetClientAsync(string serverId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (!_serverConfigs.TryGetValue(serverId, out var config))
|
if (!_serverConfigs.TryGetValue(serverId, out var config))
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
// Client/McpClientOptions.cs
|
using McpDotNet.Protocol.Types;
|
||||||
|
|
||||||
namespace McpDotNet.Client;
|
namespace McpDotNet.Client;
|
||||||
|
|
||||||
using global::McpDotNet.Protocol.Types;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public record McpClientOptions
|
public record McpClientOptions
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// Configuration/McpServerConfig.cs
|
namespace McpDotNet.Configuration;
|
||||||
namespace McpDotNet.Configuration;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration for an MCP server connection.
|
/// Configuration for an MCP server connection.
|
||||||
|
|
|
||||||
|
|
@ -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";
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
21
src/mcpdotnet/Protocol/Types/BlobResourceContents.cs
Normal file
21
src/mcpdotnet/Protocol/Types/BlobResourceContents.cs
Normal 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; }
|
||||||
|
}
|
||||||
18
src/mcpdotnet/Protocol/Types/CallToolResponse.cs
Normal file
18
src/mcpdotnet/Protocol/Types/CallToolResponse.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
|
@ -26,42 +26,6 @@ public record ClientCapabilities
|
||||||
public SamplingCapability? Sampling { get; init; }
|
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>
|
/// <summary>
|
||||||
/// Represents the roots capability configuration.
|
/// Represents the roots capability configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
10
src/mcpdotnet/Protocol/Types/IResourceContents.cs
Normal file
10
src/mcpdotnet/Protocol/Types/IResourceContents.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace McpDotNet.Protocol.Types;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for resource contents.
|
||||||
|
/// </summary>
|
||||||
|
public interface IResourceContents
|
||||||
|
{
|
||||||
|
string Uri { get; }
|
||||||
|
string? MimeType { get; }
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// Protocol/Types/Implementation.cs
|
namespace McpDotNet.Protocol.Types;
|
||||||
namespace McpDotNet.Protocol.Types;
|
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
|
|
||||||
23
src/mcpdotnet/Protocol/Types/JsonSchema.cs
Normal file
23
src/mcpdotnet/Protocol/Types/JsonSchema.cs
Normal 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; }
|
||||||
|
}
|
||||||
18
src/mcpdotnet/Protocol/Types/JsonSchemaProperty.cs
Normal file
18
src/mcpdotnet/Protocol/Types/JsonSchemaProperty.cs
Normal 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; }
|
||||||
|
}
|
||||||
13
src/mcpdotnet/Protocol/Types/ListToolsResponse.cs
Normal file
13
src/mcpdotnet/Protocol/Types/ListToolsResponse.cs
Normal 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();
|
||||||
|
}
|
||||||
|
|
@ -37,48 +37,3 @@ public record Resource
|
||||||
[JsonPropertyName("annotations")]
|
[JsonPropertyName("annotations")]
|
||||||
public Annotations? Annotations { get; init; }
|
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
Loading…
Reference in a new issue