<!-- CURSOR_SUMMARY --> > [!NOTE] > **Medium Risk** > Touches multiple toolkits’ runtime entrypoints and context/error/auth plumbing, so breakage risk is mainly around invocation/packaging and tool execution wiring rather than business logic. > > **Overview** > Migrates the BrightData, ClickHouse, LinkedIn, Math, MongoDB, Postgres, and Zendesk OSS toolkits from `arcade-tdk` to `arcade-mcp-server` APIs by updating tool decorators, `Context` types, auth classes, and exception imports. > > Adds per-toolkit `__main__.py` files that construct an `MCPApp`, register module tools, and run via configurable transport/host/port; corresponding `pyproject.toml` updates bump versions, drop `arcade-tdk`/`arcade-serve` deps, and add `project.scripts` console entrypoints. > > Updates tests and eval suites to use `arcade_mcp_server.Context` (mocked) and switches eval `ToolCatalog` imports to `arcade_core`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 9b3e31acb4b35e1d72efd47e2d279c5b19e3ecb0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
84 lines
2.3 KiB
Python
84 lines
2.3 KiB
Python
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
from arcade_mcp_server import Context
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_context():
|
|
"""Standard mock context fixture used across all arcade toolkits."""
|
|
context = MagicMock(spec=Context)
|
|
|
|
context.get_auth_token_or_empty = MagicMock(return_value="fake-token")
|
|
context.get_secret = MagicMock()
|
|
|
|
return context
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_httpx_client(mocker):
|
|
"""Mock httpx.AsyncClient for API calls."""
|
|
mock_client_class = mocker.patch("httpx.AsyncClient", autospec=True)
|
|
mock_client = AsyncMock()
|
|
mock_client_class.return_value.__aenter__.return_value = mock_client
|
|
return mock_client
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_article_response():
|
|
"""Sample article data for testing."""
|
|
return {
|
|
"id": 123456,
|
|
"title": "How to reset your password",
|
|
"body": "<p>To reset your password, follow these steps:</p>"
|
|
"<ol><li>Click forgot password</li><li>Enter your email</li></ol>",
|
|
"url": "https://support.example.com/hc/en-us/articles/123456",
|
|
"created_at": "2024-01-15T10:00:00Z",
|
|
"updated_at": "2024-06-01T15:30:00Z",
|
|
"section_id": 789,
|
|
"category_id": 456,
|
|
"label_names": ["password", "security", "account"],
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def build_search_response(sample_article_response):
|
|
"""Builder for search API responses."""
|
|
|
|
def builder(articles=None, next_page=None, count=None):
|
|
if articles is None:
|
|
articles = [sample_article_response]
|
|
|
|
response = {
|
|
"results": articles,
|
|
"next_page": next_page,
|
|
"page": 1,
|
|
"per_page": len(articles),
|
|
"page_count": 1,
|
|
}
|
|
|
|
if count is not None:
|
|
response["count"] = count
|
|
|
|
return response
|
|
|
|
return builder
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_http_response():
|
|
"""Factory for creating mock HTTP responses."""
|
|
|
|
def create_response(json_data=None, status_code=200, raise_for_status=True):
|
|
response = MagicMock()
|
|
response.json.return_value = json_data
|
|
response.status_code = status_code
|
|
|
|
if raise_for_status and status_code >= 400:
|
|
response.raise_for_status.side_effect = Exception(f"HTTP {status_code}")
|
|
else:
|
|
response.raise_for_status.return_value = None
|
|
|
|
return response
|
|
|
|
return create_response
|