146 lines · 4.3 KB · Zig
RawDownload
const std = @import("std");const mcp_auth = @import("mcp_auth.zig"); const Allocator = std.mem.Allocator; pub const ListServersFn = *const fn (ctx: *anyopaque, alloc: Allocator) anyerror![]u8;pub const SummarizeServersFn = *const fn (ctx: *anyopaque, alloc: Allocator) anyerror![]u8;pub const AuthenticateServerFn = *const fn (    ctx: *anyopaque,    name: []const u8,) anyerror!mcp_auth.AuthenticationResult;pub const ValidateAuthenticationServerFn = *const fn (    ctx: *anyopaque,    name: []const u8,) anyerror!void; pub const LogoutResult = struct {    removed: bool = false,    revocation_failed: bool = false,}; pub const LogoutServerFn = *const fn (    ctx: *anyopaque,    name: []const u8,) anyerror!LogoutResult; pub const ListResourcesFn = *const fn (    ctx: *anyopaque,    alloc: Allocator,    server_name: []const u8,    include_templates: bool,) anyerror![]u8;pub const ReadResourceFn = *const fn (    ctx: *anyopaque,    alloc: Allocator,    server_name: []const u8,    uri: []const u8,) anyerror![]u8;pub const ListPromptsFn = *const fn (    ctx: *anyopaque,    alloc: Allocator,    server_name: []const u8,) anyerror![]u8;pub const GetPromptFn = *const fn (    ctx: *anyopaque,    alloc: Allocator,    server_name: []const u8,    prompt_name: []const u8,    arguments_json: []const u8,) anyerror![]u8;pub const CompletePromptFn = *const fn (    ctx: *anyopaque,    alloc: Allocator,    server_name: []const u8,    prompt_name: []const u8,    argument_name: []const u8,    value: []const u8,) anyerror![]u8;pub const CompleteResourceFn = *const fn (    ctx: *anyopaque,    alloc: Allocator,    server_name: []const u8,    uri_template: []const u8,    variable_name: []const u8,    value: []const u8,) anyerror![]u8; pub const Request = struct {    home: ?[]const u8,    list_ctx: *anyopaque,    summarize_servers: ?SummarizeServersFn = null,    list_servers_and_tools: ListServersFn,    auth_ctx: ?*anyopaque = null,    validate_authentication_server: ?ValidateAuthenticationServerFn = null,    authenticate_server: ?AuthenticateServerFn = null,    logout_server: ?LogoutServerFn = null,    feature_ctx: ?*anyopaque = null,    list_resources: ?ListResourcesFn = null,    read_resource: ?ReadResourceFn = null,    list_prompts: ?ListPromptsFn = null,    get_prompt: ?GetPromptFn = null,    complete_prompt: ?CompletePromptFn = null,    complete_resource: ?CompleteResourceFn = null,}; pub const Display = union(enum) {    block: []u8,    line: []u8,}; /// Owns the selected display text. `deinit` releases it with the allocator/// supplied to the provider.pub const Result = struct {    display: Display,    reload: bool = false,    report_reload: bool = false,     pub fn deinit(self: Result, alloc: Allocator) void {        switch (self.display) {            .block => |text| alloc.free(text),            .line => |text| alloc.free(text),        }    }}; pub const HandleFn = *const fn (alloc: Allocator, rest: []const u8, request: Request) anyerror!Result; pub const Provider = struct {    handle_fn: HandleFn,     pub fn handle(self: Provider, alloc: Allocator, rest: []const u8, request: Request) !Result {        return self.handle_fn(alloc, rest, request);    }}; test "MCP command provider delegates requests and returns owned display text" {    const Fixture = struct {        fn list(_: *anyopaque, alloc: Allocator) ![]u8 {            return alloc.dupe(u8, "servers\n");        }         fn handle(alloc: Allocator, rest: []const u8, request: Request) !Result {            try std.testing.expectEqualStrings("list", rest);            return .{                .display = .{                    .block = try request.list_servers_and_tools(request.list_ctx, alloc),                },            };        }    };     var list_context: u8 = 0;    const provider = Provider{ .handle_fn = Fixture.handle };    const result = try provider.handle(std.testing.allocator, "list", .{        .home = null,        .list_ctx = @ptrCast(&list_context),        .list_servers_and_tools = Fixture.list,    });    defer result.deinit(std.testing.allocator);     switch (result.display) {        .block => |text| try std.testing.expectEqualStrings("servers\n", text),        .line => return error.TestExpectedEqual,    }    try std.testing.expect(!result.reload);}