Skip to main content
Glama
README.md
# cli-agent-mcp

[中文文档](README_zh.md)

Unified MCP (Model Context Protocol) server for CLI AI agents. Provides a single interface to invoke Codex, Gemini, Claude, OpenCode CLI tools, and Nano Banana Pro image generation.

## Why cli-agent-mcp?

This is more than a CLI wrapper — it's an **orchestration pattern** for multi-model collaboration.

**Can't articulate your requirements clearly?** Let Claude orchestrate. Describe what you want, and it will decompose your vague idea into concrete tasks for the right agent. The act of delegation forces clarity.

**Planning a grand product vision?** Each model brings a unique lens:
- **Codex**: The critic. Its analytical eye catches what you missed, challenges assumptions, finds edge cases.
- **Gemini**: The creative. Divergent thinking, unexpected connections, the spark you didn't know you needed.
- **Claude**: The scribe. Faithful execution, clear documentation, turning ideas into working code.
- **Banana**: The artist. High-fidelity image generation for UI mockups, product visuals, and creative assets.

**Want persistent results?** Use `handoff_file` to capture agent outputs, then let Claude synthesize insights across multiple analyses.

We don't just wrap CLIs — we provide a **thinking framework** for human-AI collaboration.

## Features

- **Unified Interface**: Single MCP server exposing multiple CLI agents
- **GUI Dashboard**: Real-time task monitoring with pywebview
- **Request Isolation**: Per-request execution context for safe concurrent usage
- **Signal Handling**: Graceful cancellation via SIGINT without killing the server
- **Debug Logging**: Comprehensive subprocess output capture for debugging

## Screenshot

![CLI Agent MCP GUI](dev-docs/screenshot/screenshot.png)

## Installation

```bash
# Install from PyPI (when published)
uvx cli-agent-mcp

# Install from GitHub
uvx --from git+https://github.com/shiharuharu/cli-agent-mcp.git cli-agent-mcp

# Install from source (editable mode for development)
uvx --from /path/to/cli-agent-mcp cli-agent-mcp

# Or use pip
pip install -e .
```

## Configuration

Configure via environment variables:

| Variable | Description | Default |
|----------|-------------|---------|
| `CAM_ENABLE` | Comma-separated list of enabled tools (empty = all) | `""` (all) |
| `CAM_DISABLE` | Comma-separated list of disabled tools (subtracted from enable) | `""` |
| `CAM_GUI` | Enable GUI dashboard | `true` |
| `CAM_GUI_DETAIL` | GUI detail mode | `false` |
| `CAM_GUI_KEEP` | Keep GUI on exit | `false` |
| `CAM_GUI_HOST` | GUI bind host | `127.0.0.1` |
| `CAM_GUI_PORT` | GUI bind port (set a fixed port to keep URL stable across restarts) | `0` (random) |
| `CAM_DEBUG` | Include debug info in MCP responses | `false` |
| `CAM_LOG_DEBUG` | Write debug logs to temp file | `false` |
| `CAM_SIGINT_MODE` | SIGINT handling (`cancel`/`exit`/`cancel_then_exit`) | `cancel` |
| `CAM_SIGINT_DOUBLE_TAP_WINDOW` | Double-tap exit window (seconds) | `1.0` |

## Tools

### codex

Invoke OpenAI Codex CLI agent for deep code analysis and critical review.

**Best for**: Code review, bug hunting, security analysis

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `prompt` | string | ✓ | - | Task instruction for the agent |
| `workspace` | string | ✓ | - | Absolute path to the project directory |
| `handoff_file` | string | ✓ | - | REQUIRED. Server-side append-only output capture (always wrapped in `<agent-output ...>`) |
| `continuation_id` | string | | `""` | Pass from previous response to continue conversation |
| `permission` | string | | `read-only` | Permission level: `read-only`, `workspace-write`, `unlimited` |
| `model` | string | | `""` | Model override (only specify if explicitly requested) |
| `report_mode` | boolean | | `false` | Generate standalone report format |
| `compact_response` | boolean | | `false` | Return compact status message instead of full output (full output still written to handoff_file) |
| `verbose_output` | boolean | | `false` | Return detailed output including reasoning |
| `context_paths` | array | | `[]` | Reference file/directory paths to provide context |
| `image` | array | | `[]` | Absolute paths to image files for visual context |
| `task_note` | string | | `""` | Display label for GUI |
| `debug` | boolean | | (global) | Override debug setting for this call |

### gemini

Invoke Google Gemini CLI agent for UI design and comprehensive analysis.

