NAME

App::MCP::CLI::Command::interactive - Agent REPL that routes natural-language queries to MCP tools via a local LLM

VERSION

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

SYNOPSIS

# Start an interactive session against a named server in your config file
mcpcli interactive --server myserver

# Alias: the 'chat' sub-command is identical
mcpcli chat --server myserver

# Use a local Perl script as the server with a custom model
mcpcli interactive --server ./server.pl --model llama3

# Point at an SSE server by URL
mcpcli interactive --server http://localhost:8080/sse

# Override every option explicitly
mcpcli interactive \
    --server   myserver       \
    --provider ollama         \
    --model    qwen2.5:1.5b   \
    --config   /etc/mcp/config.json

DESCRIPTION

App::MCP::CLI::Command::interactive implements the interactive (alias chat) sub-command of the mcpcli application. It starts a Read-Eval-Print Loop (REPL) that:

  1. Connects to the MCP server specified by --server (either as a stdio subprocess or via HTTP/SSE).

  2. Retrieves the full tool catalogue from the server with tools/list.

  3. Enters a prompt loop where each user message is forwarded to a local LLM (currently only Ollama is supported) together with the tool catalogue and a structured JSON dispatch schema.

  4. If the LLM decides to invoke a tool (action: "call_tool"), the command optionally asks the user for confirmation before executing the tools/call request and summarising the raw result via a second LLM call.

  5. If no tool is needed (action: "reply"), the LLM's plain-text answer is printed directly.

Type exit or quit (case-insensitive) at the prompt to end the session.

TRANSPORT MODES

stdio (default)

The server is launched as a child process via IPC::Open2. Messages are exchanged as newline-delimited JSON on its stdin/stdout. This is the simplest mode and works with any compliant MCP server script.

HTTP/SSE

When the resolved server endpoint begins with http:// or https://, or when the config entry contains a url key, the client connects in SSE mode. It opens the event stream with a GET request, reads the endpoint event to learn the POST URL, then sends all JSON-RPC messages as POST requests to that URL. Responses are accepted either in the POST reply body or as message events on the stream. See App::MCP::CLI::Client.

CONFIGURATION FILE

The command accepts a JSON configuration file (--config) with the following optional top-level keys:

mcpServers (object)

A map of server alias names to server descriptor objects. Each descriptor may contain:

command (string) - executable to launch (stdio mode).
args (array of strings) - additional arguments for the executable.
env (object) - environment variables for the launched server only.
url (string) - SSE endpoint URL (SSE mode).
transport (string) - informational ("stdio" or "sse"); a server is SSE when it has a url. "sse" without a url is an error.
confirmTools (boolean, default true)

When true, the agent pauses before executing any tool call and asks the user for explicit confirmation. Set to false to allow autonomous execution.

The configuration file is searched in the following order when --config is not given:

1. ./server_config.json in the current directory.
2. ./mcp-config.json in the current directory.
3. $HOME/.config/mcp-cli/config.json.

Example configuration:

{
  "confirmTools": true,
  "mcpServers": {
    "myserver": {
      "command": "node",
      "args": ["/opt/mcp/server.js"],
      "env": { "DEBUG": "1" }
    },
    "remote": {
      "url": "http://mcp.example.com/sse"
    }
  }
}

OPTIONS

--server|-s name_or_path

The MCP server to connect to (optional when the config file defines exactly one server). Can be:

  • A key in the mcpServers section of the config file.

  • A .pl file path (launched with the current Perl interpreter).

  • An http:// or https:// URL (SSE mode).

  • A bare shell command string (split on whitespace).

--provider|-p name (default: ollama)

The LLM provider to use for query routing and result summarisation. Only ollama is currently supported.

--model|-m name (default: qwen2.5:1.5b)

The Ollama model tag to query. Any model available on the Ollama instance (http://localhost:11434 unless OLLAMA_HOST is set) can be specified.

--config|-c path

Path to a JSON configuration file. See "CONFIGURATION FILE" above.

--timeout|-t seconds

How long to wait for each MCP server reply (default 30; 0 waits forever).

INTERNAL METHODS

command_names

Returns qw(interactive chat) so that the sub-command can be invoked by either name.

opt_spec

Defines the command-line option specification passed to Getopt::Long::Descriptive via App::Cmd.

execute( $opt, $args )

Main entry point. Resolves the server, connects to it, retrieves tools, and runs the agent REPL until the user types exit/quit or sends EOF.

The model's decision is validated before anything is executed: it must be a JSON object, and a requested tool must exist on the server (otherwise the request is ignored with a message). Tool failures (transport errors, JSON-RPC errors, or results flagged isError) are reported and the session continues.

_ollama_url

Returns the Ollama /api/generate URL. The base address defaults to http://localhost:11434 and can be changed with the OLLAMA_HOST environment variable (with or without the http:// prefix).

_ask_llm( $query, $tools )

Sends $query together with the serialised $tools array to the Ollama /api/generate endpoint. The system prompt instructs the model to respond with a bare JSON object in one of two forms:

{ "action": "call_tool", "tool": "<name>", "arguments": { ... } }
{ "action": "reply",     "answer": "<text>" }

Returns the decoded hashref. If the model's output is not a JSON object, or the request fails, a synthetic reply hashref describing the problem (or containing the raw text) is returned instead.

_summarize_with_llm( $query, $result )

Sends the original $query and the raw tool $result text to Ollama and asks for a concise natural-language summary. Returns the summary string, or the raw $result on failure.

DEPENDENCIES

In addition to the core App::MCP::CLI dependencies, this command requires:

  • HTTP::Tiny - for Ollama API calls and SSE transport.

A running Ollama instance on http://localhost:11434 is required for the LLM routing functionality.

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. 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

You can also look for information at:

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.