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 whenBRAVE_API_KEY,SERPER_API_KEY, or bothGOOGLE_API_KEY+GOOGLE_CSE_IDare set in the environment. The whole search ends withinfetch_timeout(default 60 s) -- a provider that never answers is a tool error -- and the requests of the default HTTP client stop atfetch_timeoutand afterstall_timeout(default 20 s) without data, as forweb_fetch.allowed_domainskeeps only results on these domains,blocked_domainsdrops results on them; a domain covers its subdomains (example.comcoversdocs.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 timeslimitresults (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. Withoutpromptit returns the URL, the status, the content type and the body, cut atmax_fetch_bytes(default 2_000_000); HTML is flattened to readable text unlessas_htmlis true. Withpromptand ananswercallback the page text (at mostmax_prompt_chars, default 100_000 characters) and the prompt go toanswer, and the tool returns what it answers -- Claude Code's WebFetch, which puts the prompt to a small model. Withoutanswerthe prompt is ignored and the page returned. The body is read in chunks and the request is cancelled oncemax_fetch_bytesis exceeded; a request that exceedsfetch_timeout(default 60 s) or stalls forstall_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'sREDIRECT DETECTEDtext), 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'sThe server returned HTTP ...text -- like Claude Code, not an error result.limitofweb_searchdefaults 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.