Files
browser/src/mcp/resources.zig
2026-02-27 22:17:15 +09:00

102 lines
3.2 KiB
Zig

const std = @import("std");
const McpServer = @import("Server.zig").McpServer;
const protocol = @import("protocol.zig");
const lp = @import("lightpanda");
pub fn handleList(server: *McpServer, req: protocol.Request) !void {
const resources = [_]protocol.Resource{
.{
.uri = "mcp://page/html",
.name = "Page HTML",
.description = "The serialized HTML DOM of the current page",
.mimeType = "text/html",
},
.{
.uri = "mcp://page/markdown",
.name = "Page Markdown",
.description = "The token-efficient markdown representation of the current page",
.mimeType = "text/markdown",
},
};
const result = struct {
resources: []const protocol.Resource,
}{
.resources = &resources,
};
try sendResult(server, req.id.?, result);
}
const ReadParams = struct {
uri: []const u8,
};
pub fn handleRead(server: *McpServer, arena: std.mem.Allocator, req: protocol.Request) !void {
if (req.params == null) {
return sendError(server, req.id.?, -32602, "Missing params");
}
const params = std.json.parseFromValueLeaky(ReadParams, arena, req.params.?, .{}) catch {
return sendError(server, req.id.?, -32602, "Invalid params");
};
if (std.mem.eql(u8, params.uri, "mcp://page/html")) {
var aw = std.Io.Writer.Allocating.init(arena);
lp.dump.root(server.page.document, .{}, &aw.writer, server.page) catch {
return sendError(server, req.id.?, -32603, "Internal error reading HTML");
};
const contents = [_]struct {
uri: []const u8,
mimeType: []const u8,
text: []const u8,
}{.{
.uri = params.uri,
.mimeType = "text/html",
.text = aw.written(),
}};
try sendResult(server, req.id.?, .{ .contents = &contents });
} else if (std.mem.eql(u8, params.uri, "mcp://page/markdown")) {
var aw = std.Io.Writer.Allocating.init(arena);
lp.markdown.dump(server.page.document.asNode(), .{}, &aw.writer, server.page) catch {
return sendError(server, req.id.?, -32603, "Internal error reading Markdown");
};
const contents = [_]struct {
uri: []const u8,
mimeType: []const u8,
text: []const u8,
}{.{
.uri = params.uri,
.mimeType = "text/markdown",
.text = aw.written(),
}};
try sendResult(server, req.id.?, .{ .contents = &contents });
} else {
return sendError(server, req.id.?, -32602, "Resource not found");
}
}
pub fn sendResult(server: *McpServer, id: std.json.Value, result: anytype) !void {
const GenericResponse = struct {
jsonrpc: []const u8 = "2.0",
id: std.json.Value,
result: @TypeOf(result),
};
try server.sendResponse(GenericResponse{
.id = id,
.result = result,
});
}
pub fn sendError(server: *McpServer, id: std.json.Value, code: i64, message: []const u8) !void {
try server.sendResponse(protocol.Response{
.id = id,
.@"error" = protocol.Error{
.code = code,
.message = message,
},
});
}