This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
MCP Yandex Tracker is a Model Context Protocol (MCP) server that provides tools for interacting with Yandex Tracker API. It implements a FastMCP server with protocol-based architecture and optional Redis caching.
task # Run all checks (format, lint, type checking, tests) - REQUIRED before commits
task format # Auto-format code
task check # Run type and format checking
task test # Run tests
uv sync # Install dependencies
uv run mcp-tracker # Run the server- Protocols (
mcp_tracker/tracker/proto/): Define API contracts (IssueProtocol,QueuesProtocol, etc.) - Client (
mcp_tracker/tracker/custom/client.py): Implements protocols, handles HTTP requests - Caching (
mcp_tracker/tracker/caching/client.py): Wraps protocols with Redis caching - MCP Server (
mcp_tracker/mcp/server.py): Server creation and configuration - MCP Tools (
mcp_tracker/mcp/tools/): Tool definitions organized by category_access.py: Access control helpers (check_issue_access,check_queue_access)queue.py/queue_write.py: Queue read-only / write toolsfield.py: Global field and metadata tools (read-only)issue_read.py/issue_write.py: Issue read-only / write toolsuser.py: User tools (read-only)__init__.py: Exportsregister_all_tools()which orchestrates tool registration*_write.pymodules are only registered whensettings.tracker_read_only=False
- Settings (
mcp_tracker/settings.py): Pydantic settings from environment variables - All protocol methods accept optional
auth: YandexAuth | Noneparameter for OAuth support. - All Pydantic models for Yandex Tracker entities inherit from
BaseTrackerEntity.
- Use pytest with asyncio mode
auto - Use aioresponses for HTTP mocking in
TrackerClienttests and@tests/aioresponses_utils.pyfor capturing request/response pairs. - Use AsyncMock with
spec=for protocol mocking in MCP tool tests - Always type-hint all parameters including fixtures
- Never import inside functions - all imports at top of file
- Never use loops for test cases - use
@pytest.mark.parametrize - Use
model_construct()for creating Pydantic model fixtures (skips validation)
| What to test | Where |
|---|---|
| TrackerClient HTTP methods | tests/tracker/custom/test_*.py |
| Caching wrappers | tests/tracker/caching/test_*_protocol.py |
| MCP tools | tests/mcp/tools/test_*_tools.py |
| OAuth provider | tests/mcp/oauth/ |
Use aioresponses to mock HTTP requests. Verify request headers and response parsing:
async def test_api_method(self, client: TrackerClient) -> None:
with aioresponses() as m:
m.get("https://api.tracker.yandex.net/v3/endpoint", payload={"key": "value"})
result = await client.api_method()
assert result.key == "value"MCP tools are tested via ClientSession.call_tool() against a real FastMCP server with mocked protocols.
Key fixtures (from tests/mcp/conftest.py):
client_session: Connected MCP client sessionclient_session_with_limits: Session with queue restrictions enabledmock_issues_protocol,mock_queues_protocol, etc.: Mocked protocol instances
Use get_tool_result_content(result) helper to extract tool return values.
async def test_tool(self, client_session: ClientSession, mock_issues_protocol: AsyncMock) -> None:
mock_issues_protocol.issue_get.return_value = sample_issue
result = await client_session.call_tool("issue_get", {"issue_id": "TEST-1"})
assert not result.isError
content = get_tool_result_content(result)
assert content["key"] == "TEST-1"For paginated methods, use side_effect for sequential returns: mock.method.side_effect = [page1, []]
- Protocol: Add method signature to
mcp_tracker/tracker/proto/*.py - Client: Implement in
mcp_tracker/tracker/custom/client.py - Caching: Add wrapper in
mcp_tracker/tracker/caching/client.py - Tool: Add function to appropriate module in
mcp_tracker/mcp/tools/:- Queue read-only tools →
queue.py - Queue write tools →
queue_write.py - Global field/metadata tools →
field.py - Issue read-only tools →
issue_read.py - Issue write tools →
issue_write.py - User tools →
user.py
- Queue read-only tools →
- Tests: Add to appropriate
tests/mcp/tools/test_*_tools.py - Docs: Update
README.md,README_ru.md, andmanifest.json
| Category | Module | Read-Only |
|---|---|---|
| Queue | queue.py |
Yes |
| Queue Write | queue_write.py |
No |
| Field | field.py |
Yes |
| Issue Read | issue_read.py |
Yes |
| Issue Write | issue_write.py |
No |
| User | user.py |
Yes |
Write tools (*_write.py) are only registered when settings.tracker_read_only=False.
- Test success case with expected return data
- Test parameter passing (verify
call_args) - Test optional parameters (provided vs omitted)
- Test queue restrictions with
client_session_with_limitsif tool accesses issues/queues - Add tool name to appropriate list in
tests/mcp/server/test_server_creation.py:- Read-only tools →
READ_ONLY_TOOL_NAMES - Write tools →
WRITE_TOOL_NAMES
- Read-only tools →
- For write tools, add test with
client_session_read_onlyto verify not registered
Authentication (one required):
TRACKER_TOKEN: Static OAuth tokenTRACKER_IAM_TOKEN: Static IAM tokenTRACKER_SA_*: Service account credentials for dynamic IAM tokens
Organization (one required):
TRACKER_CLOUD_ORG_ID: For Yandex CloudTRACKER_ORG_ID: For on-premise
Optional:
TRACKER_LIMIT_QUEUES: Restrict access to specific queuesTRACKER_READ_ONLY: Whentrue, disables all write tools (the*_write.pymodules)TOOLS_CACHE_ENABLED: Enable Redis cachingOAUTH_ENABLED: Enable OAuth provider mode