App-Raider
view release on metacpan or search on metacpan
lib/App/Raider/WebTools.pm view on Meta::CPAN
package App::Raider::WebTools;
our $VERSION = '0.003';
# ABSTRACT: MCP::Server factory with web search and fetch tools (Net::Async::WebSearch + Net::Async::HTTP)
use strict;
use warnings;
use Future::AsyncAwait;
use HTTP::Request::Common qw( GET );
use MCP::Server;
use Net::Async::HTTP;
use Net::Async::WebSearch;
use Net::Async::WebSearch::Provider::DuckDuckGo;
use Net::Async::WebSearch::Provider::Brave;
use Net::Async::WebSearch::Provider::Serper;
use Net::Async::WebSearch::Provider::Google;
use HTML::TreeBuilder;
use Exporter 'import';
our @EXPORT_OK = qw( build_web_tools_server );
sub _flatten_html {
my ($html) = @_;
my $t = HTML::TreeBuilder->new_from_content($html);
$_->delete for $t->look_down(_tag => qr/^(?:script|style|noscript)$/);
my $text = $t->as_text;
$t->delete;
$text =~ s/[ \t]+/ /g;
$text =~ s/\n{3,}/\n\n/g;
return $text;
}
sub build_web_tools_server {
my %args = @_;
my $loop = $args{loop} or die "loop is required\n";
my $max_fetch_bytes = $args{max_fetch_bytes} // 2_000_000;
my $http = Net::Async::HTTP->new(
user_agent => 'raider/0.001',
max_in_flight => 4,
);
$loop->add($http);
my $ws = Net::Async::WebSearch->new(http => $http);
$loop->add($ws);
$ws->add_provider(Net::Async::WebSearch::Provider::DuckDuckGo->new);
if ($ENV{BRAVE_API_KEY}) {
$ws->add_provider(Net::Async::WebSearch::Provider::Brave->new(
api_key => $ENV{BRAVE_API_KEY},
));
}
if ($ENV{SERPER_API_KEY}) {
$ws->add_provider(Net::Async::WebSearch::Provider::Serper->new(
api_key => $ENV{SERPER_API_KEY},
));
}
if ($ENV{GOOGLE_API_KEY} && $ENV{GOOGLE_CSE_ID}) {
$ws->add_provider(Net::Async::WebSearch::Provider::Google->new(
api_key => $ENV{GOOGLE_API_KEY},
cx => $ENV{GOOGLE_CSE_ID},
));
}
my $server = MCP::Server->new(name => 'app-raider-web', version => '1.0');
$server->tool(
( run in 1.268 second using v1.01-cache-2.11-cpan-acf6aa7dc9e )