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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ Circuit IDs are 128-bit random tokens (UUID v4), making them practically impossi

**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.

Tool invocations on the remote server are logged anonymously (tool name only, no arguments or circuit data) for usage analytics.

## Examples

> "Create a Bell state and sample it 1000 times"
Expand Down
17 changes: 17 additions & 0 deletions src/stim_mcp_server/analytics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Tool usage analytics — logs tool name only, no arguments or user data."""

from __future__ import annotations

import functools
import logging

logger = logging.getLogger("stim_mcp.tools")


def log_tool_call(fn):
"""Wrap a tool function to emit a structured log line on each invocation."""
@functools.wraps(fn)
def wrapper(*args, **kwargs):
logger.info("tool_call tool=%s", fn.__name__)
return fn(*args, **kwargs)
return wrapper
3 changes: 3 additions & 0 deletions src/stim_mcp_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

from __future__ import annotations

import logging
import os

logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s %(message)s")

from mcp.server.fastmcp import FastMCP

from .circuit_store import CircuitStore
Expand Down
6 changes: 4 additions & 2 deletions src/stim_mcp_server/tools/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import stim

from stim_mcp_server.analytics import log_tool_call

_store = None


Expand Down Expand Up @@ -125,5 +127,5 @@ def inject_noise(
def register(mcp, store) -> None:
global _store
_store = store
mcp.tool()(analyze_errors)
mcp.tool()(inject_noise)
mcp.tool()(log_tool_call(analyze_errors))
mcp.tool()(log_tool_call(inject_noise))
8 changes: 5 additions & 3 deletions src/stim_mcp_server/tools/circuit_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import stim

from stim_mcp_server.analytics import log_tool_call

SUPPORTED_TASKS = [
"repetition_code:memory",
"surface_code:rotated_memory_x",
Expand Down Expand Up @@ -143,6 +145,6 @@ def generate_circuit(
def register(mcp, store) -> None:
global _store
_store = store
mcp.tool()(create_circuit)
mcp.tool()(append_operation)
mcp.tool()(generate_circuit)
mcp.tool()(log_tool_call(create_circuit))
mcp.tool()(log_tool_call(append_operation))
mcp.tool()(log_tool_call(generate_circuit))
7 changes: 5 additions & 2 deletions src/stim_mcp_server/tools/health.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import stim

from stim_mcp_server.analytics import log_tool_call

_store = None


Expand All @@ -20,7 +22,8 @@ def hello_quantum() -> str:
"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."
"For private use, run the MCP server locally. "
"Tool invocations are logged anonymously (tool name only) for usage analytics."
),
}
)
Expand All @@ -29,4 +32,4 @@ def hello_quantum() -> str:
def register(mcp, store) -> None:
global _store
_store = store
mcp.tool()(hello_quantum)
mcp.tool()(log_tool_call(hello_quantum))
4 changes: 3 additions & 1 deletion src/stim_mcp_server/tools/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import json

from stim_mcp_server.analytics import log_tool_call

_store = None


Expand Down Expand Up @@ -59,4 +61,4 @@ def sample_circuit(circuit_id: str, shots: int = 1000) -> str:
def register(mcp, store) -> None:
global _store
_store = store
mcp.tool()(sample_circuit)
mcp.tool()(log_tool_call(sample_circuit))
4 changes: 3 additions & 1 deletion src/stim_mcp_server/tools/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import cairosvg
from mcp.server.fastmcp import Image

from stim_mcp_server.analytics import log_tool_call

_store = None


Expand Down Expand Up @@ -78,4 +80,4 @@ def get_circuit_diagram(
def register(mcp, store) -> None:
global _store
_store = store
mcp.tool()(get_circuit_diagram)
mcp.tool()(log_tool_call(get_circuit_diagram))
Loading