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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ gcloud run deploy stim-mcp \
| `MCP_HOST` | `0.0.0.0` | Bind address for HTTP mode |
| `MCP_PORT` | `8080` | Port for HTTP mode |

## Privacy & Security

Circuit IDs are 128-bit random tokens (UUID v4), making them practically impossible to guess. However, the shared server has **no authentication and no access control** — anyone who obtains a circuit ID can read and modify that circuit.

**If you care about the privacy of your circuits, run the MCP server locally** (see [Running locally](#running-locally)). The remote server is intended for experimentation and learning, not sensitive work.

## Examples

> "Create a Bell state and sample it 1000 times"
Expand Down
37 changes: 37 additions & 0 deletions docs/qa/2026-03-23/circuit-id-privacy/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# QA Report — 2026-03-23

## Feature Tested
Circuit privacy improvements: 128-bit UUID circuit IDs (B) and privacy notice in `hello_quantum` + README (A).

## Target Server
Local — Stim version: 1.15.0

## Changes Analyzed
Branch: master (uncommitted)
Files changed: `circuit_store.py`, `server.py`, `README.md`

## Test Results

| # | Description | Tool Called | Inputs | Response | Result | Notes |
|---|-------------|-------------|--------|----------|--------|-------|
| 1 | hello_quantum returns privacy_notice | `hello_quantum` | `{}` | `{"status":"ok","stim_version":"1.15.0","active_sessions":0,"privacy_notice":"..."}` | PASS | All 4 keys present |
| 2 | circuit_id is 32 hex chars (128-bit) | `create_circuit` | Bell state circuit | `{"circuit_id":"c398bf98775b46e583e9b242b9cd131b"}` | PASS | len=32, valid hex |
| 3 | sample_circuit works with 32-char ID | `sample_circuit` | `circuit_id=c398...`, `shots=500` | `{"flip_rates":[0.5,0.5]}` | PASS | Bell state ~50% correct |
| 4 | get_circuit_diagram works with 32-char ID | `get_circuit_diagram` | `circuit_id=c398...`, `diagram_type=text` | ASCII diagram returned | PASS | |
| 5 | append_operation works with 32-char ID | `append_operation` | `circuit_id=c398...`, `DETECTOR rec[-1]` | `{"success":true}` | PASS | |
| 6 | inject_noise returns 32-char noisy circuit ID | `inject_noise` | `circuit_id=c398...`, `DEPOLARIZE1`, `p=0.01` | `{"noisy_circuit_id":"6bca8139d5a74082906d5c0c4df22ce8"}` | PASS | New ID also 32 chars |
| 7 | analyze_errors handles noisy circuit gracefully | `analyze_errors` | `circuit_id=6bca...` | `{"success":false,"error":"non-deterministic detectors..."}` | PASS | Expected Stim error for this circuit shape |
| 8 | Invalid 32-char circuit ID returns graceful error | `sample_circuit` | `circuit_id=deadbeef...deadbeef` | `{"success":false,"error":"No circuit found with id '...'"}` | PASS | |

## Summary
Total: 8 | Passed: 8 | Failed: 0 | Warnings: 0

## Issues Found
None.

## Passed Checks
- ✅ `hello_quantum` returns `privacy_notice` field
- ✅ Circuit IDs are 32 hex characters (128-bit, was 8)
- ✅ All tools (`sample_circuit`, `get_circuit_diagram`, `append_operation`, `inject_noise`, `analyze_errors`) accept and return 32-char IDs correctly
- ✅ `inject_noise` derivative circuits also get 32-char IDs
- ✅ Unknown circuit IDs return graceful `success: false` errors (no crash)
2 changes: 1 addition & 1 deletion src/stim_mcp_server/circuit_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __init__(self) -> None:

def create(self, circuit: stim.Circuit) -> str:
"""Store a circuit and return a new session ID."""
circuit_id = uuid.uuid4().hex[:8]
circuit_id = uuid.uuid4().hex
self._sessions[circuit_id] = CircuitSession(circuit=circuit)
return circuit_id

Expand Down
6 changes: 6 additions & 0 deletions src/stim_mcp_server/tools/health.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ def hello_quantum() -> str:
"status": "ok",
"stim_version": stim.__version__,
"active_sessions": len(_store.list_ids()),
"privacy_notice": (
"This is a shared server. Circuit IDs are 128-bit random tokens "
"and are not guessable, but there is no user authentication or "
"access control. Do not use this server for sensitive circuits. "
"For private use, run the MCP server locally."
),
}
)

Expand Down
6 changes: 3 additions & 3 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_create_and_get(self):
store = CircuitStore()
circuit = stim.Circuit("H 0\nM 0")
cid = store.create(circuit)
assert len(cid) == 8
assert len(cid) == 32
session = store.get(cid)
assert session.circuit == circuit

Expand Down Expand Up @@ -90,7 +90,7 @@ class TestCreateCircuit:
def test_valid_circuit(self):
result = json.loads(create_circuit(BELL_CIRCUIT))
assert result["success"] is True
assert len(result["circuit_id"]) == 8
assert len(result["circuit_id"]) == 32
assert result["num_qubits"] == 2
assert result["num_measurements"] == 2

Expand Down Expand Up @@ -287,7 +287,7 @@ class TestGenerateCircuit:
def test_repetition_code(self):
result = json.loads(generate_circuit("repetition_code:memory", rounds=5, distance=3))
assert result["success"] is True
assert len(result["circuit_id"]) == 8
assert len(result["circuit_id"]) == 32
assert result["num_qubits"] > 0
assert result["num_detectors"] > 0
assert result["num_observables"] > 0
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading