NAME

Langertha::Raider::WebTools - MCP::Server factory with web search and fetch tools (Net::Async::WebSearch + Net::Async::HTTP)

VERSION

version 0.504

DESCRIPTION

The web tools of raider: an MCP::Server with web_search and web_fetch, run on the caller's IO::Async::Loop. They answer the way Claude Code's WebSearch and WebFetch do where raider has the same feature (ADR 0026).

build_web_tools_server

my $server = Langertha::Raider::WebTools::build_web_tools_server(
    loop             => $loop,         # required
    max_fetch_bytes  => 2_000_000,
    fetch_timeout    => 60,            # whole web_fetch request or web_search, seconds
    stall_timeout    => 20,            # seconds without data
    answer           => sub { my ( $text ) = @_; ...; return $future_of_text },
    max_prompt_chars => 100_000,       # page text the answer call gets
);

Returns an MCP::Server instance with two tools:

  • web_search(query, [limit], [allowed_domains], [blocked_domains]) -- multi-provider search via Net::Async::WebSearch. DuckDuckGo is always enabled (keyless). Brave, Serper and Google are auto-added when BRAVE_API_KEY, SERPER_API_KEY, or both GOOGLE_API_KEY + GOOGLE_CSE_ID are set in the environment. The whole search ends within fetch_timeout (default 60 s) -- a provider that never answers is a tool error -- and the requests of the default HTTP client stop at fetch_timeout and after stall_timeout (default 20 s) without data, as for web_fetch.

    allowed_domains keeps only results on these domains, blocked_domains drops results on them; a domain covers its subdomains (example.com covers docs.example.com), and an entry may be written as a URL. The filter is applied to the results -- that is the guarantee -- and goes into the query too (site: for a single allowed domain, -site: for each blocked one), and three times limit results (at most 50) are asked for, so filtering still leaves results. Both at once is an error, as in Claude Code.

  • web_fetch(url, [prompt], [as_html]) -- fetch a URL via Net::Async::HTTP. Without prompt it returns the URL, the status, the content type and the body, cut at max_fetch_bytes (default 2_000_000); HTML is flattened to readable text unless as_html is true. With prompt and an answer callback the page text (at most max_prompt_chars, default 100_000 characters) and the prompt go to answer, and the tool returns what it answers -- Claude Code's WebFetch, which puts the prompt to a small model. Without answer the prompt is ignored and the page returned. The body is read in chunks and the request is cancelled once max_fetch_bytes is exceeded; a request that exceeds fetch_timeout (default 60 s) or stalls for stall_timeout (default 20 s) without data is a tool error.

    A redirect is followed (up to 10) only when it stays on the same host (www. aside), scheme and port; one to another host is not fetched: the tool says where it points and how to fetch it (Claude Code's REDIRECT DETECTED text), so the permission rules (WebFetch(domain:...)) see the new host when the model asks for it. A response that is not a success is Claude Code's The server returned HTTP ... text -- like Claude Code, not an error result.

    limit of web_search defaults to 8.

answer gets the whole text for the model call (the page between ---, then the prompt) and returns a Future of the answer text; the application runs it on the run's engine (Langertha::Raider::Application).

Both tools return a tool error, and send nothing, when a module Net::Async::HTTP needs to connect does not load (IO::Async::Internals::Connector; for https IO::Async::SSL, which needs IO::Socket::SSL, Net::SSLeay and the system libssl). The error names the module. For web_fetch that holds for every redirect it follows as well: an http URL that redirects to https on the same host is the same tool error.

ENVIRONMENT

BRAVE_API_KEY

Adds Brave to web_search.

SERPER_API_KEY

Adds Serper to web_search.

GOOGLE_API_KEY

With "GOOGLE_CSE_ID", adds Google Custom Search to web_search.

GOOGLE_CSE_ID

The Custom Search engine id for "GOOGLE_API_KEY".

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests at https://github.com/Getty/langertha-raider/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

https://raudssus.de/