NAME
App::MCP::CLI::Config - Configuration loader and server resolver for App::MCP::CLI
VERSION
This module is distributed as part of App::MCP::CLI v0.0.1.
SYNOPSIS
use App::MCP::CLI::Config qw(load_config resolve_server_cmd);
# Load config from an explicit path, or auto-discover
my $config = load_config('/path/to/server_config.json');
my $config = load_config(); # auto-discovers
# Resolve a named server to a command array (stdio) or URL (SSE)
my ($cmd, $url, $env) = resolve_server_cmd($config, 'perl-math-server');
if ($url) {
# SSE transport
}
else {
# stdio transport - see App::MCP::CLI::Client, which spawns @$cmd
# with %$env applied to the child only
}
DESCRIPTION
App::MCP::CLI::Config is the shared configuration layer for all App::MCP::CLI sub-commands. It provides two exported functions:
"load_config" - reads and parses the JSON configuration file, with automatic discovery of well-known paths when no explicit path is given.
"resolve_server_cmd" - maps a server name (or bare command string, script path, or URL) to either a command array for stdio transport or a URL for SSE transport.
Centralising this logic here means that call, list, interactive, and any future sub-commands all share identical config-loading and server-resolution behaviour.
CONFIGURATION FILE FORMAT
The JSON configuration file has the following top-level structure:
{
"confirmTools": true,
"mcpServers": {
"perl-math-server": {
"command": "perl",
"args": ["stdio_server.pl"],
"env": { "DEBUG": "1" }
},
"remote-server": {
"url": "http://mcp.example.com/sse"
}
}
}
mcpServers
A JSON object whose keys are server alias names and whose values are server descriptor objects. Each descriptor supports the following fields:
command(string)-
The executable to launch when using stdio transport (e.g.
"perl","node"). Required for stdio servers. args(array of strings)-
Additional command-line arguments passed to
command(e.g.["stdio_server.pl"]). Defaults to an empty list. env(object)-
A map of environment variable names to values. The entries are passed to the server subprocess only; they are never set in the
mcpcliprocess itself. url(string)-
The SSE endpoint URL for remote servers (e.g.
"http://mcp.example.com/sse"). When present, the server is contacted via HTTP/SSE instead of a local subprocess. transport(string)-
Informational (
"stdio"or"sse"). A server is treated as SSE when it has aurl.transport: "sse"without aurlis rejected with an error.
confirmTools
Optional boolean (default true). When set to false, the interactive/chat command executes tool calls autonomously without pausing to ask the user for confirmation.
AUTO-DISCOVERY
When "load_config" is called without an argument (or with undef), it searches for a configuration file in the following locations, in order:
- 1.
./server_config.json- in the current working directory. - 2.
./mcp-config.json- in the current working directory. - 3.
$HOME/.config/mcp-cli/config.json- XDG-style user config ($USERPROFILEis used as the home directory on Windows).
If none of these paths exist, load_config returns undef and the caller must fall back to other means of locating the server (e.g. a bare --server command string).
EXPORTS
Nothing is exported by default. The following functions may be imported explicitly:
use App::MCP::CLI::Config qw(load_config resolve_server_cmd);
FUNCTIONS
load_config
Signature: load_config( [$path] ).
my $config = load_config();
my $config = load_config('/path/to/server_config.json');
Loads and parses the JSON configuration file at $path. If $path is omitted or undef, the auto-discovery sequence described in "AUTO-DISCOVERY" is used.
Returns a hashref on success, or undef when no path was given and no well-known file exists. When a path is given explicitly, a missing or unreadable file, or invalid JSON, is a fatal error (die), so typos in --config are never silently ignored. A discovered file that cannot be parsed only produces a warning on STDERR and undef.
Informational messages are written to STDERR so that STDOUT stays clean for piping.
resolve_server_cmd
Signature: resolve_server_cmd( $config, $server_input ).
my ($cmd, $url, $env) = resolve_server_cmd($config, 'perl-math-server');
my ($cmd, $url, $env) = resolve_server_cmd($config, 'http://localhost/sse');
my ($cmd, $url, $env) = resolve_server_cmd($config, 'perl stdio_server.pl');
my ($cmd, $url, $env) = resolve_server_cmd($config); # sole configured server
Resolves $server_input to a transport endpoint. $config is the hashref returned by "load_config" (may be undef).
Resolution order:
- 1. If
$server_inputis empty orundef: when the configuration defines exactly one server, that server is used; otherwise this is a fatal error that lists the available names. - 2. If
$configcontains a matchingmcpServersentry, that descriptor is used. A descriptor with aurlis an SSE server. One whosetransportisssebut which has nourl, or one with neitherurlnorcommand, is a fatal error with an explanatory message. - 3. If
$server_inputlooks like an HTTP(S) URL, SSE mode is selected. - 4. If
$server_inputends in.pland the file exists, it is run with the current Perl interpreter ($^X). - 5. Otherwise,
$server_inputis split on whitespace and used as a raw command list.
Return value is a three-element list ($cmd, $url, $env):
For stdio servers:
$cmdis an arrayref of command + arguments suitable for passing toIPC::Open2::open2;$urlisundef.For SSE servers:
$urlis the endpoint URL string;$cmdisundef.$envis a hashref of extra environment variables from the descriptor'senvblock (empty when there is none). It is not applied to the current process; App::MCP::CLI::Client sets it for the spawned server only, so variables never leak from one server to another.
SEE ALSO
JSON::MaybeXS - JSON parser used internally.
File::Spec - used for portable config path construction.
MCP specification: https://spec.modelcontextprotocol.io/
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. I will be notified and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc App::MCP::CLI::Config
You can also look for information at:
BUG Report
Search MetaCPAN
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
Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License.By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.
If your Modified Version has been derived from a Modified Version made by someone other than you,you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.
This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement,then this Artistic License to you shall terminate on the date that such litigation is filed.
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.