Peerfold logo

Peerfold

0

Build courses, manage enrollments and publish Peerfold Sites pages from Cursor through the Peerfold MCP server.

3 rules

Add to Cursor
# Authoring on Peerfold Apply these whenever you create or change course content through the Peerfold MCP server or the REST API. They are the four contracts an integration gets wrong. ## Never guess a block shape A lesson body is an ordered array of blocks. A block is `{ type, props }`, plus `children` on the container types. Ask for the shape before you write one: 1. `list_block_types` lists every type the registry allows, with its label, category, whether it nests children, and its prop names. 2. `get_block_schema` returns one type's JSON Schema, its default props, and a pasteable example node. 3. `validate_blocks` is a free dry run that returns the editor's exact per-block errors. Keep the `normalized` array it hands back so block ids stay stable. 4. `update_lesson_blocks` is the write. The same registry drives the editor, the renderer, SCORM export and these tools, so content written this way renders the same as content typed by hand. Clients that surface MCP resources can read the same reference at `peerfold://block-schema-reference.json`. ## Read before every whole-document write Several tools replace an entire document. Read the current state first, or you delete whatever you did not resend. | Replaces the whole thing | Read it with | | --- | --- | | `update_lesson_blocks` | `get_lesson_blocks` | | `set_exam_questions` | `get_exam` | | `set_access_rules` | `get_course` | | `set_course_ceus` | `get_course_ceus` | | `set_homepage` | `get_homepage` (plus `get_homepage_schema`) | | `set_portal_menu` | `get_portal_menu` | | `set_portal_footer` | `get_portal_footer` | | `set_course_landing` and `set_program_landing` (the `sections` document) | `get_course` or `get_program`, plus `get_program_landing_schema` | `set_course_settings` is the exception. It is a merge patch, field by field. Send a value to change it, omit it to keep it, send `null` to clear it. `set_course_landing` is split: its `enabled` flag merges and its `sections` document replaces. Each argument is optional, so neither can undo the other by accident. Every tool's arguments are a strict object. A misspelled or unsupported key is refused by name. Fix the name; do not retry with more fields. ## Exam rules and exam questions are two different calls `set_course_settings { exam }` carries the rules: passing score, attempts, whether results are shown. The questions are a separate document. Read them with `get_exam` and write them with `set_exam_questions`, which replaces the whole list. Omit a question's `id` on first write and a stable id is minted. Send an id you read from `get_exam` to edit that question in place, because a learner's in-flight attempt keys on it. ## Publishing is explicit, and it is a revision Nothing publishes as a side effect. Run `course_health` first. `warnings` and `issues` are advisory; `blockers` is the only list that predicts a failed publish. Then call `publish_course` on purpose, and only after the user has said yes in this conversation. If it finds structural issues it refuses once and names them. Tell the user what they are before you re-call with `confirm_issues: true`. The call returns the revision number, the live learner URL and the admin review URL. `preview_course` gives you a single-use link into the published revision as the reserved preview member. Published courses are immutable revisions. Learners keep reading the previously published revision until a new one lands, so a half-finished draft edit is never visible to anyone. Every write is audit-logged with `actorType: "mcp"` and syncs to the connected CRM through the standard outbox. An API write and a UI edit look the same downstream.
Add to Cursor
Add to Cursor