---
title: Lens Tools — MCP Server
description: Reference for all 15 lens tools in the LenserFight MCP server, grouped by safety class (Read / Write / Execute / Destructive).
---

# Lens Tools

The MCP server provides **15 tools** for managing and executing lenses. Lenses are versioned prompt templates that accept named parameters — `[[ParamName]]` for required, `[[ParamName!]]` for optional.

Tools follow the `verb_noun` naming convention (`list_lenses`, `get_lens`, `run_lens`) — the sector-standard pattern used by Anthropic's reference connectors (Gmail's `list_labels`, `get_thread`, `create_draft`).

Tools are grouped by **safety class** so a host (Claude.ai, Cursor, Claude Code) can request approval per class instead of per tool:

| Class | Count | What it does |
|---|---|---|
| [Read](#read) | 7 | No state change — list, fetch, inspect, validate |
| [Write](#write) | 4 | Creates or mutates state |
| [Execute](#execute) | 2 | Side-effects through template resolution |
| [Destructive](#destructive) | 2 | Removes or hides existing data |

---

## Read

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

### `list_lenses`

List lenses with optional filters and pagination.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `limit` | number (1–100) | No | `20` | Number of results per page |
| `offset` | number (≥ 0) | No | `0` | Pagination offset |
| `visibility` | `'public' \| 'community' \| 'private'` | No | — | Filter by visibility tier |
| `status` | `'draft' \| 'published' \| 'archived'` | No | — | Filter by status |
| `lenser_id` | UUID | No | — | Filter to a specific lenser |
| `include_archived` | boolean | No | `false` | Include archived lenses |

**Returns** `{ items, total, limit, offset, has_more }`

---

### `search_lenses`

Full-text search lenses by query string.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `query` | string (≥ 1 char) | Yes | — | Search terms |
| `visibility` | `'public' \| 'community' \| 'private'` | No | — | Filter by visibility |
| `limit` | number (1–100) | No | `20` | Results per page |
| `offset` | number | No | `0` | Pagination offset |

**Returns** Paginated results matching the query.

---

### `get_lens`

Get a lens including its head version template body and full parameter list.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens to retrieve |

**Returns** Full lens object with `versions.template_body` and `version_parameters[{ id, label, optional }]`.

---

### `list_lens_versions`

List all versions of a lens, ordered newest first.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens whose versions to list |

**Returns** `[{ id, semver, created_at, changelog }]` — or `{ lens_id, versions: [], count: 0 }` if no versions exist.

---

### `get_lens_version`

Get the full details of a specific lens version, including template body and parameter list.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The parent lens |
| `version_id` | UUID | No | Version UUID (one of `version_id` or `semver` required) |
| `semver` | string | No | Semantic version string, e.g. `"1.2.0"` |

**Returns**

```json
{
  "id": "...",
  "semver": "1.2.0",
  "template_body": "...",
  "changelog": "Added Style parameter.",
  "created_at": "2026-05-01T00:00:00Z",
  "version_parameters": [
    { "id": "...", "label": "Language", "optional": false },
    { "id": "...", "label": "Style", "optional": true }
  ]
}
```

**Error codes** `BAD_INPUT` (if neither `version_id` nor `semver` provided) · `NOT_FOUND`

---

### `extract_lens_params`

Extract the parameter schema from a lens template — lists every `[[token]]` in the template and whether it is required or optional.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens to inspect |
| `version_id` | UUID | No | Specific version (defaults to head) |

**Returns**

```json
{
  "lens_id": "...",
  "version_id": "...",
  "params": [
    { "id": "uuid", "label": "Language", "optional": false },
    { "id": "uuid", "label": "Style", "optional": true }
  ],
  "raw_tokens_in_template": ["[[Language]]", "[[Style!]]", "[[InputText]]"]
}
```

---

### `validate_lens_params`

Check whether a set of parameter values satisfies the schema of a lens version.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens to validate against |
| `version_id` | UUID | No | Specific version (defaults to head) |
| `values` | `Record<string, string>` | Yes | Parameter values to validate (case-insensitive keys) |

**Returns**

```json
{
  "valid": false,
  "missing": ["Language"],
  "unknown": ["Typo"],
  "total_params": 3,
  "provided": 2
}
```

Use this tool before calling `run_lens` when you want to surface validation errors to the user without attempting execution.

---

## Write

Mutates state — creates new resources or changes existing ones. Hosts should ask the user before approving for the first time.

### `create_lens`

Create a new lens with a template body and optional parameter declarations.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `title` | string (1–200 chars) | Yes | — | Display name |
| `template_body` | string (≥ 50 chars) | Yes | — | Prompt template. Use `[[Name]]` for required params, `[[Name!]]` for optional. |
| `visibility` | `'public' \| 'community' \| 'private'` | No | `'public'` | Initial visibility tier |
| `params` | `Array<{ label: string, optional: boolean }>` | No | — | Explicit parameter declarations (inferred from template if omitted) |

**Returns** New lens object with its `id`.

**Example template body:**

```
Summarize the following text in [[Language]] using a [[Style!]] tone.

Text: [[InputText]]
```

This template has two required parameters (`Language`, `InputText`) and one optional parameter (`Style`).

---

### `update_lens`

Create an immutable new version of an existing lens. The original version is never modified.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens to update |
| `template_body` | string (≥ 50 chars) | No | New template body (omit to keep existing) |
| `visibility` | `'public' \| 'community' \| 'private'` | No | New visibility |
| `params` | `Array<{ label: string, optional: boolean }>` | No | Updated parameter list |

**Returns** The new version object. The lens `head_version_id` is updated to point to the new version.

---

### `fork_lens`

Fork a public or community lens into a new lens owned by the caller. The fork is linked to its source via `parent_lens_id`.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `source_lens_id` | UUID | Yes | — | The lens to fork |
| `title` | string (1–200 chars) | No | `"Fork of {id}"` | Title for the new lens |
| `template_body` | string (≥ 50 chars) | No | Copied from source | Custom template body (overrides source) |
| `visibility` | `'public' \| 'community' \| 'private'` | No | `'public'` | Initial visibility of the fork |

**Returns** New lens object with `forked_from: source_lens_id`.

---

### `set_lens_visibility`

Change the visibility tier of a lens.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens to update |
| `visibility` | `'public' \| 'community' \| 'private'` | Yes | New visibility |

**Returns** `{ lens_id, visibility }`

**Visibility tiers:**

| Tier | Who can see it |
|---|---|
| `public` | Everyone, including unauthenticated users |
| `community` | Authenticated LenserFight members |
| `private` | Only the owning lenser |

---

## Execute

Resolves a template and (optionally) records a workflow run. Does **not** call any LLM — the calling assistant is what executes the returned prompt.

### `run_lens`

Resolve a lens template by substituting parameter tokens with provided values. Returns a ready-to-use prompt string.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `lens_id` | UUID | Yes | — | The lens to run |
| `version_id` | UUID | No | Head version | Specific version to use |
| `param_values` | `Record<string, string>` | No | `{}` | Key-value map of parameter names to values (case-insensitive keys) |
| `workflow_id` | UUID | No | — | If provided, creates a `workflow_runs` record with `status='pending'` for tracking |

**Returns**

```json
{
  "resolved_prompt": "Summarize the following text in English using a formal tone.\n\nText: The quick brown fox.",
  "lens_title": "Text Summarizer",
  "lens_description": "Summarizes any input text with configurable language and tone.",
  "run_id": "uuid-or-null",
  "lens_id": "...",
  "version_id": "...",
  "params_used": ["Language", "InputText"],
  "estimated_input_tokens": 42,
  "persisted": true,
  "next_step": "Execute the resolved_prompt above and return the output to the user."
}
```

**Token resolution rules:**

- Each `[[Name]]` token is replaced with `param_values[name]` (case-insensitive lookup).
- Required tokens with no provided value → `MISSING_PARAMS` error listing `missing` labels, `all_parameters`, `lens_title`, and `lens_description`.
- Optional tokens (`[[Name!]]`) with no provided value → replaced with an empty string.
- Unknown keys in `param_values` are ignored.

**Error codes** `NOT_FOUND` · `MISSING_PARAMS` (includes `{ missing, all_parameters, lens_title, lens_description }`)

---

### `find_and_run_lens`

Single-call shortcut: search for a lens by keyword, resolve its template, and return a ready-to-execute prompt — or report what parameters are still needed.

**Parameters**

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `query` | string (≥ 1 char) | Yes | — | Search terms to find the lens |
| `param_values` | `Record<string, string>` | No | `{}` | Parameter values to inject if a lens is found |
| `visibility` | `'public' \| 'community' \| 'private'` | No | — | Filter search by visibility |

**Returns**

One of three response shapes depending on what the server finds:

```json
{ "status": "ready", "resolved_prompt": "...", "lens_title": "...", "lens_description": "...", "lens_id": "..." }
{ "status": "needs_params", "missing": ["Topic", "Language"], "all_parameters": [...], "lens_title": "...", "lens_id": "..." }
{ "status": "no_match", "query": "..." }
```

**When to use `find_and_run_lens` vs `run_lens`:**

| | `find_and_run_lens` | `run_lens` |
|---|---|---|
| Know the lens ID? | No | Yes |
| Searching by topic/keyword? | Yes | No |
| Need a single tool call? | Yes | Requires `search_lenses` first |

---

## Destructive

Removes or hides existing data. Hosts should require explicit user confirmation every time.

### `archive_lens`

Archive a lens. Archived lenses are hidden from listings but not deleted and can be restored.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens to archive |

**Returns** `{ lens_id, status: 'archived' }`

**Error codes** `NOT_FOUND` · `FORBIDDEN`

---

### `delete_lens`

Soft-delete a lens. Requires explicit confirmation to prevent accidental deletion.

**Parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `lens_id` | UUID | Yes | The lens to delete |
| `confirm` | `true` (literal) | Yes | Must be exactly `true` |

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

**Error codes** `NOT_FOUND` · `FORBIDDEN`

> Deletion is soft — the lens record is marked deleted and excluded from all queries. It is not physically removed from the database.
