NAME

App::MCP::CLI::Client - Transport-neutral MCP client used by all mcpcli sub-commands

VERSION

This module is distributed as part of App::MCP::CLI v0.0.1.

SYNOPSIS

use App::MCP::CLI::Client;
use App::MCP::CLI::Config qw(load_config resolve_server_cmd);

my ($cmd, $url, $env) = resolve_server_cmd(load_config(), 'my-server');

my $client = App::MCP::CLI::Client->new(
    cmd     => $cmd,       # stdio transport, or
    url     => $url,       # HTTP/SSE transport
    env     => $env,
    timeout => 30,
);

$client->connect;                      # initialize + notifications/initialized
my $tools = $client->list_tools;       # arrayref of tool descriptors
my $res   = $client->call_tool('add_numbers', { a => 1, b => 2 });
print content_text($res->{result}) if $res->{result};
$client->close;

DESCRIPTION

App::MCP::CLI::Client hides the differences between the two transports supported by mcpcli behind one small API, so every sub-command gets the same behaviour:

  • Every wait for the server is bounded by a timeout (default 30 seconds).

  • If a stdio server exits unexpectedly, or an SSE stream is closed, a clear error is raised instead of a JSON parse failure.

  • Responses are matched to requests by id. Notifications and log lines sent by the server in between are skipped, and server-initiated ping requests are answered.

  • The initialize request is followed by the notifications/initialized notification, as required by the 2024-11-05 lifecycle.

stdio: the server is started with IPC::Open2; messages are newline-delimited JSON.

HTTP/SSE (protocol revision 2024-11-05): a long-lived GET opens the event stream, the endpoint event announces where to POST, and each response is accepted either in the POST reply body or as a message event on the stream. https:// URLs need IO::Socket::SSL.

All errors are raised with die and a message ending in a newline.

METHODS

new( %args )

Arguments: cmd (arrayref) or url (string); optional env (hashref applied only to the spawned process), timeout (seconds, 0 disables), headers (hashref, SSE only) and client_name.

Set the environment variable MCPCLI_DEBUG to see every JSON-RPC message on STDERR.

is_sse

True when the client talks HTTP/SSE.

server_info

The serverInfo hashref reported by the server (after "connect").

connect

Starts the transport and performs the MCP handshake. Returns the client.

request( $method [, $params] )

Sends a JSON-RPC request and returns the full response hashref (which has either a result or an error key). Dies on timeout or transport failure.

notify( $method [, $params] )

Sends a JSON-RPC notification (no response is expected).

list_tools

Returns an arrayref of every tool the server advertises, following nextCursor pagination. Dies if the server answers with an error.

call_tool( $name, \%arguments )

Sends tools/call and returns the full response hashref.

content_text( $result )

Exported on request. Renders the content blocks of a tools/call result as text: text blocks are returned verbatim, other block types (image, audio, resources) become a short placeholder so that nothing is silently dropped. Falls back to pretty-printed structuredContent when there is no content.

close

Shuts the connection down. For stdio servers, stdin is closed first; a server that has not exited after two seconds is sent SIGTERM, then SIGKILL. Safe to call more than once.

SEE ALSO

AUTHOR

Mohammad Sajid Anwar, <mohammad.anwar at yahoo.com>

REPOSITORY

https://github.com/manwar/App-MCP-CLI

BUGS

Please report any bugs or feature requests through the web interface at https://github.com/manwar/App-MCP-CLI/issues.

LICENSE AND COPYRIGHT

Copyright (C) 2026 Mohammad Sajid Anwar.

This program is free software; you can redistribute it and / or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0