mcp: improve error handling in resources and tools

- Handle failures during HTML, Markdown, and link serialization.
- Return MCP internal errors when result serialization fails.
- Refactor resource reading logic for better clarity and consistency.
This commit is contained in:
Adrià Arrufat
2026-03-27 11:28:47 +09:00
parent cdd33621e3
commit c8d8ca5e94
2 changed files with 42 additions and 34 deletions

View File

@@ -205,17 +205,18 @@ const ToolStreamingText = struct {
switch (self.action) {
.markdown => lp.markdown.dump(self.page.document.asNode(), .{}, w, self.page) catch |err| {
log.err(.mcp, "markdown dump failed", .{ .err = err });
return error.WriteFailed;
},
.links => {
if (lp.links.collectLinks(self.page.call_arena, self.page.document.asNode(), self.page)) |links| {
var first = true;
for (links) |href| {
if (!first) try w.writeByte('\n');
try w.writeAll(href);
first = false;
}
} else |err| {
const links = lp.links.collectLinks(self.page.call_arena, self.page.document.asNode(), self.page) catch |err| {
log.err(.mcp, "query links failed", .{ .err = err });
return error.WriteFailed;
};
var first = true;
for (links) |href| {
if (!first) try w.writeByte('\n');
try w.writeAll(href);
first = false;
}
},
.semantic_tree => {
@@ -241,6 +242,7 @@ const ToolStreamingText = struct {
st.textStringify(w) catch |err| {
log.err(.mcp, "semantic tree dump failed", .{ .err = err });
return error.WriteFailed;
};
},
}
@@ -331,7 +333,9 @@ fn handleMarkdown(server: *Server, arena: std.mem.Allocator, id: std.json.Value,
const content = [_]protocol.TextContent(ToolStreamingText){.{
.text = .{ .page = page, .action = .markdown },
}};
try server.sendResult(id, protocol.CallToolResult(ToolStreamingText){ .content = &content });
server.sendResult(id, protocol.CallToolResult(ToolStreamingText){ .content = &content }) catch {
return server.sendError(id, .InternalError, "Failed to serialize markdown content");
};
}
fn handleLinks(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arguments: ?std.json.Value) !void {
@@ -341,7 +345,9 @@ fn handleLinks(server: *Server, arena: std.mem.Allocator, id: std.json.Value, ar
const content = [_]protocol.TextContent(ToolStreamingText){.{
.text = .{ .page = page, .action = .links },
}};
try server.sendResult(id, protocol.CallToolResult(ToolStreamingText){ .content = &content });
server.sendResult(id, protocol.CallToolResult(ToolStreamingText){ .content = &content }) catch {
return server.sendError(id, .InternalError, "Failed to serialize links content");
};
}
fn handleSemanticTree(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arguments: ?std.json.Value) !void {
@@ -363,7 +369,9 @@ fn handleSemanticTree(server: *Server, arena: std.mem.Allocator, id: std.json.Va
.maxDepth = args.maxDepth,
},
}};
try server.sendResult(id, protocol.CallToolResult(ToolStreamingText){ .content = &content });
server.sendResult(id, protocol.CallToolResult(ToolStreamingText){ .content = &content }) catch {
return server.sendError(id, .InternalError, "Failed to serialize semantic tree content");
};
}
fn handleInteractiveElements(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arguments: ?std.json.Value) !void {