# Scampi

**MCP server that gives Claude Code access to external LLM tokens**

Scampi is an MCP server that enables Claude Code to offload high-volume tasks to cheap external LLM tokens. It sits between Claude Code and Z.AI's GLM models, orchestrating parallel workloads that would be wasteful to run on Claude's own context.

## Features

- **Token arbitrage**: Offload bulk work to cheap external models while Claude focuses on judgment
- **Codebase mapping**: Index files with semantic summaries for natural language search
- **Solution generation**: Generate multiple approaches in parallel with different strategies
- **Incremental caching**: Only re-process files that have changed
- **Parallel execution**: Run multiple LLM calls concurrently with rate limiting

## Quick Start

### Installation

```bash
npx scampi init
```

This will:
1. Prompt you to select your LLM provider (Z.AI)
2. Ask for your API key (masked input)
3. Save configuration to `~/.scampi/config.json`
4. Register the MCP server in Claude Code's settings

### Restart Claude Code

After running `init`, restart Claude Code to load the Scampi MCP server.

### Usage

Once installed, use Scampi tools directly in your Claude Code conversations:

```
Map my codebase first, then search for authentication logic
```

Claude Code will automatically invoke the Scampi MCP tools.

## MCP Tools

Scampi exposes six MCP tools to Claude Code:

### scampi_map_codebase

Scan and index a codebase directory to build a searchable map.

**Input:**
```json
{
  "directory": "/path/to/project"
}
```

**Output:**
```json
{
  "files_scanned": 42,
  "files_cached": 35,
  "summary": "Scanned 42 files, 35 from cache, 7 newly summarized"
}
```

**How it works:**
1. Walks the directory, collecting source files (respects `.scampiignore`)
2. Checks cache for unchanged files (using mtime + SHA256 hash)
3. Sends new/changed files to GLM 4.6v-flash for summarization
4. Each file gets: purpose summary, exports list, dependencies list
5. Writes updated cache to `<project>/.scampi/cache/map.json`

---

### scampi_search

Search the codebase for files relevant to a natural language query.

**Input:**
```json
{
  "directory": "/path/to/project",
  "query": "authentication logic"
}
```

**Output:**
```json
{
  "results": [
    {
      "file": "src/auth/login.ts",
      "relevance": "high",
      "summary": "Handles user login flow. Validates credentials against database, issues JWT tokens."
    },
    {
      "file": "src/utils/jwt.ts",
      "relevance": "medium",
      "summary": "JWT token utilities for signing and verification."
    }
  ]
}
```

**How it works:**
1. Loads cached map from `.scampi/cache/map.json`
2. Chunks file summaries into batches
3. Sends each batch to GLM 4.6v-flash in parallel
4. Ranks each file's relevance: high, medium, low, or none
5. Returns top matches sorted by relevance

---

### scampi_generate_solutions

Generate multiple solution approaches for a coding task using parallel sub-agents.

**Input:**
```json
{
  "task": "Implement a rate limiter for API requests",
  "count": 5,
  "codebase_context": "TypeScript project using Express. See src/middleware/ for existing middleware patterns.",
  "dry_run": false
}
```

**Output:**
```json
{
  "approaches": [
    {
      "id": "1",
      "approach": "Token bucket algorithm",
      "solution": "// Full implementation here..."
    },
    {
      "id": "2",
      "approach": "Sliding window counter",
      "solution": "// Full implementation here..."
    }
  ],
  "failures": []
}
```

**Dry run mode:**

Set `dry_run: true` to preview the planned approaches without executing them. This returns the approach prompts that would be sent to sub-agents, allowing review before committing tokens.

**How it works:**
1. Calls GLM 4.7 orchestrator to generate N distinct approach prompts
2. If `dry_run: true`, returns the plan here
3. Fans out through concurrency pool - each prompt becomes an independent GLM 4.7 call
4. Collects results from all sub-agents
5. Returns structured array for Claude to evaluate

---

### scampi_brainstorm

Generate diverse approach ideas without implementation. Faster and cheaper than `generate_solutions`.

**Input:**
```json
{
  "directory": "/path/to/project",
  "task": "Add user authentication",
  "count": 5
}
```

