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);}
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);
}