**Best for**: UI mockups, image analysis, requirement discovery, full-text analysis

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `prompt` | string | ✓ | - | Task instruction for the agent |
| `workspace` | string | ✓ | - | Absolute path to the project directory |
| `handoff_file` | string | ✓ | - | REQUIRED. Server-side append-only output capture (always wrapped in `<agent-output ...>`) |
| `continuation_id` | string | | `""` | Pass from previous response to continue conversation |
| `permission` | string | | `read-only` | Permission level: `read-only`, `workspace-write`, `unlimited` |
| `model` | string | | `""` | Model override |
| `report_mode` | boolean | | `false` | Generate standalone report format |
| `compact_response` | boolean | | `false` | Return compact status message instead of full output (full output still written to handoff_file) |
| `verbose_output` | boolean | | `false` | Return detailed output including reasoning |
| `context_paths` | array | | `[]` | Reference file/directory paths to provide context |
| `task_note` | string | | `""` | Display label for GUI |
| `debug` | boolean | | (global) | Override debug setting for this call |

### claude

Invoke Anthropic Claude CLI agent for code implementation.

**Best for**: Feature implementation, refactoring, code generation

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `prompt` | string | ✓ | - | Task instruction for the agent |
| `workspace` | string | ✓ | - | Absolute path to the project directory |
| `handoff_file` | string | ✓ | - | REQUIRED. Server-side append-only output capture (always wrapped in `<agent-output ...>`) |
| `continuation_id` | string | | `""` | Pass from previous response to continue conversation |
| `permission` | string | | `read-only` | Permission level: `read-only`, `workspace-write`, `unlimited` |
| `model` | string | | `""` | Model override (`sonnet`, `opus`, or full model name) |
| `report_mode` | boolean | | `false` | Generate standalone report format |
| `compact_response` | boolean | | `false` | Return compact status message instead of full output (full output still written to handoff_file) |
| `verbose_output` | boolean | | `false` | Return detailed output including reasoning |
| `context_paths` | array | | `[]` | Reference file/directory paths to provide context |
| `system_prompt` | string | | `""` | Complete replacement for the default system prompt |
| `append_system_prompt` | string | | `""` | Additional instructions appended to default prompt |
| `agent` | string | | `""` | Specify agent name (overrides default agent setting) |
| `task_note` | string | | `""` | Display label for GUI |
| `debug` | boolean | | (global) | Override debug setting for this call |

### opencode

Invoke OpenCode CLI agent for full-stack development.

**Best for**: Rapid prototyping, multi-framework projects

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `prompt` | string | ✓ | - | Task instruction for the agent |
| `workspace` | string | ✓ | - | Absolute path to the project directory |
| `handoff_file` | string | ✓ | - | REQUIRED. Server-side append-only output capture (always wrapped in `<agent-output ...>`) |
| `continuation_id` | string | | `""` | Pass from previous response to continue conversation |
| `permission` | string | | `read-only` | Permission level: `read-only`, `workspace-write`, `unlimited` |
| `model` | string | | `""` | Model override (format: `provider/model`) |
| `report_mode` | boolean | | `false` | Generate standalone report format |
| `compact_response` | boolean | | `false` | Return compact status message instead of full output (full output still written to handoff_file) |
| `verbose_output` | boolean | | `false` | Return detailed output including reasoning |
| `context_paths` | array | | `[]` | Reference file/directory paths to provide context |
| `file` | array | | `[]` | Absolute paths to files to attach |
| `agent` | string | | `build` | Agent type: `build`, `plan`, etc. |
| `task_note` | string | | `""` | Display label for GUI |
| `debug` | boolean | | (global) | Override debug setting for this call |

### banana

Generate high-fidelity images via the Nano Banana Pro API.

**Best for**: UI mockups, product visuals, infographics, architectural renders, character art

Nano Banana Pro has exceptional understanding and visual expression capabilities—your prompt creativity is the only limit, not the model.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `prompt` | string | ✓ | - | Image generation prompt |
| `save_path` | string | ✓ | - | Base directory for saving images |
| `task_note` | string | ✓ | - | Subdirectory name (English recommended, e.g., 'hero-banner'). Files saved to `{save_path}/{task_note}/` |
| `images` | array | | `[]` | Reference images (absolute paths) with optional role and label |
| `aspect_ratio` | string | | `"1:1"` | Image aspect ratio: `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9` |
| `resolution` | string | | `"1K"` | Image resolution: `1K`, `2K`, `4K` |
| `include_thoughts` | boolean | | `false` | Include thinking process in response |

