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. Trigger on "add tool", "add resource", "write test", "new server", "FastMCP", "MCP development", or "GitHub workflow".
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.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer