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, ping and logging/setLevel are the methods the modern era removed, so they come back as -32601 METHOD_NOT_FOUND and reach the caller as an X::MCP::Client::Protocol with that code. MCP::Client reads -32601 on initialize as "this is not a legacy server" and on ping as "this server has no ping", both of which are true.

  • Any other method sent without the modern params._meta block fails the version gate with -32022 UNSUPPORTED_PROTOCOL_VERSION, again as an X::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;

MCP::Client v0.6.2

talk to an MCP server, in either protocol era

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

MCP::Server:ver<0.6.0+>:auth<zef:apogee>JSON::Fast:ver<0.21.0+>:auth<zef:timo>Cro::HTTP:ver<0.8.11+>:auth<zef:cro>:api<0>MIME::Base64:ver<1.2.5+>:auth<zef:raku-community-modules>

Test Dependencies

Provides

  • MCP::Client
  • MCP::Client::Cache
  • MCP::Client::Correlator
  • MCP::Client::Exceptions
  • MCP::Client::Leases
  • MCP::Client::Leases::Table
  • MCP::Client::Policy
  • MCP::Client::Policy::Commands
  • MCP::Client::Policy::Floor
  • MCP::Client::Policy::Grants
  • MCP::Client::Policy::Rules
  • MCP::Client::Protocol
  • MCP::Client::Reasons
  • MCP::Client::Registry
  • MCP::Client::SSE
  • MCP::Client::Test::FakeTransport
  • MCP::Client::Test::InProcessTransport
  • MCP::Client::Test::ProgressKit
  • MCP::Client::Test::TestKit
  • MCP::Client::Transport
  • MCP::Client::Transport::HTTP
  • MCP::Client::Transport::Stdio
  • MCP::Client::UnknownKeys

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite — the markup and publishing tools behind this site.