Metadata-Version: 2.4
Name: parampilot-mcp
Version: 0.1.0
Summary: Agent-oriented MCP adapter for the public ParamPilot API
Project-URL: Documentation, https://github.com/JulianKimmig/parampilot-mcp#readme
Project-URL: Issues, https://github.com/JulianKimmig/parampilot-mcp/issues
Project-URL: Source, https://github.com/JulianKimmig/parampilot-mcp
Author: Julian Kimmig
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: <3.15,>=3.10
Requires-Dist: mcp<2,>=1.27
Requires-Dist: parampilot<0.2,>=0.1
Description-Content-Type: text/markdown

# ParamPilot MCP

`parampilot-mcp` is the separately releasable Model Context Protocol adapter
for the public asynchronous ParamPilot Python SDK. It supports Python 3.10
through 3.14 and keeps MCP dependencies out of the `parampilot` SDK wheel.

By default, the local stdio entry point exposes a reviewed 17-tool read-only
surface: availability, campaign list/get/status, bounded experiment and
effective-experiment reads, model-job list/get/observations/result, and
progressive campaign authoring catalog/schema/validation. It also includes
`model_job_wait`, which observes one existing durable job for at most 30 seconds
and never submits or remotely cancels work. Optional bounded authoring resources
and one static prompt are available, but the portable tool path does not depend
on them.

Setting `PARAMPILOT_ENABLE_MUTATIONS=1` opts the connection into a 31-tool
surface. In addition to configured create/domain/strategy replacement, it adds
routine `campaign_create`, `campaign_additional_fields_replace`,
`campaign_settings_update`, `experiments_batch_upsert`, and
`experiment_patch`, plus explicit `model_train`, `model_ask`, `model_predict`,
and `model_job_cancel`. It also exposes the Train-visible
`workflow_add_experiments_train_and_ask` and
`workflow_resume_add_experiments_train_and_ask` helpers. Every mutation
requires a stable logical key;
additional-fields/settings/experiment patch also require the current revision.
Model submissions return a durable job UUID immediately and never wait.
Ask/Predict never Train and surface `training_required` for a missing or stale
model. Routine tools and ordinary inference need their reviewed scope plus
explicit connection enablement, but not high-impact approval. Train, remote
cancellation, both workflow invocations, and configured domain/strategy
replacement require independently verified operation-bound approval, which the
31-tool local policy does not manufacture.

Setting `PARAMPILOT_ENABLE_HIGH_IMPACT=1` in addition to mutation enablement
opts into the 41-tool administration profile. It adds the owner-only
`campaign_access_list` read plus exactly nine high-impact tools: campaign start,
unlock, archive, and full effect replacement; experiment deletion; collaborator
grant upsert/delete; and transfer-link create/delete. The read requires campaign
owner permission and `parampilot:campaign:admin`, but not mutation approval.
Each high-impact mutation requires the current resource or collection revision,
a stable logical key, current backend permission, and a fresh independently
signed approval. None submits Train.

## Tool catalog

The profiles are cumulative: the 17 default tools are present in every
profile, mutation enablement adds 14 tools for a total of 31, and
administration enablement adds 10 more for a total of 41. This catalog covers
MCP tools only; the optional authoring resources, exposure-status resource, and
static authoring prompt are separate protocol capabilities.

### Default read-only profile

| Tool | What it does |
| --- | --- |
| `authoring_catalog` | Lists bounded reviewed authoring topics, public schema roots, versions, and component counts without returning complete schema graphs. |
| `authoring_describe_type` | Returns one exact public OpenAPI component or RFC 6901 subpath with its reachable definition closure, capped at 32 KiB. |
| `authoring_search` | Searches public component names and reviewed guidance metadata, returning at most 20 matches without complete schema graphs. |
| `authoring_validate_configured` | Validates a configured-campaign request locally and, when structurally valid, through the public no-side-effect backend endpoint. It does not certify scientific intent or authorize a later write. |
| `campaign_get` | Reads one visible campaign and its current revision for subsequent concurrency-protected operations. |
| `campaign_status_get` | Reads one campaign's current lifecycle status. |
| `campaigns_list` | Lists one bounded page of campaigns visible to the authenticated user. |
| `effective_experiments_query` | Queries one bounded page of effective experiments, including the requested transfer/grouping view. |
| `experiment_get` | Reads one experiment and its current revision for subsequent concurrency-protected operations. |
| `experiments_list` | Lists one bounded page of experiments for a campaign. |
| `model_job_get` | Reads one durable model job. |
| `model_job_observation_get` | Reads the latest bounded observation for one model job. |
| `model_job_observations_list` | Lists one bounded page of observations for a model job. |
| `model_job_result_get` | Reads the typed terminal result of a completed model job. |
| `model_job_wait` | Observes an existing job for at most 30 seconds and returns its typed terminal result when available. It never submits work or remotely cancels the job. |
| `model_jobs_list` | Lists one bounded page of durable model jobs, optionally filtered by kind or status. |
| `server_availability` | Reads public API compatibility, schema identity, and backend capability availability. |

