MCP server exposing Qiskit 2.3.1 quantum computing functionality
Project description
mcp-qiskit
MCP server exposing Qiskit 2.3.1 quantum computing functionality through the Model Context Protocol. Enables LLMs to create, manipulate, and execute quantum circuits via standardized MCP tools and resources.
mcp-name: io.github.daedalus/mcp-qiskit
Overview
This project provides a Model Context Protocol (MCP) server that exposes Qiskit quantum computing functionality to Large Language Models (LLMs). It allows AI assistants to:
- Create and manipulate quantum circuits
- Execute circuits on quantum simulators or real backends
- Analyze circuit properties (depth, gates, operations)
- Visualize circuits in various formats
- Manage quantum backends
Why Use This?
- LLM Integration: Enables AI assistants to perform quantum computing tasks without external tooling
- Standardized Interface: MCP provides a consistent tool-based interface for quantum operations
- Qiskit 2.3.1 Compatible: Specifically designed for Qiskit 2.3.1 with all its features
- Extensible: Easy to add new tools or backends
Installation
Prerequisites
- Python 3.11 or higher
- Qiskit 2.3.1
- A running MCP client (Claude Desktop, Cursor, etc.)
Install from PyPI
pip install mcp-qiskit[qiskit]
The [qiskit] extra installs the required Qiskit dependencies. Other extras available:
# Install with development dependencies
pip install mcp-qiskit[dev,test]
# Install with MCP server dependencies
pip install mcp-qiskit[mcp]
Install from Source
git clone https://github.com/daedalus/mcp-qiskit.git
cd mcp-qiskit
pip install -e ".[all]"
Quick Start
As a Python Library
from mcp_qiskit import create_quantum_circuit, add_gate, add_measurement, run_circuit
# Create a 2-qubit circuit with 2 classical bits
circuit = create_quantum_circuit(2, 2)
# Apply a Hadamard gate on qubit 0
circuit = add_gate(circuit, "h", [0])
# Apply CNOT gate (control: qubit 0, target: qubit 1)
circuit = add_gate(circuit, "cx", [0, 1])
# Measure all qubits
circuit = add_measurement(circuit, [0, 1])
# Execute on Aer simulator
result = run_circuit(circuit, "aer_simulator", shots=1024)
print(f"Measurement results: {result['counts']}")
As an MCP Server
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"mcp-qiskit": {
"command": "mcp-qiskit",
"env": {}
}
}
}
Cursor
Add to your Cursor settings under MCP Servers:
{
"mcpServers": {
"mcp-qiskit": {
"command": "mcp-qiskit",
"args": []
}
}
}
Other MCP Clients
# Run as stdio server
mcp-qiskit
# Or use the Python module directly
python -m mcp_qiskit
MCP Tools Reference
Circuit Creation Tools
create_quantum_circuit_tool
Creates an empty quantum circuit with specified number of qubits and classical bits.
Parameters:
num_qubits(int): Number of quantum bitsnum_classical_bits(int): Number of classical bits for measurements
Returns: Dictionary representing the circuit
Example:
circuit = create_quantum_circuit_tool(num_qubits=3, num_classical_bits=3)
# Returns: {"num_qubits": 3, "num_clbits": 3, "operations": [], "name": "circuit"}
add_gate_tool
Adds a quantum gate to a circuit. This tool maintains circuit state between calls.
Parameters:
circuit(dict, optional): The circuit to modify. If None, creates a new 8-qubit circuit with 8 classical bits automatically.gate_name(str): Name of the gate (e.g., "h", "x", "cx", "rx")qubits(list[int]): List of qubit indices to apply the gate to. Can be a single qubit (e.g.,[0]) or multiple qubits (e.g.,[0, 1, 2, 3]). When multiple qubits are specified for a single-qubit gate, the gate is applied to each qubit.params(list[float], optional): Parameters for parameterized gates
Supported Gates:
- Single-qubit:
h,x,y,z,s,t,sdg,tdg,i,id - Parameterized:
rx,ry,rz,u1,u2,u3,p - Multi-qubit:
cx,cy,cz,swap - Multi-controlled:
mcx,mct,mcp,ccx,toffoli,c3x,c3sx,c4x - Specialized:
rxx,ryy,rzz,ch,cswap,cu,crx,cry,crz
State Maintenance Pattern: Always pass the circuit returned by the previous call to maintain state:
# Option 1: Pass circuit explicitly
circuit = add_gate_tool(circuit=None, gate_name="h", qubits=[0]) # Creates new circuit
circuit = add_gate_tool(circuit=circuit, gate_name="x", qubits=[1]) # Appends
# Option 2: Use returned circuit
circuit = add_gate_tool(None, "h", [0])
circuit = add_gate_tool(circuit, "cx", [0, 1])
circuit = add_gate_tool(circuit, "rx", [0], [0.5])
Apply Single-Quantum Gate to Multiple Qubits:
When applying single-qubit gates (like h, x, y, z, etc.) to multiple qubits at once, use a list of qubit indices:
# Apply H gate to qubits 0, 1, 2, 3 simultaneously
circuit = add_gate_tool(circuit, "h", [0, 1, 2, 3])
# Apply X gate to qubits 4, 5, 6, 7 simultaneously
circuit = add_gate_tool(circuit, "x", [4, 5, 6, 7])
add_measurement_tool
Adds measurement operations to qubits. This tool maintains circuit state between calls.
Parameters:
circuit(dict, optional): The circuit to modify. If None, creates a new 8-qubit circuit with 8 classical bits automatically.qubits(list[int]): Qubit indices to measureclbits(list[int], optional): Classical bit indices to store results
Example:
# Maintain state between calls
circuit = add_measurement_tool(circuit=None, qubits=[0, 1]) # Creates new circuit
circuit = add_measurement_tool(circuit=circuit, qubits=[2]) # Appends measurement
# Or use returned circuit
circuit = add_measurement_tool(None, [0, 1]) # Measure q0->c0, q1->c1
circuit = add_measurement_tool(circuit, [0, 1], [1, 0]) # Measure q0->c1, q1->c0
Analysis Tools
get_circuit_depth_tool
Returns the depth (number of layers) of the circuit.
Parameters:
circuit(dict): The circuit to analyze
Returns: Integer representing circuit depth
list_available_gates_tool
Lists all available quantum gates in Qiskit.
Returns: List of gate name strings
get_gate_definition_tool
Gets detailed information about a quantum gate.
Parameters:
gate_name(str): Name of the gate
Returns: Dictionary with gate properties:
name: Gate namenum_qubits: Number of qubits the gate operates onnum_parameters: Number of parameters (0 for fixed gates)params: List of parameter values
Visualization Tools
draw_circuit_tool
Renders a circuit in various formats.
Parameters:
circuit(dict): The circuit to drawoutput_format(str): Output format - "ascii", "text", "mpl", "latex"
Returns: String representation of the circuit
Example Output (ASCII):
┌───┐
q_0: ┤ H ├──■──
└───┘┌─┴─┐
q_1: ────┤ X ├
└───┘
c: 2/═══════╪═══
0 1
Backend Tools
list_backends_tool
Lists available quantum backends.
Parameters:
filters(dict, optional): Filter criteria (e.g.,{"status": "ONLINE"})
Returns: List of backend information dictionaries
get_backend_status_tool
Gets status information for a backend.
Parameters:
backend_name(str): Name of the backend
Returns: Dictionary with:
name: Backend namestatus: Status (ONLINE/OFFLINE)num_qubits: Number of qubits
get_backend_configuration_tool
Gets detailed configuration for a backend.
Parameters:
backend_name(str): Name of the backend
Returns: Dictionary with:
name: Backend namenum_qubits: Number of qubitscoupling_map: Qubit connectivity (if applicable)basis_gates: List of available basis gatesmax_shots: Maximum allowed shots
Execution Tools
run_circuit_tool
Executes a single quantum circuit.
Parameters:
circuit(dict): Circuit to executebackend_name(str, optional): Backend name (default: "aer_simulator")shots(int, optional): Number of measurement shots (default: 1024)seed(int, optional): Random seed for reproducibility
Returns: Dictionary with:
status: "COMPLETED" or error messagebackend: Backend usedshots: Number of shotscounts: Measurement outcome counts (if shots > 0)statevector: Statevector (if shots=None)time_taken: Execution time in seconds
Example:
result = run_circuit_tool(circuit, "aer_simulator", shots=1000, seed=42)
# Returns: {"status": "COMPLETED", "counts": {"00": 512, "11": 488}, ...}
run_circuits_tool
Executes multiple circuits in a batch.
Parameters:
circuits(list[dict]): List of circuits to executebackend_name(str, optional): Backend nameshots(int, optional): Number of shotsseed(int, optional): Random seed
Returns: List of result dictionaries
Example:
circuits = [circuit1, circuit2, circuit3]
results = run_circuits_tool(circuits, shots=100)
# Returns list of 3 result dictionaries
transpile_circuit_tool
Transpiles a circuit for optimization or specific backend.
Parameters:
circuit(dict): Circuit to transpileoptimization_level(int, optional): 0-3 (default: 1)basis_gates(list[str], optional): Target basis gates
Returns: Transpiled circuit dictionary
Example:
transpiled = transpile_circuit_tool(circuit, optimization_level=2)
MCP Resources
resource://backends
Provides a list of available quantum backends. Updated dynamically based on available providers.
resource://gates
Provides a list of all available quantum gates in Qiskit.
Usage Examples
Create a Bell State
# Create 2-qubit circuit
circuit = create_quantum_circuit(2, 2)
# Create Bell state: |Φ+⟩ = (|00⟩ + |11⟩) / √2
circuit = add_gate(circuit, "h", [0])
circuit = add_gate(circuit, "cx", [0, 1])
circuit = add_measurement(circuit, [0, 1])
# Execute
result = run_circuit(circuit, "aer_simulator", shots=1000)
print(result["counts"]) # Approximately {"00": 500, "11": 500}
Run Grover's Algorithm
def create_grover_circuit(num_qubits, iterations):
circuit = create_quantum_circuit(num_qubits, num_qubits)
# Initial superposition
for i in range(num_qubits):
circuit = add_gate(circuit, "h", [i])
# Grover iterations
for _ in range(iterations):
# Oracle (marked state |11...1⟩)
for i in range(num_qubits):
circuit = add_gate(circuit, "x", [i])
circuit = add_gate(circuit, "cx", list(range(num_qubits - 1)), [num_qubits - 1])
for i in range(num_qubits):
circuit = add_gate(circuit, "x", [i])
# Diffusion operator
for i in range(num_qubits):
circuit = add_gate(circuit, "h", [i])
for i in range(num_qubits):
circuit = add_gate(circuit, "x", [i])
circuit = add_gate(circuit, "cx", list(range(num_qubits - 1)), [num_qubits - 1])
for i in range(num_qubits):
circuit = add_gate(circuit, "x", [i])
for i in range(num_qubits):
circuit = add_gate(circuit, "h", [i])
# Measurement
circuit = add_measurement(circuit, list(range(num_qubits)))
return circuit
circuit = create_grover_circuit(3, 1)
result = run_circuit(circuit, "aer_simulator", shots=1000)
Draw and Analyze Circuit
circuit = create_quantum_circuit(2, 2)
circuit = add_gate(circuit, "h", [0])
circuit = add_gate(circuit, "cx", [0, 1])
circuit = add_measurement(circuit, [0, 1])
# Get depth
depth = get_circuit_depth(circuit)
print(f"Circuit depth: {depth}")
# List gates
gates = list_available_gates()
print(f"Available gates: {len(gates)}")
# Draw circuit
ascii_output = draw_circuit(circuit, "ascii")
print(ascii_output)
Run Shor's Algorithm
from mcp_qiskit import (
create_quantum_circuit,
add_gate,
add_measurement,
run_circuit,
)
def build_shor_circuit(N=15, a=2, n_count=8):
"""Build Shor's factoring circuit for N=15 using MCX gates."""
n = N.bit_length()
circuit = create_quantum_circuit(n_count + n, n_count)
# Superposition on first register
for i in range(n_count):
circuit = add_gate(circuit, "h", [i])
# Initialize second register to |1>
circuit = add_gate(circuit, "x", [n_count])
# Controlled modular exponentiation using MCX
for i in range(n_count):
power = pow(a, 2**i, N)
for j in range(n):
if (power >> j) & 1:
circuit = add_gate(circuit, "mcx", [[i], [n_count + j]])
# Inverse QFT (simplified)
for i in range(n_count - 1, -1, -1):
for j in range(i + 1, n_count):
circuit = add_gate(circuit, "cp", [i, j], [3.14159 / (2 ** (j - i))])
circuit = add_gate(circuit, "h", [i])
# Measure first register
circuit = add_measurement(circuit, list(range(n_count)))
return circuit
# Run Shor's algorithm to factor 15
circuit = build_shor_circuit(N=15, a=2, n_count=8)
result = run_circuit(circuit, "aer_simulator", shots=1000)
print(f"Results: {result['counts']}")
See examples/shor_example.py for a complete implementation with factor extraction.
Shor's Algorithm with MCP Qiskit Tools
Build Shor's algorithm circuit to factor N=15 using the MCP Qiskit server tools:
# Step 1: Create an 8-qubit circuit with 4 classical bits
circuit = create_quantum_circuit_tool(num_qubits=8, num_classical_bits=4)
# Step 2: Apply H gates to qubits 0-3 (superposition)
circuit = add_gate_tool(circuit=circuit, gate_name="h", qubits=[0, 1, 2, 3])
# Step 3: Apply X gates to qubits 4-7 (initialize to |1⟩)
circuit = add_gate_tool(circuit=circuit, gate_name="x", qubits=[4, 5, 6, 7])
# Step 4: Add modular exponentiation using CP gates
circuit = add_gate_tool(circuit=circuit, gate_name="cp", qubits=[0, 4], params=[3.14159/2]) # CP(π/2)
circuit = add_gate_tool(circuit=circuit, gate_name="cp", qubits=[1, 6], params=[3.14159/4]) # CP(π/4)
circuit = add_gate_tool(circuit=circuit, gate_name="cp", qubits=[2, 4], params=[3.14159]) # CP(π)
circuit = add_gate_tool(circuit=circuit, gate_name="cp", qubits=[3, 4], params=[3.14159]) # CP(π)
# Step 5: Apply inverse QFT using H and CP gates (reverse order)
# CP(π/4) on [2,3], CP(π/2) on [1,2], CP(π) on [0,1]
circuit = add_gate_tool(circuit=circuit, gate_name="cp", qubits=[2, 3], params=[3.14159/4])
circuit = add_gate_tool(circuit=circuit, gate_name="cp", qubits=[1, 2], params=[3.14159/2])
circuit = add_gate_tool(circuit=circuit, gate_name="cp", qubits=[0, 1], params=[3.14159])
# H gates in reverse order
circuit = add_gate_tool(circuit=circuit, gate_name="h", qubits=[3, 2, 1, 0])
# Step 6: Measure qubits 0-3
circuit = add_measurement_tool(circuit=circuit, qubits=[0, 1, 2, 3])
# Step 7: Run on aer_simulator
result = run_circuit_tool(circuit=circuit, backend_name="aer_simulator", shots=1024, seed=42)
print(f"Measurement results: {result['counts']}")
# Extract factors from the measurement result:
# 1. Compute the phase from measurement outcome
# 2. Find order r via continued fractions
# 3. Calculate gcd(a^(r/2) ± 1, N)
# Expected: Factorization of 15 = 3 × 5
Architecture
mcp-qiskit/
├── src/mcp_qiskit/
│ ├── __init__.py # Package exports
│ ├── __main__.py # CLI entry point
│ ├── _circuit.py # Circuit operations
│ ├── _backend.py # Backend management
│ ├── _execution.py # Circuit execution
│ └── _mcp.py # MCP server definition
├── tests/ # Test suite
├── SPEC.md # Project specification
└── README.md # This file
Module Responsibilities
- _circuit.py: Quantum circuit creation, gates, measurements, visualization
- _backend.py: Backend discovery, status, configuration
- _execution.py: Circuit execution, transpilation
- _mcp.py: FastMCP server definition, tool registration
Requirements
- Python 3.11+
- qiskit >= 2.3.1
- qiskit-aer >= 0.14.0
- fastmcp >= 2.0
Development
Setup
git clone https://github.com/daedalus/mcp-qiskit.git
cd mcp-qiskit
pip install -e ".[all]"
Running Tests
pytest -v
Code Quality
# Format code
ruff format src/ tests/
# Lint
ruff check src/ tests/
# Type check
mypy src/
Pre-commit Hooks
pre-commit install
Troubleshooting
API Keys and Credentials
This package supports two types of backends:
- Aer Simulator (default) - Runs locally, no API key required
- IBM Quantum - Requires an IBM Quantum API token
Using IBM Quantum Backends
To use IBM Quantum backends, you need to provide your API token:
Option 1: Environment Variable
export IBM_QUANTUM_TOKEN="your_api_token_here"
Or in your Python code:
import os
os.environ["IBM_QUANTUM_TOKEN"] = "your_api_token_here"
Option 2: Save Credentials via Qiskit
from qiskit_ibm_provider import IBMProvider
# Save your account (only needs to be done once)
IBMProvider.save_account(token="your_api_token_here", overwrite=True)
# Now you can use IBM backends
from mcp_qiskit._backend import list_backends, get_backend
backends = list_backends() # Will include IBM backends
backend = get_backend("ibm_qasm_simulator") # Or specific IBM backend
Getting an IBM Quantum Token:
- Create an account at IBM Quantum
- Go to Account > My Tokens
- Copy your API token
Environment Variable for MCP Server:
When running as an MCP server, set the environment variable before starting:
export IBM_QUANTUM_TOKEN="your_token"
mcp-qiskit
Or in your MCP client configuration:
{
"mcpServers": {
"mcp-qiskit": {
"command": "mcp-qiskit",
"env": {
"IBM_QUANTUM_TOKEN": "your_token_here"
}
}
}
}
Backend Not Found
If you get "Backend not found", ensure the backend name is correct:
# List available backends
backends = list_backends()
print([b["name"] for b in backends])
Import Errors
Make sure Qiskit is properly installed:
pip install qiskit==2.3.1 qiskit-aer
MCP Connection Issues
Verify the server is running:
mcp-qiskit --help
License
MIT License - see LICENSE file.
Contributing
Contributions are welcome! Please open an issue or submit a PR on GitHub.
Related Projects
- Qiskit - Quantum computing SDK
- FastMCP - MCP framework
- Model Context Protocol - Protocol specification
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_qiskit-0.1.1.tar.gz.
File metadata
- Download URL: mcp_qiskit-0.1.1.tar.gz
- Upload date:
- Size: 15.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6cc028f3ea1b834a9de9d194bb179cd379300a13906a3615bd9c69ade3db4296
|
|
| MD5 |
8bb7cdb765b2052d8ec6c5e138da3452
|
|
| BLAKE2b-256 |
b63a3d275b152ef7805c9fecacfe773a2dace04d59c77256ece2a1a2a4f5ea9d
|
Provenance
The following attestation bundles were made for mcp_qiskit-0.1.1.tar.gz:
Publisher:
pypi-publish.yml on daedalus/mcp-qiskit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_qiskit-0.1.1.tar.gz -
Subject digest:
6cc028f3ea1b834a9de9d194bb179cd379300a13906a3615bd9c69ade3db4296 - Sigstore transparency entry: 1242006496
- Sigstore integration time:
-
Permalink:
daedalus/mcp-qiskit@31f05835f17a425ce8aa746d538ed45dbbd396d6 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/daedalus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@31f05835f17a425ce8aa746d538ed45dbbd396d6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcp_qiskit-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mcp_qiskit-0.1.1-py3-none-any.whl
- Upload date:
- Size: 18.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d71c78b5e6bf3bc135d7aba695b8d70b9bc540c6c15b3549a57e8985f691ce0f
|
|
| MD5 |
3d7a6dedf5fbad84929d5415210dc018
|
|
| BLAKE2b-256 |
d40f2eeb7d632a6dbe747ddfb273ad29004c949cc0b82ed45848ff80b3c3beec
|
Provenance
The following attestation bundles were made for mcp_qiskit-0.1.1-py3-none-any.whl:
Publisher:
pypi-publish.yml on daedalus/mcp-qiskit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_qiskit-0.1.1-py3-none-any.whl -
Subject digest:
d71c78b5e6bf3bc135d7aba695b8d70b9bc540c6c15b3549a57e8985f691ce0f - Sigstore transparency entry: 1242006499
- Sigstore integration time:
-
Permalink:
daedalus/mcp-qiskit@31f05835f17a425ce8aa746d538ed45dbbd396d6 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/daedalus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@31f05835f17a425ce8aa746d538ed45dbbd396d6 -
Trigger Event:
release
-
Statement type: