Shared utilities and testing infrastructure for Python MCP server projects.
uv add git+https://github.com/vhspace/mcp-commonFor testing utilities:
uv add "mcp-common[testing] @ git+https://github.com/vhspace/mcp-common"Base settings class built on pydantic-settings with .env file support:
from mcp_common import MCPSettings
from pydantic_settings import SettingsConfigDict
class MySettings(MCPSettings):
model_config = SettingsConfigDict(env_prefix="MY_SERVER_")
api_url: str
api_token: str
timeout: int = 30Built-in fields: debug, log_level, log_json, optional github_repo (owner/name) and issue_tracker_url for agent issue workflow (see Agent remediation below).
Standard markdown for agents when a tool or CLI raises: search issues → thumbs-up if exact duplicate, comment if new info → else open issue → continue the primary task (prefer handling via a subagent).
from mcp_common import format_agent_exception_remediation
from mcp_common.config import MCPSettings
from pydantic_settings import SettingsConfigDict
class MySettings(MCPSettings):
model_config = SettingsConfigDict(env_prefix="MY_MCP_")
# github_repo and issue_tracker_url inherited (optional)
text = format_agent_exception_remediation(
exception=exc,
project_repo=settings.github_repo or "myorg/my-mcp",
issue_tracker_url=settings.issue_tracker_url,
tool_or_command="my_tool",
version="1.2.3",
extra_lines=["MAAS site: central"],
)
# Append to MCP tool error text, log line, or stderr as appropriate.serverUseInstructions snippet (paste into MCP server metadata):
When a tool raises an error, the handling agent should: (1) use a subagent or
focused pass so the primary task can continue; (2) search this repo's GitHub issues
for the error; (3) if a match exists — add a thumbs-up if it is an exact duplicate,
otherwise comment with new logs/repro/version; (4) if no match — open a new issue;
(5) then continue the primary task. Optional: format_agent_exception_remediation
from mcp_common for consistent markdown (github_repo / issue_tracker_url on MCPSettings).
Structured logging with JSON mode for containers:
from mcp_common import setup_logging
logger = setup_logging(level="DEBUG", json_output=True, name="my-server")Standard health check responses:
from mcp_common import health_resource
result = health_resource("my-server", "1.0.0", checks={"db": True})
result.to_dict()
# {"name": "my-server", "version": "1.0.0", "status": "healthy", ...}Runtime version introspection:
from mcp_common import get_version
version = get_version("my-mcp-server") # "1.2.3" or "0.0.0-dev"Poll long-running operations with MCP progress notifications:
from mcp_common import OperationStates, poll_with_progress
states = OperationStates(success=["complete"], failure=["error"], in_progress=["running"])
result = await poll_with_progress(ctx, check_fn, "status", states, timeout_s=300)Shared pytest fixtures and assertions for MCP servers:
from mcp_common.testing import mcp_client, assert_tool_exists, assert_tool_success
@pytest.fixture
async def client():
async for c in mcp_client(app):
yield c
@pytest.mark.anyio
async def test_tools(client):
await assert_tool_exists(client, "my_tool")
result = await assert_tool_success(client, "my_tool", {"arg": "value"})uv sync --all-groups
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/
uv run pytest -vApache-2.0