mcp: return page state from click/fill/scroll tools

After click, fill, and scroll actions, return the current page URL
and title instead of static success messages. This gives AI agents
immediate feedback about the page state after an action, matching
the pattern already used by waitForSelector.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Van Horn
2026-03-21 08:32:32 -07:00
parent fdc79af55c
commit 87a0690776

View File

@@ -103,7 +103,7 @@ pub const tool_list = [_]protocol.Tool{
}, },
.{ .{
.name = "click", .name = "click",
.description = "Click on an interactive element.", .description = "Click on an interactive element. Returns the current page URL and title after the click.",
.inputSchema = protocol.minify( .inputSchema = protocol.minify(
\\{ \\{
\\ "type": "object", \\ "type": "object",
@@ -116,7 +116,7 @@ pub const tool_list = [_]protocol.Tool{
}, },
.{ .{
.name = "fill", .name = "fill",
.description = "Fill text into an input element.", .description = "Fill text into an input element. Returns the filled value and current page URL and title.",
.inputSchema = protocol.minify( .inputSchema = protocol.minify(
\\{ \\{
\\ "type": "object", \\ "type": "object",
@@ -130,7 +130,7 @@ pub const tool_list = [_]protocol.Tool{
}, },
.{ .{
.name = "scroll", .name = "scroll",
.description = "Scroll the page or a specific element.", .description = "Scroll the page or a specific element. Returns the scroll position and current page URL and title.",
.inputSchema = protocol.minify( .inputSchema = protocol.minify(
\\{ \\{
\\ "type": "object", \\ "type": "object",
@@ -489,7 +489,13 @@ fn handleClick(server: *Server, arena: std.mem.Allocator, id: std.json.Value, ar
return server.sendError(id, .InternalError, "Failed to click element"); return server.sendError(id, .InternalError, "Failed to click element");
}; };
const content = [_]protocol.TextContent([]const u8){.{ .text = "Clicked successfully." }}; const page_title = page.getTitle() catch null;
const result_text = try std.fmt.allocPrint(arena, "Clicked element (backendNodeId: {d}). Page url: {s}, title: {s}", .{
args.backendNodeId,
page.url,
page_title orelse "(none)",
});
const content = [_]protocol.TextContent([]const u8){.{ .text = result_text }};
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content }); try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
} }
@@ -515,7 +521,14 @@ fn handleFill(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arg
return server.sendError(id, .InternalError, "Failed to fill element"); return server.sendError(id, .InternalError, "Failed to fill element");
}; };
const content = [_]protocol.TextContent([]const u8){.{ .text = "Filled successfully." }}; const page_title = page.getTitle() catch null;
const result_text = try std.fmt.allocPrint(arena, "Filled element (backendNodeId: {d}) with \"{s}\". Page url: {s}, title: {s}", .{
args.backendNodeId,
args.text,
page.url,
page_title orelse "(none)",
});
const content = [_]protocol.TextContent([]const u8){.{ .text = result_text }};
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content }); try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
} }
@@ -546,7 +559,14 @@ fn handleScroll(server: *Server, arena: std.mem.Allocator, id: std.json.Value, a
return server.sendError(id, .InternalError, "Failed to scroll"); return server.sendError(id, .InternalError, "Failed to scroll");
}; };
const content = [_]protocol.TextContent([]const u8){.{ .text = "Scrolled successfully." }}; const page_title = page.getTitle() catch null;
const result_text = try std.fmt.allocPrint(arena, "Scrolled to x: {d}, y: {d}. Page url: {s}, title: {s}", .{
args.x orelse 0,
args.y orelse 0,
page.url,
page_title orelse "(none)",
});
const content = [_]protocol.TextContent([]const u8){.{ .text = result_text }};
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content }); try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
} }
fn handleWaitForSelector(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arguments: ?std.json.Value) !void { fn handleWaitForSelector(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arguments: ?std.json.Value) !void {