MCP tools
Every tool the purasbackend MCP server exposes, grouped by area.
The MCP server is a thin stdio wrapper over the Puras HTTP API. It loads ~/.purasbackend/config.json once per call and authenticates with the stored API key. Anything you can do here you can do over HTTP with the same key — the MCP is purely a convenience for AI coding agents.
Config
configure(api_base, api_key, project_id) -> str— persist credentials to~/.purasbackend/config.json(chmod 600). Call this once per machine.show_config() -> dict— return current config. Only the prefix of the API key is included, never the secret.
Deployments
push(project_dir, notes="", activate=true) -> dict— zip the directory (excluding.git,.venv,node_modules, etc.) and upload as a new deployment. The directory must contain askills/folder with at least oneskills/<name>/skill.yamlinside; no root manifest is needed. Activates immediately by default; in-flight jobs keep running on the previous version.list_deployments() -> list[dict]— newest first.activate_deployment(deployment_id) -> dict— rolling switch to a specific deployment.delete_deployment(deployment_id) -> str— cannot delete the currently active one.
Jobs
submit_job(skill, inputs={}, wait=false, timeout=30) -> dict— submit a job against the named skill in the active deployment. The worker readsskill.yamland dispatches to the agent loop (.mdentrypoint) or the deterministic Python runner (.py:funcentrypoint) — same submission shape either way. Usewait=trueonly for skills you expect to finish in seconds; the hard ceiling is 60s and the row may still be non-terminal on return.get_job(job_id) -> dict— current status + result.list_jobs(status="", limit=25) -> list[dict]— filter byqueued|running|succeeded|failed|cancelledor empty for all.tail_job(job_id, max_seconds=60) -> dict— polls the events endpoint until the job terminates or the deadline hits. Returns{ job, events, timed_out? }.cancel_job(job_id) -> dict— marks the job cancelled. The worker checks for cancellation between agent steps; an in-flight tool call still completes.
The legacy submit_agentic_job and submit_function_job tools are kept as aliases for backwards compatibility — both now resolve to submit_job (the worker no longer needs a type hint, the skill's manifest is the source of truth). Prefer submit_job.
Feedback
End-user (or owner) thumbs-up / down + optional comment on a job result. One row per (job, end_user_id) — calling again with the same id overwrites in place. The dashboard renders this on the job detail page; your own frontend can hit the same endpoints with the project API key.
submit_job_feedback(job_id, rating=0, comment="", end_user_id="") -> dict— upsert.ratingis-1(down) /0(no thumb) /+1(up). Either a non-zero rating or a non-empty comment is required.list_job_feedback(job_id) -> list[dict]— newest first.job_feedback_stats(job_id) -> dict—{up, down, count, score}.
Secrets
list_secrets() -> list[dict]— names only. Values are never returned by the API.set_secret(name, value) -> dict— create or overwrite. Name must match^[A-Z_][A-Z0-9_]*$.delete_secret(name) -> str.
Drive
drive_sign(path, ttl=3600) -> dict— mint a signed URL for a file under the project's drive.ttlin seconds.
Uploading and listing are HTTP-only (no MCP wrappers — multipart over stdio is awkward and AI agents push files via the API directly):
POST /v1/drive/upload— multipart upload, returns{drive_path, signed_url, ...}.GET /v1/drive/list?prefix=...— list folders + files under a project subpath.
See inputs-and-drive for the upload + read pipeline.
Docs
list_docs() -> list[dict]— every doc page available locally to this MCP install (the ones you're reading).read_doc(slug) -> str— full markdown body of a single page.search_docs(query, limit=5) -> list[dict]— ranked hits with snippets.
Conventions an AI agent should follow
- Always pass the full API key including the dot separator:
puras_live_<prefix>.<secret>. - Prefer
from puras import mediainside skill code over raw HTTP to/v1/media/generate— same backend, but the SDK handles auth, drive paths, and billing context for you. See sdk-media. - Don't push partial bundles; a deployment is the whole project. If you want to ship one fix, that's still a new full deployment.
- Don't assume
wait=truereturns terminal state. Long jobs needtail_jobor repeatedget_job.