Something went wrong. Try again.
My version of https://github.com/vercel-labs/fx
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287const std = @import("std");const mcp_contract = @import("mcp_contract.zig");const project_config = @import("project_config.zig");const streamable_http = @import("streamable_http.zig");
const Allocator = std.mem.Allocator;
pub const AddIntent = union(enum) { local: struct { name: []const u8, command: []const u8, args: []const []const u8, }, http: struct { name: []const u8, url: []const u8, },};
pub const AddIntentError = error{ McpAddUsage, McpInvalidServerName, McpConfigInvalidUrl,};
pub const ProfileAddResult = struct { profile_path: []u8, warning: ?mcp_contract.ProfileConfigWarning = null,
pub fn deinit(self: *ProfileAddResult, alloc: Allocator) void { alloc.free(self.profile_path); self.* = undefined; }};
pub const AddProfileServerFn = *const fn ( alloc: Allocator, intent: AddIntent,) anyerror!ProfileAddResult;
pub fn addProfileServerUnavailable( _: Allocator, _: AddIntent,) anyerror!ProfileAddResult { return error.McpProfileMutationUnavailable;}
pub const ProfileRemoveResult = struct { profile_path: []u8, removed: bool, warning: ?mcp_contract.ProfileConfigWarning = null,
pub fn deinit(self: *ProfileRemoveResult, alloc: Allocator) void { alloc.free(self.profile_path); self.* = undefined; }};
pub const RemoveProfileServerFn = *const fn ( alloc: Allocator, name: []const u8,) anyerror!ProfileRemoveResult;
pub fn removeProfileServerUnavailable( _: Allocator, _: []const u8,) anyerror!ProfileRemoveResult { return error.McpProfileMutationUnavailable;}
pub fn parseAddIntent(tokens: []const []const u8) AddIntentError!AddIntent { if (tokens.len == 0) return error.McpAddUsage; if (std.mem.eql(u8, tokens[0], "--transport")) { if (tokens.len != 4 or !std.mem.eql(u8, tokens[1], "http")) { return error.McpAddUsage; } if (!isValidServerName(tokens[2])) return error.McpInvalidServerName; streamable_http.validateEndpoint(tokens[3]) catch return error.McpConfigInvalidUrl; return .{ .http = .{ .name = tokens[2], .url = tokens[3] } }; } if (tokens.len < 2) return error.McpAddUsage; if (!isValidServerName(tokens[0])) return error.McpInvalidServerName; return .{ .local = .{ .name = tokens[0], .command = tokens[1], .args = tokens[2..], } };}
pub fn isValidServerName(name: []const u8) bool { if (name.len == 0) return false; for (name) |byte| { if (std.ascii.isAlphanumeric(byte) or byte == '_' or byte == '-') continue; return false; } return true;}
pub const AuthenticationStart = enum { started, busy,};
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!AuthenticationStart;pub const ValidateAuthenticationServerFn = *const fn ( ctx: *anyopaque, name: []const u8,) anyerror!void;
pub const LogoutResult = struct { busy: bool = false, removed: bool = false, revocation_failed: bool = false, repaired_entries: usize = 0, local_only: 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, project_action: ?project_config.ProjectMcpAction = null,
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);}
test "MCP add intent parses local and HTTP argv without allocation" { const local = try parseAddIntent(&.{ "fixture", "node", "server.js", "--stdio" }); switch (local) { .local => |intent| { try std.testing.expectEqualStrings("fixture", intent.name); try std.testing.expectEqualStrings("node", intent.command); try std.testing.expectEqualSlices([]const u8, &.{ "server.js", "--stdio" }, intent.args); }, .http => return error.TestUnexpectedResult, }
const remote = try parseAddIntent(&.{ "--transport", "http", "docs", "https://example.test/mcp" }); switch (remote) { .local => return error.TestUnexpectedResult, .http => |intent| { try std.testing.expectEqualStrings("docs", intent.name); try std.testing.expectEqualStrings("https://example.test/mcp", intent.url); }, }}
test "MCP add intent rejects invalid syntax names and URLs" { try std.testing.expectError(error.McpAddUsage, parseAddIntent(&.{})); try std.testing.expectError(error.McpAddUsage, parseAddIntent(&.{"only-name"})); try std.testing.expectError( error.McpAddUsage, parseAddIntent(&.{ "--transport", "sse", "docs", "https://example.test/mcp" }), ); try std.testing.expectError( error.McpInvalidServerName, parseAddIntent(&.{ "bad/name", "node" }), ); try std.testing.expectError( error.McpConfigInvalidUrl, parseAddIntent(&.{ "--transport", "http", "docs", "file:///tmp/socket" }), );}