**Environment Variables:**

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `BANANA_AUTH_TOKEN` | ✓ | - | Google API key or Bearer token |
| `BANANA_ENDPOINT` | | `https://generativelanguage.googleapis.com` | API endpoint (version path auto-appended) |

**Prompt Best Practices:**
- Explicitly request an image (e.g., start with "Generate an image:" or include `"output":"image"`)
- Use structured specs (JSON / XML tags / labeled sections) for complex requests
- Use `MUST/STRICT/CRITICAL` for non-negotiable constraints
- Add negative constraints (e.g., "no watermark", "no distorted hands")

### image

Generate images via OpenRouter-compatible or OpenAI-compatible endpoints.

**Best for**: General image generation when you need compatibility with various providers. For best results with Gemini models, use the `banana` tool instead.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `prompt` | string | ✓ | - | Image generation prompt |
| `save_path` | string | ✓ | - | Base directory for saving images |
| `task_note` | string | ✓ | - | Subdirectory name (English recommended, e.g., 'hero-banner'). Files saved to `{save_path}/{task_note}/` |
| `images` | array | | `[]` | Reference images (absolute paths) with optional role and label |
| `aspect_ratio` | string | | `"1:1"` | Image aspect ratio: `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9` |
| `resolution` | string | | `"1K"` | Image resolution: `1K`, `2K`, `4K` |
| `model` | string | | (env) | Model to use for generation |
| `api_type` | string | | (env) | API type: `openrouter_chat`, `openai_images`, `openai_responses` |

**Environment Variables:**

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `IMAGE_AUTH_TOKEN` | ✓ | - | API key for image generation |
| `IMAGE_ENDPOINT` | | `https://openrouter.ai/api` | API endpoint (version path auto-appended) |
| `IMAGE_MODEL` | | `gpt-image-1` | Default model |
| `IMAGE_API_TYPE` | | `openrouter_chat` | API type: `openrouter_chat`, `openai_images`, `openai_responses` |

### *_parallel_with_template

Batch task execution using simple placeholder templates. Available for all CLI agents:
- `codex_parallel_with_template`
- `gemini_parallel_with_template`
- `claude_parallel_with_template`
- `opencode_parallel_with_template`

**Best for**: Batch code review, batch file processing, batch analysis with structured data

**Template Syntax**:
```
Supported:
  {{ name }}              # Simple variable substitution
  {{ vars.file_path }}    # Dotted dict path (nested dict lookup)
  {{{{                    # Escape to output {{
  }}}}                    # Escape to output }}

NOT supported:
  {{ a | default(...) }}  # Filters
  {{ foo.bar() }}         # Function calls
  {{ a + b }}             # Expressions
  {% if %}...{% endif %}  # Conditionals
  {% for %}...{% endfor %} # Loops
```

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `template` | string | ✓ | - | Placeholder template for generating prompts |
| `variables` | array | ✓ | - | List of variable dicts (each generates one task) |
| `workspace` | string | ✓ | - | Absolute path to the project directory |
| `handoff_file` | string | ✓ | - | Server-side append-only output capture |
| `task_note_template` | string | | `""` | Template for per-task labels |
| `permission` | string | | `read-only` | Permission level |
| `parallel_max_concurrency` | integer | | `20` | Max concurrent tasks |
| `parallel_fail_fast` | boolean | | `false` | Stop on first failure |
| `context_paths` | array | | `[]` | Shared context paths for all tasks |
| `context_paths_parallel` | array | | `[]` | Per-task context paths (length must match variables) |

**Auto-injected variables** (available in templates, override same-named keys in variables[i]):
- `task_index`: 1-based index of current task
- `task_count`: Total number of tasks
- `vars`: The original variables[i] dict

**Example: Batch Code Review**

```json
{
  "template": "Review {{ file_path }} focusing on {{ focus }}. Task {{ task_index }}/{{ task_count }}.",
  "variables": [
    {"file_path": "src/handlers/cli.py", "focus": "error handling"},
    {"file_path": "src/handlers/parallel.py", "focus": "concurrency safety"},
    {"file_path": "src/server.py", "focus": "input validation"}
  ],
  "task_note_template": "[Review] {{ file_path }}",
  "workspace": "/path/to/project",
  "handoff_file": ".agent-handoff/review_batch.md",
  "parallel_max_concurrency": 3
}
```

### get_gui_url

Get the GUI dashboard URL. Returns the HTTP URL where the live event viewer is accessible.

No parameters required.

## Prompt Injection

Some parameters automatically inject additional content into the prompt using `<mcp-injection>` XML tags. These tags make it easy to debug and identify system-injected content.

### `report_mode`

When `report_mode` is set, output format requirements are injected:

