The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Yandex Tracker MCP listing page.
mcp-name: io.github.aikts/yandex-tracker-mcp
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with Yandex Tracker APIs. This server provides secure, authenticated access to Yandex Tracker issues, queues, comments, worklogs, and search functionality with optional Redis caching for improved performance.
Documentation in Russian is available here / Документация на русском языке доступна здесь.
TRACKER_ENTITIES_ENABLED)Choose one of the following based on your Yandex organization type:
TRACKER_CLOUD_ORG_ID env var later for Yandex Cloud-managed organizationsTRACKER_ORG_ID env var later for Yandex 360 organizationsYou can find your organization ID in the Yandex Tracker URL or organization settings.
Yandex Tracker MCP Server can be one-click installed in Claude Desktop as and extension.
*.mcpb file from GitHub Releases.The following sections show how to configure the MCP server for different AI clients. You can use either uvx yandex-tracker-mcp@latest or the Docker image ghcr.io/aikts/yandex-tracker-mcp:latest. Both require these environment variables:
TRACKER_TOKEN - Your Yandex Tracker OAuth tokenTRACKER_IAM_TOKEN - Your IAM tokenTRACKER_SA_KEY_ID, TRACKER_SA_SERVICE_ACCOUNT_ID, TRACKER_SA_PRIVATE_KEY - Service account credentialsTRACKER_CLOUD_ORG_ID - Your Yandex Cloud organization IDTRACKER_ORG_ID - Your Yandex 360 organization IDSet one of the two. Setting both makes every Tracker call fail with
Only one of org_id or cloud_org_id should be provided.The examples below useTRACKER_CLOUD_ORG_ID; on Yandex 360, replace that key withTRACKER_ORG_ID.
Configuration file path:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonUsing uvx:
Using Docker:
Using uvx:
Using Docker:
Configuration file path:
.cursor/mcp.json in your project directory~/.cursor/mcp.jsonUsing uvx:
Using Docker:
Configuration file path:
~/.codeium/windsurf/mcp_config.jsonAccess via: Windsurf Settings → Cascade tab → Model Context Protocol (MCP) Servers → "View raw config"
Using uvx:
Using Docker:
Configuration file path:
~/.config/zed/settings.jsonAccess via: Cmd+, (macOS) or Ctrl+, (Linux/Windows) or command palette: "zed: open settings"
Note: Requires Zed Preview version for MCP support.
Using uvx:
Using Docker:
Configuration file path:
.vscode/mcp.json in your project directorysettings.jsonOption 1: Workspace Configuration (Recommended for security)
Create .vscode/mcp.json:
Using uvx:
Using Docker:
Option 2: Global Configuration
Add to VS Code settings.json:
Using uvx:
Using Docker:
For other MCP-compatible clients, use the standard MCP server configuration format:
Using uvx:
Using Docker:
Important Notes:
uvx is installed and available in your system PATHThe server exposes the following tools through the MCP protocol:
| Tool | What it does | Key arguments |
|---|---|---|
queues_get_all | Every queue the token may see; returns {values, hits, pages} | fields, page (omit to walk every page), per_page |
queue_get_tags | The tags defined in the queue | queue_id (a key like "SOMEPROJECT") |
queue_get_versions | The queue's versions, with dates and status | queue_id |
queue_get_components | The queue's components as full objects, with lead, auto-assign flag and version; queue_get_metadata with expand: ["components"] gives ids and names only | queue_id |
queue_create_version | Create a version in the queue | queue_id, name, description, start_date, due_date (YYYY-MM-DD) |
queue_get_fields | The fields configured on the queue, local ones included; schema.required marks the mandatory ones | queue_id, include_local_fields |
queue_get_metadata | Name, description, default type and priority, plus whatever expand asks for | queue_id, expand (all, projects, components, versions, types, team, workflows, fields, issueTypesConfig) |
queue_get_fields before issue_create, but it is not the whole registry: system fields such as parent or estimation are settable without appearing there, and get_global_fields lists every field the organization has.queue_get_metadata with expand: ["issueTypesConfig"] is where the resolutions valid for each issue type come from - issue_close needs one of them.TRACKER_LIMIT_QUEUES. hits / pages from queues_get_all are reported only for an explicit single page on a server without the allow-list, since the totals count queues the allow-list then hides.A component is a label grouping a queue's issues by product, process or owner. Its numeric id is what issue_create / issue_update take in components.
| Tool | What it does | Key arguments |
|---|---|---|
component_get | One component with queue, lead, assignAuto and version | component_id (from queue_get_components or an issue's components) |
component_create | Create a component in a queue | queue_id, name, description, lead (a login or uid), assign_auto |
component_update | Change name, description, lead or auto-assign flag; omitted fields keep their value, clear_lead removes the lead | component_id, name, description, lead, assign_auto, clear_lead, version |
component_delete | Delete a component | component_id |
TRACKER_LIMIT_QUEUES and TRACKER_READ_ONLY_QUEUES apply through the component's queue: component_update and component_delete read the component first to learn it, and a component in a queue outside TRACKER_LIMIT_QUEUES is reported as not found.Projects, portfolios and goals are separate Yandex Tracker entities (distinct from queues), exposed through the Tracker "entities" API. Custom (organization-defined) attributes are not modeled and are not returned.
These tools are opt-in. They are registered only when
TRACKER_ENTITIES_ENABLED=true(defaultfalse), because they add a large tool manifest and are not covered by the queue restrictions — see Queue Access Control.
The three entity types share one tool set, so it is listed once - the row says what the tool does, the columns which name to call:
| What it does | Projects | Portfolios | Goals |
|---|---|---|---|
| One entity by id or shortId | project_get | portfolio_get | goal_get |
Search by name substring and/or field filters; returns {values, hits, pages} | project_find | portfolio_find | goal_find |
A page of comments; returns {comments, next_cursor} | project_get_comments | portfolio_get_comments | goal_get_comments |
| Create, returning the entity | project_create | portfolio_create | goal_create |
| Change any field creation takes | project_update | portfolio_update | goal_update |
Delete it, and with with_board its board too - goals have no board | project_delete | portfolio_delete | goal_delete |
| Add a comment | project_add_comment | portfolio_add_comment | goal_add_comment |
| Edit a comment | project_update_comment | portfolio_update_comment | goal_update_comment |
| Delete a comment | project_delete_comment | portfolio_delete_comment | goal_delete_comment |
| Append one checklist item | project_add_checklist_item | portfolio_add_checklist_item | - |
| Edit one checklist item, leaving the fields you omit as they are | project_update_checklist_item | portfolio_update_checklist_item | - |
| Move a checklist item before another one | project_move_checklist_item | portfolio_move_checklist_item | - |
| Delete one checklist item | project_delete_checklist_item | portfolio_delete_checklist_item | - |
| Edit several existing items by id | project_update_checklist | portfolio_update_checklist | - |
| Delete the whole checklist | project_delete_checklist | portfolio_delete_checklist | - |
entity_id and fields; the *_find tools take input, filter, order_by, order_asc, root_only, page, per_page. Create and update take summary (required on create), description, lead, team_users, clients, followers, start (goals have none), end, tags, entity_status, parent_entity, team_access and links, and update also comment and version (optimistic locking). Every tool takes the same fields selector and returns the entity.links are added, never replaced, and the API never returns them: an existing link cannot be read back or removed through this server, and a links-only update is rejected rather than reported as a success Tracker silently ignores.checklistItems (the checklist tools return the whole entity, so ask for them to see the result), metricItems, and a goal's keyResultItems - the last two are read-only. Goals use their own entityStatus values (draft, according_to_plan, at_risk, blocked, achieved, partially_achieved, not_achieved, exceeded, cancelled). Bulk changes are not supported.| Tool | What it does | Key arguments |
|---|---|---|
users_get_all | A page of the organization's users; returns {values, hits, pages} | page, per_page, fields |
user_get | One user by login or uid | user_id ("john.doe" or "12345") |
user_get_current | The user the current token belongs to | - |
users_search | Find users by login, email or real name | login_or_email_or_name |
users_search matches login and email exactly first and falls back to fuzzy name matching (80% similarity, at most the three best matches).users_get_all is the last one when page equals pages.| Tool | What it does | Key arguments |
|---|---|---|
get_global_fields | Every global field of the organization, with its schema and type | - |
Queue-local fields are not here - queue_get_fields returns them together with the global ones.
| Tool | What it does | Key arguments |
|---|---|---|
get_statuses | Every issue status the organization defines | - |
get_issue_types | Every issue type, for the type argument of issue_create / issue_update | - |
get_priorities | Every priority, with id, key, name and order | - |
get_resolutions | Every resolution, for the resolution_id of issue_close | - |
These four are organization-wide. A queue may accept only some of the values they list, and Tracker answers 422 for one it does not accept - queue_get_metadata with expand: ["issueTypesConfig"] says which resolutions each issue type takes.
| Tool | What it does | Key arguments |
|---|---|---|
issue_templates_get_all | The issue templates, with the fieldTemplates values they prefill; returns {values, hits, pages} | queue, page (omit to walk every page), per_page |
issue_template_get | One issue template by id | template_id |
comment_templates_get_all | The comment templates, with the template text and its summonees / maillistSummonees | queue, page, per_page |
comment_template_get | One comment template by id | template_id |
issue_create and issue_add_comment take no template_id: read the template and pass its values as the write tool's own arguments. Macros such as {{today}} arrive literally.fieldTemplates.description; the template's own description describes the template.queue returns that queue's templates plus the ones bound to no queue, which are usable everywhere. TRACKER_LIMIT_QUEUES applies: templates of a restricted queue are omitted from the listings and rejected on direct access, while templates without a queue stay visible.| Tool | What it does | Key arguments |
|---|---|---|
boards_get_all | The organization's agile boards; returns {boards, next_cursor} | queue, fields, cursor (the previous next_cursor), per_page |
board_get | One board with autoFilterSettings (what it collects), estimateBy, useRanking and its working calendar | board_id, fields |
board_get_columns | The board's columns with the issue statuses that land in each | board_id |
board_get_sprints | The board's sprints with status (draft, in_progress, released, archived) and planned/actual dates | board_id, fields |
queue is matched against the board's own filter and misses the boards that filter by something else - a personal board filtering by assignee, for one. To catch those, read a few issues of the queue with issues_find and look at their boards field.TRACKER_LIMIT_QUEUES does not filter them: only the queue argument of boards_get_all is checked, and what these tools return can name restricted queues.board_get_sprints is rejected for it. The sprint id it returns is what issue_create / issue_update take.| Tool | What it does | Key arguments |
|---|---|---|
issue_get | One issue by key: the full record, the current version included | issue_id, include_description |
issue_get_url | The web URL of an issue | issue_id |
issue_get_comments | A page of comments, oldest first; returns {comments, next_cursor} | issue_id, cursor, per_page, fields |
issue_add_comment | Add a comment; summonees is what notifies a user, an @login in the text notifies nobody | issue_id, text, summonees, maillist_summonees, markup_type, is_add_to_followers |
issue_update_comment | Edit a comment | issue_id, comment_id, text, summonees, maillist_summonees |
issue_delete_comment | Delete a comment | issue_id, comment_id |
issue_get_links | Links to related, blocking and duplicate issues | issue_id |
issue_add_link | Link two issues | issue_id, relationship, issue |
issue_delete_link | Remove a link | issue_id, link_id (from issue_get_links) |
issue_get_worklogs | The time logged on one or more issues | issue_ids, fields |
issue_add_worklog | Log spent time | issue_id, duration (ISO-8601, PT1H30M), comment, start |
issue_update_worklog | Edit a worklog entry | issue_id, worklog_id, duration, comment, start |
issue_delete_worklog | Delete a worklog entry | issue_id, worklog_id |
issue_get_attachments | Attachment metadata | issue_id, fields |
issue_get_checklist | The checklist, with the item ids the write tools need | issue_id |
issue_add_checklist_items | Append items in order, creating the checklist if there is none | issue_id, items (text, checked, assignee, deadline) |
issue_update_checklist_item | Change one item; the fields you omit keep their value | issue_id, checklist_item_id, text, checked, assignee, deadline, clear_assignee, clear_deadline |
issue_delete_checklist_item | Delete one item | issue_id, checklist_item_id |
issue_get_transitions | The status transitions available right now, with their ids | issue_id |
issue_execute_transition | Run a transition, returning the transitions available afterwards | issue_id, transition_id, comment, fields |
issue_close | Find a transition to a done status and run it with a resolution | issue_id, resolution_id, comment, fields |
issue_get_changelog | Field edits, status transitions, comment changes and fired triggers; returns {entries, next_cursor} | issue_id, cursor, per_page, field, type |
issue_create | Create an issue, returning it | queue, summary, type, description, markup_type, assignee, priority, parent, sprint, followers, components, tags, project, fields |
issue_update | Change any of those fields; the ones you omit stay as they are | issue_id, version, and the arguments issue_create takes |
issue_move | Move an issue to another queue, which changes its key (TASKS-1 → NEWQUEUE-42) | issue_id, queue, notify, notify_author, move_all_fields, initial_status |
version goes stale on its own. Queue triggers and automation run right after issue_create and bump it, so the version it returns is routinely already old. Re-read it with issue_get immediately before issue_update, or omit it to update the latest version unconditionally; a stale one fails with an editing conflict.id and/or key, or - for type, priority and parent - the bare key or id. components take {"id": ...} or {"name": ...}, and components / followers replace the current list rather than adding to it. Anything without a dedicated argument goes into the fields map, keyed by the field id from queue_get_fields; an entry there overrides the dedicated argument, and an explicit null clears the field.issue_execute_transition only takes ids from issue_get_transitions, and before issue_close read the issue's type with issue_get and the resolutions valid for that type from queue_get_metadata with expand: ["issueTypesConfig"] - each type has its own set. Where the client supports elicitation, issue_move asks the user to confirm its flags first, and declining aborts the move.Every tool here respects TRACKER_LIMIT_QUEUES and TRACKER_READ_ONLY_QUEUES; the ones that write are registered only when TRACKER_READ_ONLY is off.
| Tool | What it does | Key arguments |
|---|---|---|
issues_find | Search issues with Yandex Tracker Query Language; returns {values, hits, pages} | query, fields, include_description, page, per_page |
issues_count | How many issues match a query; returns {"count": N} | query |
fields uses Tracker's own spelling (storyPoints, not story_points) and accepts any field name, a queue's local and the organization's custom fields included - pass the field id from queue_get_fields. A name Tracker does not know is dropped silently.include_description is ignored when description is listed in fields: naming it there is an explicit request for it.per_page defaults to 100 and can be lowered when a page does not fit the context window.The MCP server can also be run in streamable-http mode for web-based integrations or when stdio transport is not suitable.
You may skip configuring TRACKER_CLOUD_ORG_ID or TRACKER_ORG_ID if you are using the following format when connecting to MCP Server (example for Claude Code):
or
You may also skip configuring global TRACKER_TOKEN environment variable if you choose to use OAuth 2.0 authentication (see below).
The Yandex Tracker MCP Server supports OAuth 2.0 authentication as a secure alternative to static API tokens. When configured, the server acts as an OAuth provider, facilitating authentication between your MCP client and Yandex OAuth services.
The MCP server implements a standard OAuth 2.0 authorization code flow:
To enable OAuth authentication, set the following environment variables:
With OAUTH_USE_SCOPES=true (the default) the server requests, advertises and requires the Yandex
Tracker scopes tracker:read and tracker:write - or tracker:read alone when
TRACKER_READ_ONLY=true, so a read-only instance never asks the user for write access. Setting
OAUTH_USE_SCOPES=false drops scopes from the flow entirely, which is what Yandex Cloud federation
requires.
{MCP_SERVER_PUBLIC_URL}/oauth/yandex/callbacktracker:read - Read permissions for Trackertracker:write - Write permissions for Tracker| Feature | OAuth | Static Token |
|---|---|---|
| Security | Dynamic tokens with expiration | Long-lived static tokens |
| User Experience | Interactive login flow | One-time configuration |
| Token Management | Automatic refresh | Manual rotation |
| Access Control | Per-user authentication | Shared token |
| Setup Complexity | Requires OAuth app setup | Simple token configuration |
When OAuth is enabled, MCP clients will need to:
Note: Not all MCP clients currently support OAuth authentication. Check your client's documentation for OAuth compatibility.
Example configuration for Claude Code:
The MCP server supports two different storage backends for OAuth data (client registrations, access tokens, refresh tokens, and authorization states):
The in-memory store keeps all OAuth data in server memory. This is the default option and requires no additional configuration.
Characteristics:
Configuration:
The Redis store provides persistent storage for OAuth data using a Redis database. This ensures OAuth sessions survive server restarts and enables multi-instance deployments.
Characteristics:
Configuration:
Storage Behavior:
oauth:* prefixes to avoid conflicts with other Redis dataWhen using Redis store, you must configure encryption to protect OAuth tokens at rest. Token values are encrypted using Fernet (AES-128) and Redis keys use SHA-256 hashes instead of raw tokens, preventing token exposure if Redis is compromised.
Generate an encryption key:
Configuration:
Key rotation allows seamless key updates: add the new key first, wait for old tokens to expire, then remove the old key.
Important Notes:
OAUTH_STORE setting only affects OAuth data storage; tools caching uses TOOLS_CACHE_ENABLEDYandex Tracker MCP Server supports multiple authentication methods with a clear priority order. The server will use the first available authentication method based on this hierarchy:
Dynamic OAuth Token (highest priority)
OAUTH_ENABLED=true, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, MCP_SERVER_PUBLIC_URLOAUTH_SERVER_URL=https://auth.yandex.cloud/oauth, OAUTH_TOKEN_TYPE=Bearer, OAUTH_USE_SCOPES=falsePassthrough Bearer OAuth Token
Authorization: Bearer <token> headerStatic OAuth Token
TRACKER_TOKEN (your OAuth token)Static IAM Token
TRACKER_IAM_TOKEN (your IAM token)Dynamic IAM Token (lowest priority)
TRACKER_SA_KEY_ID, TRACKER_SA_SERVICE_ACCOUNT_ID, TRACKER_SA_PRIVATE_KEYUse this mode when a trusted gateway handles user authentication, looks up the user's Yandex OAuth token, and forwards the request to the MCP server with that token in the request header:
This passthrough token is used only when MCP OAuth middleware has not provided an access token for the request. In OAuth-enabled deployments with an active MCP OAuth session, the MCP OAuth token takes priority.
This configuration enables authentication through Yandex Cloud OIDC applications, which is required for federated accounts in Yandex Cloud. Federated users authenticate through their organization's identity provider (IdP) and use this OAuth flow to access Yandex Tracker APIs.
Access to queues can be scoped at three levels, from coarse to fine-grained:
TRACKER_LIMIT_QUEUES — allow-list of queue keys. Queues outside the list
are treated as not found / not allowed for both reads and writes. Keys are
matched ignoring case, here and in TRACKER_READ_ONLY_QUEUES, so dev and
DEV name the same queue. The one exception is the board tools: a board belongs
to the organization rather than to a queue, so they are not filtered and can name
a restricted queue in a board's settings.TRACKER_READ_ONLY — when true, all write tools are unregistered, so the
whole instance is read-only.TRACKER_READ_ONLY_QUEUES — per-queue read-only allow-list. Write tools stay
registered, but any mutating call (create/update/move/comment/worklog/link,
queue version creation) targeting a listed queue is rejected, while reads keep
working. Queues not listed here remain read-write.Project/portfolio/goal tools are outside this model. A project, portfolio or goal isn't reliably mappable to a single queue, so none of the three settings above constrain them — neither the read tools (
project_get,project_find,*_get_comments, …) nor the write tools (including comment and checklist tools). Enabling them grants org-wide access to those entities for anyone who can reach the server. For this reason they are opt-in: they are registered only whenTRACKER_ENTITIES_ENABLED=true(defaultfalse), which also keeps the tool manifest small for deployments that don't need them.TRACKER_READ_ONLYstill applies: it unregisters entity write tools along with all other write tools.
This lets a single instance be read-write on some queues and read-only on
others at the same time — e.g. TRACKER_LIMIT_QUEUES=DEV,MGMT together with
TRACKER_READ_ONLY_QUEUES=MGMT gives full access to DEV and read-only
visibility into MGMT. This is especially useful for a shared MCP gateway where
end users reach Tracker only through the server and never hold the raw token
themselves.
These checks are in-process guardrails. For clients that hold the raw Tracker token directly, real limits should additionally be enforced on the token itself.
The image defaults to TRANSPORT=stdio, which talks over the container's stdin/stdout and
opens no port. Set TRANSPORT=streamable-http for the examples below, where the server is
reached over HTTP; for a stdio client, run the container with -i and no -p instead (see
the MCP Client Configuration examples).
Using pre-built image:
Building locally:
This project is licensed under the terms specified in the LICENSE file.
For issues and questions: