McpProcess starts a server through the SDK stdio client under the startup timeout and keeps a stderr tail for its errors. McpCatalogCache runs one shared discovery per server config in a temp dir, with the environment from the process spawn policy. It keeps successes for the process lifetime and failures for 60 s. Deviation from the plan: the discovery process is disposed and its temp dir deleted in the background, after the catalogue is returned. SDK 2.2 waits the whole ShutdownTimeout (5 s) with stdin still open before it kills the process, so an awaited dispose held every first activation for 5 s. A new test (Discovery_returns_without_waiting_for_the_server_shutdown) covers this. Spec section 3 gets the new GetAsync signature, the detached discovery and the background cleanup. Section 5 now describes the SDK's shutdown order correctly.
25 lines
1.4 KiB
C#
25 lines
1.4 KiB
C#
using System.Text.Json;
|
|
using ModelContextProtocol.Protocol;
|
|
|
|
namespace Volcanic.AgenticCore.Extensions.Mcp;
|
|
|
|
/// <summary>One server tool: the name on the wire, the name the agent sees, and its schema verbatim.</summary>
|
|
internal sealed record McpCatalogTool(string McpName, string ExposedName, string? Description, string? Title, JsonElement InputSchema);
|
|
|
|
/// <summary>A server's <c>tools/list</c> result, discovered once per host process.</summary>
|
|
internal sealed record McpCatalog(string ServerName, string? ServerInfoName, string? ServerVersion, IReadOnlyList<McpCatalogTool> Tools)
|
|
{
|
|
public static McpCatalog From(string serverName, McpServerConfig config, Implementation? info, IReadOnlyList<Tool> tools)
|
|
{
|
|
var exposed = ToolNaming.Expose([.. tools.Select(t => t.Name)], config.ToolPrefix);
|
|
return new McpCatalog(serverName, info?.Name, info?.Version,
|
|
[.. tools.Select((t, i) => new McpCatalogTool(t.Name, exposed[i], t.Description, t.Annotations?.Title ?? t.Title, t.InputSchema.Clone()))]);
|
|
}
|
|
}
|
|
|
|
/// <summary>A server could not be started or didn't answer the handshake. The message includes its stderr tail.</summary>
|
|
internal sealed class McpServerStartException(string message, Exception? inner = null) : Exception(message, inner);
|
|
|
|
/// <summary>A running server exited; the next call starts a new process.</summary>
|
|
internal sealed class McpServerExitedException(string message) : Exception(message);
|