* Update documentation for ClassroomIO: change Fumadocs to Blume, revise MDX format conventions, and clarify sidebar navigation requirements. * docs: update README and scripts for improved preview and error handling * docs: update Discord link in configuration and documentation * docs: add token-auth route and update documentation formatting * Fix formatting in auto-comment-issues.yml * Fix JSON syntax by adding a comma * fix(docs): declare Blume's Astro build deps so Cloudflare build resolves them blume build generates an Astro project under apps/docs/.blume/ that imports astro, @astrojs/mdx, @tailwindcss/vite, tailwindcss, @tailwindcss/typography, @shikijs/twoslash and @scalar/astro. Under pnpm's isolated node_modules these are nested inside blume and not resolvable from the docs app, so a clean --frozen-lockfile build (Cloudflare) fails at 'Cannot find module astro/config'. Declare them directly in @cio/docs, pinned to blume's resolved versions. * refactor(docs): update API reference paths and documentation for clarity * fix: change platofrm url to docs home page * Refactor documentation for self-hosting ClassroomIO - Removed the Supabase Cloud setup guide as it is no longer needed. - Updated the Enterprise SSO documentation to include a reference link for SSO & licensing. - Added new documentation for Content Security Policy (CSP) configuration. - Created a new section for configuring SMTP for email notifications. - Introduced a comprehensive configuration index for self-hosted ClassroomIO, detailing environment variables and their usage. - Added documentation for optional integrations including Google OAuth, OpenAI, and Unsplash. - Documented the generation and usage of required secrets for ClassroomIO. - Created a section for SSO & licensing, detailing the requirements for Enterprise features. - Added object storage configuration documentation, covering both bundled MinIO and external S3-compatible services. - Documented versioning and upgrade processes for ClassroomIO. - Updated the Coolify and Docker self-hosting guides to streamline configuration references and upgrade instructions. - Enhanced the Railway self-hosting guide with links to relevant configuration sections. - Updated token authentication documentation to reference SSO & licensing. * Add comprehensive guides for ClassroomIO features and functionalities - Introduced a new guide for the Student Dashboard, detailing navigation and features available to students. - Added a guide on using Tags for organizing and filtering courses within ClassroomIO. - Created a guide on how to take attendance in courses, including marking attendance and related functionalities. - Developed a Terminology guide to clarify key terms used throughout ClassroomIO. - Implemented a Token Auth guide for signing users into ClassroomIO from external applications using JWT. - Added instructions for using math in the editor with LaTeX support. - Created a guide for customizing the welcome email sent to students upon enrollment in courses. - Added a guide explaining what ClassroomIO is and its key features. - Updated the home documentation to provide a clearer overview of ClassroomIO and its resources. - Enhanced self-hosted configuration documentation with a new guide for deploying ClassroomIO on Dokploy. - Updated links in the self-hosted configuration documentation for better navigation. - Added new images to support the Dokploy deployment guide. - Updated asset packaging script to handle redirects for the new guide structure. - Fixed footer link to point to the correct Getting Started guide. * chore: uprage version * feat(docs): add DigitalOcean deployment guide and flatten guides structure - Add a guide for deploying ClassroomIO on DigitalOcean using Docker Compose and Caddy for automatic HTTPS. - List DigitalOcean as a deployment option in the self-hosting index. - Move guides out of content/docs/guides into content/docs (student-dashboard, tags, terminology, token-auth, what-is-classroomio, audience, cohorts, community, course, enterprise-sso, mcp, organization, quickstart/*). - Rename home.mdx to index.mdx. - Update package-assets script to emit redirects for the old guides paths. --------- Co-authored-by: Rotimi Best <[email protected]>
481 lines
12 KiB
Plaintext
481 lines
12 KiB
Plaintext
---
|
|
title: MCP
|
|
description: Connect Claude Code, Codex, Cursor, OpenCode, and other MCP clients to ClassroomIO for draft-based course authoring.
|
|
---
|
|
|
|
`@classroomio/mcp` is a thin stdio MCP server for ClassroomIO course authoring.
|
|
|
|
It does not parse PDFs or generate course structures itself. The agent does that work. The MCP
|
|
server exposes tools, validates tool input, and forwards authenticated requests to the
|
|
ClassroomIO API.
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
Teacher / Admin
|
|
|
|
|
v
|
|
Claude Code / Codex / Cursor / OpenCode / other MCP client
|
|
|
|
|
| 1. Reads prompt, PDF, or existing course goal
|
|
| 2. Produces or edits normalized course JSON
|
|
v
|
|
@classroomio/mcp (stdio)
|
|
|
|
|
| 3. Sends authenticated tool calls
|
|
| Authorization: Bearer <cio_mcp_...>
|
|
v
|
|
ClassroomIO API
|
|
|
|
|
| 4. Validates payloads
|
|
| 5. Resolves the organization from the key
|
|
| 6. Creates drafts or applies changes to a course
|
|
v
|
|
ClassroomIO DB
|
|
```
|
|
|
|
## Core Principles
|
|
|
|
1. The agent owns reasoning.
|
|
2. The MCP package owns transport and input validation.
|
|
3. ClassroomIO API remains the trust boundary for auth, validation, and persistence.
|
|
4. Draft creation and publish are separate operations.
|
|
5. Updating an existing course is done through a seeded draft, not blind writes to the live
|
|
course.
|
|
|
|
## Authentication
|
|
|
|
Generate an org-scoped MCP key from `Automation -> MCP` in the ClassroomIO dashboard.
|
|
|
|
The MCP process sends that key as a bearer token on every request.
|
|
|
|
ClassroomIO API:
|
|
|
|
1. hashes and verifies the key
|
|
2. resolves the owning organization
|
|
3. checks the key scopes
|
|
4. executes the requested action
|
|
|
|
The MCP package never decides permissions.
|
|
|
|
## Required Environment Variables
|
|
|
|
- `CLASSROOMIO_API_URL`
|
|
- `CLASSROOMIO_API_KEY`
|
|
- `CLASSROOMIO_USER_AGENT` optional
|
|
|
|
## Run the MCP Server
|
|
|
|
Published package:
|
|
|
|
```bash
|
|
CLASSROOMIO_API_URL=https://api.classroomio.com \
|
|
CLASSROOMIO_API_KEY=<cio_mcp_key> \
|
|
npx -y @classroomio/mcp
|
|
```
|
|
|
|
From the monorepo:
|
|
|
|
```bash
|
|
pnpm build --filter=@classroomio/mcp
|
|
CLASSROOMIO_API_URL=http://localhost:3081 \
|
|
CLASSROOMIO_API_KEY=<cio_mcp_key> \
|
|
node packages/mcp/dist/index.js
|
|
```
|
|
|
|
## Client Setup
|
|
|
|
### Claude Code
|
|
|
|
```bash
|
|
claude mcp add-json classroomio '{
|
|
"command": "npx",
|
|
"args": ["-y", "@classroomio/mcp"],
|
|
"env": {
|
|
"CLASSROOMIO_API_URL": "https://api.classroomio.com",
|
|
"CLASSROOMIO_API_KEY": "<cio_mcp_key>"
|
|
}
|
|
}'
|
|
```
|
|
|
|
### Codex
|
|
|
|
```bash
|
|
codex mcp add classroomio \
|
|
--env CLASSROOMIO_API_URL=https://api.classroomio.com \
|
|
--env CLASSROOMIO_API_KEY=<cio_mcp_key> \
|
|
-- npx -y @classroomio/mcp
|
|
```
|
|
|
|
### OpenCode
|
|
|
|
```json
|
|
{
|
|
"$schema": "https://opencode.ai/config.json",
|
|
"mcp": {
|
|
"classroomio": {
|
|
"type": "local",
|
|
"command": ["npx", "-y", "@classroomio/mcp"],
|
|
"enabled": true,
|
|
"environment": {
|
|
"CLASSROOMIO_API_URL": "https://api.classroomio.com",
|
|
"CLASSROOMIO_API_KEY": "<cio_mcp_key>"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Cursor
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"classroomio": {
|
|
"command": "npx",
|
|
"args": ["-y", "@classroomio/mcp"],
|
|
"env": {
|
|
"CLASSROOMIO_API_URL": "https://api.classroomio.com",
|
|
"CLASSROOMIO_API_KEY": "<cio_mcp_key>"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Tool Surface
|
|
|
|
Current tools:
|
|
|
|
- `list_org_courses`
|
|
- `get_course_structure`
|
|
- `reorder_course_content`
|
|
- `update_course_landing_page`
|
|
- `create_course_draft`
|
|
- `create_course_draft_from_course`
|
|
- `get_course_draft`
|
|
- `update_course_draft`
|
|
- `publish_course_draft`
|
|
- `publish_course_draft_to_existing_course`
|
|
- `tag_course_draft`
|
|
- `tag_courses`
|
|
- `list_course_exercises`
|
|
- `get_course_exercise`
|
|
- `create_course_exercise`
|
|
- `create_course_exercise_from_template`
|
|
- `update_course_exercise`
|
|
|
|
## Draft Model
|
|
|
|
A draft is a saved, structured course proposal. It is not the live course.
|
|
|
|
Draft payload shape:
|
|
|
|
```text
|
|
draft
|
|
course
|
|
tags[]
|
|
sections[]
|
|
lessons[]
|
|
lessonLanguages[]
|
|
warnings[]
|
|
sourceReferences[] optional
|
|
exercises[] optional
|
|
```
|
|
|
|
Drafts support:
|
|
|
|
- review before publish
|
|
- iterative edits from the agent
|
|
- safer updates to existing courses
|
|
- auditability of AI-generated structure
|
|
|
|
Lesson authoring rule:
|
|
|
|
- `lessonLanguages[].content` should contain only the lesson body HTML
|
|
- do not include the lesson title
|
|
- do not use `h1` or `h2` in lesson content
|
|
- start headings at `h3`
|
|
- ClassroomIO already renders the lesson title in the course UI
|
|
|
|
## After Publish
|
|
|
|
Once a draft has been published, the live course becomes the safer source of truth.
|
|
|
|
Recommended agent rule:
|
|
|
|
- if the draft is still `DRAFT`, continue editing that draft
|
|
- if the draft is `PUBLISHED`, do not keep reusing it for major follow-up edits
|
|
- instead, read the live course and create a fresh draft from that course
|
|
|
|
Recommended post-publish sequence:
|
|
|
|
1. `get_course_structure`
|
|
2. `create_course_draft_from_course`
|
|
3. `update_course_draft`
|
|
4. `publish_course_draft_to_existing_course`
|
|
|
|
Why:
|
|
|
|
- teachers may edit the live course in the UI after publish
|
|
- another agent session may have changed the course
|
|
- reusing an old published draft can overwrite newer live changes
|
|
|
|
For exercises on an already-published course, prefer the direct exercise tools instead of creating a whole new draft when the user only wants to add or revise exercises.
|
|
|
|
## User Flows
|
|
|
|
### Flow 1: Create a new course from a prompt
|
|
|
|
Typical flow:
|
|
|
|
1. Agent plans the course.
|
|
2. Agent calls `create_course_draft`.
|
|
3. User asks for revisions.
|
|
4. Agent calls `update_course_draft`.
|
|
5. User approves.
|
|
6. Agent calls `publish_course_draft`.
|
|
|
|
Publish returns:
|
|
|
|
- `courseId`
|
|
- `courseUrl`
|
|
- `bannerImageUrl` when a banner was explicitly provided or generated
|
|
- `tagNames`
|
|
|
|
`publish_course_draft` can also:
|
|
|
|
- use an explicit `bannerImageUrl`
|
|
- generate a random Unsplash-based banner from the course title or a custom query
|
|
|
|
### Flow 2: Update a landing page with AI-generated copy and media
|
|
|
|
User says:
|
|
|
|
```text
|
|
Rewrite this course landing page to feel more premium, generate a new cover image, and add three believable reviews.
|
|
```
|
|
|
|
Expected tool sequence:
|
|
|
|
1. Agent calls `list_org_courses` if it needs to resolve the course ID by name first.
|
|
2. Agent calls `update_course_landing_page`.
|
|
|
|
What the landing-page tool can update:
|
|
|
|
- title
|
|
- short description
|
|
- overview
|
|
- requirements
|
|
- goals
|
|
- pricing fields
|
|
- instructor section
|
|
- reviews
|
|
- landing page image
|
|
|
|
The tool can either:
|
|
|
|
- use an explicit `imageUrl`
|
|
- or generate a random Unsplash-based image with `generateImage` and `imageQuery`
|
|
|
|
### Flow 3: Create a draft from a PDF
|
|
|
|
User says:
|
|
|
|
```text
|
|
I have my course in a PDF. Extract it and turn it into a ClassroomIO course draft.
|
|
```
|
|
|
|
Expected tool sequence:
|
|
|
|
1. Agent reads the PDF itself.
|
|
2. Agent restructures the content into normalized JSON.
|
|
3. Agent calls `create_course_draft`.
|
|
4. User reviews the draft.
|
|
5. Agent calls `update_course_draft` if needed.
|
|
6. User approves.
|
|
7. Agent calls `publish_course_draft`.
|
|
|
|
Important:
|
|
|
|
- the PDF does not need to be uploaded to MCP
|
|
- the MCP package only receives structured JSON
|
|
|
|
### Flow 4: Tag a draft before publish
|
|
|
|
User says:
|
|
|
|
```text
|
|
Add tags for algebra, beginner, and exponential growth to this draft.
|
|
```
|
|
|
|
Expected tool sequence:
|
|
|
|
1. Agent calls `tag_course_draft`.
|
|
2. User reviews the updated draft tags.
|
|
3. Agent later calls `publish_course_draft`.
|
|
|
|
Result:
|
|
|
|
- the draft stores tag names
|
|
- publish ensures the tags exist in ClassroomIO
|
|
- publish assigns those tags to the live course
|
|
|
|
### Flow 5: Update an existing course safely
|
|
|
|
User says:
|
|
|
|
```text
|
|
Take my existing Algebra course, reorganize it, and rewrite the lesson content for a beginner audience.
|
|
```
|
|
|
|
When the course already exists, use the live course as the source of truth.
|
|
|
|
Expected tool sequence:
|
|
|
|
1. `list_org_courses` if the agent needs to resolve the course ID by name
|
|
2. Agent calls `get_course_structure` with the existing `courseId`.
|
|
3. Agent optionally calls `create_course_draft_from_course` to persist a seeded draft.
|
|
4. Agent updates the draft with the new structure and content using `update_course_draft`.
|
|
5. User reviews the changes.
|
|
6. Agent calls `publish_course_draft_to_existing_course`.
|
|
|
|
What this publish does today:
|
|
|
|
- updates the existing course title, description, type, and metadata
|
|
- can set a generated course cover from Unsplash
|
|
- returns the public `courseUrl`
|
|
- updates existing sections when the draft keeps their IDs
|
|
- updates existing lessons when the draft keeps their IDs
|
|
- creates new sections and lessons for draft items without matching live IDs
|
|
- upserts lesson language content
|
|
- merges draft tags into the existing course
|
|
|
|
### Flow 6: Reorder live course content
|
|
|
|
User says:
|
|
|
|
```text
|
|
Move the quiz before lesson 2 and put the recap lesson into the last section.
|
|
```
|
|
|
|
Use `reorder_course_content` when the live course only needs structural moves:
|
|
|
|
- reorder sections
|
|
- reorder lessons or exercises within a section
|
|
- move lessons or exercises between sections
|
|
|
|
This is the fast path for live structure edits and avoids creating a draft when lesson content is not changing.
|
|
|
|
Expected tool sequence:
|
|
|
|
1. Agent calls `reorder_course_content`.
|
|
|
|
Use this direct path when the live course only needs section ordering or lesson or exercise moves between sections.
|
|
It avoids the full draft round-trip for simple structural changes.
|
|
|
|
### Flow 7: Add exercises to a live course
|
|
|
|
User says:
|
|
|
|
```text
|
|
Add a 5-question multiple-choice exercise to lesson 3.
|
|
```
|
|
|
|
Expected tool sequence:
|
|
|
|
1. Agent calls `list_course_exercises` if it needs current context.
|
|
2. Agent calls `create_course_exercise` for a brand new exercise.
|
|
3. Agent calls `update_course_exercise` for later revisions.
|
|
|
|
Use this direct path when the course is already live and the change is exercise-specific.
|
|
|
|
What it does not do today:
|
|
|
|
- automatically delete sections or lessons that are absent from the draft
|
|
- automatically delete lesson locales that are absent from the draft
|
|
|
|
That behavior is intentional. The current update path is non-destructive by default.
|
|
|
|
## How Existing-Course Updates Work
|
|
|
|
When a draft is seeded from a live course:
|
|
|
|
- section `externalId` values are the real section IDs
|
|
- lesson `externalId` values are the real lesson IDs
|
|
|
|
As long as the agent preserves those IDs while editing the draft, publish-to-existing-course can map draft items back to the live records and update them safely.
|
|
|
|
If the agent adds a brand new section or lesson, it should assign a new synthetic `externalId`. ClassroomIO will create that record on publish.
|
|
|
|
## Input Contract Notes
|
|
|
|
For large updates, the agent should:
|
|
|
|
1. call `get_course_structure`
|
|
2. keep existing `externalId` values for records it wants to update
|
|
3. only generate new `externalId` values for new records
|
|
4. avoid deleting records from the draft unless the user explicitly wants omitted content to remain untouched
|
|
|
|
Publish input also supports:
|
|
|
|
- `bannerImageUrl`: use this exact course cover
|
|
- `bannerImageQuery`: search Unsplash with this query
|
|
- `generateBannerImage`: fetch a random Unsplash image using the course title or query
|
|
|
|
Tagging tools use:
|
|
|
|
- `tagNames`: human-readable tag names, not tag IDs
|
|
- `mode: "merge" | "replace"`
|
|
- `groupName` optional, defaults to `Automation`
|
|
|
|
The API creates missing tags automatically when needed.
|
|
|
|
Exercise tools use the live course directly:
|
|
|
|
- `list_course_exercises`
|
|
- `get_course_exercise`
|
|
- `create_course_exercise`
|
|
- `create_course_exercise_from_template`
|
|
- `update_course_exercise`
|
|
|
|
Supported `questionTypeId` values for exercise payloads:
|
|
|
|
- `1` `RADIO` - Single answer
|
|
- `2` `CHECKBOX` - Multiple answers
|
|
- `3` `TEXTAREA` - Paragraph
|
|
- `4` `TRUE_FALSE` - True/False
|
|
- `5` `SHORT_ANSWER` - Short answer
|
|
- `6` `NUMERIC` - Numeric answer
|
|
- `7` `FILL_BLANK` - Fill in the blank
|
|
- `8` `FILE_UPLOAD` - File upload
|
|
- `9` `MATCHING` - Matching
|
|
- `10` `ORDERING` - Ordering
|
|
- `11` `HOTSPOT` - Hotspot
|
|
- `12` `LINK` - Links
|
|
|
|
## Operational Notes
|
|
|
|
- `create_course_draft_from_course` may add warnings if a live course uses legacy lesson notes instead of localized lesson content
|
|
- if a course has ungrouped lessons, the seeded draft may add a synthetic `Ungrouped` section so the structure stays valid
|
|
- published drafts are treated as finalized snapshots
|
|
|
|
## Recommended Agent Behavior
|
|
|
|
For small edits, an agent can still read the course structure and modify only the affected items in the draft.
|
|
|
|
For broad revisions, prefer this sequence:
|
|
|
|
1. `get_course_structure`
|
|
2. `create_course_draft_from_course`
|
|
3. `update_course_draft`
|
|
4. `publish_course_draft_to_existing_course`
|
|
|
|
That keeps major AI-assisted edits reviewable and explicit.
|
|
|
|
:::note[Operational Rule]
|
|
Keep published drafts for history and auditability. Do not treat omission from a draft as an
|
|
instruction to delete live sections or lessons. Destructive changes should only happen through
|
|
explicit user intent.
|
|
:::
|