Skip to main content

ptm-mcp

MCP (Model Context Protocol) stdio server for the Prompt Test Manager API.

Lets agents built on top of MCP-capable clients (Claude Desktop, Claude Code, Codex, etc.) call PTM as first-class tools: list prompts, run evaluations, update prompt content, submit optimizations. All traffic is tagged with X-PTM-Client: ptm-mcp/<version> + a per-process X-PTM-MCP-Session UUID so the PTM backend can rate-limit, budget, and audit agent traffic separately from humans and service accounts.

Prereqs

  • Python >= 3.12.
  • A reachable PTM backend (>= 1.9.0) and a personal access token or service-account token with the scopes your flow needs.

Install

pip install ptm-mcp

Or zero-install via uvx:

uvx ptm-mcp

ptm-mcp pulls in ptm-client and the mcp SDK automatically.

Configure your MCP client

Claude Desktop

Config file:

OS Path
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json

Merge into mcpServers (create the key if it doesn't exist):

{
  "mcpServers": {
    "ptm": {
      "command": "uvx",
      "args": ["ptm-mcp"],
      "env": {
        "PTM_API_BASE_URL": "https://ptm.example.com",
        "PTM_API_TOKEN": "ptm_u_PASTE_HERE",
        "PTM_MCP_READ_ONLY": "true"
      }
    }
  }
}

Fully quit + reopen Claude Desktop after editing. stderr lands in ~/Library/Logs/Claude/mcp-server-ptm.log (macOS) or %APPDATA%\Claude\logs\mcp-server-ptm.log (Windows).

Claude Code

# macOS / Linux
claude mcp add --transport stdio --scope user ptm \
  --env PTM_API_BASE_URL=https://ptm.example.com \
  --env PTM_API_TOKEN=ptm_u_PASTE_HERE \
  --env PTM_MCP_READ_ONLY=true \
  -- uvx ptm-mcp

# Windows (PowerShell / cmd) - needs cmd /c wrapper
claude mcp add --transport stdio --scope user ptm `
  --env PTM_API_BASE_URL=https://ptm.example.com `
  --env PTM_API_TOKEN=ptm_u_PASTE_HERE `
  --env PTM_MCP_READ_ONLY=true `
  -- cmd /c uvx ptm-mcp

Codex

~/.codex/config.toml (macOS / Linux) or %USERPROFILE%\.codex\config.toml (Windows):

[mcp_servers.ptm]
command = "uvx"
args = ["ptm-mcp"]
env = { PTM_API_BASE_URL = "https://ptm.example.com", PTM_API_TOKEN = "ptm_u_PASTE_HERE", PTM_MCP_READ_ONLY = "true" }
startup_timeout_sec = 10
tool_timeout_sec = 60

Or CLI-first: codex mcp add ptm -- uvx ptm-mcp (with --env KEY=VAL per var).

Environment variables

Consumed at startup. Missing required values fail fast with a descriptive error.

Variable Required Default Notes
PTM_API_BASE_URL yes - e.g. https://ptm.example.com
PTM_API_TOKEN yes - PTM bearer. Service-account tokens preferred for long-running agent sessions.
PTM_MCP_READ_ONLY no false Set to true to lock to read-only (recommended for service accounts that should never write).
PTM_MCP_TIMEOUT_SECONDS no 30 Per-request timeout (1..600).
PTM_MCP_LOG_LEVEL no INFO DEBUG / INFO / WARNING / ERROR / CRITICAL.
PTM_SSL_VERIFY no true Set to false to disable TLS certificate verification (allows self-signed / invalid certs against a homelab PTM). Local dev only - never disable in production.
CF_ACCESS_CLIENT_ID no - Cloudflare Access service-token Client ID. Paired with CF_ACCESS_CLIENT_SECRET.
CF_ACCESS_CLIENT_SECRET no - Cloudflare Access service-token Client Secret. Paired with CF_ACCESS_CLIENT_ID.
CF_ACCESS_JWT no - Cloudflare Access user JWT (alternative to the service-token pair).
PTM_CF_AUTO_DISCOVER no true Falsy value opts out of auto-discovery via cloudflared.

Startup scrubs every env var outside a narrow allow-list (cloud creds, GitHub tokens, etc. get dropped).

Cloudflare Access

If your PTM deployment sits behind Cloudflare Access:

  • Default path (recommended): install cloudflared (brew install cloudflared or equivalent) and run cloudflared access login https://your-ptm-host once. ptm-mcp auto-detects CF challenges and injects the cached JWT on request.
  • Service token (CI / headless): ask an admin to mint a service token for the PTM app in Cloudflare Zero Trust -> Access -> Service Auth. Set CF_ACCESS_CLIENT_ID + CF_ACCESS_CLIENT_SECRET in the MCP env block. Explicit config disables auto-discovery.
  • Direct access (no CF Access): skip this section; no CF env vars needed.

On a Cloudflare Access block, ptm-mcp surfaces a CloudflareAccessError with the exact next step rather than a raw JSON decode crash.

Tool inventory

75 tools total (33 read + 42 write) + 5 resource URI patterns. Write tools are gated by PTM_MCP_READ_ONLY=false; the backend enforces per-prompt ownership, group membership, admin role, and the manage_tool_registry / manage_skill_catalog permissions on top of the PAT's scopes. ptm-mcp relays backend errors verbatim with actionable hints; it does not re-implement permission checks.

Read (33)

list_providers, list_prompts, get_prompt, get_prompt_tests, get_prompt_contents, load_prompt, list_groups, list_prompt_versions, get_prompt_version, compare_prompt_versions, list_runs, get_run, get_run_report, get_optimization_status, get_optimization_history, get_optimization_detail, list_tools, get_tool_dependents, export_tool_registry, get_prompt_git_sync_status, get_skill_git_sync_status, list_git_integrations, list_gpg_keys, get_gpg_public_key, list_triage, list_skills, search_skills, get_skill, get_skill_contents, list_skill_versions, compare_skill_versions, run_skill_inline, run_prompt_inline.

get_skill_contents - Fetch skill bundle in memory (no disk write). Returns parsed prompt.md + manifest + files. No runs row, no LLM call. Increments inline-usage counter.

get_prompt_contents - Same for a library prompt: prompt_text, version, tests, deepeval_metrics, tool_definitions. Active version by default; pass version=N for a specific version.

run_skill_inline / run_prompt_inline - Client inline run: returns the bundle/prompt contents for the caller to execute locally on the current session's model. No server LLM call, no DeepEval, no run row.

Write (42, gated by PTM_MCP_READ_ONLY)

Eval / optimization (4): run_manual_eval (QA eval with custom prompt + test cases), run_prompt_eval (QA eval against stored test suite), submit_optimization, cancel_optimization.

submit_optimization accepts variance-aware fields: stability_samples, validation_samples, flakiness_threshold, min_consistent_improvement, variance_aware_mutator, variance_signal, enforce_target_score, chained_baseline_mode. Omit any to inherit admin defaults.

Inline eval (4): run_skill_eval_ptm / run_prompt_eval_ptm (PTM runs the LLM + DeepEval server-side, persists a scored run row), run_skill_eval_client_and_ptm / run_prompt_eval_client_and_ptm (returns the bundle for local execution AND enqueues a parallel scored PTM eval; response includes run_key for polling).

Library mutation (9): create_prompt, update_prompt, activate_prompt_version, share_prompt, unshare_prompt, add_prompt_to_group, remove_prompt_from_group, transfer_prompt_ownership, update_prompt_sampling.

Skill Library (6): install_skill, load_skill (installs the bundle into the native-agent skills dir, no LLM call, no run row), publish_skill, update_skill, deprecate_skill, activate_skill_version (version rollback/forward).

Tool Registry (4): create_tool, update_tool, deprecate_tool, delete_mock_profile.

Git sync (5): configure_prompt_git_sync, configure_skill_git_sync, set_git_integration, delete_git_integration, create_git_sync_pr.

GPG keys (5): generate_gpg_key, import_gpg_key, export_gpg_secret_key, set_primary_gpg_key, delete_gpg_key.

Triage (4): promote_run_to_golden, resolve_triage_item, reopen_triage_item, bulk_resolve_triage.

Runs (1): submit_run_feedback.

Permissions model

Action Required
Read tools Valid PAT (results filtered by visibility scope)
update_prompt, activate_prompt_version Prompt owner OR prompt-overwrite role
share_prompt, group tools Admin OR group-manager role
transfer_prompt_ownership Admin ONLY
Eval + run tools run_evaluations scope
get_skill_contents, get_prompt_contents install_skill scope

Backend error codes surface as actionable tool errors:

  • 403 -> "Permission denied. Check prompt ownership or required role."
  • 404 -> "Not found. Verify prompt_id / skill_id and PAT visibility scope."
  • 409 -> "Conflict. Repository-backed prompt (edit source files) OR concurrent writer. Re-fetch and retry."
  • 422 -> "Validation failed - : ." when the backend names the offending field (e.g. team: String should have at least 1 character), otherwise a generic causes list (empty required field, prompt_text length max 500k, test / metric shapes, field types).

Resources (5 URI patterns)

  • ptm://prompts/{prompt_id} - active version's prompt_text (text/plain)
  • ptm://prompts/{prompt_id}/v{N} - that version's prompt_text (text/plain)
  • ptm://runs/{run_key}/report.md - markdown report (text/markdown)
  • ptm://runs/{run_key}/report.html - HTML report (text/html)
  • ptm://optimizations/{optimization_id}/report.md - markdown summary (text/markdown)

Dynamic segments are allow-list validated (^[a-zA-Z0-9_.-]+$ plus explicit ./.. rejection).

Security defaults

  • PTM_MCP_READ_ONLY=true blocks every write tool at call time.
  • X-PTM-Client + X-PTM-MCP-Session on every outbound request so the backend can classify and audit agent traffic.
  • Env scrub at startup drops anything outside the allow-list.
  • Startup preflight (/healthz + /auth/me + /meta) with exponential backoff on transient failures and dedicated exit codes per failed layer.

Exit codes

Code Meaning
0 clean shutdown
1 unhandled exception
2 /healthz unreachable after 31s of backoff
3 /auth/me rejected the token
4 backend version < 1.9.0 or unparseable
130 interrupted (SIGINT)

Status

0.19.0. 75 tools: full PTM surface (prompts, evals, optimization, triage, runs, skills, tool registry, git sync, GPG keys, inline execution + contents fetch) + 5 resource URI patterns, read-only gate, Cloudflare Access auto-discovery. See CHANGELOG.md for release notes.

Release files for ptm-mcp 0.21.0

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

Source distribution (sdist)

Source distribution for ptm-mcp 0.21.0
File Size Uploaded
ptm_mcp-0.21.0.tar.gz 65.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ptm-mcp 0.21.0
File Interpreter ABI Platform
ptm_mcp-0.21.0-py3-none-any.whl Python 3 none any Details

Total release size: 140.1 kB

Release files / ptm_mcp-0.21.0.tar.gz

Download URL ptm_mcp-0.21.0.tar.gz
Size 65.4 kB
Tags Source
SHA-256 checksum
How to use checksums
38c56e0e2a591a604df31f041eca9541743aa8da98e80d1d42472e443213178a
BLAKE2b-256 checksum
How to use checksums
9f20fbc737bc14d323a1005ce6647dc22bf47a8fbe379076283e5838022cdd6b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.15

Release files / ptm_mcp-0.21.0-py3-none-any.whl

Download URL ptm_mcp-0.21.0-py3-none-any.whl
Size 74.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
59038d90bbc40d133529aab4730c68ab18b7c901112b98e767271c5ef28c8bf2
BLAKE2b-256 checksum
How to use checksums
c2be1d0bc3ea01c40e020a8d41f14eefb5c9a783aa619926adc28abdb5fc406c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.15

Release history Release notifications | RSS feed

This release

0.21.0 This release

2 release files

0.20.0

2 release files

0.18.0

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.14.1

2 release files

0.14.0

2 release files

0.13.0

2 release files

0.12.1

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

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