Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
392 changes: 392 additions & 0 deletions docs/mcp.md

Large diffs are not rendered by default.

147 changes: 147 additions & 0 deletions examples/mcp_client_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
"""End to end demo: talk to the SuperQuantX MCP server over stdio.

This is exactly what an AI assistant (Claude Desktop, Cursor, ...) does: it
spawns ``superquantx-mcp`` (or ``python -m superquantx.mcp``) as a subprocess
and speaks the Model Context Protocol over stdin/stdout.

Usage::

pip install "superquantx[mcp,qiskit,pennylane]"
python examples/mcp_client_demo.py # uses python -m superquantx.mcp
python examples/mcp_client_demo.py --script # uses the superquantx-mcp script
python examples/mcp_client_demo.py --json out.json
"""

from __future__ import annotations

import argparse
import json
import shutil
import sys
import time

import anyio
from mcp import Client, StdioServerParameters


BELL_QASM3 = """OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
bit[3] c;
h q[0];
cx q[0], q[1];
cx q[1], q[2];
c = measure q;
"""

GATE_LIST = {
"n_qubits": 2,
"gates": [
{"gate": "ry", "qubits": [0], "params": ["pi/3"]},
{"gate": "cx", "qubits": [0, 1]},
],
}

SQUARE_WITH_DIAGONAL = [[0, 1], [1, 2], [2, 3], [3, 0], [0, 2]]


def calls(backends: list[str]) -> list[tuple[str, dict]]:
plan: list[tuple[str, dict]] = [
("list_backends", {}),
("backend_versions", {}),
("bell_state_demo", {"shots": 1000}),
]
for b in backends:
plan.append(
("run_circuit", {"circuit": BELL_QASM3, "backend": b, "shots": 1000})
)
plan.append(
("run_circuit", {"circuit": GATE_LIST, "backend": "simulator", "shots": 1000})
)
for b in backends:
plan.append(
(
"qsvm_classify",
{"dataset": "moons", "backend": b, "n_samples": 40, "seed": 7},
)
)
plan.append(
(
"qsvm_classify",
{"dataset": "iris", "backend": "simulator", "n_samples": 40, "seed": 7},
)
)
for b in backends:
plan.append(
(
"qaoa_maxcut",
{"edges": SQUARE_WITH_DIAGONAL, "backend": b, "p": 1, "seed": 0},
)
)
plan.append(
("run_circuit", {"circuit": "OPENQASM 2.0; qreg q[64]; h q[0];"})
) # rejected: too many qubits
return plan


async def main(args: argparse.Namespace) -> int:
if args.script:
exe = shutil.which("superquantx-mcp")
if exe is None:
print("superquantx-mcp not found on PATH", file=sys.stderr)
return 2
params = StdioServerParameters(command=exe, args=[])
else:
params = StdioServerParameters(
command=sys.executable, args=["-m", "superquantx.mcp"]
)

transcript: list[dict] = []
async with Client(params) as client:
tools = await client.list_tools()
names = [t.name for t in tools.tools]
print(f"connected via {params.command} {' '.join(params.args)}")
print(f"tools: {names}\n")
transcript.append({"launch": [params.command, *params.args], "tools": names})

for name, arguments in calls(args.backends):
t0 = time.perf_counter()
result = await client.call_tool(name, arguments)
wall = round((time.perf_counter() - t0) * 1000, 1)
payload = result.structured_content
if payload is None:
payload = {"raw": [getattr(c, "text", str(c)) for c in result.content]}
print(f"=== {name}({json.dumps(arguments)[:120]}) [{wall} ms round trip]")
print(json.dumps(payload, indent=2)[: args.max_chars])
print()
transcript.append(
{
"tool": name,
"arguments": arguments,
"round_trip_ms": wall,
"result": payload,
}
)

if args.json:
with open(args.json, "w") as fh:
json.dump(transcript, fh, indent=2)
print(f"wrote {args.json}")
return 0


if __name__ == "__main__":
p = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
p.add_argument(
"--script",
action="store_true",
help="launch the superquantx-mcp console script",
)
p.add_argument(
"--backends", nargs="+", default=["simulator", "qiskit", "pennylane"]
)
p.add_argument("--json", help="write the full transcript to this file")
p.add_argument("--max-chars", type=int, default=2500)
sys.exit(anyio.run(main, p.parse_args()))
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ nav:
- Overview: user-guide/overview.md
- Quantum Backends: user-guide/backends.md
- Algorithms: user-guide/algorithms.md
- MCP Server for AI Assistants: mcp.md
- Tutorials:
- Basic Quantum Computing: tutorials/basic-quantum.md
- Quantum Machine Learning: tutorials/quantum-ml.md
Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ ocean = [
"dimod>=0.12.22",
]

