Metadata-Version: 2.4
Name: mcpcaller
Version: 1.0.0
Summary: Native CLI for any MCP server.
Author: Daniel Holoubek
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: authlib>=1.7.2
Requires-Dist: filelock>=3.29.0
Requires-Dist: httpx>=0.28.1
Requires-Dist: jsonschema>=4.0
Requires-Dist: keyring>=25.7.0
Requires-Dist: mcp<2,>=1.27
Requires-Dist: platformdirs>=4.9.6
Requires-Dist: pydantic>=2.0
Requires-Dist: rich<16,>=14
Requires-Dist: typer>=0.25.1
Description-Content-Type: text/markdown

# mcpcaller

A stateless CLI that turns any MCP server into a native shell experience. Every
tool becomes a command with typed flags, auto-discovered help, OAuth handled
automatically, and zero JSON-by-hand.

## Install

```bash
uv tool install mcpcaller
# or
pipx install mcpcaller
```

## Quick start

Add a stdio server (the official filesystem server is a good first target):

```bash
mcpcaller add fs -- npx -y @modelcontextprotocol/server-filesystem ~
```

Add a remote HTTP server. If it requires OAuth, your browser opens once and the
token is saved in your OS keychain:

```bash
mcpcaller add prod https://mcp.example.com
```

For headless/CI environments, pass an API token as a static header instead:

```bash
mcpcaller add prod https://mcp.example.com --header "Authorization=Bearer $API_TOKEN"
```

Or use the device-code grant when there's no browser available:

```bash
mcpcaller add prod https://mcp.example.com --device-code
```

List what's available, then call a tool:

```bash
mcpcaller tools                          # all tools on the current server
mcpcaller describe read_file             # full schema for one tool
mcpcaller read_file --path ~/notes.md
```

Resources and prompts are first-class:

```bash
mcpcaller resources
mcpcaller read file:///etc/hosts

mcpcaller prompts
mcpcaller prompt summarise --doc file:///etc/hosts
```

## Calling tools

Each tool's `inputSchema` becomes typed flags automatically. Examples (against a
hypothetical issue tracker):

```bash
mcpcaller search_issues --query "bug" --status open --limit 20
mcpcaller search_issues --tags backend --tags urgent          # repeated arrays
mcpcaller search_issues --tags backend,urgent                  # comma-split arrays
mcpcaller create_issue --title "x" --filter__env prod          # nested objects via __
mcpcaller create_issue --filter '{"env":"prod","sev":"high"}'  # JSON escape hatch

# Read the value from a file (@-) or stdin (@-)
mcpcaller ingest --body @payload.json
echo '{"a":1}' | mcpcaller ingest --body @-
```

Run any tool with `--help` to see its schema-derived flag list:

```bash
mcpcaller search_issues --help
```

## Selecting a server

In order of precedence:

1. Explicit positional: `mcpcaller prod search_issues ...`
2. `--server` flag: `mcpcaller search_issues --server prod ...`
3. `MCPCALLER_SERVER` env var (handy in CI)
4. The current server (`mcpcaller use <name>` to switch)

Run `mcpcaller help selection` for the long version, including how the
positional-vs-tool collision rule works.

## Output

- Default: human-readable, status messages on stderr, data on stdout (so pipes
  work).
- `--json` emits the raw `tools/call` / `resources/read` / `prompts/get` result.
- `--raw` emits only the first text content block, no framing.
- `--quiet` / `-q` suppresses spinners and status lines.
- `--verbose` / `-v` shows wire-level JSON-RPC for debugging.
- `--no-color` disables ANSI colour output (also honours `NO_COLOR`).

## Exit codes

| Code | Meaning |
|---|---|
| 0 | success |
| 1 | tool returned `isError: true` |
| 2 | usage error (bad flag, missing required) |
| 3 | auth error (token invalid, refresh failed) |
| 4 | transport error (server unreachable, schema lock contention) |
| 5 | schema mismatch after refresh |
| ≥64 | server-defined error mapped from JSON-RPC code |

## Auth

OAuth 2.1 with discovery, Dynamic Client Registration, and PKCE. `mcpcaller add`
runs the whole flow if it sees a 401 on the first probe; if you skip it with
`--no-login`, the next call that returns 401 triggers it lazily. Tokens live in
the OS keychain (macOS Keychain / libsecret on Linux / Windows Credential
Manager) with a chmod-600 file fallback for headless setups.

```bash
mcpcaller login <name>           # re-run OAuth (e.g. for a scope change)
mcpcaller logout <name>          # wipe tokens
mcpcaller refresh-token <name>   # force a refresh (debugging)
```

In CI, set `MCPCALLER_TOKEN_<NAME>=<token>` to bypass the keychain entirely. (The
suffix is the server name uppercased with `-` replaced by `_`.)

`mcpcaller help auth` covers the full set of auth modes; `mcpcaller help transports`
covers stdio vs HTTP vs SSE.

## Inspecting servers

```bash
mcpcaller servers                    # what's configured
mcpcaller current                    # which one is the default
mcpcaller use <name>                 # switch the default
mcpcaller status                     # auth + schema state per server
mcpcaller refresh                    # re-fetch schema cache for the current server
mcpcaller refresh --all              # re-fetch everything
mcpcaller search <pattern>           # grep across tool/resource/prompt names + descriptions
```

## Scripting

```bash
# Pipe JSON results through jq:
mcpcaller search_issues --query "bug" --json | jq '.content[0].text'

# Use --raw when you want only the text payload:
mcpcaller get_token --raw | pbcopy

# Pin a server in CI:
MCPCALLER_SERVER=prod mcpcaller list_jobs --json
```

## Develop

```bash
uv sync
uv run pytest
uv run ruff check src/ tests/
uv run ruff format src/ tests/
```

Shell completion:

```bash
mcpcaller completion bash    # or zsh / fish / powershell
```
