Metadata-Version: 2.5
Name: blankstate-mcp
Version: 0.5.0
Summary: Blankstate MCP server — protocol sensing, validation, Programmatic Dive, and Stage tools
Project-URL: Homepage, https://blankstate.ai
Project-URL: Documentation, https://api.blankstate.ai/docs
Project-URL: Repository, https://github.com/blankstate-ai/blankstate-py
Project-URL: Issues, https://github.com/blankstate-ai/blankstate-py/issues
Author-email: Blankstate <hello@blankstate.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: blankstate,mcp,model-context-protocol,protocol,sgm
Requires-Python: >=3.10
Requires-Dist: blankstate-sdk<0.6.0,>=0.5.0
Requires-Dist: mcp<2.0.0,>=1.0.0
Requires-Dist: python-dotenv<2.0.0,>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Description-Content-Type: text/markdown

# blankstate-mcp

**Protocol-based sensing and validation for autonomous AI agents.**

PyPI: `[blankstate-mcp](https://pypi.org/project/blankstate-mcp/)` · import package: `blankstate_mcp`

The Blankstate MCP Server exposes Blankstate measurement, **Programmatic Dive**, and **Stage / World** authoring as MCP tools.
It lets any MCP-compatible agent (Cursor, Claude Desktop, and others) sense interactions against
Blankstate Protocols, validate actions before executing them, run a Stage dive
(`open` → `act` → `status` → `close`), author a Stage, run and read its Worlds, and check quota status.

Protocols are **universal sensors** — the same protocol measures any content modality:
conversations, commands, documents, agent actions. The measurement engine determines signal,
not the input type.

## Features

- **Twenty-three MCP tools**
  - Sense: `bks_sense`, `bks_validate`, `bks_status`
  - Dive: `bks_dive_open`, `bks_dive_act`, `bks_dive_status`, `bks_dive_close`
  - Stages: `bks_stage_list`, `bks_stage_create`, `bks_stage_get`, `bks_stage_edit`, `bks_stage_check`, `bks_stage_estimate`, `bks_stage_run`, `bks_stage_versions`, `bks_stage_restore`, `bks_stage_variant`
  - Worlds: `bks_world_list`, `bks_world_get`, `bks_world_set`, `bks_world_review`, `bks_world_rename`, `bks_world_delete`
- **Token-only boot**: `python -m blankstate_mcp` with only `BLANKSTATE_API_TOKEN` — Dive tools work without protocols
- **Optional Stage default**: Atlas copies `BLANKSTATE_STAGE_ID` into MCP env. `bks_dive_open` uses it when you omit `stage_id`
- **Protocol and Metric support**: Sense against a single Protocol or a Metric that aggregates multiple Protocols with weights
- **SGM 1.0 and 1.5**: Full output for both engine versions (resonance, evidence, and extended analysis in v1.5)
- **Three modes**: `block` (reject action), `feedback` (allow + suggest), `audit` (log only)
- **Drop-in integration**: Works with any MCP-compatible agent



## Quick Start



### 1. Get an API Token