**Output:**
```json
{
  "ideas": [
    {
      "id": 1,
      "approach": "JWT with refresh tokens",
      "rationale": "Stateless authentication suitable for API-first architecture",
      "tradeoffs": "- Pro: Scalable, no session storage\n- Con: Token revocation requires extra infrastructure",
      "implementation_hints": "- Use httpOnly cookies for refresh tokens\n- Consider token blacklist for logout"
    }
  ]
}
```

**Key differences from generate_solutions:**
- Single LLM call instead of 1 + N (orchestrator + sub-agents)
- Returns structured ideas, not implementations
- Much faster and more cost-effective
- Claude implements after receiving ideas

---

### scampi_get_files

Retrieve file contents from a mapped codebase with optional cached summaries.

**Input:**
```json
{
  "directory": "/path/to/project",
  "files": ["src/auth/login.ts", "src/utils/jwt.ts"],
  "include_summary": true
}
```

**Output:**
```json
{
  "files": [
    {
      "path": "src/auth/login.ts",
      "content": "// File contents here...",
      "summary": "Handles user login flow..."
    }
  ]
}
```

**How it works:**
1. Validates directory path (security check for path traversal)
2. Loads cache to get file summaries
3. Reads file contents from disk
4. Returns content with optional cached summaries

---

### scampi_query_graph

Query the dependency graph for a specific file.

**Input:**
```json
{
  "directory": "/path/to/project",
  "file": "src/auth/login.ts",
  "query_type": "all"
}
```

**Output:**
```json
{
  "file": "src/auth/login.ts",
  "dependencies": ["src/utils/jwt.ts", "src/db/users.ts"],
  "dependents": ["src/routes/auth.ts", "src/middleware/auth.ts"],
  "exports": ["login", "logout", "validateSession"]
}
```

**Query types:**
- `dependencies`: Files that the queried file imports
- `dependents`: Files that import the queried file
- `exports`: Symbols exported by the queried file
- `all`: All of the above

## Configuration

### User Config: `~/.scampi/config.json`

```json
{
  "provider": "zai",
  "apiKey": "sk-...",
  "models": {
    "primary": "glm-4.7",
    "flash": "glm-4.6v-flash"
  },
  "concurrency": 4
}
```

| Field | Description | Default |
|-------|-------------|---------|
| `provider` | LLM provider identifier | `"zai"` |
| `apiKey` | API key for the provider | Required |
| `models.primary` | Model for complex tasks (orchestration, solution generation) | `"glm-4.7"` |
| `models.flash` | Model for fast tasks (file summarization, search) | `"glm-4.6v-flash"` |
| `concurrency` | Maximum concurrent API requests | `4` |
| `timeout` | Request timeout in milliseconds | `30000` (30s) |

**Updating model names:**

The model names are configured during `scampi init`. If Z.AI releases new models:

1. Edit `~/.scampi/config.json` directly to update model names
2. Or run `scampi init` again to reconfigure with updated models

