import sys from pathlib import Path import httpx import pytest import respx from mcp.client import Client sys.path.insert(0, str(Path(__file__).resolve().parents[1])) import server # noqa: E402 @pytest.fixture(autouse=True) def no_trello_env(monkeypatch): for name in ("TRELLO_API_KEY", "TRELLO_TOKEN", "TRELLO_BOARD_ID"): monkeypatch.delenv(name, raising=False) async def _call(name, arguments): async with Client(server.mcp, mode="2026-07-28") as client: return await client.call_tool(name, arguments) @pytest.mark.asyncio async def test_config_hint_reaches_model(): # SDK прячет текст обычных исключений — без TrelloToolsServer модель # видела бы только «Error executing tool trello_list_labels». result = await _call("trello_list_labels", {}) assert result.is_error assert "TRELLO_API_KEY / TRELLO_TOKEN не заданы" in result.content[0].text @pytest.mark.asyncio async def test_http_error_shows_status_without_credentials(monkeypatch): monkeypatch.setenv("TRELLO_API_KEY", "key123") monkeypatch.setenv("TRELLO_TOKEN", "tok456") with respx.mock: respx.get(url__startswith="https://api.trello.com/1/cards/abc").mock( return_value=httpx.Response(404) ) result = await _call("trello_get_card", {"card_url": "https://trello.com/c/abc"}) text = result.content[0].text assert result.is_error and "HTTP 404 от api.trello.com/1/cards/abc" in text assert "key123" not in text and "tok456" not in text @pytest.mark.asyncio async def test_unexpected_crash_stays_hidden(monkeypatch): async def crash(card_url): raise KeyError("internal detail") monkeypatch.setattr(server.trello, "get_card", crash) result = await _call("trello_get_card", {"card_url": "https://trello.com/c/abc"}) assert result.is_error and "internal detail" not in result.content[0].text