```xml
<your prompt>

<mcp-injection type="output-format">
  <output-requirements>
    <rule>This response will be saved as a standalone document.</rule>
    <rule>Write so it can be understood WITHOUT any prior conversation context.</rule>
    <rule>Do NOT reference "above", "previous messages", or "as discussed".</rule>
    <rule>Use the same language as the user's request.</rule>
  </output-requirements>
  <structure>
    <section name="Summary">3-7 bullet points with key findings and conclusions</section>
    <section name="Context">Restate the task/problem so readers understand without chat history</section>
    <section name="Analysis">Step-by-step reasoning with evidence; include file:line references</section>
    <section name="Recommendations">Actionable next steps ordered by priority</section>
  </structure>
  <note>Write with enough detail to be useful standalone, but avoid unnecessary filler.</note>
</mcp-injection>
```

### `context_paths`

When `context_paths` is provided, reference paths are injected:

```xml
<your prompt>

<mcp-injection type="reference-paths">
  <description>
    These paths are provided as reference for project structure.
    You may use them to understand naming conventions and file organization.
  </description>
  <paths>
    <path>/src/api/handlers.py</path>
    <path>/config/settings.json</path>
  </paths>
</mcp-injection>
```

## Stateless Design

**Important**: Each tool call is stateless - the agent has NO memory of previous calls.

- **New conversation** (no `continuation_id`): Include ALL relevant context in your prompt - background, specifics, constraints, and prior findings.
- **Continuing conversation** (with `continuation_id`): The agent retains context from that session, so you can be brief.

If your request references prior context (e.g., "fix that bug", "continue the work"), you must either:
1. Provide `continuation_id` from a previous response, OR
2. Expand the reference into concrete details

## Handoff File

`handoff_file` is REQUIRED for all CLI tools. The server appends each tool output to this file after execution.

Behavior (always):
- Append-only (never overwrite)
- Wrapped as `<agent-output ...>` with `agent`, `continuation_id`, `task_note`, `task_index`, `status`
- `task_index`: single task = `0`; parallel tasks = `1..N`
- On failure, still appends with `status="error"` and an `Error: ...` message

Safety notes:
- Avoid concurrent writes to the same path (outputs may interleave)
- Avoid double-write conflict: do NOT point `handoff_file` at a file the agent is asked to edit
- Recommended: use `.agent-handoff/` (e.g., `.agent-handoff/handoff_chain.md`)

Example wrapper:

```
<agent-output agent="gemini" continuation_id="abc123" task_note="UI audit" task_index="0" status="success">
... agent response (Markdown) ...
</agent-output>
```

### Migration: `save_file` → `handoff_file`

`save_file`, `save_file_with_wrapper`, and `save_file_with_append_mode` were removed. Use `handoff_file` instead (required; always append; always wrapper).

## Response Format

All responses are wrapped in XML format:

### Success Response

```xml
<response>
  <thought_process>...</thought_process>  <!-- Only when verbose_output=true -->
  <answer>
    Agent's response content...
  </answer>
  <continuation_id>session-id-here</continuation_id>
  <debug_info>...</debug_info>  <!-- Only when debug=true -->
</response>
```

### Error Response

Error responses include partial progress to enable retry:

```xml
<response>
  <error>Error message</error>
  <thought_process>...</thought_process>  <!-- Collected steps before error -->
  <partial_answer>...</partial_answer>    <!-- Partial output if any -->
  <continuation_id>session-id</continuation_id>
  <hint>Task failed. Above is the output collected so far. You can send 'continue' with this continuation_id to retry.</hint>
  <debug_info>...</debug_info>
</response>
```

## Permission Levels

| Level | Description | Codex | Gemini | Claude | OpenCode | Banana |
|-------|-------------|-------|--------|--------|----------|--------|
| `read-only` | Can only read files | `--sandbox read-only` | Read-only tools only | `--tools Read,Grep,Glob` | `edit: deny, bash: deny` | Read workspace images only |
| `workspace-write` | Can modify files within workspace | `--sandbox workspace-write` | All tools + sandbox | `--tools Read,Edit,Write,Bash` | `edit: allow, bash: ask` | Write to workspace only |
| `unlimited` | Full system access (use with caution) | `--sandbox danger-full-access` | All tools, no sandbox | `--tools default` | `edit: allow, bash: allow` | Full access |

## Debug Mode

Enable debug mode to get detailed execution information:

```bash
# Enable debug info in responses
export CAM_DEBUG=true

# Enable detailed log file
export CAM_LOG_DEBUG=true
```

