Add ToolAnnotations support (#124)

* Add ToolAnnotations support

* Address feedback
This commit is contained in:
Stephen Toub 2025-03-28 11:08:29 -04:00 • committed by GitHub
commit 62e92fa154
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
70 changed files with 645 additions and 394 deletions

View file

@ -10,7 +10,7 @@ namespace TestServerWithHosting.Tools;
[McpServerToolType] [McpServerToolType]
public static class SampleLlmTool public static class SampleLlmTool
{ {
[McpServerTool("sampleLLM"), Description("Samples from an LLM using MCP's sampling feature")] [McpServerTool(Name = "sampleLLM"), Description("Samples from an LLM using MCP's sampling feature")]
public static async Task<string> SampleLLM( public static async Task<string> SampleLLM(
IMcpServer thisServer, IMcpServer thisServer,
[Description("The prompt to send to the LLM")] string prompt, [Description("The prompt to send to the LLM")] string prompt,

View file

@ -10,7 +10,7 @@ namespace TestServerWithHosting.Tools;
[McpServerToolType] [McpServerToolType]
public static class SampleLlmTool public static class SampleLlmTool
{ {
[McpServerTool("sampleLLM"), Description("Samples from an LLM using MCP's sampling feature")] [McpServerTool(Name = "sampleLLM"), Description("Samples from an LLM using MCP's sampling feature")]
public static async Task<string> SampleLLM( public static async Task<string> SampleLLM(
IMcpServer thisServer, IMcpServer thisServer,
[Description("The prompt to send to the LLM")] string prompt, [Description("The prompt to send to the LLM")] string prompt,

View file

@ -33,7 +33,7 @@ public static class AIContentExtensions
Throw.IfNull(content); Throw.IfNull(content);
AIContent ac; AIContent ac;
if (content is { Type: "image", MimeType: not null, Data: not null }) if (content is { Type: "image" or "audio", MimeType: not null, Data: not null })
{ {
ac = new DataContent(Convert.FromBase64String(content.Data), content.MimeType); ac = new DataContent(Convert.FromBase64String(content.Data), content.MimeType);
} }
@ -112,6 +112,7 @@ public static class AIContentExtensions
Text = textContent.Text, Text = textContent.Text,
Type = "text", Type = "text",
}, },
DataContent dataContent => new() DataContent dataContent => new()
{ {
Data = dataContent.GetBase64Data(), Data = dataContent.GetBase64Data(),
@ -121,6 +122,7 @@ public static class AIContentExtensions
dataContent.HasTopLevelMediaType("audio") ? "audio" : dataContent.HasTopLevelMediaType("audio") ? "audio" :
"resource", "resource",
}, },
_ => new() _ => new()
{ {
Text = JsonSerializer.Serialize(content, McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object))), Text = JsonSerializer.Serialize(content, McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object))),

View file

@ -469,7 +469,7 @@ public static class McpClientExtensions
{ {
message.Contents.Add(new TextContent(sm.Content.Text)); message.Contents.Add(new TextContent(sm.Content.Text));
} }
else if (sm.Content is { Type: "image", MimeType: not null, Data: not null }) else if (sm.Content is { Type: "image" or "audio", MimeType: not null, Data: not null })
{ {
message.Contents.Add(new DataContent(Convert.FromBase64String(sm.Content.Data), sm.Content.MimeType)); message.Contents.Add(new DataContent(Convert.FromBase64String(sm.Content.Data), sm.Content.MimeType));
} }
@ -512,11 +512,11 @@ public static class McpClientExtensions
{ {
foreach (var lmc in lastMessage.Contents) foreach (var lmc in lastMessage.Contents)
{ {
if (lmc is DataContent dc && dc.HasTopLevelMediaType("image")) if (lmc is DataContent dc && (dc.HasTopLevelMediaType("image") || dc.HasTopLevelMediaType("audio")))
{ {
content = new() content = new()
{ {
Type = "image", Type = dc.HasTopLevelMediaType("image") ? "image" : "audio",
MimeType = dc.MediaType, MimeType = dc.MediaType,
Data = dc.GetBase64Data(), Data = dc.GetBase64Data(),
}; };

View file

@ -9,22 +9,24 @@ namespace ModelContextProtocol.Client;
public sealed class McpClientTool : AIFunction public sealed class McpClientTool : AIFunction
{ {
private readonly IMcpClient _client; private readonly IMcpClient _client;
private readonly Tool _tool;
internal McpClientTool(IMcpClient client, Tool tool) internal McpClientTool(IMcpClient client, Tool tool)
{ {
_client = client; _client = client;
_tool = tool; ProtocolTool = tool;
} }
/// <inheritdoc/> /// <summary>Gets the protocol <see cref="Tool"/> type for this instance.</summary>
public override string Name => _tool.Name; public Tool ProtocolTool { get; }
/// <inheritdoc/> /// <inheritdoc/>
public override string Description => _tool.Description ?? string.Empty; public override string Name => ProtocolTool.Name;
/// <inheritdoc/> /// <inheritdoc/>
public override JsonElement JsonSchema => _tool.InputSchema; public override string Description => ProtocolTool.Description ?? string.Empty;
/// <inheritdoc/>
public override JsonElement JsonSchema => ProtocolTool.InputSchema;
/// <inheritdoc/> /// <inheritdoc/>
public override JsonSerializerOptions JsonSerializerOptions => McpJsonUtilities.DefaultOptions; public override JsonSerializerOptions JsonSerializerOptions => McpJsonUtilities.DefaultOptions;
@ -37,7 +39,7 @@ public sealed class McpClientTool : AIFunction
arguments as IReadOnlyDictionary<string, object?> ?? arguments as IReadOnlyDictionary<string, object?> ??
arguments.ToDictionary(); arguments.ToDictionary();
CallToolResponse result = await _client.CallToolAsync(_tool.Name, argDict, cancellationToken).ConfigureAwait(false); CallToolResponse result = await _client.CallToolAsync(ProtocolTool.Name, argDict, cancellationToken).ConfigureAwait(false);
return JsonSerializer.SerializeToElement(result, McpJsonUtilities.JsonContext.Default.CallToolResponse); return JsonSerializer.SerializeToElement(result, McpJsonUtilities.JsonContext.Default.CallToolResponse);
} }
} }

View file

@ -37,14 +37,9 @@ public static partial class McpServerBuilderExtensions
{ {
if (toolMethod.GetCustomAttribute<McpServerToolAttribute>() is not null) if (toolMethod.GetCustomAttribute<McpServerToolAttribute>() is not null)
{ {
if (toolMethod.IsStatic) builder.Services.AddSingleton((Func<IServiceProvider, McpServerTool>)(toolMethod.IsStatic ?
{ services => McpServerTool.Create(toolMethod, new McpServerToolCreateOptions() { Services = services }) :
builder.Services.AddSingleton(services => McpServerTool.Create(toolMethod, services: services)); services => McpServerTool.Create(toolMethod, typeof(TTool), new() { Services = services })));
}
else
{
builder.Services.AddSingleton(services => McpServerTool.Create(toolMethod, typeof(TTool), services: services));
}
} }
} }
@ -71,18 +66,13 @@ public static partial class McpServerBuilderExtensions
{ {
if (toolType is not null) if (toolType is not null)
{ {
foreach (var method in toolType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)) foreach (var toolMethod in toolType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{ {
if (method.GetCustomAttribute<McpServerToolAttribute>() is not null) if (toolMethod.GetCustomAttribute<McpServerToolAttribute>() is not null)
{ {
if (method.IsStatic) builder.Services.AddSingleton((Func<IServiceProvider, McpServerTool>)(toolMethod.IsStatic ?
{ services => McpServerTool.Create(toolMethod, new McpServerToolCreateOptions() { Services = services }) :
builder.Services.AddSingleton(services => McpServerTool.Create(method, services: services)); services => McpServerTool.Create(toolMethod, toolType, new() { Services = services })));
}
else
{
builder.Services.AddSingleton(services => McpServerTool.Create(method, toolType, services: services));
}
} }
} }
} }

View file

@ -25,7 +25,7 @@ public sealed class StdioServerTransport : TransportBase, IServerTransport
private readonly TextReader _stdInReader; private readonly TextReader _stdInReader;
private readonly Stream _stdOutStream; private readonly Stream _stdOutStream;
private SemaphoreSlim _sendLock = new(1, 1); private readonly SemaphoreSlim _sendLock = new(1, 1);
private Task? _readTask; private Task? _readTask;
private CancellationTokenSource? _shutdownCts; private CancellationTokenSource? _shutdownCts;

View file

@ -4,7 +4,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// Base for objects that include optional annotations for the client. The client can use annotations to inform how objects are used or displayed. /// Base for objects that include optional annotations for the client. The client can use annotations to inform how objects are used or displayed.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public abstract record Annotated public abstract record Annotated
{ {

View file

@ -4,7 +4,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// Represents annotations that can be attached to content. /// Represents annotations that can be attached to content.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public record Annotations public record Annotations
{ {

View file

@ -4,7 +4,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// Used for completion requests to provide additional context for the completion options. /// Used for completion requests to provide additional context for the completion options.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class Argument public class Argument
{ {

View file

@ -2,7 +2,7 @@
/// <summary> /// <summary>
/// Used by the client to invoke a tool provided by the server. /// Used by the client to invoke a tool provided by the server.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class CallToolRequestParams : RequestParams public class CallToolRequestParams : RequestParams
{ {

View file

@ -11,7 +11,7 @@
/// However, any errors in _finding_ the tool, an error indicating that the /// However, any errors in _finding_ the tool, an error indicating that the
/// server does not support tool calls, or any other exceptional conditions, /// server does not support tool calls, or any other exceptional conditions,
/// should be reported as an MCP error response. /// should be reported as an MCP error response.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class CallToolResponse public class CallToolResponse
{ {

View file

@ -5,7 +5,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// Represents the capabilities that a client may support. /// Represents the capabilities that a client may support.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class ClientCapabilities public class ClientCapabilities
{ {
@ -30,7 +30,7 @@ public class ClientCapabilities
/// <summary> /// <summary>
/// Represents the roots capability configuration. /// Represents the roots capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class RootsCapability public class RootsCapability
{ {
@ -47,7 +47,7 @@ public class RootsCapability
/// <summary> /// <summary>
/// Represents the sampling capability configuration. /// Represents the sampling capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class SamplingCapability public class SamplingCapability
{ {
@ -60,7 +60,7 @@ public class SamplingCapability
/// <summary> /// <summary>
/// Represents the logging capability configuration. /// Represents the logging capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class LoggingCapability public class LoggingCapability
{ {
@ -76,7 +76,7 @@ public class LoggingCapability
/// <summary> /// <summary>
/// Represents the prompts capability configuration. /// Represents the prompts capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class PromptsCapability public class PromptsCapability
{ {
@ -101,7 +101,7 @@ public class PromptsCapability
/// <summary> /// <summary>
/// Represents the resources capability configuration. /// Represents the resources capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class ResourcesCapability public class ResourcesCapability
{ {
@ -150,7 +150,7 @@ public class ResourcesCapability
/// <summary> /// <summary>
/// Represents the tools capability configuration. /// Represents the tools capability configuration.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class ToolsCapability public class ToolsCapability
{ {

View file

@ -2,7 +2,7 @@
/// <summary> /// <summary>
/// A request from the client to the server, to ask for completion options. /// A request from the client to the server, to ask for completion options.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class CompleteRequestParams : RequestParams public class CompleteRequestParams : RequestParams
{ {

View file

@ -4,7 +4,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// The server's response to a completion/complete request /// The server's response to a completion/complete request
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class CompleteResult public class CompleteResult
{ {

View file

@ -4,7 +4,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// Represents a completion object in the server's response /// Represents a completion object in the server's response
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class Completion public class Completion
{ {

View file

@ -4,13 +4,13 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// Represents the content of a tool response. /// Represents the content of a tool response.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// There are multiple subtypes of content, depending on the "type" field, these are represented as separate classes. /// There are multiple subtypes of content, depending on the "type" field, these are represented as separate classes.
/// </summary> /// </summary>
public class Content public class Content
{ {
/// <summary> /// <summary>
/// The type of content. This determines the structure of the content object. Can be "image", "text", "resource". /// The type of content. This determines the structure of the content object. Can be "image", "audio", "text", "resource".
/// </summary> /// </summary>
[JsonPropertyName("type")] [JsonPropertyName("type")]

View file

@ -4,7 +4,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// <summary> /// <summary>
/// A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. /// A request to include context from one or more MCP servers (including the caller), to be attached to the prompt.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
[JsonConverter(typeof(JsonStringEnumConverter<ContextInclusion>))] [JsonConverter(typeof(JsonStringEnumConverter<ContextInclusion>))]
public enum ContextInclusion public enum ContextInclusion

View file

@ -7,7 +7,7 @@
/// ///
/// While these align with the protocol specification, /// While these align with the protocol specification,
/// clients have full discretion over model selection and should inform users before sampling. /// clients have full discretion over model selection and should inform users before sampling.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class CreateMessageRequestParams : RequestParams public class CreateMessageRequestParams : RequestParams
{ {

View file

@ -6,7 +6,7 @@ namespace ModelContextProtocol.Protocol.Types;
/// The client's response to a sampling/create_message request from the server. /// The client's response to a sampling/create_message request from the server.
/// The client should inform the user before returning the sampled message, to allow them to inspect the response (human in the loop) /// The client should inform the user before returning the sampled message, to allow them to inspect the response (human in the loop)
/// and decide whether to allow the server to see it. /// and decide whether to allow the server to see it.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see> /// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">See the schema for details</see>
/// </summary> /// </summary>
public class CreateMessageResult public class CreateMessageResult
{ {

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