Sign up at [atlas.blankstate.ai](https://atlas.blankstate.ai) and generate an API token.
Find your Protocol ID at **API Dashboard → Explorer → /protocols**.

### 2. Install the server

Use a virtual environment or **[pipx](https://pipx.pypa.io/)** so dependencies stay isolated:

```bash
pipx install blankstate-mcp
# or: python3 -m pip install blankstate-mcp
```



### 3. Add to Your Agent Configuration

Point the MCP host at the same Python you installed into. Two common patterns:

**Option A — run as a module** (`python3` must have `blankstate-mcp` installed):

```jsonc
{
  "mcpServers": {
    "blankstate": {
      "command": "python3",
      "args": ["-m", "blankstate_mcp"],
      "env": {
        "BLANKSTATE_API_TOKEN": "your-token-here",
        "BLANKSTATE_STAGE_ID": "stg_xxxxxxxx", // optional — default for bks_dive_open
        "BLANKSTATE_PROTOCOLS": "proto-xxxxxxxx-...:1.0" // optional — only for bks_sense / bks_validate
      }
    }
  }
}
```

**Option B — console script** (after `pipx install blankstate-mcp`, the `blankstate-mcp` executable is on `PATH`):

```jsonc
{
  "mcpServers": {
    "blankstate": {
      "command": "blankstate-mcp",
      "args": [],
      "env": {
        "BLANKSTATE_API_TOKEN": "your-token-here",
        "BLANKSTATE_STAGE_ID": "stg_xxxxxxxx", // optional — default for bks_dive_open
        "BLANKSTATE_PROTOCOLS": "proto-xxxxxxxx-...:1.0" // optional — only for bks_sense / bks_validate
      }
    }
  }
}
```

**Windows:** Use `"command": "python"` or the full path to `python.exe`, or the launcher, e.g. `"command": "py"` with `"args": ["-3", "-m", "blankstate_mcp"]`, depending on how Python is installed. If the host cannot find the interpreter, set `command` to the absolute path returned by `where python` (cmd) or `Get-Command python` (PowerShell).

> **Important**: Use the actual Protocol UUID from Atlas (e.g. `proto-6d28a7b8-...:0.1`), not a friendly name. Find yours at Atlas → API Dashboard → Explorer → `/protocols`.
> Token is required. Protocol and Stage id are optional.
> Stage can work without protocol UUIDs.



### 4. Done

Your agent now has the twenty-three tools listed below. Dive works with the token alone. If Atlas filled in `BLANKSTATE_STAGE_ID`, `bks_dive_open` can run without passing `stage_id`. Stage writes need `stages:read` and `stages:write`; estimating, starting, pausing, and carrying on a World needs `runs:dry`.

## MCP Tools

Once connected, your agent has these tools:

### `bks_sense`

Measure any content against a Protocol or Metric. Returns a resonance score, per-metamarker
breakdown, glass-box evidence, and fidelity assessment.

```
Input: content (required), protocol_id?, metric_id?, language?
```

Protocols are universal — they measure conversations, commands, documents, and agent
actions the same way. v1.5 protocols provide extended signal analysis output.

When `metric_id` is provided, all component protocols are evaluated and scores are
aggregated by weight into a single composite score.

### `bks_validate`

Validate a proposed agent action (before executing it) against all configured Protocols
and Metrics. The action arguments are content-extracted and evaluated.

```
Input: tool_name (required), tool_args (required)
```

Returns `ALLOWED`, `BLOCKED` (with evidence and matched nuances), or `FEEDBACK`
depending on the configured mode. In `block` mode a blocked action is returned as
an MCP error, stopping the agent from proceeding.

### `bks_status`

Check API connectivity, authentication, remaining ICS credits, and the full list of
configured Protocols and Metrics.

```
Input: (none)
```



### `bks_dive_open`

Open a Programmatic Dive against a published Stage (`POST /api/v1/dive/open`).
Returns `dive_id`, rules, the opening observation, and envelope.

```
Input: stage_id?, session_id?, password?, agent?, seed?
```

`stage_id` is optional when `BLANKSTATE_STAGE_ID` is set in MCP env. A tool argument still wins over the env default.

`agent` is `{ id?, version? }` — your audit tag, not Blankstate's model.

### `bks_dive_act`

Submit one action. `turn` is an idempotency key. Returns the next observation and
running totals, or a StageCard if the dive auto-closes.

```
Input: dive_id (required), action (required string or DiveAction), turn?
```



### `bks_dive_status`

Inspect an open or closed Dive without advancing the world.

```
Input: dive_id (required)
```



### `bks_dive_close`

Close the Dive and emit the StageCard (`POST /api/v1/dive/{dive_id}/close`).
Idempotent: closing an already-closed dive returns the same card.

```
Input: dive_id (required), summary?
```

Stage id is **not baked into the package**. Pass it on `bks_dive_open`, or set
`BLANKSTATE_STAGE_ID` (Atlas MCP snippet) as the default. Use a Stage your token
is entitled to dive (`stg_…` from Atlas).

### Stage tools

Stage a situation from your agent. A Stage is the situation you author and version; a World is one run of it.
Stages are staged as Proxy Worlds (`world: "proxy"`, dived by agents). Creating and editing are free.
Writes are applied whole or refused whole: a refusal names each item and why (`issues`), and an edit on an
old rev is refused with the current `rev`. The token needs `stages:read`, `stages:write` to create or edit, and
`runs:dry` to estimate, start, pause and carry on Worlds.

A World started here is the World Atlas runs and lists. It follows the Stage's run plan and this run's options, and counts in its unit
(days, or turns of a conversation, with the interactions so far): it goes on until the Stage's own stop, this run's budget, day or time, your
organisation's ICS runs out, or you pause or stop it. A World at the end of its history can be made longer with `run.history` (that keeps the version) and then carried on.
Opening it in Atlas carries it on in the page. What a token may spend is the ICS cap set on its
connection in Atlas, and a daily allowance; each token may also start a set number of Worlds a day (refused with
`daily_cap` past it, until midnight UTC).

| Tool | Input | Does |
|---|---|---|
| `bks_stage_list` | none | Your Stages: id, title, `world`, rev, Worlds run. Free |
| `bks_stage_create` | `world` (`"proxy"`), `premise`, `scale?`, `ops?` | A Stage from a premise, with typed operations in the same call. Applied whole or refused whole. Returns id, rev 1, and the outline. Free |
| `bks_stage_get` | `stage_id` | The outline: actants, links, principles, Moments, objectives and targets, protocols, locks, drawn agents, surfaces and their mix, rev |
| `bks_stage_edit` | `stage_id`, `if_rev`, `ops` | Typed operations against the rev you read. An objective can be read on the seeded agents (`cases`), as a share (`rate_*`), or on the World's events (`reach_*`, `count_*`). `run.history` makes the history longer and keeps the version. An edit on an old rev is refused with the current `rev` |
| `bks_stage_check` | `stage_id` | What is thin, each with a question, and the gaps. Free |
| `bks_stage_estimate` | `stage_id`, `span`, `seed?` | What `span` days (or turns) of a World ask on a seed: interactions written, how many are already kept, agents, time (`minutes`, `minutes_max`), the ICS range, contrast pairs (`pair_passages`), and what each objective read on events would count (`expect`). Free |
| `bks_stage_run` | `stage_id`, `wait_seconds?`, `seed?`, `budget_ics?`, `until_day?`, `minutes?`, `pauses?`, `target?` | Start a World. `seed` repeats a draw on the same version. Run options pause it by budget, day, time, or a reached objective. Waits up to `wait_seconds`, then returns where it is. Spends ICS as it runs |
| `bks_world_set` | `stage_id`, `world_id`, `state` (`running` \| `paused` \| `stopped`), plus the same run options when `state` is `running` | Pause, stop, or carry on a World. Carrying on is refused at the end of its history until `run.history` makes that history longer |
| `bks_world_list` | `stage_id` | The Stage's Worlds, newest first: version, status, the day each is on, who writes it while it runs, and how many objectives it met. Free |
| `bks_world_get` | `stage_id`, `world_id`, `trajectories?` | One World's status and outcome: objectives, spread over other seeds, levers, proposals, ICS, and `next_steps` once paused or stopped. `trajectories: true` adds each protocol's trajectory evidence. Free |
| `bks_world_review` | `stage_id`, `world_id`, `keep?`, `discard?` | Keep or discard what a World proposes, by id. A discard holds for that World only. Free |
| `bks_world_rename` | `stage_id`, `world_id`, `name` | Rename a World (at most 80 characters). Free |
| `bks_world_delete` | `stage_id`, `world_id` | Delete a World. One still running stops first. Free |
| `bks_stage_versions` | `stage_id`, `from?`, `to?` | Kept versions, and what changed between two. Free |
| `bks_stage_restore` | `stage_id`, `if_rev`, `version` | Make a kept version the Stage again, against the rev you read |
| `bks_stage_variant` | `stage_id`, `world_id`, `label`, `varies`, `question?` | A Variant Stage that varies `system`, `population`, `environment`, and/or `clock`, and holds the rest |


Every tool declares a title, whether it is read-only or destructive, and an `outputSchema`; its answer comes as
`structuredContent` next to the text. The server also sends instructions and the ready-made prompts
`build_stage`, `run_world`, `read_world`, and `improve_stage` for the tools it offers.

## Installation

Install from PyPI (recommended: **pipx** for a global CLI isolated from system Python):

```bash
pipx install blankstate-mcp
```

Other options:

```bash
python3 -m pip install blankstate-mcp
# editable from the blankstate-py monorepo:
# python3 -m pip install -e "./packages/sdk" -e "./packages/mcp"
```

The MCP config must use the **same** `python3` (or the `blankstate-mcp` script from that environment) that has the package installed.

## Configuration



### Environment Variables


| Variable               | Description                                                          | Default                     |
| ---------------------- | -------------------------------------------------------------------- | --------------------------- |
| `BLANKSTATE_API_TOKEN` | **Required.** Bearer token from Atlas                                |                             |
| `BLANKSTATE_STAGE_ID`  | Optional. Default Stage for `bks_dive_open` (Atlas MCP tab)          |                             |
| `BLANKSTATE_API_URL`   | Optional. Do not set this unless you need a custom host (local/dev). | `https://api.blankstate.ai` |
| `BLANKSTATE_PROTOCOLS` | Optional. Comma separated Protocol IDs (sense / validate)            |                             |
| `BLANKSTATE_METRICS`   | Optional. Comma separated Metric IDs                                 |                             |
| `BLANKSTATE_THRESHOLD` | Score threshold (0.0 to 1.0)                                         | `0.7`                       |
| `BLANKSTATE_MODE`      | `block`, `feedback`, or `audit`                                      | `block`                     |




### Config File

For advanced configuration, create `~/.blankstate/config.json`:

```json
{
  "apiToken": "your-token-here",
  "stageId": "stg_xxxxxxxx",
  "defaultThreshold": 0.7,
  "defaultMode": "block",
  "protocols": [
    {
      "id": "circuit-breaker:1.0",
      "mode": "block",
      "threshold": 0.7,
      "tools": ["exec", "write"]
    },
    {
      "id": "code-quality:1.0",
      "mode": "feedback",
      "threshold": 0.5,
      "tools": ["write"]
    }
  ]
}
```



### Protocol Configuration Options


| Option      | Type                           | Description                                            |
| ----------- | ------------------------------ | ------------------------------------------------------ |
| `id`        | `string`                       | Protocol ID with version (e.g., `circuit-breaker:1.0`) |
| `mode`      | `block` | `feedback` | `audit` | How to handle triggered Protocols                      |
| `threshold` | `number`                       | Score threshold (0.0 to 1.0) for triggering the action |
| `tools`     | `string[]`                     | Tool types this Protocol applies to                    |




### Metric Configuration Options


| Option      | Type                           | Description                                      |
| ----------- | ------------------------------ | ------------------------------------------------ |
| `id`        | `string`                       | Metric ID from Atlas                             |
| `mode`      | `block` | `feedback` | `audit` | How to handle triggered Metrics                  |
| `threshold` | `number`                       | Score threshold (overrides Atlas default if set) |
| `tools`     | `string[]`                     | Tool types this Metric applies to                |




### Tool Types


| Type        | Description                          |
| ----------- | ------------------------------------ |
| `exec`      | Shell commands, terminal execution   |
| `write`     | File creation, modification, patches |
| `browser`   | Web navigation, form submission      |
| `messaging` | Email, Slack, Discord, etc.          |
| `all`       | All tool types (default)             |




## Modes



### Block Mode (Default)

When a Protocol triggers above the threshold, the tool call is **rejected**:

```
[BLANKSTATE] Action Blocked

Protocol: circuit-breaker:1.0
Nuances Matched: scope_violation, destructive_pattern
Evidence: targeting home directory with recursive deletion

Message: Action blocked by Protocol circuit-breaker:1.0.
The requested action has been suspended for safety review.
```



### Feedback Mode

Tool call **executes**, but the agent receives improvement suggestions:

```json
{
  "result": { ... },
  "blankstate_feedback": [
    {
      "source": "code-quality:1.0",
      "score": 0.65,
      "suggestions": ["missing_error_handling", "no_input_validation"]
    }
  ]
}
```

Use feedback mode to help agents write better code or follow best practices.

### Audit Mode

Tool call **executes** and evaluations are logged for compliance tracking:

```json
{
  "result": { ... },
  "blankstate_audit": [
    {
      "timestamp": "2026-01-31T12:00:00Z",
      "tool": "execute_command",
      "source": "compliance-check:1.0",
      "score": 0.3,
      "action": "allowed"
    }
  ]
}
```



## Available Protocols

Browse available Protocols and their capabilities at [doc.blankstate.ai/protocol-versions](https://doc.blankstate.ai/protocol-versions).

### Circuit Breaker (circuit-breaker:1.0)

Designed for autonomous agent safety. Detects scope violations, destructive patterns, credential exposure, and risky communication patterns.

### Custom Protocols

Create your own Protocols in [Atlas](https://atlas.blankstate.ai) and reference by ID:

```json
{
  "protocols": [
    { "id": "my-org/custom-policy:1.0", "mode": "block" }
  ]
}
```



## Metrics

Metrics aggregate multiple Protocols into a single weighted score. Metrics are defined in Atlas and referenced by ID:

```json
{
  "metrics": [
    {
      "id": "agent-safety-score",
      "mode": "block",
      "threshold": 0.7
    }
  ]
}
```

The protocol weights and composition are managed in Atlas. The threshold here is optional and overrides the Atlas default if you need different behavior for MCP.

Use Metrics when you want to combine multiple Protocols with weights, or when you need a pre configured safety suite.

## Programmatic Usage

You can use the MCP server or the tool wrapper from Python (`blankstate_mcp`):

```python
import asyncio

from blankstate_mcp import BlankstateMCPServer, load_config, validate_config


async def main() -> None:
    config = load_config()
    validate_config(config)
    server = BlankstateMCPServer(config)
    await server.start()
    await server.wait_until_stopped()


asyncio.run(main())
```

Or use the tool wrapper directly (validate before executing a tool in your own agent loop):

```python
import asyncio

from blankstate_mcp import create_tool_wrapper, load_config, validate_config


async def main() -> None:
    config = load_config()
    validate_config(config)
    wrapper = create_tool_wrapper(config)

    result = await wrapper.wrap_tool_call(
        "execute_command",
        {"command": "rm -rf ~/"},
    )
    if result.blocked and result.result is not None:
        print("Blocked:", result.result.message)
    else:
        print("Proceed with execution")


asyncio.run(main())
```



## Integration Examples



### MCP Compatible Agents

Any agent that supports the Model Context Protocol can use Blankstate. Add to your agent's MCP configuration file:

```json
{
  "mcpServers": {
    "blankstate": {
      "command": "python3",
      "args": ["-m", "blankstate_mcp"],
      "env": {
        "BLANKSTATE_API_TOKEN": "your-token",
        "BLANKSTATE_STAGE_ID": "stg_xxxxxxxx",
        "BLANKSTATE_PROTOCOLS": "circuit-breaker:1.0"
      }
    }
  }
}
```

The exact config file location depends on your agent. Common locations:

- `~/.config/<agent>/config.json`
- `~/<agent>/settings.json`



### Direct API Integration

For agents without MCP support, you can call the Blankstate API directly. See the [API documentation](https://doc.blankstate.ai) for details.

## ICS Billing

Blankstate uses **ICS (Interaction Computed Signal)** billing:

- **ICS consumed only on detection**: no charge for tool calls that pass validation
- **Usage tracked** per API token in the Atlas dashboard
- **Credits managed** in Atlas: individual accounts receive monthly free credits

This means you can monitor thousands of tool calls and only pay when something is caught. Pricing and credit allocation are configured in your [Atlas account](https://atlas.blankstate.ai).

## Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                      YOUR MACHINE                                │
│                                                                  │
│  ┌────────────────┐         ┌──────────────────────────────┐    │
│  │   Agent        │  MCP    │   blankstate-mcp             │    │
│  │   (Any MCP     │ ──────> │                              │    │
│  │   compatible   │         │  Intercepts tool calls       │    │
│  │   agent)       │         │  Calls configured Protocols  │    │
│  └────────────────┘         │  Applies mode decisions      │    │
│                             └──────────────┬───────────────┘    │
│                                            │                     │
└────────────────────────────────────────────┼─────────────────────┘
                                             │
                                             │ HTTPS + Bearer Token
                                             ▼
┌──────────────────────────────────────────────────────────────────┐
│                    BLANKSTATE CLOUD                              │
│                                                                  │
│   Protocol evaluation (pure sensors)                             │
│   Returns score, nuances, evidence                               │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘
```



## Contributing

```bash
git clone https://github.com/blankstate-ai/blankstate-py.git
cd blankstate-py
python3 -m pip install -e "./packages/sdk" -e "./packages/mcp[dev]"
pytest packages/mcp/tests -q
```



## Troubleshooting



### Issue in Cursor / Claude Desktop (Windows)

Some hosts spawn subprocesses without your shell `PATH`. Use the **full path** to `python.exe` (or to the `blankstate-mcp` script in your pipx/venv `Scripts` folder) in `"command"`, or configure the host’s environment so `python` / `blankstate-mcp` resolves correctly.

### "Missing API token"

Set `BLANKSTATE_API_TOKEN` in the `env` block of your MCP config, or in `~/.blankstate/config.json`.

### `"stage_id" is required unless BLANKSTATE_STAGE_ID is set`

`bks_dive_open` needs a Stage. Pass `stage_id` on the tool call, or set `BLANKSTATE_STAGE_ID` in MCP env (Atlas copies this on the Stage page).

### "No protocol or metric configured" (on `bks_sense` / `bks_validate`)

The server boots with a token alone. `bks_sense` and `bks_validate` still need a protocol
or metric at call time. Set `BLANKSTATE_PROTOCOLS` or `BLANKSTATE_METRICS` in the `env` block:

```json
"BLANKSTATE_PROTOCOLS": "proto-xxxxxxxx-...:1.0"
```

Both can be set at the same time. Protocols are evaluated directly; Metrics aggregate multiple protocols. Dive tools do not need this.

### Protocol ID format

Use the UUID-based ID from Atlas (e.g. `proto-6d....:0.2`),
not a friendly name. Find your Protocol ID at Atlas → API Dashboard → Explorer → `/protocols`.

### "API request failed: 401"

Token is invalid or expired. Generate a new one at [atlas.blankstate.ai](https://atlas.blankstate.ai).

### "API request failed: 404"

Protocol not found. Verify the ID and version exist in your Atlas account.

## Links

- [Blankstate](https://blankstate.ai)
- [Atlas Dashboard](https://atlas.blankstate.ai)
- [API Reference](https://api.blankstate.ai/docs)
- [GitHub Issues](https://github.com/blankstate-ai/blankstate-py/issues)



## License

MIT License. See [LICENSE](LICENSE) for details.