> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# From MCP

> Install a streamable-HTTP MCP server's tools as one CLI.

An MCP server's tools become one CLI: each tool is a subcommand that takes
the tool's arguments as one JSON object. Profiles, network rules and
snapshots apply to it as to any CLI.

## Register a server

`mcpCli` reads the server's tool list and returns a `CLI`; install it
with `registerCli`, passing the same config:

```ts theme={null}
import { Workspace, mcpCli } from '@struktoai/mirage-node'

const config = {
  url: 'https://mcp.example.com/mcp',
  auth: { type: 'bearer', token: process.env.ISSUES_TOKEN! },
}
const ws = new Workspace({})
ws.registerCli('issues', await mcpCli(config), config)
```

```bash theme={null}
issues --help
issues search-issues --help
issues search-issues '{"query": "login bug"}'
```

A tool named `search_issues` becomes the subcommand `search-issues`; its
`--help` prints the tool's description and the JSON schema of its
arguments. `mcpCli` rejects with `MCPToolsError` when the server cannot be
listed or its tools cannot all become distinct subcommands.

The tool list is read once, at registration. To pick up tools the server
added later, list them again, then remove the CLI and register the new one:

```ts theme={null}
const cli = await mcpCli(config)
await ws.unregisterCli('issues')
ws.registerCli('issues', cli, config)
```

## Authentication

`auth` sets the one header every request carries. Leave it out for a
server that needs none.

| `auth` | Header sent |
| - | - |
| `{ type: 'bearer', token: T }` | `Authorization: Bearer T` |
| `{ type: 'header', name: N, token: T }` | `N: T` |

The token is redacted in snapshots. The URL is saved as written, so keep
credentials in `auth`, not in the URL. A token must be printable ASCII
with no leading or trailing space; any other is refused at registration.

## Register from YAML

An MCP server is a `clis:` entry with `cli: mcp`. The token can come from
`${VAR}` or a [credential pointer](https://docs.mirage.strukto.ai/home/authentication.md):

```yaml workspace.yaml theme={null}
mounts:
  /:
    vfs: ram
clis:
  issues:
    cli: mcp
    config:
      url: https://mcp.example.com/mcp
      auth:
        type: bearer
        token:
          from: env
          key: ISSUES_TOKEN
```

`mirage workspace create workspace.yaml` builds it on the server, and
`configToWorkspaceArgs` lists each server as it loads the file.

## Call a tool

| Call | Result |
| - | - |
| `issues search-issues '{"query": "x"}'` | the tool's answer on stdout, exit 0 |
| `issues list-labels` | the tool called with `{}` |
| the tool reports an error | its text on stderr, exit 1 |
| the server cannot be reached | `search-issues: MCP server failed: <reason>`, exit 1 |
| the server gives no answer within 5 minutes | `search-issues: MCP server timed out`, exit 1 |
| the operand is not one JSON object | `search-issues: invalid JSON`, `JSON must be an object` or `takes one JSON object`, exit 2, nothing sent |

Text content prints as text; any other content prints as one line of
JSON. A failed call is not retried. Cancelling the line cancels the call.

A `preNetwork` policy or a `network` setting that excludes the server's
host refuses the call before anything is sent; a config's `network` also
refuses listing its servers when it loads.

## Profiles

A profile names a tool the way it names any CLI subcommand:

```yaml theme={null}
profiles:
  triage:
    commands:
      deny:
        - commands: ["issues delete-issue"]
          reason: triage never deletes
```

A tool the server marks `readOnlyHint` runs as a read; every other tool
counts as a write.

## On a server

The [server](https://docs.mirage.strukto.ai/typescript/access/server.md) takes `cli: mcp` entries in a
workspace's create body.
[`PUT /v1/workspaces/{id}/clis/{name}`](https://docs.mirage.strukto.ai/home/access/http#install-an-mcp-cli)
installs one on a live workspace, and
[`DELETE`](https://docs.mirage.strukto.ai/home/access/http#remove-an-mcp-cli) removes it. `${VAR}` is
expanded only in files; over HTTP, send the token or a pointer.

## Snapshots

A snapshot keeps the tool list, so loading one rebuilds the CLI without
contacting the server. The token is redacted, so pass the config again as
the fourth argument:

```ts theme={null}
const ws = await Workspace.load('snap.tar', {}, {}, { issues: config })
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.