### Tools added by mutation enablement

Set `PARAMPILOT_ENABLE_MUTATIONS=1` to add these 14 tools. Every mutation uses a
stable logical key. Tools that mention independent approval fail closed until
the approval runtime provides a matching, fresh proof.

| Tool | What it does |
| --- | --- |
| `campaign_additional_fields_replace` | Replaces the complete additional-field schema using the current campaign revision. It neither starts the campaign nor creates a Train job. |
| `campaign_create` | Creates one unconfigured draft campaign. It neither starts the campaign nor creates a Train job. |
| `campaign_create_configured` | Validates the final bundle and atomically creates one configured draft. It neither starts the campaign nor creates a Train job. |
| `campaign_domain_replace` | After independent approval, validates and replaces the complete draft domain using the current campaign revision. It never starts the campaign or trains a model. |
| `campaign_settings_update` | Replaces mutable campaign metadata and settings using the current campaign revision. It never starts the campaign or trains a model. |
| `campaign_strategy_replace` | After independent approval, validates and replaces the complete draft strategy using the current campaign revision. It never starts the campaign or trains a model. |
| `experiment_patch` | Patches one experiment using its current revision. It invalidates freshness when required but never creates a Train job. |
| `experiments_batch_upsert` | Atomically upserts 1–500 ordered JSON experiment rows into a started campaign; one invalid row commits nothing. It never creates a Train job. |
| `model_ask` | Submits one bounded Ask job and immediately returns its durable job ID. It never trains and returns `training_required` when the model is missing or stale. |
| `model_job_cancel` | After independent approval, requests remote cancellation of one durable job. Completion may win the race, so the returned job state is authoritative. |
| `model_predict` | Submits one bounded prediction job and immediately returns its durable job ID. It never trains and returns `training_required` when the model is missing or stale. |
| `model_train` | The only individual model-job tool that can Train. After independent approval, it submits an explicit cost-bearing training job and immediately returns its durable job ID. |
| `workflow_add_experiments_train_and_ask` | After independent approval, uploads experiments, explicitly Trains, and then Asks through a multi-call workflow. It is non-transactional, makes no rollback claim, and returns a caller-held recovery checkpoint. |
| `workflow_resume_add_experiments_train_and_ask` | Resumes the upload/Train/Ask workflow from a caller-held checkpoint without repeating completed mutation stages. It requires the unchanged request and workflow key. |

### Tools added by administration enablement

Set both `PARAMPILOT_ENABLE_MUTATIONS=1` and
`PARAMPILOT_ENABLE_HIGH_IMPACT=1` to add these 10 tools. Except for the
owner-only `campaign_access_list` read, every tool in this group requires a
current revision, stable logical key, backend permission, and fresh independent
approval.

| Tool | What it does |
| --- | --- |
| `campaign_access_delete` | Revokes one collaborator's campaign access using the current complete grant-set revision. |
| `campaign_access_list` | Lists one bounded page of campaign access grants for an owner-authorized caller. |
| `campaign_access_upsert` | Creates or replaces one collaborator's `read` or `modify` access using the current complete grant-set revision. |
| `campaign_archive` | Archives one campaign, removing it from normal active reads. The MCP surface provides no inverse operation. |
| `campaign_effects_replace` | Replaces the complete ordered effect set and recalculates derived values. Recovery requires resubmitting a previously retained set. |
| `campaign_start` | Starts one configured campaign and enables its active lifecycle. It never creates a Train job. |
| `campaign_transfer_link_create` | Creates one source-to-target campaign transfer mapping, which can change inherited experiment data. |
| `campaign_transfer_link_delete` | Deletes one campaign transfer mapping and stops its inherited-data contribution. |
| `campaign_unlock` | Unlocks an eligible campaign for further mutation. It never creates a Train job. |
| `experiment_delete` | Permanently deletes one local experiment. The MCP surface provides no inverse operation and never creates a Train job. |

