Skip to main content

marqov-mcp

An MCP server for the Marqov quantum orchestration platform, so Claude Code — or any MCP client, or your own agent — can discover backends, price runs, execute on a free simulator, and inspect jobs directly.

Preview. Tool contract version 1. The tools are stable enough to build against. Browser authorization and stored credentials are supported (see Authentication).

You need a Marqov account. The platform is in an invite-only beta. Without an account, list_backends and check_backend_availability still work; every other tool needs a key from a Marqov team. Full guide: AI Assistants (MCP Server).

What it is, and what it is not

This wraps the Marqov control plane: backends, cost estimates, jobs, traces, budget, playground.

It is not a Qiskit MCP. A model writes Qiskit competently from its own weights, and wrapping circuit construction in a tool call spends context to buy nothing. What a model cannot know from its weights is your live fleet, your prices, your job IDs and your team's budget — which is exactly where tools earn their place.

Authentication

You supply your own Marqov API key. The server holds no user model, no session store and no state; it forwards your key and the platform decides, per request.

Authorise this machine in a browser:

marqov-mcp login          # shows a code, opens the consent page, stores the key it is granted
marqov-mcp status --check # confirms the platform accepts it

You get a short code, a team owner or admin approves it on the Marqov site, and the key is issued to this machine — scoped, capped and revocable. The approver can grant less than was asked for, so check what login reports at the end.

--level asks for a permission level (default simulate, the lowest that can run simulations), --spend-limit asks for a daily cap in USD, and --client-name sets the name shown on the approval screen.

No browser, or no admin to hand? marqov-mcp login --paste still takes a key you minted yourself.

Or supply it per-process:

export MARQOV_API_KEY="marqey_..."       # Team -> Marqov API Keys in the Marqov UI
export MARQOV_BASE_URL="https://app.marqov.ai"   # optional

The environment wins if both are present, so an exported key always overrides a stored one. If MARQOV_API_KEY is not set, the server also reads MARQOV_PLATFORM_KEY, the variable the marqov Python SDK uses, so one exported key serves both. marqov-mcp logout removes the stored credential.

Only team owners and admins can authorise agent access today. If you are neither, ask one of them to approve the code login shows you.

Mint the key with the lowest permission level you need and a daily spend limit. The key carries its own permission tier (browse / simulate / qpu / seal), team scope and spend ceiling, all enforced server-side — the server can do nothing your key cannot.

Scope is your team, not you personally. A key is team-scoped, so list_jobs will show work submitted by anyone on the team, not only your own. That is correct behaviour.

list_backends needs no key at all, so you can discover the fleet before you have an account.

Install

Requires uv.

uvx marqov-mcp login
claude mcp add --scope user marqov \
  -e MARQOV_BASE_URL=https://app.marqov.ai \
  -- uvx marqov-mcp

Or copy .mcp.json.example to .mcp.json in a project after logging in. The server uses the stored credential, or MARQOV_API_KEY if explicitly set in its environment.

Desktop clients may not inherit shell variables. Browser login stores the credential where the server can resolve it without putting a literal key into client configuration.

Tools

Tool Needs What it does
list_backends — The fleet: slug, provider, type, qubits, availability
check_backend_availability — Only what is up, with queue times and pricing
estimate_cost browse Price a run without running it
run_on_simulator simulate Run a program on a free simulator, get counts. Currently failing on the platform side; use the Local Simulator on the Run page meanwhile
list_jobs browse This team's jobs, filterable by status and date
get_job_status browse Where a job got to
get_job_result browse The full result payload
get_job_trace browse Execution trace — the debugging tool
get_team_usage browse The team's recorded spend for a month, by provider, backend and day
save_script simulate Save source to the team's script library; idempotent on a caller-supplied key
get_execution_options browse Where a saved script can run, why not elsewhere, and the team's available balance
analyse_script simulate The platform's pre-run analysis of a saved script for one backend: cost, checks, can_run
submit_managed_run simulate Submit a saved task/workflow script as a tracked job on a free managed simulator, under a required cap; dry-run by default

get_team_usage reports spend, not headroom: the usage API does not expose the team's spending limit or a key's daily cap, and the tool says so rather than inventing a budget. It also reports pending_settlement_jobs, completed paid jobs whose charge has not settled and so are not yet in the totals. get_execution_options does report the team's available balance, because the platform returns it with the per-script preflight.

