Allow JsonSerializerOptions parameters for user-defined and inputs and hardcode everything else to the source generator. (#182)
* Allow user-defined JsonSerializerOptions for user-defined and inputs and hardcode everything else to the source generator. * Add validation for user-defined JsonSerializerOptions. * Remove out of date comment. * Address feedback and add tests
This commit is contained in:
parent
4b38d3e71b
commit
f1af251c32
4 changed files with 632 additions and 372 deletions
|
|
@ -255,8 +255,8 @@ internal sealed class AIFunctionMcpServerTool : McpServerTool
|
|||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// TODO: Once we shift to the real AIFunctionFactory, the request should be passed via AIFunctionArguments.Context.
|
||||
Dictionary<string, object?> arguments = request.Params?.Arguments is IDictionary<string, object?> existingArgs ?
|
||||
new(existingArgs) :
|
||||
Dictionary<string, object?> arguments = request.Params?.Arguments is { } paramArgs ?
|
||||
paramArgs.ToDictionary(entry => entry.Key, entry => entry.Value.AsObject()) :
|
||||
[];
|
||||
arguments[RequestContextKey] = request;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using ModelContextProtocol.Protocol.Transport;
|
|||
using ModelContextProtocol.Protocol.Types;
|
||||
using ModelContextProtocol.Shared;
|
||||
using ModelContextProtocol.Utils;
|
||||
using System.Text.Json.Nodes;
|
||||
using ModelContextProtocol.Utils.Json;
|
||||
|
||||
namespace ModelContextProtocol.Server;
|
||||
|
||||
|
|
@ -131,13 +131,15 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
|
||||
private void SetPingHandler()
|
||||
{
|
||||
SetRequestHandler<JsonNode, PingResult>(RequestMethods.Ping,
|
||||
(request, _) => Task.FromResult(new PingResult()));
|
||||
SetRequestHandler(RequestMethods.Ping,
|
||||
(request, _) => Task.FromResult(new PingResult()),
|
||||
McpJsonUtilities.JsonContext.Default.JsonNode,
|
||||
McpJsonUtilities.JsonContext.Default.PingResult);
|
||||
}
|
||||
|
||||
private void SetInitializeHandler(McpServerOptions options)
|
||||
{
|
||||
SetRequestHandler<InitializeRequestParams, InitializeResult>(RequestMethods.Initialize,
|
||||
SetRequestHandler(RequestMethods.Initialize,
|
||||
(request, _) =>
|
||||
{
|
||||
ClientCapabilities = request?.Capabilities ?? new();
|
||||
|
|
@ -147,23 +149,27 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
_endpointName = $"{_endpointName}, Client ({ClientInfo?.Name} {ClientInfo?.Version})";
|
||||
GetSessionOrThrow().EndpointName = _endpointName;
|
||||
|
||||
return Task.FromResult(new InitializeResult()
|
||||
return Task.FromResult(new InitializeResult
|
||||
{
|
||||
ProtocolVersion = options.ProtocolVersion,
|
||||
Instructions = options.ServerInstructions,
|
||||
ServerInfo = options.ServerInfo,
|
||||
Capabilities = ServerCapabilities ?? new(),
|
||||
});
|
||||
});
|
||||
},
|
||||
McpJsonUtilities.JsonContext.Default.InitializeRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.InitializeResult);
|
||||
}
|
||||
|
||||
private void SetCompletionHandler(McpServerOptions options)
|
||||
{
|
||||
// This capability is not optional, so return an empty result if there is no handler.
|
||||
SetRequestHandler<CompleteRequestParams, CompleteResult>(RequestMethods.CompletionComplete,
|
||||
SetRequestHandler(RequestMethods.CompletionComplete,
|
||||
options.GetCompletionHandler is { } handler ?
|
||||
(request, ct) => handler(new(this, request), ct) :
|
||||
(request, ct) => Task.FromResult(new CompleteResult() { Completion = new() { Values = [], Total = 0, HasMore = false } }));
|
||||
(request, ct) => Task.FromResult(new CompleteResult() { Completion = new() { Values = [], Total = 0, HasMore = false } }),
|
||||
McpJsonUtilities.JsonContext.Default.CompleteRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.CompleteResult);
|
||||
}
|
||||
|
||||
private void SetResourcesHandler(McpServerOptions options)
|
||||
|
|
@ -184,11 +190,24 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
|
||||
listResourcesHandler ??= (static (_, _) => Task.FromResult(new ListResourcesResult()));
|
||||
|
||||
SetRequestHandler<ListResourcesRequestParams, ListResourcesResult>(RequestMethods.ResourcesList, (request, ct) => listResourcesHandler(new(this, request), ct));
|
||||
SetRequestHandler<ReadResourceRequestParams, ReadResourceResult>(RequestMethods.ResourcesRead, (request, ct) => readResourceHandler(new(this, request), ct));
|
||||
SetRequestHandler(
|
||||
RequestMethods.ResourcesList,
|
||||
(request, ct) => listResourcesHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.ListResourcesRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListResourcesResult);
|
||||
|
||||
SetRequestHandler(
|
||||
RequestMethods.ResourcesRead,
|
||||
(request, ct) => readResourceHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.ReadResourceRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ReadResourceResult);
|
||||
|
||||
listResourceTemplatesHandler ??= (static (_, _) => Task.FromResult(new ListResourceTemplatesResult()));
|
||||
SetRequestHandler<ListResourceTemplatesRequestParams, ListResourceTemplatesResult>(RequestMethods.ResourcesTemplatesList, (request, ct) => listResourceTemplatesHandler(new(this, request), ct));
|
||||
SetRequestHandler(
|
||||
RequestMethods.ResourcesTemplatesList,
|
||||
(request, ct) => listResourceTemplatesHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesResult);
|
||||
|
||||
if (resourcesCapability.Subscribe is not true)
|
||||
{
|
||||
|
|
@ -202,8 +221,17 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
throw new McpServerException("Resources capability was enabled with subscribe support, but SubscribeToResources and/or UnsubscribeFromResources handlers were not specified.");
|
||||
}
|
||||
|
||||
SetRequestHandler<SubscribeRequestParams, EmptyResult>(RequestMethods.ResourcesSubscribe, (request, ct) => subscribeHandler(new(this, request), ct));
|
||||
SetRequestHandler<UnsubscribeRequestParams, EmptyResult>(RequestMethods.ResourcesUnsubscribe, (request, ct) => unsubscribeHandler(new(this, request), ct));
|
||||
SetRequestHandler(
|
||||
RequestMethods.ResourcesSubscribe,
|
||||
(request, ct) => subscribeHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.SubscribeRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.EmptyResult);
|
||||
|
||||
SetRequestHandler(
|
||||
RequestMethods.ResourcesUnsubscribe,
|
||||
(request, ct) => unsubscribeHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.UnsubscribeRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.EmptyResult);
|
||||
}
|
||||
|
||||
private void SetPromptsHandler(McpServerOptions options)
|
||||
|
|
@ -286,8 +314,17 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
}
|
||||
}
|
||||
|
||||
SetRequestHandler<ListPromptsRequestParams, ListPromptsResult>(RequestMethods.PromptsList, (request, ct) => listPromptsHandler(new(this, request), ct));
|
||||
SetRequestHandler<GetPromptRequestParams, GetPromptResult>(RequestMethods.PromptsGet, (request, ct) => getPromptHandler(new(this, request), ct));
|
||||
SetRequestHandler(
|
||||
RequestMethods.PromptsList,
|
||||
(request, ct) => listPromptsHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.ListPromptsRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListPromptsResult);
|
||||
|
||||
SetRequestHandler(
|
||||
RequestMethods.PromptsGet,
|
||||
(request, ct) => getPromptHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.GetPromptRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.GetPromptResult);
|
||||
}
|
||||
|
||||
private void SetToolsHandler(McpServerOptions options)
|
||||
|
|
@ -370,8 +407,17 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
}
|
||||
}
|
||||
|
||||
SetRequestHandler<ListToolsRequestParams, ListToolsResult>(RequestMethods.ToolsList, (request, ct) => listToolsHandler(new(this, request), ct));
|
||||
SetRequestHandler<CallToolRequestParams, CallToolResponse>(RequestMethods.ToolsCall, (request, ct) => callToolHandler(new(this, request), ct));
|
||||
SetRequestHandler(
|
||||
RequestMethods.ToolsList,
|
||||
(request, ct) => listToolsHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.ListToolsRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListToolsResult);
|
||||
|
||||
SetRequestHandler(
|
||||
RequestMethods.ToolsCall,
|
||||
(request, ct) => callToolHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.CallToolRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.CallToolResponse);
|
||||
}
|
||||
|
||||
private void SetSetLoggingLevelHandler(McpServerOptions options)
|
||||
|
|
@ -386,6 +432,10 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
throw new McpServerException("Logging capability was enabled, but SetLoggingLevelHandler was not specified.");
|
||||
}
|
||||
|
||||
SetRequestHandler<SetLevelRequestParams, EmptyResult>(RequestMethods.LoggingSetLevel, (request, ct) => setLoggingLevelHandler(new(this, request), ct));
|
||||
SetRequestHandler(
|
||||
RequestMethods.LoggingSetLevel,
|
||||
(request, ct) => setLoggingLevelHandler(new(this, request), ct),
|
||||
McpJsonUtilities.JsonContext.Default.SetLevelRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.EmptyResult);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
using ModelContextProtocol.Protocol.Messages;
|
||||
using Microsoft.Extensions.AI;
|
||||
using ModelContextProtocol.Client;
|
||||
using ModelContextProtocol.Protocol.Messages;
|
||||
using ModelContextProtocol.Protocol.Types;
|
||||
using ModelContextProtocol.Utils;
|
||||
using Microsoft.Extensions.AI;
|
||||
using ModelContextProtocol.Utils.Json;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
|
|
@ -25,9 +27,12 @@ public static class McpServerExtensions
|
|||
throw new ArgumentException("Client connected to the server does not support sampling.", nameof(server));
|
||||
}
|
||||
|
||||
return server.SendRequestAsync<CreateMessageResult>(
|
||||
new JsonRpcRequest { Method = RequestMethods.SamplingCreateMessage, Params = request },
|
||||
cancellationToken);
|
||||
return server.SendRequestAsync(
|
||||
RequestMethods.SamplingCreateMessage,
|
||||
request,
|
||||
McpJsonUtilities.JsonContext.Default.CreateMessageRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.CreateMessageResult,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -164,9 +169,12 @@ public static class McpServerExtensions
|
|||
throw new ArgumentException("Client connected to the server does not support roots.", nameof(server));
|
||||
}
|
||||
|
||||
return server.SendRequestAsync<ListRootsResult>(
|
||||
new JsonRpcRequest { Method = RequestMethods.RootsList, Params = request },
|
||||
cancellationToken);
|
||||
return server.SendRequestAsync(
|
||||
RequestMethods.RootsList,
|
||||
request,
|
||||
McpJsonUtilities.JsonContext.Default.ListRootsRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListRootsResult,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>Provides an <see cref="IChatClient"/> implementation that's implemented via client sampling.</summary>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using ModelContextProtocol.Protocol.Types;
|
||||
using ModelContextProtocol.Server;
|
||||
using ModelContextProtocol.Utils;
|
||||
using ModelContextProtocol.Utils.Json;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
|
|
@ -476,7 +477,7 @@ internal static partial class TemporaryAIFunctionFactory
|
|||
description: parameter.GetCustomAttribute<DescriptionAttribute>(inherit: true)?.Description,
|
||||
hasDefaultValue: parameter.HasDefaultValue,
|
||||
defaultValue: parameter.HasDefaultValue ? parameter.DefaultValue : null,
|
||||
serializerOptions), AIJsonUtilities.DefaultOptions.GetTypeInfo<JsonElement>());
|
||||
serializerOptions), McpJsonUtilities.JsonContext.Default.JsonElement);
|
||||
|
||||
parameterSchemas.Add(parameter.Name, parameterSchema);
|
||||
if (!parameter.IsOptional)
|
||||
|
|
|
|||
Loading…
Reference in a new issue