Class: Aspera::Cli::Plugins::Mcp

Inherits:
Base
  • Object
show all
Defined in:
lib/aspera/cli/plugins/mcp.rb

Overview

Plugin to start the MCP (Model Context Protocol) server. The server action accepts an optional Hash argument (extended value) to configure the MCP server and transport.

Supported keys in the options Hash:

transport:              "stdio" (default) or "http"
extra_args:             Array<String> - flags prepended to every ascli call
                      (default: ["--interactive=no", "--transfer.asynchronous=true"])
max_text_bytes:         Integer - max bytes of JSON text content for list results (default 100_000)
# stdio transport:
max_line_bytes:         Integer - max JSON frame size (default 4 MiB)
# http transport:
port:                   Integer - TCP port (default 3000)
bind:                   String  - bind address (default "127.0.0.1")
stateless:              Boolean - stateless mode (default false)
allowed_origins:        Array<String>
allowed_hosts:          Array<String>
session_idle_timeout:   Integer (seconds)
max_sessions:           Integer
# MCP::Server options:
instructions:           String  - hint shown to the AI client
protocol_version:       String  - e.g. "2024-11-05"
validate_tool_call_arguments: Boolean (default true)

Examples:

ascli mcp server
ascli mcp server @json:{"instructions":"Aspera transfers"}
ascli mcp server @json:{"transport":"http","port":3000}
ascli mcp server @json:{"protocol_version":"2024-11-05","max_line_bytes":1048576}

Constant Summary collapse

DEFAULT_INSTRUCTIONS =

Default instructions shown to the AI client when none are provided by the user.

"This is the Aspera CLI (ascli) MCP server (IBM Aspera file transfer and management).\nIt exposes a single tool, execute_ascli_command, which runs any ascli command in-process.\nRefer to the tool description for full syntax, discovery steps, and examples.\n\nKey plugins: aoc (Aspera on Cloud), faspex5 (Faspex 5), node (Node API),\nserver (FASP/SSH server), config (local configuration), console, orchestrator,\nats (Aspera Transfer Service), preview, shares, cos, httpgw, faspio, alee.\n\nRecommended workflow for any task:\n1. Call [\"config\", \"commands\"] to map all 800+ commands to their syntax.\n   Never guess subcommand names from training data \u2014 always verify with this call.\n2. For any command whose syntax shows a <data> argument, call it with \"help\"\n   instead of the real value to see the full field schema before constructing\n   the @json:{...} payload. This is mandatory \u2014 never infer fields from errors.\n2b. For any list command, add --query=help to discover available filter parameters.\n    Example: [\"aoc\", \"admin\", \"user\", \"list\", \"--query=help\"]\n3. Call [\"config\", \"options\", \"<plugin>\"] to list every --flag accepted by a\n   plugin with its allowed values (e.g. --auth=basic|oauth2|..., --url, --preset).\n4. When credentials are already saved, use --preset=name instead of inline\n   credentials. Call [\"config\", \"preset\", \"list\"] to see saved presets.\n\nAUTOMATIC FLAGS\nThe server automatically injects --interactive=no and --transfer.asynchronous=true\nbefore every command. Do NOT add them yourself \u2014 they are already applied.\nIf credentials are missing, the command returns an error; report it and stop.\nThe transfer agent defaults to \"direct\" (in-process ascp). To use the IBM Aspera\nDesktop Client for all transfers, the server can be started with extra_args including\n--transfer.agent=desktop:\n  ascli mcp server @json:{\"extra_args\":[\"--interactive=no\",\"--transfer.asynchronous=true\",\"--transfer.agent=desktop\"]}\n\nCREDENTIAL INTEGRITY\nUse saved presets by default \u2014 do not specify server address or credentials if a\ndefault preset is already configured, unless the user asks otherwise.\nCall [\"config\", \"preset\", \"overview\"] to check available presets.\nSome plugins support web-based authentication: the user logs in via a browser\n(use --auth=web or follow the wizard).\nIf the user explicitly provides credentials inline (--url, --username, --password,\n--private-key), use those exact values verbatim \u2014 never silently substitute a\npreset or a different server. Report errors as-is and stop.\n\nTRANSFER OPTIONS\nAny flags explicitly requested by the user (--transfer.agent=<agent>, --to-folder,\netc.) must be passed verbatim. Never omit or replace them.\nThe agent is selected with \"--transfer.agent=<agent>\" (e.g. \"--transfer.agent=desktop\",\n\"--transfer.agent=direct\", \"--transfer.agent=node\").\nFor a graphical transfer (IBM Aspera Desktop Client), use --transfer.agent=desktop.\nBecause --transfer.asynchronous=true is injected automatically, transfer commands\nreturn a job_id immediately \u2014 never retry a command that already returned one.\nAsync transfer lifecycle:\n  submit  \u2192 e.g. [\"server\", \"download\", \"/file\", \"--to-folder=/tmp\"] \u2192 returns job_id\n  monitor \u2192 [\"config\", \"transfer\", \"status\", \"<job_id>\"]\n  list    \u2192 [\"config\", \"transfer\", \"list\"]\n  cleanup \u2192 [\"config\", \"transfer\", \"cleanup\"]\n\nFILE LIST FOR TRANSFERS\nFor all transfers (upload, download, package send, \u2026), append source file paths\nat the end of the args array \u2014 no --sources flag needed.\n[\"server\", \"upload\", \"--to-folder=/dst\", \"/local/a.txt\", \"/local/b.txt\"]\n[\"aoc\", \"packages\", \"send\", \"@:\", \"name=pkg\", \"[email protected]\", \"END\",\n \"/local/a.txt\", \"/local/b.txt\"]\n".strip

