Metadata-Version: 2.5
Name: softqcos-mcp
Version: 3.11.0
Summary: QCOS MCP Server — typed quantum computing tools for AI agents via Model Context Protocol
Author-email: SoftQuantus innovative OÜ <support@softquantus.com>
Maintainer-email: SoftQuantus innovative OÜ <support@softquantus.com>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: mcp<2.0.0,>=1.5.0
Requires-Dist: softqcos-sdk<4,>=3.11.0
Requires-Dist: starlette>=0.37
Requires-Dist: uvicorn>=0.30
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# SoftQCOS MCP

[![PyPI version](https://img.shields.io/pypi/v/softqcos-mcp.svg)](https://pypi.org/project/softqcos-mcp/)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)

A [Model Context Protocol](https://modelcontextprotocol.io) server that gives
an AI agent typed tools over the QCOS REST API at `https://api.softquantus.com`.
Each tool is one call to that API, made with the caller's own API key. The
server has no privileges of its own and runs nothing the API does not serve.

The MCP server, the Python SDK (`softqcos-sdk`) and the CLI (`softqcos`) are
released together and always carry the same version number. The table at the
end of this page lists which tools each version added.

## Install

```bash
pip install softqcos-mcp
```

Python 3.11 or newer. The package installs one command, `softqcos-mcp`, which
starts the server. It installs `softqcos-sdk` as a dependency.

## Run it

```bash
softqcos-mcp
```

The server speaks **Streamable HTTP** (stateless) and listens on
`http://127.0.0.1:8100/mcp`, this machine only. Stop it with Ctrl-C.
`softqcos-mcp --help` and `softqcos-mcp --version` print and exit without
starting a server.

Check that it is up:

```bash
curl -s http://127.0.0.1:8100/health
```

It answers `{"status":"ok","service":"softqcos-mcp"}`.

For a client that starts its MCP servers itself, over stdin/stdout, run it as
`softqcos-mcp --transport stdio` (see Claude Desktop below). Over stdio there is
no header to carry a key, so the tools act for the key in `QCOS_API_KEY`.

| Flag | Environment variable | Default | Meaning |
|---|---|---|---|
| `--transport` | | `http` | `http` (Streamable HTTP on `/mcp`) or `stdio` |
| `--host` | `SOFTQCOS_MCP_HOST` | `127.0.0.1` | HTTP address to bind |
| `--port` | `SOFTQCOS_MCP_PORT` | `8100` | HTTP port to bind |
| | `QCOS_API_KEY` | none | your key; over stdio every tool uses it |
| | `QCOS_API_URL` | `https://api.softquantus.com` | the QCOS API the tools call |
| | `QCOS_LOG_LEVEL` | `info` | server log level |
| | `QCOS_ENV` | `development` | `production` requires a bearer token on `/mcp`, see below |
| | `QCOS_MCP_BEARER_TOKEN` | none | the token `/mcp` demands when `QCOS_ENV=production` |

A flag wins over its environment variable. Binding anything other than
loopback (`--host 0.0.0.0`) exposes `/mcp` to the network; read "Running it for
others" first.

## Your API key

Create an API key at <https://platform.softquantus.com/#apikeys>. The MCP
client sends it on every request in the `x-api-key` header (`x-qcos-api-key`
is accepted too). The server forwards it to the API for that call and keeps
nothing.

Identity comes from the key alone. `x-tenant-id`, `x-project-id` and
`x-user-id` headers are ignored: anyone could write any value in them.

## Connect a client

Claude Code:

```bash
claude mcp add --transport http softqcos http://127.0.0.1:8100/mcp --header "x-api-key: $QCOS_API_KEY"
```

Cursor (`.cursor/mcp.json`) and other clients that take a URL and headers:

```json
{
  "mcpServers": {
    "softqcos": {
      "url": "http://127.0.0.1:8100/mcp",
      "headers": { "x-api-key": "<your key>" }
    }
  }
}
```

VS Code (`.vscode/mcp.json`):

```json
{
  "servers": {
    "softqcos": {
      "type": "http",
      "url": "http://127.0.0.1:8100/mcp",
      "headers": { "x-api-key": "${input:qcos-api-key}" }
    }
  },
  "inputs": [
    { "id": "qcos-api-key", "type": "promptString", "description": "QCOS API key", "password": true }
  ]
}
```

Claude Desktop (`claude_desktop_config.json`) starts the server itself, over
stdio:

```json
{
  "mcpServers": {
    "softqcos": {
      "command": "softqcos-mcp",
      "args": ["--transport", "stdio"],
      "env": { "QCOS_API_KEY": "<your key>" }
    }
  }
}
```

If Claude Desktop cannot find `softqcos-mcp`, put the full path that
`which softqcos-mcp` prints in `command`.

From Python, with the `mcp` package this server already depends on:

```python
import asyncio
import os

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client


async def main() -> None:
    headers = {"x-api-key": os.environ["QCOS_API_KEY"]}
    async with streamablehttp_client("http://127.0.0.1:8100/mcp", headers=headers) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = (await session.list_tools()).tools
            print(len(tools), "tools")
            result = await session.call_tool("qcos_get_v1_runtime_capabilities", {})
            print(result.structuredContent)


asyncio.run(main())
```

## What each tool needs

Every tool belongs to one class, and the class decides what the caller must
present. A tool refused for a missing requirement returns an error result that
names the reason; it never runs halfway.

| Class | What it does | Caller key | Entitlement |
|---|---|---|---|
| public | catalogues, backend lists, estimates, health | not needed | not needed |
| tenant | reads, cancels and releases your own jobs, evidence, sessions | required | not needed |
| compute | uses QCOS compute without naming a device | required | required |
| device | sends work to a named backend (`backend_id`) | required | required, for that backend |

Public examples: `qcos_get_v1_runtime_capabilities`, `qcos_get_v1_backends`,
`qcos_post_v1_estimate`, `qcos_qec_codes_catalog`. Tenant examples:
`qcos_get_v1_jobs`, `qcos_get_v1_jobs_job_id_result`,
`qcos_get_v1_runtime_jobs_job_id_execution_evidence`. Device example:
`qcos_post_v1_jobs`.

Tenant tools stay available when an entitlement has run out, so a job can
always be read and cancelled.

"Not needed" is this server's own check: it forwards a public call without
asking for a key. The API can still ask for one, and `api.softquantus.com`
does for most public tools (`qcos_get_v1_runtime_capabilities` needs a key with
`qcos:read`), so send your key on every call. A public call that arrives
without `x-api-key` goes out under the server process's own `QCOS_API_KEY` when
one is set, and with no key otherwise.

**Compute and device tools check the entitlement with the QCOS server's own
gate, which ships with the QCOS server and not with this package.** A server
started from `pip install softqcos-mcp` cannot load it, so it refuses those
tools with `entitlement_gate_unavailable` instead of running them unchecked.
Public and tenant tools work. To run a circuit from your own machine today,
use the SDK or the CLI, which call the API directly and are checked there.

## Running it for others

`QCOS_ENV=production` makes `/mcp` demand
`Authorization: Bearer <QCOS_MCP_BEARER_TOKEN>` on every request, and the
server refuses to start without that token. The bearer token says which
gateway is calling; it is shared by every caller and identifies no customer,
so each request still needs the customer's own `x-api-key`. `/health` is
always open.

Do not set `QCOS_API_KEY` on a server other people call: their public calls
without a key of their own would run under it.

Put the server behind TLS before it leaves the machine. API keys travel in a
header, and plain HTTP shows them to anyone on the path.

## What each version added

Generated from the code at release time, so it cannot drift from what this
version runs. Tool names as a client sees them.

<!-- BEGIN release-surface: generated by scripts/gen_client_surface.py; edit the script, not this block -->

Package version on this source tree: **3.11.0**. `softqcos-sdk`, `softqcos` and
`softqcos-mcp` always carry the same number, so the row a name sits in is the
first version of THIS package that has it. A version is listed once it is tagged;
it reaches PyPI when that release is published, and
`pip index versions softqcos-mcp` shows which versions PyPI has.

| Version | Added |
|---|---|
| 3.11.0 | `qcos_science_jobspec`, `qcos_science_physics`, `qcos_science_simulation_export`, `qcos_science_simulation_graph_plan`, `qcos_science_simulation_graph_run`, `qcos_science_simulation_plan`, `qcos_science_simulation_run`, `qcos_science_solver`, `qcos_science_solver_resolve`, `qcos_science_solvers`, `qcos_science_surrogate_train` |
| 3.10.0 | `qcos_science_algorithm`, `qcos_science_algorithms`, `qcos_science_capabilities`, `qcos_science_eigensolve`, `qcos_science_evolve`, `qcos_science_optimize`, `qcos_science_plan`, `qcos_science_resource_estimate`, `qcos_science_simulate_quantum_system`, `qcos_science_validate` |
| 3.9.0 | `qcos_delete_v1_hal_jobs_job_id`, `qcos_get_v1_hal_backends`, `qcos_get_v1_hal_backends_name`, `qcos_get_v1_hal_jobs_job_id`, `qcos_get_v1_hal_jobs_job_id_result`, `qcos_post_v1_hal_jobs`, `qcos_quantus_analyze_problem`, `qcos_quantus_build_problem`, `qcos_quantus_compile_problem`, `qcos_quantus_execute`, `qcos_quantus_execution_store`, `qcos_quantus_explain_coefficient`, `qcos_quantus_explain_execution`, `qcos_quantus_get_advantage`, `qcos_quantus_get_evidence`, `qcos_quantus_get_execution`, `qcos_quantus_get_lifecycle`, `qcos_quantus_list_backends`, `qcos_quantus_normalize_data`, `qcos_quantus_routing_rules`, `qcos_quantus_seal_execution`, `qcos_quantus_suitability`, `qcos_quantus_validate_problem`, `qcos_research_apps_get`, `qcos_research_apps_list`, `qcos_research_apps_molecular_vqe_run`, `qcos_research_apps_plan` |
| 3.8.3 | `qcos_get_v1_runtime_evidence`, `qcos_get_v1_runtime_evidence_list`, `qcos_get_v1_runtime_evidence_trust`, `qcos_post_v1_runtime_evidence_verify` |
| 3.8.2 | `qcos_post_v1_runtime_dynamics_analyze`, `qcos_post_v1_runtime_state_analyze` |
| <=3.8.0 | 86 tools, all present in 3.8.0, the first version of the shared numbering |

<!-- END release-surface -->

## License

Copyright © 2024-2026 SoftQuantus innovative OÜ. All Rights Reserved.

QCOS™ is a trademark of SoftQuantus innovative OÜ.
Registry Code: 17048927 | Tallinn, Estonia

- License: https://softquantus.com/legal/license
- EULA: https://softquantus.com/legal/eula
- Support: support@softquantus.com
