Metadata-Version: 2.5
Name: yandex-tracker-mcp-lite
Version: 0.1.1
Summary: Unofficial lean MCP server for Yandex Tracker: 9 tools, compact answers, the whole API behind one escape hatch.
Project-URL: Homepage, https://github.com/tonysafonov/yandex-tracker-mcp-lite
Project-URL: Issues, https://github.com/tonysafonov/yandex-tracker-mcp-lite/issues
Author: Anton Safonov
License-Expression: MIT
License-File: LICENSE
Keywords: claude,codex,llm,mcp,tracker,yandex,yandex-tracker
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Bug Tracking
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: mcp<3,>=2.3
Description-Content-Type: text/markdown

# yandex-tracker-mcp-lite

Unofficial MCP server for [Yandex Tracker](https://tracker.yandex.ru) that keeps your agent's context for your work: **9 tools, about 1.2k tokens of tool definitions**. The official server costs about 24.8k tokens before you ask anything, the most popular community server about 20.7k.

> Лёгкий неофициальный MCP-сервер для Яндекс Трекера: 9 инструментов, около 1,2 тыс. токенов на описания инструментов вместо 24,8 тыс. у официального и 20,7 тыс. у aikts, ответы в 1,4–30 раз короче, всё остальное API доступно через один инструмент `call_api`. Настройка одной командой: `uvx yandex-tracker-mcp-lite setup`.

```bash
uvx yandex-tracker-mcp-lite setup
```

<!-- mcp-name: io.github.tonysafonov/yandex-tracker-mcp-lite -->

## Measured

Same organisation, same questions, measured with [`bench/measure.py`](bench/measure.py) on 2026-11-08 against the official server at `mcp.tracker.yandex.net` and [aikts/yandex-tracker-mcp](https://github.com/aikts/yandex-tracker-mcp) (commit `51a0c0d`, default settings and with `TRACKER_ENTITIES_ENABLED`). Character counts are exact; tokens are estimated at 3.3 characters per token.

**Tool definitions.** "Seen by the model" is name + description + input schema, the part a client sends to the model in every session. The full `tools/list` also carries output schemas and annotations, which clients keep to themselves; for aikts those output schemas are 128k of its 201k characters.

| | tools | `tools/list` chars | seen by the model, chars | ≈ tokens |
|---|---|---|---|---|
| official | 71 | 84,684 | 81,761 | 24,776 |
| aikts | 55 | 200,864 | 68,226 | 20,675 |
| aikts + entities | 94 | 468,529 | 144,825 | 43,886 |
| **lite** | **9** | **4,355** | **4,044** | **1,225** |

**Answers** to the same questions, characters returned (aikts needs two calls for an issue with comments):

| question | official | aikts | **lite** |
|---|---|---|---|
| who am I | 107 | 206 | **74** |
| read an issue | 707 | 2,561 | **511** |
| issue + last 5 comments | 1,454 | 4,000 | **691** |
| search a queue (12 issues) | 3,537 | 27,785 | **918** |
| available transitions | 1,022 | 210 | **31** |

Clients that load MCP tools on demand (Claude Code's tool search) pay less of the definitions up front; Codex, Cursor and Claude Desktop pay all of it in every session. The answers are smaller everywhere.

## Set up in two minutes

You need: a Tracker organisation you belong to, [uv](https://docs.astral.sh/uv/) (for `uvx`), and a browser where you are signed in to Yandex with the account you use in Tracker.

### The quick way

Run this **in your own terminal** (not through an agent's shell: the token would end up in its transcript):

```bash
uvx yandex-tracker-mcp-lite setup
```

It walks you through the steps below, opens the right pages, reads the token with a hidden prompt, detects whether your organisation is Yandex Cloud or Yandex 360, checks access, explains what is wrong if it fails, and adds the server to Claude Code. For other clients it prints ready configs (the token masked unless you pass `--show-token`).

### By hand

**1. Create an OAuth app** at [oauth.yandex.ru/client/new](https://oauth.yandex.ru/client/new):

- choose **«Для доступа к API или отладки»** (API access or debugging). "No access to user data" there refers to the Yandex ID profile, not to Tracker;
- name it anything, give a contact email;
- in **«Доступ к данным»** type «трекер» and add **«Чтение из трекера»** (`tracker:read`) and **«Запись в трекер»** (`tracker:write`);
- **«Создать приложение»**, copy the **ClientID**. You don't need the client secret.

**2. Issue a token.** Open this link with your ClientID, check that the account in the corner is the one you use in Tracker, press **«Разрешить»** and copy the token (`y0_…`, valid for a year):

```
https://oauth.yandex.ru/authorize?response_type=token&client_id=<ClientID>
```

**3. Find the organisation id.** Tracker → **Администрирование** → **Организации**, field **«Идентификатор»**. The card's title tells you which variable to use:

| card title | variable |
|---|---|
| Yandex Cloud Organization | `TRACKER_CLOUD_ORG_ID` |
| Яндекс 360 для бизнеса | `TRACKER_ORG_ID` |

**4. Check it works** (replace the two values, keep the quotes):

```bash
export TRACKER_TOKEN='y0_...'
export TRACKER_CLOUD_ORG_ID='bpf...'        # or TRACKER_ORG_ID for Yandex 360

curl -s https://api.tracker.yandex.net/v3/myself \
  -H "Authorization: OAuth $TRACKER_TOKEN" \
  -H "X-Cloud-Org-ID: $TRACKER_CLOUD_ORG_ID"   # X-Org-ID for Yandex 360
```

You should see your login. If not, see [Troubleshooting](#troubleshooting).

**5. Add the server.** In the same shell:

Claude Code:

```bash
claude mcp add --scope user tracker \
  -e TRACKER_TOKEN="$TRACKER_TOKEN" \
  -e TRACKER_CLOUD_ORG_ID="$TRACKER_CLOUD_ORG_ID" \
  -- uvx yandex-tracker-mcp-lite
```

Codex (`~/.codex/config.toml`):

```toml
[mcp_servers.tracker]
command = "uvx"
args = ["yandex-tracker-mcp-lite"]
env = { TRACKER_TOKEN = "y0_...", TRACKER_CLOUD_ORG_ID = "bpf..." }
```

Cursor, Claude Desktop, anything else (`mcpServers` JSON):

```json
{
  "mcpServers": {
    "tracker": {
      "command": "uvx",
      "args": ["yandex-tracker-mcp-lite"],
      "env": { "TRACKER_TOKEN": "y0_...", "TRACKER_CLOUD_ORG_ID": "bpf..." }
    }
  }
}
```

Restart the client and ask something like «что у меня в работе в трекере?».

### Troubleshooting

| you see | it means | fix |
|---|---|---|
| `tracker:read OAuth scope is required` | the OAuth app has no Tracker access | add both Tracker accesses to the app (step 1), then issue a new token (step 2) |
| `401 … expired_token` / `INVALID` | wrong or expired token | copy it again, or issue a new one |
| `403 Organization is not available, not ready or not found` | wrong org id, wrong header, or the token belongs to another account | re-copy the id; try the other variable; sign in to the right account and repeat step 2 |
| `OAuth token … issued after '2026-06-01', is not supported for IAM token exchange` | you went the `yc` CLI route | `yc` tokens no longer exchange for IAM tokens; use the OAuth app above |
| everything is read-only in Tracker | the organisation's free period ended | add a billing account in Tracker; reads keep working |

**Keep the token secret.** It acts as you in Tracker. If it leaks (pasted into a chat, committed), revoke it in [Yandex ID → Безопасность](https://id.yandex.ru/security) and issue a new one.

### Variables

| variable | |
|---|---|
| `TRACKER_TOKEN` | OAuth token. Or `TRACKER_IAM_TOKEN` (12 h, Yandex Cloud orgs, e.g. from a service account). |
| `TRACKER_CLOUD_ORG_ID` / `TRACKER_ORG_ID` | organisation id, see step 3 |
| `TRACKER_READ_ONLY=1` | optional: only `whoami`, `search_issues`, `get_issue` and GET-only `call_api` (≈ 600 tokens) |

**Saving the extra process.** `uvx` keeps a small `uv` process (~26 MB) alongside the server. To avoid it, install once with `uv tool install yandex-tracker-mcp-lite` and use `yandex-tracker-mcp-lite` as the command instead of `uvx yandex-tracker-mcp-lite`. Update with `uv tool upgrade yandex-tracker-mcp-lite`.

The names match [aikts/yandex-tracker-mcp](https://github.com/aikts/yandex-tracker-mcp), so switching is a change of command.

## Tools

| tool | what it does |
|---|---|
| `whoami` | login, name, email; a quick check that the token works |
| `search_issues` | Tracker query language or a preset (`mine`, `created`, `following`). One line per issue: `key \| status \| assignee \| updated \| summary`, with a next-page hint |
| `get_issue` | all fields in one call; `comments=N` adds the last N comments, `attachments=true` downloads images to local files the agent can open, `changelog=true` adds field history |
| `add_comment` | markdown comment, optionally summoning people |
| `transition_issue` | without `status`: lists the transitions available now; with it: matches an id, a name or the target status |
| `update_issue` | any fields: `{"assignee": "me", "tags": {"add": ["x"]}, "deadline": "2026-12-01"}` |
| `create_issue` | new issue, any extra fields |
| `link_issues` | relates, depends on, subtask, duplicates, epic |
| `call_api` | any Tracker API v3 request: boards, sprints, worklogs, checklists, projects, queues |

## How it stays small

Following Anthropic's [Writing effective tools for agents](https://www.anthropic.com/engineering/writing-tools-for-agents) and the [Claude Code MCP docs](https://code.claude.com/docs/en/mcp):

- **A few tools for whole workflows, one escape hatch for the rest.** `get_issue` answers "what's going on with DEV-123" in one call instead of four. Rare operations go through `call_api(method, path, body)`, which costs ~200 tokens and covers the whole API.
- **Server instructions that say when to look here.** With tool search only tool names and server instructions load up front, so the instructions lead with the words people use: Yandex Tracker, Яндекс Трекер, задачи, тикеты, issue keys like DEV-123.
- **Help arrives with the error.** The query-language cheat sheet is not in any schema. When Tracker rejects a query, the error comes back with it. 401/403/404 errors say what to check next, and a search that has more pages says how to get them.
- **Answers are shrunk, not dumped.** Reference objects become their display text (`"assignee": "Анна Петрова"`, `"parent": "DEV-0 Auth epic"`), bookkeeping fields (`self`, `version`, uids, counters) and empty values are dropped, timestamps lose their seconds, JSON has no indentation. `call_api` keeps ids and keys, because follow-up calls need them.
- **People by name.** `assignee`, `followers` and `summon` take a login, an email, a display name or `me`. If a name matches several people the call fails with the candidates instead of guessing.
- **Annotations that clients act on.** Read tools are `readOnlyHint` (Claude Code runs them in parallel), `update_issue` is `idempotentHint` (safe to retry after a dropped connection), creating tools are non-destructive.
- **Schemas without pydantic decoration.** No auto-generated `title`s, no `anyOf: [X, null]`.

## Limitations

- File upload is not supported yet (`call_api` sends JSON).
- Name resolution loads the organisation's user list once per session (up to 1000 users).
- Not affiliated with Yandex.

## Development

```bash
uv run pytest                                      # offline tests
TRACKER_TEST_QUEUE=TEST uv run pytest -m live -s   # creates, edits, links and closes issues in TEST
uv run python bench/measure.py --issue TEST-1 --queue TEST [--aikts ~/src/yandex-tracker-mcp]
```

MIT licence.
