mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 12:44:43 +00:00
mcp: add Model Context Protocol server support
Adds a new `mcp` run mode to start an MCP server over stdio. Implements tools for navigation and JS evaluation, along with resources for HTML and Markdown page content.
This commit is contained in:
97
src/mcp/resources.zig
Normal file
97
src/mcp/resources.zig
Normal file
@@ -0,0 +1,97 @@
|
||||
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);
|
||||
try lp.dump.root(server.page.window._document, .{}, &aw.writer, server.page);
|
||||
|
||||
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);
|
||||
try lp.markdown.dump(server.page.window._document.asNode(), .{}, &aw.writer, server.page);
|
||||
|
||||
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,
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user