NAME
Langertha::Raider::MCP::Stdio - Internal JSON-RPC over the stdin and stdout of an MCP server process
VERSION
version 0.504
SYNOPSIS
# Internal to Langertha-Raider -- no API promise.
my $wire = Langertha::Raider::MCP::Stdio->new(
loop => $loop,
command => 'npx',
args => [ '-y', '@bytebase/dbhub' ],
env => \%child_env, # the whole environment of the process
cwd => $root,
);
$wire->start;
my $result = await $wire->request_f( 'initialize', { ... } );
$wire->notify( 'notifications/initialized' );
my @last = $wire->stderr_tail;
await $wire->stop_f;
DESCRIPTION
Internal module. Its interface may change without notice.
The stdio transport of a configured MCP server (ADR 0029 §10): the process runs in its own session (setsid, no terminal, so a Ctrl-C of the REPL does not reach it), in "cwd", with exactly "env" as its environment; JSON-RPC messages are lines on its stdin and stdout. Its stderr never reaches raider's terminal: the last "stderr_lines" lines are kept for the status report ("stderr_tail"). Lines on stdout that are not JSON are ignored.
A request the server sends (ping, roots/list, ...) is answered by "on_request"; without one, ping gets an empty result and every other method "Method not found". Notifications from the server are ignored.
Written for raider because the installed Net::Async::MCP::Transport::Stdio takes only a command: no environment, no working directory, and it throws stderr away.
loop
The IO::Async::Loop the process runs on. Required.
command
The program, looked up on PATH by exec. Required.
args
Its arguments. Default none.
env
The whole environment of the process. Default empty.
cwd
Its working directory. Required.
stderr_lines
How many lines of stderr "stderr_tail" keeps. Default 20.
kill_grace
Seconds "stop_f" waits after closing stdin before TERM, and again before KILL. Default 2.
on_request
sub { my ( $method, $params ) = @_; return $result } for requests the server sends; dying answers with an error. Optional.
on_notification
sub { my ( $method, $params ) = @_; ... }, called for every notification the server sends (notifications/tools/list_changed, ...). Optional.
on_exit
sub { my ( $exit_info ) = @_; ... }, called once when the process has ended (see "exited"). Optional.
exited
undef while the process runs (or before "start"), then { code => N, signal => N, error => '...' | undef }.
start
Starts the process. A program that cannot be run ends right away with exit code 127 and the reason on stderr, as a shell would.
pid
The process id (also its process group), or undef.
is_running
True between "start" and the end of the process.
request_f
my $result = await $wire->request_f( 'tools/call', { name => 'x', arguments => {} } );
Sends a request; the future is done with its result, or fails with MCP error CODE: MESSAGE (category mcp, the error object as detail), or with MCP server exited ... when the process ends first. Cancelling the future sends notifications/cancelled.
notify
$wire->notify( 'notifications/initialized' );
Sends a notification; nothing when the process is gone.
stderr_tail
The last lines the process wrote to stderr (at most "stderr_lines", each cut at 500 characters).
exit_text
How the process ended, as a phrase: exited with code 1, killed by signal 9, cannot start: ...; undef while it runs.
stop_f
await $wire->stop_f;
Ends the process the way the MCP specification asks: closes its stdin, sends TERM to its process group after "kill_grace" seconds, KILL after as many again. Done when it has exited.
kill_now
Sends KILL to the process group at once (when the object goes away, or the program ends, before "stop_f" could finish).
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.