The hosted HTTP entry point remains fail-closed until the hosted identity and
transport tasks are complete:

```console
parampilot-mcp-http
```

The runtime dependency boundary is limited to `parampilot>=0.1,<0.2` and the
stable MCP Python SDK line `mcp>=1.27,<2`. Production code must not import
ParamPilot backend, frontend, worker, BoFire, or repository-only modules.

## Local stdio

Install `parampilot-mcp` and the compatible public `parampilot` SDK, then
provide one fixed API origin and token to the process:

```console
export PARAMPILOT_API_URL=https://parampilot.example
export PARAMPILOT_API_TOKEN='replace-with-a-user-token'
parampilot-mcp-stdio
```

To expose the fourteen configured, routine, model-job, and workflow mutation
tools on an explicitly enabled connection:

```console
export PARAMPILOT_ENABLE_MUTATIONS=1
parampilot-mcp-stdio
```

To enable the 41-tool administration profile, create a private approval state
directory and a separate 256-bit signing key once:

```console
install -d -m 700 /absolute/path/to/parampilot-approvals
parampilot-mcp-approval-keygen /absolute/path/to/parampilot-approval.key
export PARAMPILOT_ENABLE_MUTATIONS=1
export PARAMPILOT_ENABLE_HIGH_IMPACT=1
export PARAMPILOT_APPROVAL_DIRECTORY=/absolute/path/to/parampilot-approvals
export PARAMPILOT_APPROVAL_KEY_FILE=/absolute/path/to/parampilot-approval.key
parampilot-mcp-stdio
```

The directory must remain mode `0700` and the key file mode `0600`; symlinks,
relative paths, missing state, and malformed keys fail closed. Keep the key and
approval command outside model-controlled input.

An administration invocation uses this explicit two-process flow:

1. Invoke the exact tool once. It returns `policy_denied` with an `apv1-...`
   challenge reference and writes a key-, credential-, and revision-value-free
   pending challenge.
2. In a separate trusted terminal, inspect and approve that reference:

   ```console
   parampilot-mcp-approve \
     --directory /absolute/path/to/parampilot-approvals \
     --key-file /absolute/path/to/parampilot-approval.key \
     apv1-replace-with-the-returned-reference
   ```

   The command prints exactly one consequence/confirmation line. Type the exact
   word `approve` only after reviewing it.
3. Promptly repeat the unchanged tool invocation with the same revision,
   logical key, and payload. The signed proof is consumed once. Changed,
   expired, cross-principal, cross-operation, or replayed evidence fails before
   backend mutation.

The runtime binds approval to the authenticated principal, exact operation,
canonical payload, public targets, revision, and logical key; verifies its HMAC
signature and maximum-five-minute lifetime; and durably consumes its nonce.
Approval evidence is never accepted as a tool argument. Approval does not
override backend roles or optimistic concurrency. If permission or state
changes between approval and dispatch, reread, review, and obtain fresh
approval for the reconciled request.

For exact retries, reuse the same logical key only with the unchanged request.
After a revision conflict, reread the campaign, review the new state, and use a
new logical key for the revised request. Validation and digest receipts record
provenance; they do not grant approval.

Access writes are collection-protected: use the complete grant-set ETag from
`client.campaign_access.list_with_metadata(campaign_id).require_etag()`, not
the campaign ETag. Upsert creates or replaces one collaborator's `read` or
`modify` grant; delete revokes it immediately. Transfer-link changes use the
target campaign ETag and can change inherited experiment data.

Archive and experiment delete have no inverse on this MCP surface. Full effect
replacement overwrites the entire ordered set; recovery requires resubmitting
a previously retained set under a new current revision, key, and approval.
Grant and transfer deletions can be recreated only through a newly reviewed
request. Start can be reversed with a separately approved unlock when the
backend permits it. These administration operations invalidate or change
state, but they never create a Train job.