Preparing a run (milestone 2). save_script, get_execution_options and analyse_script take a user to the doorstep of a tracked or paid run with every check the platform offers. The only submission this server makes is the free managed run described under milestone 3; paid runs are submitted in the web app or the SDK. analyse_script returns the analysis_id a paid submission requires, which is single-use and expires after fifteen minutes; the user submits it with the script_id in the web app or the SDK. Analysing a saved script persists an analysis row on the platform, which is why it needs simulate. save_script sends one request with an Idempotency-Key (pass idempotency_key to make a retry identical) and returns the key with every outcome.

Submitting a tracked run (milestone 3). submit_managed_run is the one tool that can create a job. It speaks the platform's managed contract (marqov.public-submission/v1), which admits a run atomically against a mandatory per-job cap, and it is restricted on purpose:

  • Free managed simulators only. Today that is marqov-sim, the one managed destination the platform also vouches as free of provider cost. Paid hardware stays unreachable from this server until an API key can cancel a job.
  • A cap is required and bounded twice. The caller must pass cap_cents, the most the platform may reserve of the team's funding for the job. The platform caps a job at $100; this server refuses anything above 500 cents by default. An operator may raise that with MARQOV_MCP_MAX_CAP_CENTS, never past 2500. "Free of provider cost" does not mean the platform reserves nothing: the cap covers compilation and tasks, and an insufficient balance or spending limit is refused with HTTP 402.
  • Dry run by default. The default call checks the key's team, the runtimes enabled for it, the cap against the runtime's range, and the saved source, then returns the exact request without sending it. dry_run=false sends it. MARQOV_MCP_SUBMIT_DRY_RUN=1 forces dry run whatever the caller passes.
  • One key, identical bytes. The platform deduplicates on the UUID Idempotency-Key plus the body and returns the original receipt for an identical retry, so the client's bounded retry of a connection error or a 503 is a replay, not a second job. A read timeout is never retried. Every outcome returns the key, and the advice is always to retry with the same key, never a fresh one.
  • Source is pinned. The submission carries the SHA-256 of the saved script as read during preflight; if the script changes before admission the platform refuses with HTTP 409, and a receipt describing different source is reported as an error that names the admitted job.

Admission means funded and queued, not finished: follow the returned job_id with get_job_status.

Projects tools (opt-in, default off)

Thirteen more tools read and write a team's Projects (living lab notebooks) and can seal one into an immutable Capsule. They are not registered unless you set MARQOV_MCP_ENABLE_PROJECTS=1, because they are a step past this server's read-and-simulate posture and whether they stay is an open decision. With the flag off the surface is exactly the thirteen tools above.

Tool Needs What it does
list_projects browse The team's Projects
read_project_workspace browse The Workspace's blocks, paged and trimmed; one block in full by id
list_scripts browse Discover saved team scripts with pagination
read_script browse Read current source and requirements in pages, with content digests
create_project_from_job simulate Seed a new Project from an existing completed job; dry-run by default
add_markdown_block simulate Append a markdown block
add_script_block simulate Append a block referencing a saved script, optionally associated with the completed job that ran it
add_result_block simulate Append a result block pinned to a completed job
add_image_block simulate Upload a local PNG/JPEG/GIF/WebP and append it
add_dated_update simulate Append a dated update, optionally with a first note
get_seal_readiness browse Blockers and warnings a Capsule seal would hit; read-only
prepare_capsule browse Check readiness, metadata and version conflicts; return a proposed seal request
seal_project seal Seal into an immutable Capsule (dry-run by default, needs certify=true)

A Project can have several Workspaces. These tools use the one the platform names as primary, never an archived one, and refuse rather than guess if several are active and none is primary. The platform seals one Workspace, so readiness blocks while several are active.

Design rules: writes are append-only (no edit or delete of an existing block) and target the Workspace only, never the Report. Block content is user-authored data and is described to the model as such.

Update notes are new blocks; even the empty markdown block seeded by the platform is left untouched. Projects writes are sent once. Ordinary appends and seals do not deduplicate retries. After an ambiguous failure, inspect the Workspace or Capsule versions before retrying. If a dated update succeeds but its note fails, the error includes the new update_group_id so the caller can append the note without recreating the update.

