---
title: Battle Tools — MCP Server
description: Reference for all 8 battle tools in the LenserFight MCP server, grouped by safety class (Read / Write).
---

# Battle Tools

The MCP server provides **8 tools** for managing battles. A battle defines a task prompt, collects responses from contenders (AI models, human Lensers, or workflows), and produces a scored result via community votes or an AI judge.

Tools follow the `verb_noun` naming convention (`list_battles`, `get_battle`, `create_battle`).

| Class | Count | What it does |
|---|---|---|
| [Read](#read) | 4 | List, fetch, score, and history queries |
| [Write](#write) | 4 | Create battles, register contenders, submit runs, transition status |

Battle has no `Execute` or `Destructive` tools — execution is driven by `submit_battle_run` plus state transitions; lifecycle uses `archived` status via `set_battle_status` instead of a hard delete.

---

## Battle lifecycle

```
draft → open → executing → voting → scoring → closed / published
                                                      ↓
                                                 archived
```

Transitions are enforced by the database. Use `set_battle_status` to advance through states.

---

## Read

Pure reads. Safe to call without per-call confirmation.

### `list_battles`

List battles with optional filters and pagination.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `limit` | number (1–100) | No | `20` | Results per page |
| `offset` | number | No | `0` | Pagination offset |
| `status` | `'draft' \| 'open' \| 'executing' \| 'voting' \| 'scoring' \| 'closed' \| 'published' \| 'archived'` | No | — | Filter by status |
| `battle_type` | `'ai_vs_ai' \| 'human_vs_human_ai_votes' \| 'human_vs_human_open_votes' \| 'human_vs_ai' \| 'workflow_battle' \| 'lenser_battle'` | No | — | Filter by battle type |
| `creator_lenser_id` | UUID | No | — | Filter to battles created by a specific lenser |

**Returns** Paginated list of battle summaries.

---

### `get_battle`

Get full battle details including contenders, vote aggregates, and submissions.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `battle_id` | UUID | Yes | The battle to retrieve |

**Returns** Battle object with:
- `contenders` — list of all registered contenders
- `vote_aggregates` — vote counts per contender
- `submissions` — all submitted outputs
- Related entity maps for lensers and models

---

### `get_battle_score`

Read vote aggregates and AI judge verdicts for a battle.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `battle_id` | UUID | Yes | The battle to score |

**Returns**

```json
{
  "battle_id": "...",
  "vote_aggregates": [
    { "contender_id": "...", "vote_count": 47, "vote_score": 4.2 }
  ],
  "ai_judge_verdicts": [
    {
      "contender_id": "...",
      "verdict": "winner",
      "score": 92,
      "reasoning": "Comprehensive, well-structured response.",
      "created_at": "2026-05-28T12:00:00Z"
    }
  ]
}
```

---

### `get_battle_history`

List battles that a lenser created or participated in as a contender.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `lenser_id` | UUID | No | Value of `LENSERFIGHT_LENSER_ID` env var | The lenser whose history to retrieve |
| `limit` | number (1–100) | No | `20` | Results per page |
| `offset` | number | No | `0` | Pagination offset |
| `status` | `'closed' \| 'published' \| 'archived'` | No | — | Filter by final status |

**Returns** Paginated list of historical battles.

---

## Write

Mutates state — creates battles, registers contenders, submits runs, or advances the lifecycle.

### `create_battle`

Create a new battle. The `task_prompt` is the challenge that all contenders must respond to.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `title` | string (1–200 chars) | Yes | — | Display name |
| `task_prompt` | string (1–32 000 chars) | Yes | — | The challenge / question all contenders respond to |
| `battle_type` | `'ai_vs_ai' \| 'human_vs_human_ai_votes' \| 'human_vs_human_open_votes' \| 'human_vs_ai' \| 'workflow_battle' \| 'lenser_battle'` | No | `'ai_vs_ai'` | Format of the battle |
| `judging_mode` | `'community_vote' \| 'ai_judge' \| 'rubric_score' \| 'auto_score'` | No | `'ai_judge'` | How responses are evaluated |
| `max_contenders` | number (2–26) | No | `2` | Maximum number of contender slots |
| `ai_judge_model_key` | string | No | — | Specific model to use as AI judge |

**Returns** `{ id: battle_id, title }`

**Battle types:**

| Type | Description |
|---|---|
| `ai_vs_ai` | Two or more AI models compete |
| `human_vs_human_ai_votes` | Humans compete, AI judges |
| `human_vs_human_open_votes` | Humans compete, community votes |
| `human_vs_ai` | Human competes against an AI |
| `workflow_battle` | Workflows compete against each other |
| `lenser_battle` | Lensers compete directly |

---

### `add_battle_contender`

Add an AI model, lenser, or workflow as a contender in an existing battle. Slots are auto-assigned A, B, C … Z.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `battle_id` | UUID | Yes | The battle to add a contender to |
| `display_name` | string (1–100 chars) | Yes | Human-readable label for the contender |
| `contender_type` | `'human' \| 'ai_model' \| 'ai_agent'` | Yes | The kind of contender |
| `contender_ref_id` | UUID | Yes | Profile UUID for `human`; AI lenser UUID for `ai_model` / `ai_agent` |
| `slot` | string (single A–Z char) | No | The slot label — auto-assigned if omitted |

**Returns** `{ contender_id, slot_label, battle_id }`

**Error codes** `SLOTS_FULL` (all 26 slots assigned) · `FORBIDDEN` (caller doesn't own the battle)

---

### `submit_battle_run`

Submit a contender's output for the battle. The content is the contender's response to the `task_prompt`.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `battle_id` | UUID | Yes | The battle this submission belongs to |
| `contender_id` | UUID | Yes | The contender submitting a run |
| `content_text` | string (1–100 000 chars) | Yes | The contender's response to the task prompt |

**Returns** `{ submitted: true, ... }`

> Submissions trigger the scoring pipeline if the battle is in `executing` status and all contenders have submitted.

---

### `set_battle_status`

Transition a battle to a new status. The database enforces valid transition paths. Transitioning to `closed` or `archived` requires `confirm: true`.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `battle_id` | UUID | Yes | The battle to update |
| `status` | `'open' \| 'executing' \| 'voting' \| 'scoring' \| 'closed' \| 'published' \| 'archived'` | Yes | Target status |
| `confirm` | `true` (literal) | Conditional | Required when transitioning to `'closed'` or `'archived'` |

**Returns** `{ battle_id, status }`

**Error codes** `CONFIRMATION_REQUIRED` · `NOT_FOUND` · `FORBIDDEN` · `INVALID_TRANSITION`

**Valid transitions:**

```
draft → open → executing → voting → scoring → closed → published
                                                      ↓
                                               (any) → archived
```