Experiment batch upsert accepts an ordered atomic JSON batch of 1–500 rows and
requires an already started campaign. Results remain compact recovery
references: campaign/experiment IDs and state, or batch index/created/UUID
tuples.

`model_train`, `model_ask`, and `model_predict` accept 1–500 candidates/rows
where applicable and return immediately. Preserve the returned job UUID and use
the read tools or `model_job_wait` to recover. A local wait timeout, host
cancellation, or MCP disconnect leaves the remote job running. Only
`model_job_cancel` requests remote cancellation, under its own stable key and
approval gate; the returned state is authoritative if completion wins the race.

The two Train-visible workflow tools accept 1–500 experiment rows, request
1–500 suggestions, and use one stable `workflow_key` to derive fixed subkeys
for upload, Train, Ask, and explicit cancellation recovery. The workflow is
multi-call and non-transactional: it makes no rollback claim. Each Train or Ask
wait is capped at 30 seconds and never remotely cancels work. Success includes
ordered suggested experiment UUIDs and a version-one `caller_held` checkpoint;
stage failures return that checkpoint and the failed phase. Resume requires the
same campaign, experiment semantics, suggestion count, and workflow key.
Checkpoints contain public UUIDs, hashes, stage data, and allowlisted typed job
results—never credentials, client objects, API origins, or scientific rows.
Local stdio does not persist checkpoints; the caller must retain and resubmit
them. Hosted durable principal-bound checkpoint storage remains deferred with
hosted HTTP.

`PARAMPILOT_API_URL` must be an exact HTTPS origin without a path, query,
fragment, or embedded credentials. Plain HTTP is accepted only for explicit
loopback hosts such as `http://127.0.0.1:8000`. The optional
`PARAMPILOT_SCHEMA_COMPATIBILITY` policy is `strict` by default and may be set
to `warn` or `ignore`.

Startup checks the public API major, schema policy, and every capability needed
by the exposed surface before accepting MCP traffic. The token and origin are
process-owned configuration: they never appear in MCP tool arguments,
resources, prompts, results, or audit records. Standard output carries MCP
protocol frames only; payload-free audit events and startup errors use standard
error.

MCP resource discovery includes seven reviewed authoring guides and
`parampilot://status/exposure`. The status resource is bounded JSON containing
the MCP and SDK versions, public API major/capabilities/schema digest, reviewed
knowledge/schema/manifest versions, exact 39/34/5 operation accounting, and
safe exclusion explanations. It never includes credentials, user identity,
private paths, SDK method names, review owners, or test references.

If startup fails:

- `PARAMPILOT_API_TOKEN is required` means the variable is absent or blank.
- An origin error means the URL is not an exact trusted HTTPS or loopback
  origin.
- A preflight error means the configured backend rejected authentication,
  lacks a required capability, has an incompatible API major, or failed the
  selected schema-compatibility policy.

Claude Code and Claude models are not installation or qualification
requirements. The approved first-release local host target is Codex over
stdio.

## Development

The standalone development environment resolves the compatible public
`parampilot>=0.1,<0.2` SDK from PyPI. Run the locked validation suite after
changing MCP source, reviewed contracts, or the dependency graph:

```console
uv sync --all-groups --locked
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv audit --locked
uv build --no-build-isolation
uv run python -m parampilot_mcp_release.wheel_cli \
  dist/parampilot_mcp-0.1.0-py3-none-any.whl
```

The wheel inspection emits deterministic JSON containing the exact artifact
SHA-256, member count, and runtime requirements. It fails closed on duplicate
or noncanonical archive paths, unexpected package trees, private imports or
paths, sensitive bearer material, dependency drift, and disagreement among the
distribution name, package version, Python range, license, and installed
package contract.

## License

This separately distributed package is licensed under Apache-2.0; see
`LICENSE` and `NOTICE`. That grant is package-local and does not relicense the
private ParamPilot monorepo.

The public repository is the package source of truth. A successful `main`
push runs the complete public CI matrix, exports the exact validated wheel and
source distribution, and publishes those artifacts to PyPI through the
repository's `pypi` trusted-publisher environment.
