MCP::Client::Test::InProcessTransport
NAME
MCP::Client::Test::InProcessTransport - drive a live MCP::Server with no wire
DESCRIPTION
A transport whose "server" is an MCP::Server object in this very process.
Requests are handed to handle-modern-request, the seam
MCP::Server::HTTP uses, and its response is turned back into the promise
MCP::Client expects ā JSON-RPC error to X::MCP::Client::Protocol, result
through normalize-result, notifications to &on-notification.
That makes it the cheapest possible contract test: real server code, real
result envelopes, real cache metadata, real error codes, and not one subprocess,
socket or serialisation step in the way. What it cannot test is the wire itself
ā framing, line splitting, a server that dies ā which is what the spawned
fixture in t/08 and t/09 is for.
Modern era only
handle-modern-request forces the modern era (see its documentation in
MCP::Server): it does not sniff the message, it declares it. So a legacy-era
request sent through this transport is answered the way a 2026-07-28 server
answers one, which is to say it fails cleanly:
initialize,pingandlogging/setLevelare the methods the modern era removed, so they come back as-32601 METHOD_NOT_FOUNDand reach the caller as anX::MCP::Client::Protocolwith that code.MCP::Clientreads-32601oninitializeas "this is not a legacy server" and onpingas "this server has no ping", both of which are true.Any other method sent without the modern
params._metablock fails the version gate with-32022 UNSUPPORTED_PROTOCOL_VERSION, again as anX::MCP::Client::Protocol.
Nothing hangs and nothing throws an untyped exception, but a client that is pushed down the legacy path against this transport will fail its handshake. Use the spawned fixture for legacy coverage.
EXAMPLES
use MCP::Server;
use MCP::Client;
use MCP::Client::Test::InProcessTransport;
use MCP::Client::Test::TestKit;
my $server = MCP::Server.new(:name<contract>, :version<1.0.0>);
$server.plug(MCP::Client::Test::TestKit.new);
my $wire = MCP::Client::Test::InProcessTransport.new(server => $server);
my $client = MCP::Client.new(transport => $wire, log-level => 'info');
is $client.era, 'modern';
is $client.call-tool('echo', { text => 'hi' })<content>[0]<text>, 'hi';
is $wire.requests-for('tools/call').elems, 1;