The from-job creation route deduplicates on the Idempotency-Key plus the request body. Its two replay outcomes are named: a key still being processed (HTTP 409) says to wait and retry with the same key and identical arguments; a key reused with different arguments (HTTP 422) says to inspect existing state before choosing a new key. Other conflicts (HTTP 409, such as an existing Capsule version) and rejected writes (HTTP 400) state that nothing new was created.

All failed tool operations return the standard MCP isError: true alongside an actionable text explanation, including missing credentials, permission failures, HTTP errors and transport failures. Readiness checks fail when a dependency cannot be checked, so unavailable data cannot produce a false readiness result.

Tools also advertise MCP read-only, destructive and idempotency hints. These describe effects for downstream clients; platform authorization remains the enforcement point.

Bounded reads and pagination. list_projects returns next_offset; pass it as offset to continue until null. read_project_workspace pages blocks with next_offset. To read a long block, supply block_id, then pass its next_content_offset as content_offset until null. max_chars for workspace previews is limited to 0–4000. Each page of a block carries content_sha256 for the whole block; if it changes between pages, a colleague edited the block mid-read and the pages must not be joined.

get_job_result keeps small results as their original JSON. Large results return a json-text-page object with content, total_chars, content_sha256 and next_offset. Concatenate the content pages in order and parse the combined JSON; pass next_offset as offset until null. max_chars is 1–4000. Offsets count characters, including Unicode. No available result is an explicit error; inspect get_job_status for the job state.

Every tool response is redacted and capped at 32,000 characters. Oversized responses without dedicated pagination return an explicit truncated preview. Invalid JSON and platform error envelopes never become successful tool results.

Dry run. Every write takes dry_run. A dry run does the reads it needs, records the exact request it would have sent, and sends nothing. MARQOV_MCP_PROJECTS_DRY_RUN=1 forces this for every write whatever the model passes; MARQOV_MCP_DRY_RUN_LOG=/path.jsonl appends each record as a JSON line. seal_project defaults to dry run, and a real seal needs dry_run=false and certify=true, because the certification is a statement about accuracy that belongs to the user.

The in-memory dry-run history retains the latest 100 records. The optional JSONL log is the durable record.

get_seal_readiness checks the platform's structural requirements and additionally blocks empty source, unavailable result payloads, empty narrative and placeholder-only narrative. The seal endpoint remains the authority. As on the platform, having no result blocks at all is a warning, permitting reference-only Capsules.

Readiness also returns evidence: one entry per script and result block saying what it pins and whether a seal would carry a submitted-source snapshot (executed_source_sealed) or the current saved revision. The list is bounded to 60 entries, with evidence_truncated set when a Project has more. capsule_source_policy states the platform's rule in words, and workspace_fingerprint digests the blocks a seal would read.

Existing results to Capsule preparation

  1. Find a completed run with list_jobs, then inspect get_job_status and get_job_result. Keep the exact job ID with the observations; a free synchronous simulator run has no job record and cannot become a result-block reference.
  2. Choose an existing Project with list_projects, or preview create_project_from_job. To create the new notebook, repeat with dry_run=false and the preview's idempotency_key. This route supports idempotent recovery: retain the key and identical arguments after an uncertain response. The tool verifies that the new Workspace actually contains the expected result block; partial failures preserve the project ID so the caller can recover without creating another notebook.
  3. Read the Workspace. A notebook created from a job returns result_block_ids and any script_ids. Inspect saved code and dependencies with read_script; use list_scripts to discover existing library references. Follow next_offset and check content_sha256 stays constant across script pages.
  4. For an existing Project, append the intended result with add_result_block and, when verified, the saved-script reference with add_script_block. Result appends check that the job completed and has a payload; script appends reject empty or deleted source. A library match alone does not establish an execution relationship. When the job ran that exact saved script, pass its job_run_id to add_script_block so the platform records the association and seals the submitted-source snapshot. The tool reads the association back from the receipt: a platform that does not record it returns an error naming the appended block as reference-only, so the caller never describes current source as executed code and never appends the block twice.
  5. Append narrative with add_markdown_block or add_dated_update, citing exact job and result-block IDs. Distinguish observations, interpretation, and provenance limitations. Seeded narrative placeholders are preserved; readiness warns that they will appear in the Capsule and blocks preparation until substantive narrative exists.
  6. Call prepare_capsule with the intended name, new version, and contributor details. It uses read-only requests, checks metadata and existing versions, and returns prepared_for_seal, blockers, warnings, and the proposed request. It never records certification or seals. seal_project with its default dry-run can record that same request. An ordinary dry run records intent; it does not validate readiness.
  7. Preparation and sealing are tied together by workspace_fingerprint. Pass it to seal_project as expected_workspace_fingerprint: the seal re-reads the Workspace and refuses, sending nothing, if any block was added, reordered or edited since the user reviewed the prepared request. A dry run with the fingerprint reports workspace_fingerprint_matches without sealing.