Constants inherited from Base

Base::FILTER_ARGS

Instance Attribute Summary

Attributes inherited from Base

#context, #help_path

Instance Method Summary collapse

Methods inherited from Base

#action_for, #add_manual_header, application_name, #bulk_result, command, command_registry, commands_under, #config, crud_commands, declare_options, define_action_method, #dispatch_child, #dispatch_from_registry, #dispatch_leaf, #entity_create, #entity_delete, entity_display_name, #entity_list, #entity_modify, #entity_res_path, #entity_show, #execute_action, #execute_leaf, file_matcher, #formatter, #generate_help, #http_config, #initialize, #invoke_action, option, #options, #persistency, #presets, #progress_bar, #query_read_delete, #resolve_argument, root_setup, #transfer, use_options, used_option_sources

Constructor Details

This class inherits a constructor from Aspera::Cli::Plugins::Base

Instance Method Details

#action_server(mcp_options: nil) ⇒ Object

Raises:



123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/aspera/cli/plugins/mcp.rb', line 123

def action_server(mcp_options: nil, **)
  require 'aspera/cli/mcp_tool'
  mcp_options = (mcp_options || {}).transform_keys(&:to_sym)
  unknown = mcp_options.keys - SERVER_KEYS - CONFIG_KEYS - STDIO_KEYS - HTTP_KEYS - TOOL_KEYS - i[transport port bind]
  Aspera.assert(unknown.empty?, type: Cli::BadArgument) { "Unknown MCP option(s): #{unknown.join(', ')}" }
  Cli::McpTool.max_text_bytes = mcp_options.delete(:max_text_bytes)
  Cli::McpTool.extra_args     = mcp_options.delete(:extra_args)
  transport = mcp_options.delete(:transport) || 'stdio'
  raise Cli::BadArgument, "Unknown transport: #{transport}. Use 'stdio' or 'http'" \
    unless %w[stdio http].include?(transport.to_s)
  Log.log.info { "Starting MCP server (transport=#{transport})..." }
  start_mcp_server(transport: transport.to_sym, mcp_options: mcp_options)
  Result::Nothing.new
end