# MCP server for AI assistants (superquantx-mcp, python -m superquantx.mcp)
mcp = [
"mcp>=2.3,<3",
]

# Development dependencies - latest versions
dev = [
"pytest>=8.0.0",
Expand Down Expand Up @@ -141,6 +146,7 @@ Changelog = "https://github.com/SuperagenticAI/superquantx/blob/main/CHANGELOG.m

[project.scripts]
superquantx = "superquantx.cli:main"
superquantx-mcp = "superquantx.mcp.server:main"

[tool.hatch.version]
path = "src/superquantx/version.py"
Expand Down
53 changes: 53 additions & 0 deletions skills/superquantx/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
name: superquantx
description: Use when the user wants to run, compare, or explain quantum circuits, Bell or GHZ states, quantum kernel SVM classification, or QAOA MaxCut across quantum SDKs (built-in simulator, Qiskit, PennyLane, Cirq, Braket, TKET) through the SuperQuantX MCP server.
---

# SuperQuantX quantum workflows (MCP)

The `superquantx` MCP server exposes six read-only tools. They run on local noiseless simulators
unless the server operator set `SUPERQUANTX_MCP_ALLOW_HARDWARE=1`.

If the tools are not available, ask the user to install and register the server:

```bash
pip install "superquantx[mcp,qiskit,pennylane]"
# then add {"command": "<venv>/bin/superquantx-mcp"} under mcpServers in the client config
```

See `docs/mcp.md` in the SuperQuantX repository for Claude Desktop and Cursor snippets.

## Workflow

1. **Start with `list_backends`.** Use only backends whose `status` is `working`. Tell the user
which ones are `not_installed` and the install hint from `error`, rather than guessing.
2. **Pick the tool:**
- Run a circuit: `run_circuit` with OpenQASM 2, OpenQASM 3, or a JSON gate list
(`{"n_qubits": 2, "gates": [{"gate": "h", "qubits": [0]}, {"gate": "cx", "qubits": [0, 1]}]}`).
Parameters can be numbers or strings like `"pi/2"`.
- Show entanglement across SDKs: `bell_state_demo`.
- Classification: `qsvm_classify` (datasets `moons`, `circles`, `blobs`, `xor`, `iris`, or `X`/`y`).
- Optimization: `qaoa_maxcut` with `edges` like `[[0,1],[1,2],[2,0]]`.
- Environment report: `backend_versions`.
3. **Compare backends** by calling the same tool with `backend` set to each working backend.
4. **Read results correctly:**
- Counts are little-endian: qubit 0 is the rightmost bit (`"01"` means qubit 0 is 1).
- Always check `"ok"`. On `false`, show `error.message`; for `ValidationError` fix the input
(limits are in the message) instead of retrying unchanged.
- For `qsvm_classify`, report the quantum accuracy next to `classical_rbf_baseline` and check
`kernel_diagnostics.looks_valid`.
- For `qaoa_maxcut`, report `best_sampled_cut` against `classical_brute_force.max_cut`, plus
`approximation_ratio`.

## Honesty rules

- Never claim quantum advantage or speedup from these results. They are toy-scale, noiseless
simulations; brute force and classical SVMs are faster and often as accurate. Repeat the tool's
`note` field when summarizing.
- Do not claim hardware execution unless the result's `device` is a real device.
- Simulator results are exact up to shot noise; mention shot counts when comparing distributions.

## Limits (defaults, configurable by the operator)

10 qubits, 10000 shots, 500 gates, 80 QSVM samples with up to 4 features, QAOA up to 10 nodes and
3 layers. Hard ceilings: 16 qubits, 100000 shots.
14 changes: 14 additions & 0 deletions src/superquantx/mcp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Model Context Protocol (MCP) server for SuperQuantX.

Lets AI assistants such as Claude Desktop and Cursor drive quantum workloads
across SDKs through the SuperQuantX unified API. Install with
``pip install "superquantx[mcp]"`` and run ``superquantx-mcp``.

The tool implementations in :mod:`superquantx.mcp.tools` are plain Python and
do not need the ``mcp`` package; only :func:`build_server` / :func:`main` do.
"""

from .server import build_server, main


__all__ = ["build_server", "main"]
7 changes: 7 additions & 0 deletions src/superquantx/mcp/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Allow ``python -m superquantx.mcp``."""

from .server import main


if __name__ == "__main__":
main()
Loading
Loading