Check [Z.AI's documentation](https://open.bigmodel.cn/) for available model IDs.

### Project Ignore: `.scampiignore`

Create a `.scampiignore` file in your project root to exclude files from scanning. Follows `.gitignore` syntax.

**Built-in defaults (always excluded):**

| Category | Patterns |
|----------|----------|
| **Version Control** | `.git`, `.svn`, `.hg`, `.bzr` |
| **Dependencies** | `node_modules`, `vendor`, `bower_components`, `jspm_packages`, `.pnpm` |
| **Build Outputs** | `dist`, `build`, `out`, `target`, `bin`, `obj`, `_build`, `.next`, `.nuxt`, `.output`, `.svelte-kit` |
| **Cache** | `.cache`, `__pycache__`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.tox`, `.nox`, `.eggs`, `*.egg-info`, `.cargo`, `.gradle`, `.maven` |
| **IDE/Editor** | `.idea`, `.vscode`, `.vs`, `.fleet` |
| **Virtual Envs** | `venv`, `.venv`, `env`, `.env`, `virtualenv`, `.virtualenv` |
| **Coverage/Testing** | `coverage`, `.nyc_output`, `htmlcov` |
| **Logs/Temp** | `logs`, `tmp`, `temp`, `.tmp` |
| **OS Files** | `.DS_Store`, `Thumbs.db` |

**Example `.scampiignore`:**
```
# Ignore test fixtures
tests/fixtures/

# Ignore generated files
*.generated.ts

# Ignore large data files
data/

# Use negation to include something that would be ignored
!important-build/
```

### Cache Location

Codebase maps are cached at `<project>/.scampi/cache/map.json`.

Add `.scampi/` to your project's `.gitignore` as the cache is machine-specific.

## CLI Commands

### `npx scampi init`

Interactive setup wizard:
- Selects LLM provider
- Collects API key (masked input)
- Saves config to `~/.scampi/config.json`
- Registers MCP server in `~/.claude/settings.json`

### `npx scampi serve`

Starts the MCP server (stdio transport). This is called automatically by Claude Code.

### `npx scampi version`

Shows version information.

### `npx scampi`

Shows help and available commands.

## Troubleshooting

### "Configuration not found" error

Run `npx scampi init` to set up your configuration.

### "API key not configured" error

Your config file exists but is missing the API key. Run `npx scampi init` to reconfigure.

### "No codebase map found" error

Run `scampi_map_codebase` first before using `scampi_search`. The search tool requires a pre-built index.

### Tools not appearing in Claude Code

1. Ensure you ran `npx scampi init` successfully
2. Check that `~/.claude/settings.json` contains the Scampi MCP server entry
3. Restart Claude Code after installation

If needed, manually add to `~/.claude.json`:

**macOS/Linux:**
```json
{
  "mcpServers": {
    "scampi": {
      "command": "npx",
      "args": ["scampi", "serve"]
    }
  }
}
```

**Windows:**
```json
{
  "mcpServers": {
    "scampi": {
      "command": "cmd",
      "args": ["/c", "npx", "scampi", "serve"]
    }
  }
}
```

### API rate limiting (429 errors)

Scampi uses a concurrency pool to limit parallel requests. If you still hit rate limits:
1. Reduce `concurrency` in `~/.scampi/config.json` (try `2` or `3`)
2. Wait a few minutes before retrying

### Timeouts on large codebases

For very large codebases:
1. Use `.scampiignore` to exclude unnecessary directories
2. Run mapping in stages by specifying subdirectories
3. The incremental cache will speed up subsequent runs

### Windows limitations

The MCP server uses Unix signals (SIGINT/SIGTERM) for graceful shutdown, which have limited support on Windows. On Windows:
- The server will still start and function correctly
- Graceful shutdown may not work as expected via signals
- The server will exit when Claude Code terminates or when stdin is closed

For production use on Windows, consider running Scampi through WSL2 for full signal support.

## Two-Model Strategy

Scampi uses two GLM models optimized for different tasks:

| Model | Role | Use Cases |
|-------|------|-----------|
| GLM 4.7 | Primary | Orchestration planning, solution generation, complex reasoning |
| GLM 4.6v-flash | Fast | File summarization, search queries, high-volume tasks |

This strategy maximizes value: expensive reasoning where it matters, cheap tokens for bulk work.

## Development

### Setup

```bash
git clone https://github.com/ajhcs/scampi.git
cd scampi
npm install
npm run build
```

### Scripts

| Script | Description |
|--------|-------------|
| `npm run build` | Compile TypeScript |
| `npm run dev` | Run in development mode |
| `npm test` | Run tests |
| `npm run test:watch` | Run tests in watch mode |
| `npm run test:coverage` | Generate coverage report |

### Project Structure

```
scampi/
├── bin/cli.ts                  # CLI entry point
├── src/
│   ├── server/                 # MCP server implementation
│   │   ├── index.ts            # Server setup
│   │   ├── schemas.ts          # Input/output schemas
│   │   └── tools/              # Tool implementations
│   ├── llm/                    # LLM integration
│   │   ├── client.ts           # API wrapper
│   │   ├── pool.ts             # Concurrency limiter
│   │   └── retry.ts            # Retry logic
│   ├── cache/                  # Caching system
│   │   ├── map.ts              # Cache I/O
│   │   └── incremental.ts      # Change detection
│   ├── config/                 # Configuration
│   └── utils/                  # Utilities
└── tests/                      # Test suite
```

## License

MIT

## Links

- [GitHub Repository](https://github.com/ajhcs/scampi)
- [Report Issues](https://github.com/ajhcs/scampi/issues)
- [Z.AI Documentation](https://open.bigmodel.cn/)
- [Model Context Protocol](https://modelcontextprotocol.io/)
