mcp: handle errors during resource and tool streaming

This commit is contained in:
Adrià Arrufat
2026-03-01 20:23:23 +09:00
parent 947e672d18
commit b3d52c966d
2 changed files with 23 additions and 16 deletions

View File

@@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const lp = @import("lightpanda"); const lp = @import("lightpanda");
const log = lp.log;
const protocol = @import("protocol.zig"); const protocol = @import("protocol.zig");
const Server = @import("Server.zig"); const Server = @import("Server.zig");
@@ -58,8 +59,12 @@ const ResourceStreamingResult = struct {
try jw.writer.writeByte('"'); try jw.writer.writeByte('"');
var escaped = protocol.JsonEscapingWriter.init(jw.writer); var escaped = protocol.JsonEscapingWriter.init(jw.writer);
switch (self.format) { switch (self.format) {
.html => try lp.dump.root(self.server.page.document, .{}, &escaped.writer, self.server.page), .html => lp.dump.root(self.server.page.document, .{}, &escaped.writer, self.server.page) catch |err| {
.markdown => try lp.markdown.dump(self.server.page.document.asNode(), .{}, &escaped.writer, self.server.page), log.err(.mcp, "html dump failed", .{ .err = err });
},
.markdown => lp.markdown.dump(self.server.page.document.asNode(), .{}, &escaped.writer, self.server.page) catch |err| {
log.err(.mcp, "markdown dump failed", .{ .err = err });
},
} }
try jw.writer.writeByte('"'); try jw.writer.writeByte('"');
jw.endWriteRaw(); jw.endWriteRaw();
@@ -79,7 +84,7 @@ pub fn handleRead(server: *Server, arena: std.mem.Allocator, req: protocol.Reque
}; };
if (std.mem.eql(u8, params.uri, "mcp://page/html")) { if (std.mem.eql(u8, params.uri, "mcp://page/html")) {
const result = ResourceStreamingResult{ const result: ResourceStreamingResult = .{
.contents = &.{.{ .contents = &.{.{
.uri = params.uri, .uri = params.uri,
.mimeType = "text/html", .mimeType = "text/html",
@@ -88,7 +93,7 @@ pub fn handleRead(server: *Server, arena: std.mem.Allocator, req: protocol.Reque
}; };
try sendResult(server, req.id.?, result); try sendResult(server, req.id.?, result);
} else if (std.mem.eql(u8, params.uri, "mcp://page/markdown")) { } else if (std.mem.eql(u8, params.uri, "mcp://page/markdown")) {
const result = ResourceStreamingResult{ const result: ResourceStreamingResult = .{
.contents = &.{.{ .contents = &.{.{
.uri = params.uri, .uri = params.uri,
.mimeType = "text/markdown", .mimeType = "text/markdown",

View File

@@ -126,21 +126,23 @@ const ToolStreamingText = struct {
var escaped = protocol.JsonEscapingWriter.init(jw.writer); var escaped = protocol.JsonEscapingWriter.init(jw.writer);
const w = &escaped.writer; const w = &escaped.writer;
switch (self.action) { switch (self.action) {
.markdown => try lp.markdown.dump(self.server.page.document.asNode(), .{}, w, self.server.page), .markdown => lp.markdown.dump(self.server.page.document.asNode(), .{}, w, self.server.page) catch |err| {
log.err(.mcp, "markdown dump failed", .{ .err = err });
},
.links => { .links => {
const list = Selector.querySelectorAll(self.server.page.document.asNode(), "a[href]", self.server.page) catch |err| { if (Selector.querySelectorAll(self.server.page.document.asNode(), "a[href]", self.server.page)) |list| {
log.err(.mcp, "Error querying links: {s}", .{@errorName(err)}); var first = true;
return; for (list._nodes) |node| {
}; if (node.is(Element)) |el| {
var first = true; if (el.getAttributeSafe(String.wrap("href"))) |href| {
for (list._nodes) |node| { if (!first) try w.writeByte('\n');
if (node.is(Element)) |el| { try w.writeAll(href);
if (el.getAttributeSafe(String.wrap("href"))) |href| { first = false;
if (!first) try w.writeByte('\n'); }
try w.writeAll(href);
first = false;
} }
} }
} else |err| {
log.err(.mcp, "query links failed", .{ .err = err });
} }
}, },
} }