Guide development of Qiskit MCP servers. Use when creating tools, resources, tests, or new servers. Helps with async patterns, pytest fixtures, GitHub CI/CD setup, and code quality...
When helping with MCP server development in this repository:
server.py and core modules before adding new functionalityasync def, delegate to core module functions# This code is part of Qiskit.
#
# (C) Copyright IBM 2025.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
Tools go in server.py and delegate to async functions in the core module:
# Example: from qiskit_<name>_mcp_server.<core> import my_function
from qiskit_ibm_runtime_mcp_server.ibm_runtime import my_function
@mcp.tool()
async def my_tool_name(param: str, optional_param: int = 10) -> dict[str, Any]:
"""Clear description of what this tool does.
Args:
param: Description of the parameter
optional_param: Description with default behavior
Returns:
Description of the return structure
"""
return await my_function(param, optional_param)
Key patterns:
_tool suffixdict[str, Any]All tools return consistent response format:
# Success
return {"status": "success", "data": result, ...}
# Error
return {"status": "error", "message": "Description of what went wrong"}
@mcp.resource("protocol://path", mime_type="application/json")
async def get_resource_name() -> dict[str, Any]:
"""Description of the resource."""
return await get_data_from_core_module()
Tests use pytest with mocked services. See tests/conftest.py for fixtures.
import pytest
from unittest.mock import Mock, patch
@pytest.mark.asyncio
async def test_my_tool(mock_service):
"""Test description."""
with patch(
"qiskit_<name>_mcp_server.<core>.ExternalService",
return_value=mock_service,
):
result = await my_function()
assert result["status"] == "success"
Common fixture patterns in conftest.py (names vary by server):
mock_*_service - Mocked external service (e.g., mock_runtime_service, mock_http_client)mock_env_vars - Sets environment variables like QISKIT_IBM_TOKENreset_* - Resets global state between tests (often autouse=True)Run from the server directory:
uv run ruff format src/ tests/ # Format
uv run ruff check src/ tests/ # Lint
uv run mypy src/ # Type check
uv run pytest # Test
When creating a new server qiskit-<name>-mcp-server:
pyproject.toml:[tool.uv.workspace]
members = [..., "qiskit-<name>-mcp-server"]
README.md - Setup instructions and usagelangchain_agent.ipynb - Interactive Jupyter tutoriallangchain_agent.py - CLI agent supporting multiple LLM providers.github/workflows/test.yml:lint job (install, ruff, mypy, bandit steps)test-<name> job.github/workflows/publish-pypi.yml:workflow_dispatch optionspublish-<name> jobpublish-meta-package needs array.github/workflows/publish-mcp-registry.yml:workflow_dispatch optionspublish-<name>-mcp-registry jobqiskit-<name>-mcp-server/
āāā src/qiskit_<name>_mcp_server/
ā āāā __init__.py # Package init, version
ā āāā server.py # FastMCP server, @mcp.tool() and @mcp.resource()
ā āāā <core>.py # Async business logic
āāā tests/
ā āāā conftest.py # Fixtures for mocking
ā āāā test_*.py # Test files
āāā examples/
ā āāā README.md # Example documentation
ā āāā langchain_agent.ipynb # Jupyter notebook tutorial
ā āāā langchain_agent.py # CLI agent example
āāā pyproject.toml
āāā server.json # MCP Registry metadata
āāā pytest.ini # (optional) pytest configuration
āāā .env.example # (optional) Environment variable template
āāā LICENSE # Apache 2.0 license (copy from root)
āāā README.md
āāā run_tests.sh
| Task | File | Pattern |
|---|---|---|
| Add tool | server.py |
@mcp.tool() decorator |
| Add resource | server.py |
@mcp.resource("uri") decorator |
| Core logic | <core>.py |
Async functions, return dicts |
| Test fixtures | tests/conftest.py |
@pytest.fixture |
| Unit tests | tests/test_*.py |
@pytest.mark.asyncio |
| New server CI | .github/workflows/test.yml |
Add lint steps + test job |
| New server CD (PyPI) | .github/workflows/publish-pypi.yml |
Add publish job |
| New server CD (MCP) | .github/workflows/publish-mcp-registry.yml |
Add publish job |
| MCP Registry metadata | server.json |
JSON with name, version, packages |
For comprehensive documentation, read AGENTS.md in the repository root.