How it Works

MCP Tools

MCP tools your AI uses to drive a MarcoPolo workspace.

The tools below cover workspace commands, connection discovery, live queries, and demo installation. Almost everything else — testing credentials, inspecting metadata, authoring and running queries, browsing storage, scheduling jobs — happens inside the workspace through the connection CLI and cron, which your AI invokes via workspace_shell.

You don't call these by name. Your AI picks the right one based on what you ask. But understanding them helps when you want more control or need to debug unexpected behavior.

workspace_shell

Runs a command in the remote workspace.

workspace_shell(command, timeout=30)

This is how your AI reads files, writes queries, runs scripts, drives the connection CLI, manages scheduled jobs, and inspects git state. The workspace is a Linux environment at /workspace — anything you can do from a shell, your AI can do here.

You: "Pull last quarter's revenue."

Your AI writes a query file with workspace_shell (heredoc into connections/<name>/queries/<file>.sql), then runs connection query <name> --file ... --json through workspace_shell to execute it.

Each call returns an execution record:

{
  "execution_id": "exec_...",
  "status": "succeeded",
  "exit_code": 0,
  "stdout": "...",
  "stderr": "",
  "failure": null,
  "next_actions": []
}

status is succeeded, failed, or running. When a command fails, failure.kind says why: command_failed, timed_out, or lost.

Long-running commands. timeout is how long the call waits for the command, from 1 to 300 seconds. A command that outlives it keeps running in the background, and the call returns status: "running" with its execution_id. Your AI checks on it later with workspace_shell("execution status <execution_id>"), which returns the record with the final exit code, output, and failure once the command finishes. Every command is stopped after 300 seconds of total runtime, and a workspace runs one background command at a time.

One general-purpose tool keeps the MCP surface small: full Linux semantics, and the workspace becomes the durable surface — not a constantly-shifting MCP API.

connections_list

Lists the connections visible to you in the workspace.

connections_list()
You: "What data do I have access to?"

Your AI calls connections_list and reads the result. Each entry carries the connection itself (name, display_name, connection_type, ownership and sharing details), its capabilities, and its workspace_path. A connection with queryable: false needs provider authorization first; the entry's next_step says what to do. Only query a connection whose capabilities include query.

Your AI passes the connection's name to the connection CLI through workspace_shell.

data_query

Runs a bounded, governed query from a saved query file and returns the rows.

data_query(connection_name, query_file, params=None, max_rows=500)

data_query is for generated code that re-queries live data each time it runs: live artifacts, external web apps, scheduled scripts, and other programs that fetch fresh data on load. For agent-driven analysis and one-off snapshots, your AI uses workspace_shell with connection query instead.

  • query_file is the full workspace-relative path, e.g. connections/<name>/queries/<file>.sql. Paths resolve from /workspace. Your AI authors the file through workspace_shell first, so the query text is durable and reusable.
  • params fills the query's parameters.
  • max_rows caps the rows returned, from 1 to 5000.
{
  "success": true,
  "connection_name": "snowflake-demo",
  "query_file": "connections/snowflake-demo/queries/daily_revenue.sql",
  "rows": [{ ... }, ...],
  "row_count": 30,
  "max_rows": 500,
  "run_id": "...",
  "relation_name": "..."
}

rows is a parsed list of records, and row_count is the total number of rows the query produced.

install_demo_connection

Installs a hosted demo connection directly — no browser flow, no credentials.

install_demo_connection(demo_connection, display_name=None, intent_text=None)

Use this to evaluate MarcoPolo without bringing your own data, or to reproduce a workflow against a known dataset. See Demo Connections for the full catalog and what each demo contains.

You: "Set me up with the Snowflake demo."
AI calls install_demo_connection(demo_connection="snowflake-demo")
   → success: true
   → connection_name: "snowflake-demo"; confirm with connections_list()

If demo_connection is ambiguous or unknown, the response carries available_demo_connections and the AI retries with a specific id.

How the tools fit together

A typical question chains them:

  1. connections_list() — what's available?
  2. workspace_shell("cat connections/<name>/README.md ...") — read the seeded docs.
  3. workspace_shell("connection describe <name> --json") — refresh metadata if stale.
  4. workspace_shell("""cat > connections/<name>/queries/<file>.sql <<'SQL' ...SQL""") — author the query.
  5. workspace_shell("connection query <name> --file ... --json") — execute, materialize into DuckDB.
  6. data_query(...) from a live artifact or app that re-runs the saved query on every load.

install_demo_connection is useful at the start of a workflow, when you want to try a hosted demo. To connect your own data, use the web app.

For verb-level reference (every flag of connection list, connection query, connection browse, scheduling with crontab, etc.), see Connection CLI & cron.

On this page