NAME
Langertha::Raider::MCP::Server - Internal client of one configured MCP server, mounted as an engine MCP server
VERSION
version 0.504
SYNOPSIS
# Internal to Langertha-Raider -- no API promise.
my $server = Langertha::Raider::MCP::Server->new(
spec => $mcp_config->server('github'), # an entry of Langertha::Raider::MCP::Config
loop => $loop,
);
await $server->initialize; # never fails: status connected or failed
say $server->status.': '.( $server->reason // '' );
my $tools = await $server->list_tools; # names mcp__github__*
my $result = await $server->call_tool( 'mcp__github__create_issue', \%args );
await $server->stop_f;
DESCRIPTION
Internal module. Its interface may change without notice.
One configured MCP server (ADR 0029 §10) as raider mounts it: an object that answers initialize, list_tools and call_tool like Net::Async::MCP, so it is one more entry of the engine's mcp_servers and Langertha::Raider calls it as it calls every other.
Start. "start_f" (and "initialize") connects once: the transport (Langertha::Raider::MCP::Stdio or Langertha::Raider::MCP::HTTP), the
initializehandshake, thenotifications/initializednotification and the tool list, all within "startup_timeout_ms". It never fails: "status" becomesconnected, orfailedwith "reason"; a stdio process of a failed start is stopped.Protocol. Raider speaks the established handshake of the MCP revisions 2024-11-05 to 2025-11-25: it asks for "client_protocol_version" and accepts any revision of "known_protocol_versions" the server answers with. The stateless 2026-07-28 revision (
server/discover) is not spoken; a server that knows only that one fails with a reason that says so. The installed Net::Async::MCP speaks only that revision, which is why raider has its own client here (ADR 0029).Tools. The server's tools are listed once, at the start, under the names the model sees:
mcp__KEY__TOOLwith the tool part normalised ("tool_name" in Langertha::Raider::MCP::Config). Two tools that normalise to the same name: the first is kept. "call_tool" sends the original name.Calls are bounded by the server's
timeout_ms(itstimeout, elseMCP_TOOL_TIMEOUT); a call that runs out is cancelled (notifications/cancelled) and fails. A result keeps what the server sent, except_metakeys underraider/: a foreign server cannot hand the raider instructions through them (Langertha::Raider takes user messages from_meta.raider/messagesof its own sources).
spec
The server's entry of "servers" in Langertha::Raider::MCP::Config. Required.
loop
The IO::Async::Loop. Required.
startup_timeout_ms
How long the start may take, in milliseconds. Default 30000.
base_env
The environment a stdio server inherits (before its own env). Default a copy of %ENV.
kill_grace
Seconds between closing a stdio server's stdin, TERM and KILL. Default 2.
on_status
sub { my ( $server ) = @_; ... }, called whenever "status" changes. Optional.
max_output_tokens
How many tokens (about four characters each) of a tool result's text raider passes on; more is cut with a note (ADR 0029 Addendum 1). Default 25000 (MAX_MCP_OUTPUT_TOKENS).
on_tools_changed
sub { my ( $server ) = @_; ... }, called when the server announced notifications/tools/list_changed, at once: the tools are listed again in the background, and "list_tools" waits for that. Optional.
status
configured before the start, starting, then connected or failed; stopped after "stop_f".
reason
Why it failed (or stopped), with the last stderr line of a stdio server.
protocol_version
The revision the server answered with.
server_info
The server's serverInfo (name, version), or {}.
instructions
The server's instructions, or undef.
warnings
What went wrong without stopping the server: a tool dropped because its name collides, ...
name
key
transport
The server's name, key and transport from "spec".
client_protocol_version
The revision raider asks for in initialize: 2025-11-25.
known_protocol_versions
The revisions raider accepts in the answer: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05. They differ in features raider does not use; the handshake, tools/list and tools/call are the same in all of them.
fingerprint
What the server is started with, as one string: the transport, the command, arguments, working and project directory and the whole environment of a stdio server, the URL and headers of an HTTP one, the tool prefix and the call timeout. Two clients with the same fingerprint talk to the same thing (/reload keeps such a client).
pid
The process id of a running stdio server, else undef.
stderr_tail
The last lines a stdio server wrote to stderr.
child_env
The environment a stdio server is started with: "base_env" without inherited CLAUDE_PLUGIN_ROOT / CLAUDE_PLUGIN_DATA, then the entry's env, then CLAUDE_PROJECT_DIR (the project dir, as Claude Code sets it) and, for a plugin's server, its CLAUDE_PLUGIN_ROOT and CLAUDE_PLUGIN_DATA.
start_f
await $server->start_f;
Connects once (see "DESCRIPTION"); every later call returns the same future. Never fails.
initialize
The same as "start_f", under the name Langertha::Raider::Application calls on every engine MCP server before a raid.
tool_names
The names the model sees (mcp__KEY__TOOL), in the server's order.
original_name
my $name = $server->original_name('mcp__github__create_issue'); # create_issue
The tool's name on the server, or undef for a name it does not offer.
list_tools
my $tools = await $server->list_tools;
The tools under their prefixed names (after the start; empty unless connected), each a copy of the server's definition. While the server's answer to a notifications/tools/list_changed is being fetched, it waits for it.
call_tool
my $result = await $server->call_tool( 'mcp__github__create_issue', \%args );
Calls the tool by its original name, bounded by timeout_ms of the "spec". Fails when the server is not connected, the name is unknown, the server answers with a JSON-RPC error, the process is gone or the time is up (MCP tool call timed out after N s).
limit_content
my $content = $server->limit_content( $result->{content}, $is_error );
The content blocks of a tool result with their text held to "max_output_tokens" (four characters count as a token, as a rough estimate): text over the limit is cut and a note block says how much there was and how to raise the limit. A result with an image block is passed on as it is, as Claude Code does not cut it either. An error result whose text is over about 11000 characters keeps its first and last 5000, with a marker between them that says how many characters were removed (Claude Code's rule). Claude Code saves the whole text to a file and names the path; raider keeps no such file and cuts.
has_prompts
has_resources
True when the connected server announced the prompts / resources capability.
list_prompts_f
my $prompts = await $server->list_prompts_f; # [ { name, description, arguments => [ { name, required } ] } ]
The server's prompts, listed on first use and again after notifications/prompts/list_changed. Empty unless connected; a failing prompts/list is an empty list.
get_prompt_f
my $prompt = await $server->get_prompt_f( 'pr_review', { number => '456' } );
# { description => ..., messages => [ { role => 'user', content => { type => 'text', text => ... } } ] }
prompts/get, with the same call timeout as a tool. Fails when the server is not connected or answers with an error.
list_resources_f
my $resources = await $server->list_resources_f; # [ { uri, name, mimeType, description } ]
The server's resources (resources/list), cached like the prompts; ui:// resources and those of media type text/html;profile=mcp-app are left out (Claude Code does the same).
read_resource_f
my $contents = await $server->read_resource_f('file:///a'); # [ { uri, mimeType, text | blob } ]
resources/read.
stop_f
await $server->stop_f;
Stops the server: a stdio process as "stop_f" in Langertha::Raider::MCP::Stdio, an HTTP session with DELETE. Status stopped.
kill_now
Kills a stdio process at once.
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.