Provenance limit: the platform snapshots the submitted source and its SHA-256 on every job at submission, and its seal route uses that snapshot for a script block that is associated with the job. But the public job-status API exposes neither the snapshot, its hash nor script_id, so this server cannot verify an association itself; it reports what the platform recorded. A script block with no association is sealed from the current saved revision, which can change after a run. read_script explicitly returns the current saved revision, and reference-only script blocks must not be described as verified execution snapshots. An inline-code job may have no saved script; do not attach an unrelated library entry to bypass a readiness blocker. Recording an association from add_script_block or create_project_from_job needs a platform that accepts job_run_id on script blocks, which the platform does not yet do; on the current platform both tools report the reference as unassociated. Actual sealing still requires explicit user instruction and certification plus a seal-tier key; preparation is an advisory check, not a guarantee of platform acceptance.

Submitting to real hardware is not available through this server. It can show you QPUs and price them, but not run on them — use the web UI or the marqov SDK.

Develop

uv run --extra dev pytest          # offline suite
uv run --extra dev ruff check .
MARQOV_API_KEY=marqey_... uv run --extra dev pytest -m live   # real platform

The live suite is opt-in and hits app.marqov.ai. It uses MARQOV_API_KEY if set, otherwise the credential stored by marqov-mcp login. It is worth running before any release: both bugs found in this server's first live run — a playground cold start outrunning the client timeout, and a 404 blaming team scoping for a job that simply had no trace — were invisible to the mocked tests. Note that it includes one free simulator execution (run_on_simulator), which creates no job record and costs nothing.

Releasing

Releases are published to PyPI by .github/workflows/publish.yml through PyPI trusted publishing, so no token lives in the repository. To cut one:

  1. Set version in pyproject.toml and __version__ in src/marqov_mcp/__init__.py, move the CHANGELOG.md heading from "unreleased" to the date, and merge.
  2. Create a GitHub release tagged vX.Y.Z (the workflow refuses a tag that does not match the package version).
  3. The workflow runs Ruff and the offline suite, builds, and publishes. uvx marqov-mcp then resolves for everyone.

One-time setup is described at the top of the workflow file: a pending trusted publisher on pypi.org for marqov-mcp pointing at this repository and workflow, and a GitHub environment named pypi.

Status

Preview. The default surface covers watching, preparing, and free managed runs; see CHANGELOG.md. Report bugs in Issues and security problems as described in SECURITY.md.

Licence

Apache-2.0.

Metadata

Release files for marqov-mcp 0.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for marqov-mcp 0.3.2
File Size Uploaded Provenance Actions
marqov_mcp-0.3.2.tar.gz 176.7 kB With provenance Details for marqov_mcp-0.3.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for marqov-mcp 0.3.2
File Interpreter ABI Platform Actions
marqov_mcp-0.3.2-py3-none-any.whl Python 3 none any Details for marqov_mcp-0.3.2-py3-none-any.whl

Total release size: 242.8 kB

Release files / marqov_mcp-0.3.2.tar.gz

Download URL marqov_mcp-0.3.2.tar.gz
Size 176.7 kB
Tags Source
SHA-256 checksum
How to use checksums
8f4f56f4ede7606eb8df762dc45cfa771143a517f9ce812998f3d6442c83d479
BLAKE2b-256 checksum
How to use checksums
a563a11e3c6f737e5fd6b500ad59d39ea016b6a3da84af50a50adee30a175f9b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Release files / marqov_mcp-0.3.2-py3-none-any.whl

Download URL marqov_mcp-0.3.2-py3-none-any.whl
Size 66.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5d96ae7c11834cb4b4ce2c599fd15903f926ea15ab3029b0eb711846f09818c7
BLAKE2b-256 checksum
How to use checksums
9eb5a0f06f0277931527189c0f7e1e3795e154c297205035ab344a6b3a4df77c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Security for marqov-mcp 0.3.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for marqov_mcp-0.3.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.3.2 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page