When `CAM_LOG_DEBUG=true`, logs are written to:
```
/tmp/cli-agent-mcp/cam_debug_YYYYMMDD_HHMMSS.log
```

Debug output includes:
- Full subprocess command
- Complete stdout/stderr output
- Return codes
- MCP request/response summaries

## MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop `claude_desktop_config.json`):

### Basic Configuration

```json
{
  "mcpServers": {
    "cli-agent-mcp": {
      "command": "uvx",
      "args": ["cli-agent-mcp"]
    }
  }
}
```

### Install from GitHub

```json
{
  "mcpServers": {
    "cli-agent-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/shiharuharu/cli-agent-mcp.git",
        "cli-agent-mcp"
      ]
    }
  }
}
```

### With Debug Mode

```json
{
  "mcpServers": {
    "cli-agent-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/shiharuharu/cli-agent-mcp.git",
        "cli-agent-mcp"
      ],
      "env": {
        "CAM_DEBUG": "true",
        "CAM_LOG_DEBUG": "true"
      }
    }
  }
}
```

### Disable GUI

```json
{
  "mcpServers": {
    "cli-agent-mcp": {
      "command": "uvx",
      "args": ["cli-agent-mcp"],
      "env": {
        "CAM_GUI": "false"
      }
    }
  }
}
```

### Limit Available Tools

```json
{
  "mcpServers": {
    "cli-agent-mcp": {
      "command": "uvx",
      "args": ["cli-agent-mcp"],
      "env": {
        "CAM_ENABLE": "claude,gemini"
      }
    }
  }
}
```

### Disable Image Tools

```json
{
  "mcpServers": {
    "cli-agent-mcp": {
      "command": "uvx",
      "args": ["cli-agent-mcp"],
      "env": {
        "CAM_DISABLE": "banana,image"
      }
    }
  }
}
```

## Project Structure

```
cli-agent-mcp/
├── src/cli_agent_mcp/
│   ├── __init__.py          # Package exports
│   ├── __main__.py          # Entry point
│   ├── app.py               # Server lifecycle (run_server, main)
│   ├── server.py            # MCP protocol adapter (create_server)
│   ├── tool_schema.py       # Tool descriptions and JSON schemas
│   ├── config.py            # Configuration management
│   ├── gui_manager.py       # GUI dashboard manager
│   ├── orchestrator.py      # Request registry
│   ├── signal_manager.py    # Signal handling (SIGINT/SIGTERM)
│   ├── handlers/            # Tool handlers
│   │   ├── base.py          # ToolContext, ToolHandler base class
│   │   ├── cli.py           # CLI tools (codex/gemini/claude/opencode)
│   │   ├── parallel.py      # Parallel execution (*_parallel tools)
│   │   ├── parallel_with_template.py  # Template-based parallel (*_parallel_with_template)
│   │   └── image_tools.py   # Image tools (banana/image)
│   ├── utils/               # Utility functions
│   │   ├── xml_wrapper.py   # XML escaping and wrapper building
│   │   ├── prompt_injection.py  # Prompt injection helpers
│   │   └── simple_template.py   # Simple placeholder template engine
│   └── shared/              # Shared modules
│       ├── invokers/        # CLI invoker implementations
│       ├── parsers/         # Output parsers
│       ├── gui/             # GUI components
│       └── response_formatter.py  # Response formatting
└── tests/
```

## Development

```bash
# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest
```

## License

MIT

TDQS

A3.9/5.0

Scored across 11 tools

Disambiguation4/5

Most tools have distinct purposes targeting different AI agents or functions (e.g., banana for image generation, claude for code implementation, get_gui_url for dashboard access). However, there is some overlap between 'banana' and 'image' as both handle text-to-image generation and editing, which could cause confusion despite different backend providers.

Naming Consistency3/5

The naming is mixed: some tools use simple names (banana, image, claude, codex, gemini, opencode), while others append '_parallel' for parallel execution variants (claude_parallel, codex_parallel, gemini_parallel, opencode_parallel). This pattern is somewhat consistent for parallel tools, but the base names lack a uniform verb_noun structure, making it less predictable overall.

Tool Count4/5

With 11 tools, the count is reasonable for a CLI agent server that orchestrates multiple AI agents and utilities. It covers core agents, their parallel versions, and auxiliary functions like image generation and GUI access, though it might be slightly heavy if some tools are rarely used.

Completeness4/5

The tool set provides good coverage for running various AI agents (claude, codex, gemini, opencode) with parallel execution options, plus image generation and GUI access. A minor gap is the lack of tools for managing agent sessions or configurations, but core workflows are well-supported.

Maintenance

ActivityInactive
ResponsivenessUnresponsive