@opentrain-ai/mcp
v0.49.0
Published
OpenTrain MCP server for agent-first LMS retraining, adaptive job Task Checklist authoring, employer-only Reviewer Feedback review/triage/access/settings, jobs, people, work, messaging, payments, and Instructions.
Readme
OpenTrain MCP
MCP server for OpenTrain public API workflows: agent registration, job posting, proposal review, hiring, contracts and milestones, messaging, credits, webhooks, team management, and the canonical rich instructions attached to real jobs. It also exposes Project To-dos, quizzes, and the complete Training/LMS lifecycle over the same canonical records used by the OpenTrain dashboard and public API.
Money never moves from this server. Ordinary hire, milestone funding/approval, and contract-end requests record a pending approval for a signed-in human. The separate default-off admin-balance tools only write $0 internal-funding markers after the server independently verifies every canonical OpenTrain-admin gate; they never expose payout release, which remains human-authorized.
Restricted admin-balance milestone cancellation (0.27.3)
opentrain_cancel_admin_balance_milestone cancels one eligible
ADMIN_BALANCE-funded milestone for a verified canonical platform admin. It
requires contractId, milestoneId, and a stable idempotencyKey; set
notifyCounterparty: true only when a notification is wanted. The strict
response always reports fundingDisposition: 'NO_MONEY_MOVED' and
moneyMoved: false: no Stripe refund is created and payout release remains
human-only. Card- and credit-funded milestones are refused with a typed human
approval requirement. Reusing the same key and payload replays the durable
result. This tool requires MCP 0.27.3 and the matching serving API.
Install
Add to any MCP-capable client (Claude Code, Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"opentrain": {
"command": "npx",
"args": ["-y", "@opentrain-ai/mcp@latest"]
}
}
}With Claude Code:
claude mcp add opentrain -- npx -y @opentrain-ai/mcp@latestWhen running from a monorepo checkout that already has an
@opentrain-ai/mcp workspace, include @latest so npm resolves the published
package instead of an unbuilt local workspace.
No credentials are needed to start. For an existing account, use the browser
login flow below when the server rollout is enabled. opentrain_register_agent
creates a new anonymous account; it is not a login fallback for an existing user.
ChatGPT / Hosted MCP
The npm package above is a local stdio server. For ChatGPT developer mode, the OpenAI API Playground, or MCP Inspector, use the hosted HTTPS MCP endpoint:
https://app.opentrain.ai/mcpThe hosted endpoint exposes the parity-matched remote-safe tool set:
opentrain_search_jobsandopentrain_get_job— anonymous public job search and job detail.opentrain_auth_status— protected token/account check.opentrain_create_admin_balance_milestoneandopentrain_fund_admin_balance_milestone— restricted canonical-admin-only, request-idempotent creation or in-place internal funding. Hourly/per-label creation accepts or derives volume; in-place funding requires an existing eligibleNOT_FUNDEDmilestone. Both move $0 and create no Stripe charge or PaymentIntent. Scope possession alone is never authority.opentrain_create_job_draftandopentrain_update_job_draft_fields— protected draft workflow tools.opentrain_job_instructions_*— protected reads, no-write previews, image uploads, and confirmed writes against a real job's Instructions tab.- Project To-do and quiz tools (
opentrain_list_project_todos,opentrain_create_project_todo,opentrain_set_project_todo_future_assignment,opentrain_assign_project_todo_quiz, …) — explicit-audience authoring, request-bound preflight, provider-aware assignment, future-hire policy, results, grading, release, and retakes.opentrain_manage_project_todo_quizactionform_patch_draftchanges single draft questions (orderedadd/update/remove/moveoperations keyed by stable question ids) atexpectedRevisionand returns the new revision and the structural diff. opentrain_export_project_todos_csv— one job's Project To-do assignment CSV (formula-neutralized,worker_emailblank). The export is one response with no row cap.delivery: inline(default) returns the CSV instructuredContent.delivery: resourcereturns only a receipt (rowCount,asOf,filename,redactions,contentType,byteSize,sha256,resourceUri) plus aresource_link. The result schema is closed, one strict variant per delivery, and checked before return: a route body with an undocumented or a missing field is a tool error. Readopentrain://jobs/{jobId}/project-todos/export/csvfor the bytes: the route'scsvbyte for byte, with_meta{rowCount, asOf, byteSize, sha256}. A read re-fetches the live export under your own credential (no snapshot), so a different hash means the rows changed. Both deliveries are bounded by the export route's response, which the hosting platform caps at about 4.5 MB of JSON (HTTP 413 above it); the resource's own 20 MiB ceiling (PROJECT_TODOS_EXPORT_RESOURCE_TOO_LARGE) is not reached in practice. Receipt + read is larger than the inline result; useresourcewhen you need only the receipt or your host keeps resource bytes out of your context.opentrain_read_project_todo_quizzes— job-local quiz reads (forms,form,results,attempt,roster,export-csv).delivery: inline(default) returns the route body instructuredContent. Onlyresource=attemptandresource=export-csvacceptdelivery: resource; any otherresourcerefusesdelivery.resourcereturns only a receipt plus aresource_link: for an attemptattemptId,formId,jobId,answerCount,expectedAnswerCount; for the exportjobId,formId,formVersionId,filename,rowCount,redactions; for bothdelivery,resourceUri,contentType,byteSize,sha256. Readopentrain://project-todos/quizzes/attempts/{attemptId}for the attempt as compact JSON, oropentrain://jobs/{jobId}/project-todos/quizzes/forms/{formId}/results/csv{?formVersionId}for the route'scsvbyte for byte._metacarries the counts,byteSizeandsha256. A read re-fetches the live data under your own credential (no snapshot). A receipt or read whose response names a different attempt, job or form fails closed. The attempt body is checked against one closed schema for either delivery and for the read: a field the contract does not name is an error, and no attempt bytes leave. Theforms,form,resultsandrosterbodies are closed and checked the same way. Bounded by the route's response (about 4.5 MB of JSON); the 20 MiB ceiling (PROJECT_TODO_QUIZ_RESOURCE_TOO_LARGE) is not reached in practice. On the hosted service an attempt resource read carries the JSON as an escaped string, so it reaches that cap at a somewhat smaller attempt than the route response does.- Selective coaching tools (DEV-2741, action-specific): employer
opentrain_quiz_coaching_queue|state|cycles|threads|commentsreads, keyedopentrain_quiz_coaching_comment|redo_selection|cancel_draft| resolve_thread|reopen_thread|accept|send_back_confirmwrites, the no-write read-scopedopentrain_quiz_coaching_send_back_plan+opentrain_quiz_retake_planpreviews, keyedopentrain_quiz_retake_apply. These are employer tools; freelancer API keys cannot read, answer, or submit quizzes. Answer keys and worker personal data never appear. - Freelancer API keys are read-only:
messages:readis their only private scope, and public job search needs no scope. Message sends and all other mutations remain unavailable. - Coaching C4 tools add ungated capability discovery, bounded exports,
deterministic queue filters, and private feedback-image
prepare/finalize/status/delivery. Delivery returns a short-lived MCP
resource_linkfor agent visual inspection while structured content stays free of the signed URL; image bytes are never accepted as base64 tool arguments. Stdio alone adds a local-file upload convenience over the same canonical prepare/finalize operations. - Quiz authoring images (DEV-2678):
opentrain_quiz_form_image_prepare,opentrain_quiz_form_image_finalizeandopentrain_quiz_form_images_list(same closed contract on hosted MCP) upload a private image for a job-scoped quiz form; stdio adds the local-file one-shotopentrain_quiz_form_image_upload. Finalize returnsimageNode: put it into a question's rich content in the draft with alt text ordecorative: true. No base64, no storage path, no delivery URL. opentrain_lms_*— course authoring, assessments, private assets, immutable publishing, job linking, Training activation, assignment, review, and hosted visual proof.opentrain_lms_render_previewandopentrain_lms_step_previewreturn revision-bound PNG/ARIA/diagnostics evidence; verified bounded PNGs may be inline image blocks and otherwise degrade honestly to short-lived resource links. Preview-link tools mint, inspect, list, and revoke navigation-only signed-in employer review links.opentrain_lms_get_preview_audit_planandopentrain_lms_capture_preview_audit_targetlet an agent resumably inspect every pinned lesson in canonical order through that same worker renderer. Canonical course trees may persist an advisory authoring intent used by validation and Preview defaults while assignments remain authoritative.opentrain_lms_retraining_scaffold_caseturns one DRAFT retraining case into deterministic employer-private authoring guidance and ordered existing operations with strictly zero course, assessment, Preview, assignment, Project To-do, notification, or attempt writes.opentrain_agreements_*— OpenTrain Agreements documents: list/get, create, PDF upload prepare/finalize (one-time signed PUT flagged sensitive), field placement, handle-only page previews, and confirmed publish (see "OpenTrain Agreements documents" below).opentrain_job_checklists_*— adaptive job Task Checklist authoring with full web-builder parity: atomic create, CAS drafts, exact-rule no-write validate/resolve, confirmed publish, versions, submissions, reorder, the worker-visibility toggle, and stateless browser preview grants.opentrain_job_feedback_*— employer-only Reviewer Feedback: list/search, detail + event history, summaries, subject-roster discovery, submit, CAS-fenced triage, subject linking, reviewer access, and the confirmed per-job toggle. Subjects never read feedback through any agent surface.opentrain_people_table_*— a job's People table: describe, query rows, columns, cells, saved views and the changes feed (no export). Names are masked, contact, financial and compliance columns are redacted, and only employer custom columns are written.
Public search works without linking. Account-specific tools require OpenTrain
bearer-token auth and return MCP OAuth challenges when called unauthenticated.
The local stdio package remains the full self-registration flow because it can
store the generated ot_pat_ token in the user's local
~/.config/opentrain/cli.json without exposing secrets in tool output.
Reusable private video library
MCP 0.11+ exposes eleven opentrain_video_library_* tools with parity across
stdio and hosted MCP: list/get, upload prepare/status/cancel, draft
Instructions/LMS reference attach/detach, MP4 download prepare/status/grant,
and playback metadata. Hosted MCP accepts metadata only—never local paths or
video bytes. Download grants require the explicitly minted videos:download
scope.
For optional stdio file transfer, set readable upload roots with the platform path delimiter (colon on Linux/macOS):
export OPENTRAIN_MCP_VIDEO_UPLOAD_ROOTS="/approved/uploads:/another/read-root"
export OPENTRAIN_MCP_VIDEO_DOWNLOAD_DIR="/approved/downloads"The download setting is one writable directory, not a root list. Canonical realpath and no-follow checks reject traversal and symlink escapes. Reference tools atomically mutate canonical Instructions/LMS draft content and placement metadata; they never publish immutable worker-visible pins.
OpenTrain Agreements documents (Unreleased)
Eight opentrain_agreements_* tools cover the agreements document operations
on stdio (the hosted MCP exposes the same names): tool name = opentrain_ +
the registry operation id with dots replaced by underscores.
| Tool | Operation | REST |
| ------------------------------------------------ | -------------------------------------- | ------------------------------------------------- |
| opentrain_agreements_documents_list | agreements.documents.list | GET /agreements/documents |
| opentrain_agreements_documents_get | agreements.documents.get | GET /agreements/documents/{documentId} |
| opentrain_agreements_documents_create | agreements.documents.create | POST /agreements/documents |
| opentrain_agreements_documents_upload_prepare | agreements.documents.upload_prepare | POST /agreements/documents/uploads/prepare |
| opentrain_agreements_documents_upload_finalize | agreements.documents.upload_finalize | POST /agreements/documents/uploads/finalize |
| opentrain_agreements_fields_set | agreements.fields.set | PUT /agreements/documents/{documentId}/fields |
| opentrain_agreements_preview | agreements.preview | GET /agreements/documents/{documentId}/preview |
| opentrain_agreements_versions_publish | agreements.versions.publish | POST /agreements/documents/{documentId}/publish |
Reads need agreements:read; mutations need agreements:write plus an
idempotencyKey (sent as Idempotency-Key; a replay returns the stored
outcome with replayed: true). The family is default-off
(AGENT_SURFACE_AGREEMENTS_ENABLED) and rollout-gated (agreements_native).
Inputs and structuredContent.result are the closed contract shapes, validated
before any request and on every response. Failures are isError text carrying
the HTTP status, code, details.reason (for example REVISION_CONFLICT,
UPLOAD_INCOMPLETE, PUBLISH_WARNINGS_UNWAIVED) and request id, with URLs
and tokens redacted.
- Upload is prepare → signed PUT → finalize. The prepare result carries the
one-time PUT URL in
structuredContent.result.upload.url, flagged by_meta["opentrain/sensitive"] = { paths: ["result.upload.url"], handling }(dot paths insidestructuredContent; the hosted MCP uses the same key and shape). Use it once; never log, persist or echo it. It never appears in the text content or in errors. This server never carries PDF bytes. - Previews return short-lived resource handles only, never image bytes. Save
the PNGs with
opentrain agreements preview --out <dir>or an authenticatedGET /api/public/v1/agreements/resources/{id}. - Publishing freezes an immutable version and requires
confirmLive: true; it is refused before any request otherwise (CONFIRMATION_REQUIRED).
Shared folder Instructions (0.27.0+)
Contract tools negotiate the additive dashboardUrl field with
X-OpenTrain-Features: contract-dashboard-url-v1; clients may omit the header
for the legacy response shape. The MCP client sends this header automatically.
Both stdio and hosted MCP expose the same eight migration operations:
opentrain_inspect_folder_instructions,
opentrain_preview_folder_instruction_change,
opentrain_confirm_folder_instruction_change,
opentrain_get_folder_instruction_change,
opentrain_apply_folder_instruction_change,
opentrain_cancel_folder_instruction_change,
opentrain_resume_folder_instruction_change and
opentrain_export_folder_instruction_recovery.
Another 25 opentrain_folder_instructions_* tools cover shared canonical
page/tree, preview/preflight, history, schema, link, verify and image/video
authoring. Discover their closed schemas and per-operation
opentrain.ai/authoring-retry metadata rather than assuming every write retries
the same way. All require current folder-employer authority and the existing
Instructions scopes. Existing job tools remain unchanged.
Preview/status/recovery are read-only. Confirmation binds the reviewed digest
and freezes writers; apply waits for drain, preserves originals and commits
verified content atomically. Inspect the same operation after uncertainty and
require VERIFIED_READBACK. First activation must use this reviewed workflow;
ordinary authoring cannot activate an empty folder. Incompatible published-mode
folder writes refuse without enabling release/read/ack features. Shared content
is visible to all eligible child-job workers; language labels are not access
controls. See the folder workflow.
Authentication
Browser login (0.27.0+, rollout-gated)
MCP 0.27.0+ includes opentrain_auth_login_start and
opentrain_auth_login_status in the local stdio server. The server migration
and agent_browser_login rollout must be delivered before login can succeed.
A disabled rollout returns a refusal, not a new account. Package publication
does not enable the separate browser-login rollout.
- Call
opentrain_auth_login_startwith an optionaldeviceLabel,lane(EMPLOYERorWORKER) and space-separatedscoperequest. - Give the returned
verificationUriCompleteanduserCodeto the person. They open normal OpenTrain in any browser, match the code, sign in, and explicitly approve their identity/context and permissions. Do not request their password, browser cookie, polling secret or API key. - Resume
opentrain_auth_login_statuswith the sameloginIdand optionalwaitSeconds(0–120). HonorintervalSeconds.PENDING,SLOW_DOWNandTIMEOUTpreserve the handle;DENIEDandEXPIREDare terminal. - After approval, call
opentrain_auth_statusto check the actual credential source and account. An environment key can shadow the saved browser session. While no credential is configured,opentrain_auth_statusalso reports an unexpired sign-in started on this machine for this origin (pendingLogin { loginId, expiresAt }plusinstructions) so the client finishes it withopentrain_auth_login_statusinstead of starting another. It only reads the local pending-login file: no poll, no write, and never the polling secret.
The CLI and stdio server share one private local credential provider. A long-lived
stdio process picks up a login or access-token rotation without a restart;
its configured origin still has to match the session issuer. The CLI can also
start/resume the same login and revoke it with opentrain auth logout. Browser
logout preserves an unrelated saved key and never revokes an environment key.
Pending polling secrets and access/refresh tokens never enter MCP output.
The headless-host store uses 0700 directories and 0600 atomic files with a shared
cross-process refresh lock; it is not an OS keychain and does not protect against
arbitrary code running as the same OS user. Never share the profile directory.
Hosted MCP browser consent (rollout-gated)
The device flow above is for local stdio MCP. Hosted clients use their own
HTTP OAuth authorization-code flow with PKCE S256 and resource
https://app.opentrain.ai/mcp. They open normal OpenTrain sign-in and explicit
consent; opening the link alone does not grant access. Do not forward a hosted
MCP access token to the public REST API or ask a user to paste browser cookies.
This source supports HTTPS client-ID metadata documents with validated exact
client IDs and registered redirects. Non-URL client IDs require an exact
operator registration; an arbitrary client name is not a registration. The
server validates metadata through bounded, DNS-pinned HTTPS requests. Discovery
and consent preserve opaque state and return the matching authorization-server
issuer. This is not a claim that every external client/version has passed testing.
Turning off agent_browser_login refuses new device and hosted login requests.
It does not mass-revoke existing sessions or disable API keys; already-issued
legacy authorization codes retain their exchange path. Missing/expired credentials
and structured scope shortages may require reauthorization. A disabled feature,
wrong organization, or other permission denial is a tool error, not a reason to
loop through login. Never automatically replay an uncertain mutation after login.
Employer and freelancer Settings expose Connected agents alongside API keys. Users can inspect and explicitly revoke only their own connections, including CLI, local MCP and hosted clients. A failed inventory read is shown as unavailable with a read-only retry, not as an empty list. Final server/migration rollout, browser role tests, and actual hosted-client interoperability remain release gates. Hosted-client compatibility must be verified for the actual connecting product and version; successful local stdio login is not proof that a hosted OAuth client supports the same flow.
Credential precedence and API-key compatibility
The server starts without any credentials. Resolution order:
OPENTRAIN_PERSONAL_API_TOKENenv var (wins outright when set)- A saved browser session in the shared OpenTrain profile
${XDG_CONFIG_HOME:-~/.config}/opentrain/cli.json - The saved static API key in that profile
- No credential — explicit browser-login and new-account onboarding remain available; authenticated operations refuse without creating an account
For an existing employer account, create a personal API token from Employer
Settings -> Developer -> API keys and provide it as OPENTRAIN_PERSONAL_API_TOKEN
or save it with opentrain auth login --api-key .... Static keys remain supported
for CI and existing integrations. Browser login preserves each lane's canonical
permissions; it does not make freelancer access writable or bypass restricted
platform-admin eligibility and human payment approval.
Environment
OPENTRAIN_API_BASE_URL- Base URL for the OpenTrain app/API. Defaults to
https://app.opentrain.ai. - Example local development value:
http://127.0.0.1:3000.
- Base URL for the OpenTrain app/API. Defaults to
OPENTRAIN_PERSONAL_API_TOKEN(optional)- Personal OpenTrain API token (
ot_pat_…). Optional: without it the server falls back to saved credentials or tokenless onboarding.
- Personal OpenTrain API token (
Tools
Onboarding (no token needed):
opentrain_register_agent- Registers a brand-new anonymous agent account via
POST /api/agent/identity. - Persists the token + claim token to the shared config file (mode 0600); raw secrets are not echoed in tool output.
- Refuses to overwrite existing credentials unless
force: true.
- Registers a brand-new anonymous agent account via
opentrain_claim_account- Emails the human owner a claim invite via
POST /api/agent/identity/claim. - Returns the verification URI + user code to relay to the human.
- Emails the human owner a claim invite via
opentrain_claim_status- Polls
POST /api/agent/oauth/token(claim grant). Honorsauthorization_pending/slow_down; on success upgrades and saves the claimed token.
- Polls
Shared job operations — Work Catalog, coordination modes, external attestations (0.23.0+, DEV-3191):
opentrain_list_job_context_work_definitions/opentrain_get_job_context_work_definition/opentrain_list_job_context_work_executionsand theopentrain_*_job_context_work_*mutations — the dynamic per-job Work Catalog. Work is PER-JOB catalog data, never a platform enum; every covered response'ssync.workCatalogteaches the catalog head/status, the winner-only setup lease, pending human approvals, and this job's work-coordination mode. Definition-bound mutations present the FULL binding (versionNumber + contentHash + coordinationSignature); every execution mints ONE coordinating action (the single claim authority).sync.workCatalog.coordination.modeis the singleton typed policyWORK_COORDINATION_MODE(recorded only by a non-agent human job manager viaopentrain_record_job_context_policy):OPEN(default when no row exists),COORDINATED(every guarded mutation — e.g.opentrain_send_managed_job_message— must present a claimed action bound to an OPEN work execution, defined or provisional),MANAGED(that execution must be DEFINED work under an ACTIVE definition). Anullmode is fail-closed, never OPEN. A refused guarded mutation surfaces the closed 409 details{reason: JOB_OPS_WORK_COORDINATION_REQUIRED, requirement, mode}in the tool error text: begin defined/provisional work, claim the coordinating action it mints, retry.opentrain_record_job_context_observationaccepts a top-levelexternalAttestation(ATTEST: bounded per-jobsource.systemslug, optional locator/subject, claim, non-futureattestedAt, REQUIREDexpiresAt≤ 30 days, optionalsupersedesObservationId;INVALIDATE:invalidatesObservationId,invalidationSourceWEBHOOK|UI|AGENT|HUMAN, reason,invalidatedAt) with authorityOBSERVED, plus a top-levelactorAgentLabelstored canonically ascreatedByAgentText(a nested label is refused). The server proves the same-context lineage before writing (readable non-future target, same source + subject, one live ender per target, ONE current head per source + subject). The guide (opentrain_get_job_context_guide/ resourceopentrain://jobs/{jobId}/operations/guide) carriesexternalCoverage: everything not CURRENTLY attested is UNKNOWN; each entry carries status, canonical attribution, bounded evidence, and the ending receipt.
Job posting:
opentrain_create_job_draft- Primary workflow: send a full plain-text
jobDescription(or a supportedcanonicalJob/importPayload); OpenTrain parses it server-side. - Returns validation state; each missing field carries an "ask:" question to relay to the human plus the field name(s) to set.
- Primary workflow: send a full plain-text
opentrain_update_job_draft_fields- Patches draft fields by name (the gap-filling step after asking the human).
opentrain_discard_job_draft- Deletes a never-published draft (no proposals, in no folder) so it leaves
the job list. Organization owners only; requires
confirm: true; published jobs useopentrain_close_job.
- Deletes a never-published draft (no proposals, in no folder) so it leaves
the job list. Organization owners only; requires
opentrain_publish_job- Publishes a publish-ready draft live (same validation + moderation pipeline as the in-app flow; per-account daily limits).
Proposals and hiring:
opentrain_list_jobs— own jobs with status filter + pagination.opentrain_list_proposals— candidates for a job with bid/status/AI-interview and match-score signals (the hire-decision surface).opentrain_get_proposal— full candidate evaluation: bid, AI-interview score- summary, location/identity verification, Open Label assessment, and
contract state. Pass
includeInterview: truefor the sanitized AI-interview transcript.
- summary, location/identity verification, Open Label assessment, and
contract state. Pass
opentrain_get_freelancer_profile— masked freelancer profile by id or slug: skills, stats, work/label experience, education, reviews, languages. Names stay masked and personal contact details are never returned. Emails, phone numbers and links in employer review comments come back as[REDACTED_*]placeholders, recorded inredactionswith sourceEMPLOYER_REVIEW(DEV-3129); the agency website stays as a public business field.opentrain_get_candidate_dossier— privacy-safe, viewer-scoped candidate dossier for a proposal (masked profile, verification verdicts incl. identity assurance, factual engagement disposition, review/contract roll-ups). Optional strictevidence: "full"adds ten bounded metadata-only evidence families (25-item caps, truthful truncation, typed continuation). Both the input and the response are validated against the exact closed contract schema — a server/tool version mismatch fails as a typed error telling you to upgrade this package, never as silently forwarded unvalidated data. Lockstep rule: every server-side addition to the dossier response ships with a same-batch schema update and release of this package, so an unknown field always means "upgrade", never "pass it through".opentrain_get_candidate_dossier_resume_link— audited LINK-ONLY resume access (DEV-2977 B3.5): a fresh 600-second signed URL when AVAILABLE, or a truthful typed unavailable state.structuredContentIS the raw five-variant{url, expiresAt, availability, reason, provenanceStatus, provenance}response object — no{apiBaseUrl, result}envelope (hosted-MCP parity). Requires BOTHcandidate_dossier:readANDcandidate_documents:read; every admitted access is audited append-only BEFORE the URL is disclosed; the tool never follows redirects or fetches bytes, and the response is runtime-validated against the exact closed five-variant machine — an AVAILABLE url must be an absolute http(s) URL with no embedded credentials and the expiry a calendar-valid RFC3339 date-time (mismatches are typed upgrade errors). Denials preserve the server's bounded error code, typed reason (e.g.SELF_ACCESS_NOT_SUPPORTED), and request id. Since 0.22.0 (DEV-3024) the response is the five-variant provenance union: AVAILABLE carriesprovenanceStatus: "AVAILABLE"plus aprovenanceobject observed at issuance (sanitized original file name, allowlisted MIME type, byte size, upload/modified instants,observedAt, an opaquestorageEtagthat is NOT a checksum, andchecksumreserved for an authoritative SHA-256 — null today) orprovenanceStatus: "UNAVAILABLE"withprovenance: null; every unavailable state carriesNOT_APPLICABLE+ null. Provenance is an observation, never a binding on the bytes a later download returns.opentrain_list_candidate_dossier_applications— PLATFORM-ADMIN ONLY platform-wide application history for one candidate user id (DEV-2887): PROPOSAL and INVITE rows counted SEPARATELY, exact all-row counts (proposals, invites, distinct jobs, distinct organizations, contracts resulted), a proposal velocity summary, rate-integrity bid statuses, raw outcome flags, and exact offer-linked contract results. Requirescandidate_dossier:readplus the named canonical-admin exception; ordinary employers receive the uniform not-found and candidate self a typedSELF_ACCESS_NOT_SUPPORTEDdenial.nextCursoris bound to the candidate and the ORIGINALasOf.structuredContentIS the raw validated page.opentrain_list_job_invitations/opentrain_get_job_invitation— canonical invitation state for an owned job (DEV-2846,proposals:read+ the hiring feature, inside the default-offproposal_managementfamily —AGENT_SURFACE_PROPOSAL_MANAGEMENT_ENABLED): an invitation a newer one replaced reads EXPIRED with nolinkedProposalId(DEV-3285); any other reads HIRED > APPLIED > DECLINED > EXPIRED > INVITED (EXPIRED once the job closes or 30 days after sending,expiresAton every row),hireAcceptancePendingonly for a REAL live hire authorization, masked identity, hidden/banned/closed candidates withheld from pages ANDtotalCount, filters applied before the exact count and keyset cursor; the lookup reads the uniform{ invited: false, invitation: null }for unknown, hidden, and never-invited candidates alike.structuredContentIS the raw validated page/lookup.opentrain_list_candidate_dossier_reviews/opentrain_list_candidate_dossier_contract_history— cursor-paged full lists behind the dossier's bounded previews (a non-nullnextCursormeans more pages; nothing truncates silently). The reviews page redacts contact details and links in employer review comments and lists them asPRIVACY_MASKEDredactions(DEV-3129).opentrain_get_participant_work_email— audited managed-work-email read (DEV-3031 B3.6): the canonical@opentrain.workprimary address for a participant you manage through EXACTLY ONE of{contractId},{proposalId}, or{jobId, personUserId}(a bare user id is never accepted; strict own-key input — mixed/unknown keys fail with zero network).structuredContentIS the raw closed eight-state response — no envelope. ONLYACTIVEcarries an address (normalized lowercase, exactly underopentrain.work); the personal signup/login email is NEVER returned, denial text is a bounded projection that never echoes server error text, and every authenticated attempt is audited append-only BEFORE any address is disclosed. Requires the dedicatedparticipant_work_email:readscope.opentrain_invite_freelancer— invite a freelancer to a published job.opentrain_hire_proposal— request a hire with a first escrow milestone. Does NOT hire or move money: records a pending approval and returns anapprovalUrla signed-in human must confirm in the OpenTrain app (~72h expiry). Requires a claimed account + payment method or covering credit balance.opentrain_start_proposal_conversation— open the pre-hire DM thread for a proposal so messages can flow before hiring.
Jobs (beyond drafting):
opentrain_search_jobs— public job search (no token sent):q,category,domain,language,country,payType,limit(1–25, default 10) andcursor; closed{ jobs, nextCursor, generatedAt }.opentrain_get_job— one public job byidor canonical joburl(no token sent);{ id, status: "closed" }for a closed, private or unknown job.opentrain_update_published_job— patch fields on a live job.opentrain_close_job— close a published job to new proposals.opentrain_discard_job_draft— delete a never-published draft.
Contracts and milestones (co-signed money movement):
opentrain_get_contract_history— DEV-2830 canonical engagement history for EXACTLY onecontractIdorproposalId(viewcurrent | timeline): proposal → contract(s) → milestones/payouts.current.accessderives only from participationState ACTIVE/REACTIVATED (ACTIVE | NONE | CONFLICT with every such contract listed — nothing is picked silently; the proposal's HIRED label is never access); rehire links only fromadmin_balance.rehire_createdaudit rows; purpose only from work-project evidence (a capped/partial set stays UNSPECIFIED,evidenceTruncated); timeline only from durable stored timestamps; bounded with explicittruncatedflags, no cursor; unknown/foreign/self selectors are one opaque 404.structuredContent.resultis the raw closed response.opentrain_list_contracts/opentrain_get_contract— contract status, milestones with funding/approval state, budget consumption, and the post-hire job DM conversationId. DEV-2839: the list is a bounded page — optionallimit(1..100, server default 50) andcursor(opaquenextCursorbound to the ORIGINAL jobId/status/asOf) with truthfultotalCount/hasMore/collectedCount/complete; walk pages with the cursor (no unbounded all mode). A job-scoped call without limit/cursor keeps the unchanged unpaged list.structuredContent.resultis the raw page validated against the closed contract schema; a database-budget overrun is a typed retryable 503CONTRACT_LIST_TIMEOUT.opentrain_create_milestone— add an unfunded milestone directly.opentrain_request_milestone_funding/opentrain_request_milestone_approval— record a pending approval and return anapprovalUrl; a signed-in human confirms in the OpenTrain app before any money is held or released.opentrain_end_contract— ends only after every milestone is terminal; unresolved drafts, funded/payment, review, or refund states return structured blockers with the required next action.opentrain_get_approval— re-check a pending approval's status.opentrain_cancel_admin_balance_milestone— cancel one eligible internally funded milestone with a keyed, no-money-moved result; notifications are opt-in and card/credit funding remains human-approved.
Updates feed and webhooks:
opentrain_poll_updates— cursor-based delta feed of account events (new proposals, messages, contract/milestone changes, approval confirmations, budget state changes). PersistnextCursorbetween polls.opentrain_create_webhook/opentrain_list_webhooks/opentrain_get_webhook/opentrain_delete_webhook— signed HMAC push deliveries of the same events instead of polling. The signing secret is shown once at creation.
Credits (prepaid balance):
opentrain_get_credits— available/reserved balance.opentrain_create_credit_top_up— returns a Stripe Checkout URL a human completes; the agent cannot pay.opentrain_get_credit_top_up— top-up status.opentrain_list_credit_ledger— append-only ledger entries.
Messaging inspection (0.27.2):
opentrain_list_messaging_members: paginated current roster; removed history and managed work emails are explicit opt-ins.opentrain_get_messaging_member: exactly one user/contract/managed-address selector and observational add/remove eligibility.opentrain_list_job_conversations: separate proposal DMs, Job DMs and channels, with bounded response evidence. FollownextCursor;updatedAfteris not a complete message-edit feed.opentrain_audit_notification_emails: job-authorized observations for message IDs, bounded conversation/time range or milestone/recipient. Stored messages andSENTdo not establish primary delivery. Missing evidence stays unknown; BCC counts are envelope evidence only.
All four are read-only, require messages:read and canonical access, and expose
validated structuredContent plus a response_format text selector. Managed
addresses also require participant_work_email:read. No read repairs or creates
conversations/memberships. Strict stdio response schemas require the matching
API release; published MCP 0.27.3 includes this cancellation operation and the
preceding messaging batch.
Messaging and payments:
opentrain_read_messages— omitconversationIdto list conversation summaries; provide it to read messages. Read-only.opentrain_send_message— send a message in a conversation the token owner participates in (claimed accounts only). This generic tool is intentionally outside shared Job Operations synchronization.opentrain_edit_message/opentrain_delete_message— author-only CAS mutations of a message YOU sent (correct an already-sent instruction or credential; delete is a NON-destructive tombstone — prior values survive only in the append-only server-side revision ledger). PassexpectedRevision= the message readbackrevision; the required idempotency key uses the canonical 1-128[A-Za-z0-9._:-]grammar (minimum ONE char). Summaries never echo message content.opentrain_get_message_attachment— retrieve one authorized attachment by the opaqueattachmentIdreturned by message/audit/thread reads. One authenticated, auditeddelivery=autorequest returns a verified PNG/JPEG/WebP/GIF up to 4 MiB as an MCP image block agents can inspect; everything else becomes a resource link atopentrain://messages/{messageId}/attachments/{attachmentId}. Reading that resource returns a verified blob up to 20 MiB. The server and MCP both verify identity, size, SHA-256, sniffed type, and resolved delivery; no storage path, signed URL, bucket, or credential is exposed.opentrain_send_managed_job_message— the required job-manager send: uses a complete claimed-action guard and stable key, rechecks the latest message, and commits the message plus shared-context advance atomically. Requiresmessages:writeandmessages:manage.opentrain_list_pending_payments— pending funding/payout state, no payment execution controls.opentrain_verify_payout— retrieves current Stripe transfer state and reports reversal, identity mismatch, or disagreement with OpenTrain.opentrain_preflight_payout_recovery— exhaustively searches matching amount/destination/milestone transfers and tells the operator to stop if an unreversed equivalent already exists. This is a read-only duplicate guard; it never creates or reconciles a transfer.
Team:
opentrain_get_team— organization, members, invites.opentrain_invite_team_member— invite a human teammate by email (claimed accounts only).
Instructions (job-first tools over the one canonical source):
opentrain_job_instructions_inspect— the exact tree and employer URL for one job.opentrain_job_instructions_capabilities— supported schema, rich nodes, limits, and guarantees.opentrain_job_instructions_read_page— one rich TipTap JSON page plus its checksum.opentrain_job_instructions_page_link— the actor-aware exact-page URL, with optional server-validated stable-node anchor.opentrain_job_instructions_search— the employer editor's ranked full-text search (typo-tolerant fallback) over the job's effective draft scopes (own set + inherited folder set — what inspect/read_page read; never a worker's released view). Page groups with up to five block hits each: stable block ids, anchor ids for deep links, the nearest heading, inert plain-text snippets with code-point highlight ranges.truncated=truemeans the ranked window filled — narrow the query;hasMore/nextCursorpage the ranked page groups (the cursor is bound to the job, the query and the ranked window; a foreign one, or one issued before the Instructions changed, fails withINVALID_CURSOR). Requiresinstructions:read.opentrain_job_instructions_preview— validate and render a page without writing.opentrain_job_instructions_preflight— validate and sign one exact mutation without writing.opentrain_job_instructions_upload_image— upload a supported image without changing a page.opentrain_job_instructions_plan_image— derive the deterministic final URL without uploading.opentrain_job_instructions_create_page— idempotently create a page in the actual job tab.opentrain_job_instructions_patch_page— checksum-guarded stable-node edits.opentrain_job_instructions_replace_page— explicit checksum-guarded full replacement.opentrain_job_instructions_update_page— rename, reparent, or reorder.opentrain_job_instructions_archive_page— explicitly confirmed archival.opentrain_job_instructions_preflight_tree/opentrain_job_instructions_apply_tree— validate and atomically swap a complete one-level page tree.opentrain_job_instructions_verify— semantic and checksum verification of every canonical page.opentrain_job_instructions_visual_review— authenticated employer/sidebar screenshot plan with an explicit worker-proof boundary.opentrain_job_instructions_schema_upgrade— idempotent v1 → v2 page upgrade with a required quiescence window and canonical readback.opentrain_job_instructions_youtube_node— offline normalization of a supported YouTube URL into the canonical schema-v2 node.opentrain_job_instructions_release_prepare/release_preview/release_publish/release_list— immutable worker releases from the same job-owned draft, with an explicit delivery policy and audited overrides.opentrain_job_instructions_history_list/history_read/history_compare— employer-only draft checkpoints per page: cursor-paged provenance list, one checkpoint's content, and the checkpoint→current (or checkpoint→checkpoint) block diff.opentrain_job_instructions_history_checkpoint— explicit manual restore point, optionally receipt-tracked with an idempotency key.opentrain_job_instructions_history_restore— DESTRUCTIVE replacement of live page content from a checkpoint. The schema requires literalconfirmRestore: true+confirmLive: true, a freshexpectedChecksumfrom compare, and anidempotencyKey; the server records a durable undo baseline first and returns409on live drift. History payloads never expose TipTap room identifiers, and success proves storage + checksum readback only — never collaboration sync or browser rendering.
The server advertises job-tree and job-page resources under
opentrain://jobs/{jobId}/instructions. Standalone workspaces, manuals,
bindings, changesets, and publications were removed; they are not a second
instruction source. Job pages support one subpage level. Image uploads accept
JPEG, PNG, WebP, GIF, and AVIF up to 4 MB. Every draft mutation requires
confirmLive: true and the signed token from its exact no-write preflight;
full replacement also
requires a fresh checksum and confirmReplace: true. Complete tree apply uses
deterministic staging, an exact-active-set fence, one database pointer swap,
and idempotent recovery so employers do not see partial page assemblies.
Whether workers see a confirmed write at once or only after a separate publish
is stated per read by opentrain_job_instructions_capabilities
(mutations.workerVisibility: IMMEDIATE, ON_PUBLISH, or MIXED while the
worker-read cutover is partially rolled out — treat a draft write as undelivered
until published). Release tools return 404 for actors outside that rollout.
Content schema v2 adds details, callouts, YouTube, audio, and attachment nodes. Existing pages remain on their persisted schema until explicitly upgraded. MCP create, preview, patch, replace, tree apply, and readback operations preserve the page schema and reject v2-only nodes on v1 pages. YouTube normalization accepts supported YouTube URL forms, retains only the validated 11-character video id plus safe attributes, and renders through the privacy-enhanced player.
Training/LMS:
opentrain_lms_capabilities— canonical schema, content nodes, assessment settings, asset types/limits, and truthful workflow availability. It includes the shared TipTaplmsLessonprofile, registry version, per-block author/edit/render support, attributes, and private-media semantics. Agents author that canonical JSON directly and must not invent HTML or an MCP-only lesson model.- Course and assessment tools — create/recover, read, validate, update, publish, and bind immutable assessment/course versions.
opentrain_lms_prepare_asset_upload/opentrain_lms_finalize_asset_upload— short-lived direct-storage grants plus server-verified checksum, length, MIME, and container finalization for large private media. Never log a grant.- Job Training tools — read/set Training and list/link/unlink courses. Linking, enabling, publishing, and assigning are deliberately separate operations.
- Assignment and review tools — assign an immutable version, report progress, remind/cancel, grade, release results, decide PASS/FAIL, and return work with another attempt.
opentrain_lms_list_assignments— page mode (cursor+limit, default 50, max 200) returns the raw page withhasMoreandnextCursor; the text saysPARTIAL RESULTwith the exact next cursor,complete, orINCONSISTENT PAGE(retry-only guidance).all: truecollects every page (effective page size on every request, de-duplicated by assignment id, repeated-cursor safe) and returnshasMore, the page-leveljobIdand authorizedlinks[], andcollection{pageSize, pagesFetched, collectedCount, complete, finalCursor, stopReason, duplicatesDropped}; any page error, id-less row, job mismatch, or inconsistent page fails the whole call. Course and version reads (opentrain_lms_get_course,opentrain_lms_list_course_versions,opentrain_lms_get_course_version) carry a privacy-safeattributionblock (creator, revision-bound last material updater, version author, publisher; stable ids always, display fields only for current organization identities, explicitnotAvailableReasonfor historical gaps), and the frozen tree inopentrain_lms_get_course_versionis the complete immutable inventory.opentrain_lms_export_assignments— masked assignment reporting ascsv,jsonorjsonl.delivery: inline(default) returns one bounded page (cursor+limit, max 5000).delivery: resourcewalks every page fromcursoron and returns only a receipt (rowCount,pages,startCursor,completefrom the cursor,nextCursor: null,contentType,byteSize,sha256,resourceUri) plus aresource_link; the rows never enter the result. Readopentrain://lms/jobs/{jobId}/assignments/export/{format}(or…/from/{cursor}for a tail) for the bytes — serialized exactly as the CLI'slms assignments export --outputwrites the file, so the hashes agree — with_meta{rowCount, pages, startCursor, complete, byteSize, sha256}. A read re-walks the live export under your own credential (the URI grants nothing): there is no snapshot, so_meta.sha256equals the receipt's only if no row changed in between — a different hash means the rows changed; re-run the tool for a fresh receipt. The whole artifact is bounded at 20 MiB, checked after each page; the page cap (LMS_EXPORT_PAGE_CAPwithresumeCursor), a repeated cursor (LMS_EXPORT_CURSOR_REPEATED), an oversized export (LMS_EXPORT_RESOURCE_TOO_LARGE) and a malformed page are typed failures with nothing delivered. Cost: the receipt is a few percent of the inline page walk, but receipt + read is larger than the walk — useresourcewhen you need only the receipt or your host keeps resource bytes out of your context.opentrain_lms_get_attempt_evidence— one assessment attempt's immutable evidence (lms:read): question snapshots, the worker's answers, closed outcomes and manual grades; never answer keys, pass thresholds or attempt policies. One attempt can pass the 25,000-token default MCP output limit (Native Forms allow 500 questions and 10,000-character prompts).delivery: inline(default) returns the evidence instructuredContent.delivery: resourcereturns only a receipt — the same result withoutquestions,missedQuestionIdsandunansweredQuestionIds, plusquestionCount,missedQuestionCount,unansweredQuestionCount(null whenNOT_SUBMITTED),delivery,resourceUri,contentType,byteSize,sha256— and aresource_link. Readopentrain://lms/assignments/{assignmentId}/attempts/{attemptId}/evidencefor the questions: the route body as compact JSON, checked against the same closed schema, with_meta{evidenceState, questionCount, byteSize, sha256}. A read re-fetches the live evidence under your own credential (no snapshot), so a new manual grade changes the hash. A receipt or read whose response names a different assignment or attempt than the one requested fails closed; nothing is delivered. Both deliveries are bounded by the route's response, which the hosting platform caps at about 4.5 MB of JSON (HTTP 413 above it); the resource's own 20 MiB ceiling (LMS_ATTEMPT_EVIDENCE_RESOURCE_TOO_LARGE) is not reached in practice.opentrain_lms_get_course_answer_key— the employer-only answer key for a course (lms:read): every quiz in course order with the correct choices marked, expected values, points, and each quiz pass rule. OmitversionIdfor the current draft (quizzes resolved the way publishing would freeze them) or pass one published version id. Never share it with learners; the worker-facing Preview keeps hiding answer keys.
The local stdio package and hosted endpoint expose the same business actions. Local-only orchestration such as filesystem checkout/diff/reconcile remains a CLI concern; all canonical validation, revision fencing, authorization, and mutations stay on the public API.
Shared job operations (manager, MCP 0.27.3+):
Version and schema-drift diagnostics
The stdio server reports its installed package version in the MCP initialize
handshake as serverInfo.version. Record that value when diagnosing a client
or server mismatch; it is the version that actually handled the session, not
the version a global install or lockfile happens to advertise. A bounded
job-operations response-schema error also includes the installed
@opentrain-ai/mcp version and tells you to upgrade and refresh any cached
npx package before retrying. Do not keep retrying an unchanged malformed
response.
For a fresh package check, inspect the registry version and then force a fresh one-shot package resolution:
npm view @opentrain-ai/mcp version
printf '%s\n' \\
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"version-probe","version":"1.0"}}}' \\
'{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}' \\
| npx --yes --package=@opentrain-ai/mcp@latest opentrain-mcpThe second command starts the stdio server and returns its initialize
response; read serverInfo.version there. Existing MCP hosts may cache an
npx package, so refresh that host/package cache after upgrading. A local
handshake proves only the installed client version and protocol wiring; it is
not an authenticated production-operation retest.
Mutation-tool descriptions and input schemas (MCP 0.16.0+) come from the canonical Job Operations agent-mutation catalog shared with the CLI, hosted MCP, and OpenAPI, so every surface documents the same operation with the same fields, enums, and bounds; cross-surface parity is CI-pinned.
opentrain_get_job_contextis the MANDATORY first call before managing an existing employer job. The compact snapshot automatically carries the top-10 fresh priority attention signals with their derived claim state, signal counts, per-rule evaluator health, the effective typed policies, and the Agent Guide digest — there is no second bootstrap call. Initialize instructions teach the full context-first protocol to every connected agent — including protocol step 15: durable sync start/resume, the one Agent Guide read the bootstrap envelope directs, the exact delta readrecommendation.agent_guide_changednames when the head moved (added/changed sections,removedSectionIdstombstones), acknowledging only delivered context, RECOMMENDED Playbook proposals with human publication, and per-job work types (never fixed grading/retraining enums) are AUTOMATIC; the human never needs to know to ask for the setup.opentrain_list_job_context_signals/opentrain_get_job_context_signal— deterministic attention signals (SHADOW rules are excluded at the database query level;includeShadow: trueis an explicit audit read).opentrain_acknowledge/snooze/dismiss_job_context_signal— triage with the exactexpectedSignalRevision; triage never claims work and never clears a condition (only the deterministic evaluator clears).opentrain_claim_job_context_signal— the ONLY path that turns a signal into owned work; eligibility is ACTIVE + FRESH + effective OPEN/ACKNOWLEDGED, non-shadow, and the signedclaimReceiptcomes back with the action.opentrain_get_job_context_effective_policies/opentrain_list_job_context_policy_history/opentrain_record_job_context_policy/opentrain_verify_job_context_policy_enforcement— typed, attributed, superseding durable policies with atomic WORKFLOW/CANONICAL_DB enforcement and evidence-verified EXTERNAL enforcement.opentrain_get_job_context_agent_guide(MCP 0.26.0+) — the Agent Guide, the ONE operational guidance document for agents managing a job (worker-facing Job Instructions are a separate surface): the canonical typed projection plus the human-published Playbook (bounded Markdown sections with stablesectionIds and per-section SHA-256contentHashes,playbookVersion, publisher) and the open-proposal count under onecontextRevision. Bootstrapsync.nextOperationsends withjob_operations.agent_guide.get; afterwardsrecommendation.agent_guide_changednames the exactopentrain_get_job_context_playbook_deltaread (added/changed sections,removedSectionIdstombstones). Also the read-only Markdown resourceopentrain://jobs/{jobId}/operations/agent-guide.opentrain_get_job_context_playbook,opentrain_list_job_context_playbook_versions,opentrain_get_job_context_playbook_version,opentrain_get_job_context_playbook_delta— the published Playbook head, newest-first history, one exact version, and the exact section delta.opentrain_submit_job_context_playbook_proposal,opentrain_list_job_context_playbook_proposals,opentrain_resolve_job_context_playbook_proposal— agent writes to guidance are PROPOSALS (RECOMMENDED, never enforced;basePlaybookVersionmust equal the head).opentrain_publish_job_context_playbookis the HUMAN job-manager court (agent principals are refused); ACCEPT of a proposal is that same court.opentrain_get_job_context_operating_guide— the canonical typed projection of the Agent Guide alone (without the Playbook; structured JSON + deterministic Markdown, guideVersion + SHA-256 checksum), kept for published clients — new work readsopentrain_get_job_context_agent_guide. The Markdown is also the read-only resourceopentrain://jobs/{jobId}/operations/guide.opentrain_get_job_setup(MCP 0.15.0+) — the deterministic SHARED guided-setup packet: missing operating brief/typed workflow/required operating choices with canonical evidence, ordered questions, evidence-backed proposed defaults, validated canonical write previews, and the in-progresssetup.*dedupe view. While setup is incomplete every covered result'ssync.recommendationscarriesrecommendation.job_setup_incomplete, whose chain DRIVES the multi-agent flow in order: read the packet; inspectinProgress(stand down on a truncated view or a foreign ACTIVEsetup.*intent / OPEN proposal); declare your ownsetup.*intent viaopentrain_declare_job_context_intent(a DUPLICATE names the live winner — it does not transfer ownership, so the loser stands down). Prove ownership by comparing the intent's non-nullsessionIdwith this result's non-nullsync.session.sessionIdand matchingprincipalUserId; a visible winner ID is never enough. Only that same-durable-session winner presents the questions/drafts to the responsible human. Immediately before approved writes, re-read setup and prove the binding still holds; then use only the normal brief/policy tools. A null or mismatched session means establish a durable per-agent session or coordinate with the owner; verify, resolve your intent, hand off. A status of INDETERMINATE is fail-closed nonterminal evidence — follow the packet'sevidenceRecoveryread and retry; never prompt from it. Record an approved postponement as the component'sOPERATING_RULE.setup_deferral_*typed policy; once COMPLETE or DEFERRED, stop prompting — completion is shared across the employer team.- Every one of these tools advertises AND runtime-validates exact closed input/output schemas; typed-policy payloads are the three closed contract-v1 variants, never a generic object.
- MCP 0.11.0 automatically threads one private server-minted session credential
and the latest per-job sync token across every covered native or bridged tool
call. Every covered result includes
syncandsyncCoverage; inspect conflicts, recommendations, and next operations before acting. Raw signed credentials and tokens never enter model-visible tool results. opentrain_poll_job_context_syncprovides a bounded real-time wait.opentrain_declare_job_context_intent,opentrain_list_job_context_intents, andopentrain_resolve_job_context_intentcoordinate spontaneous work before it begins.opentrain_submit_job_context_proposal,opentrain_list_job_context_proposals,opentrain_review_job_context_proposal, andopentrain_withdraw_job_context_proposalrecord non-enforced alternatives when managers disagree. Review links a separately authorized canonical change and never executes one.opentrain_get_job_context_overlaysandopentrain_set_job_context_overlayseparate owner-controlled TEAM guidance, one manager's PERSONAL memory, and one connection's SESSION scratch. Overlay text is attributed and untrusted; it cannot alter readiness, gates, or policy.opentrain_send_managed_job_messagealways uses the exact synchronizedmessaging_management.messages.sendoperation and requires a fulljobOperationsGuardplus an 8-128-character idempotency key matching[A-Za-z0-9._:-]. It requires bothmessages:manageandmessages:write.opentrain_send_messageis generic and deliberately cannot accept a guard or advance shared context.- Initialize instructions teach this loop automatically. Capability recommendations are product discovery, not write authority: inspect evidence and show a zero-write proposal—such as a focused LMS retraining outline—before creating or assigning anything.
Account and discovery:
opentrain_auth_status— callsGET /api/public/v1/auth/me, returns the resolved token owner, access mode, and effective scopes. Full access keys expand live as new self-serve capabilities ship; the storage sentinel is never exposed.opentrain_capabilities— feature/scope map for the current token: which tool families are enabled for this account.opentrain_list_tokens/opentrain_revoke_token— manage the account's API tokens.
Adaptive job Task Checklists (job_checklists:read/write; default-off
agent surface; thirteen opentrain_job_checklists_* tools):
opentrain_job_checklists_list/_get/_capabilities— definitions, builder detail with CAS revisions, served operations and limits.opentrain_job_checklists_create/_manage/_publish/_reorder/_set_enabled— receipt-backed mutations: atomic complete-draft create, expectedDraftVersion-fenced saves and retire/restore, confirmed double-CAS publish reporting the applied impact and sweep counts, strict reorder, and the worker-visibility toggle (authoring keeps working while off).opentrain_job_checklists_validate/_resolve— no-write preflights running the EXACT publish rule set / the pure worker-runtime resolver.opentrain_job_checklists_versions/_submissions— immutable history and privacy-filtered submissions.opentrain_job_checklists_preview— stateless revision-exact browser preview link; the secret rides the returned URL fragment.
Job reviewer feedback (job_feedback:read/write; default-off
privacy-sensitive agent surface; twelve opentrain_job_feedback_* tools —
employer-only, subjects never read feedback through any agent surface):
opentrain_job_feedback_settings/_set_enabled— the per-job toggle (readable while off;confirm: truerequired in both directions). Every other feedback tool is a typed 409 while the toggle is off.opentrain_job_feedback_list/_get/_summary— list/search with authoritative CONCERN-lane status counts plusrecordedCountand assessment counts (DEV-3168 filters:assessment,lane—lane=RECORDEDcannot combine with a concrete status/severity), full detail with append-only event history, and server-computed aggregates including per-person rating distributions, latest anchored rating, and rated-n-of-m (never average, score, or rank these sparse ratings). Non-concern rows are the "Recorded" lane: stored severity MINOR / status OPEN are compatibility shadows — present them as "Recorded".opentrain_job_feedback_roster— closed canonical subject discovery (the id source for submit/link targeting).opentrain_job_feedback_submit/_triage/_link_subject— receipt-backed (in-transaction) submit (legacy severity+report shape, or the DEV-3168 balanced shape:assessmentwith optional anchored ratings; severity present ⇔ a concern is flagged), CAS-fenced triage (requiredexpectedUpdatedAt), and one-way legacy subject reconciliation.opentrain_job_feedback_access_list/_access_set/_access_bulk— reviewer-grant management; bulk is one all-or-nothing transaction.
Job People table (people_table:read/write; default-off people_table
agent surface; six opentrain_people_table_* tools plus the Agent notes tool
opentrain_people_agent_notes). Columns are addressed by id (country,
custom:<fieldId>) and people by jobPersonId; names are the public
"First L." (else Unnamed candidate) and selectable only: no search,
filter, sort or facet runs on a name. Contact, financial and compliance columns are redacted, and naming
one is refused like an unknown column (COLUMN_NOT_QUERYABLE); Project To-do
columns also need project_todos:read and Screening lms:read. Banned,
closed and non-visible candidates never appear:
opentrain_people_table_describe— every column with its exposure, capabilities and filter operators, the limits, views and defaults. Start here.opentrain_people_table_query—query(one keyset page: filter AST over column ids, up to fiv
