npm scorm-mcp-serverstdioMITupdated 14d ago
Turn self-contained HTML, a Claude Design .dc bundle or a mobile-learning platform content export (Excel activity templates + media) into a SCORM 2004 (or 1.2) package ready to import into any LMS β assets inlined for 100% offline, completion / progress / score tracking injected, ADL schemas bundled.
What can you do with SCORM Packager (HTML β SCORM 2004)?
scorm-mcp-server
Turn self-contained HTML, a Claude Design
.dcbundle or a mobile-learning platform content export (Excel activity templates + media) into a SCORM 2004 (or 1.2) package ready to import into any LMS β assets inlined for 100% offline, completion / progress / score tracking injected, ADL schemas bundled.

The bundled local harness (scorm-test-harness.html) playing a package: progress 0 β 100%, completion, and the live LMS API-call log (0 errors). Illustration.
An MCP server exposing three tools: scorm_package converts a finished HTML learning module into a .zip (PIF) any SCORM-compliant LMS can import, scorm_validate checks any existing SCORM zip (made by any tool) and explains exactly why an LMS would reject it, and scorm_selftest is a 1-second health check.
Principle: WRAP, don't rewrite. Your HTML is preserved; the tool only:
- Inlines every asset (CSS,
@import, fonts, JS, images,srcset, favicons) as data URIs β runs 100% offline. - Injects a small runtime that reports completion, progress (%) and time spent, with resume across sessions.
- Generates the manifest and bundles the 15 official ADL XSD schemas β the manifest is validated against them (real conformance, not just "well-formed").
β Status β validated on a real LMS
- 325/325 automated checks green: 23 converter Β· 15 runtime Β· 15 MCP Β· 1 schema conformance (
xmllint) Β· 6 security Β· 11 features Β· 13 auto-milestones Β· 21 V2 (bundle /.dc/ score) Β· 10 output-dir Β· 9 tracking-signal Β· 32 hardening Β· 29 SCORM 1.2 Β· 12 CLI/batch Β· 16 web UI Β· 44 mobile-learning migration Β· 35 package validation Β· 33 question-level interactions β plus 6 bonus strict-runtime checks (scorm-again). - SCORM Cloud (real LMS): imports cleanly (recognized as SCORM 2004 4th Ed., "manifest looks great"), and the dashboard reports completion = complete, success = passed, time tracked.
Input formats
Input (input_path or html) |
Handling |
|---|---|
A single self-contained .html (e.g. Claude Design "standalone HTML" export) |
assets inlined, runtime injected β v1 path |
A folder or .zip (multi-file module) |
whole tree preserved; entry HTML inlined; manifest lists every file |
A Claude Design .dc bundle (*.dc.html + support.js + _ds/) |
auto-detected; CDN libs (React/Babelβ¦) vendored offline via window.__resources (no source patch); runtime injected before support.js |
A mobile-learning platform content export (Excel activity templates + media/) |
auto-detected; an interactive HTML course is rebuilt from the templates β info / transition / flash cards, quiz questions, media codes ([media:β¦], [H1:β¦], [quote:β¦], !!), scored quizzes reporting cmi.score β then packaged. Course title derived from the template names; with --batch, a whole catalogue migrates in one run |
Pass a .dc bundle as its folder or .zip (not the lone .dc.html, which is inert without its siblings).
Scores & quizzes (optional)
Set mastery_score (0..1) to enable score-based success and add sequencing objectives to the manifest. Report the score from your content in one line β no SCORM knowledge required:
window.SCORM2004.score(8, 0, 10); // raw, min, max
window.dispatchEvent(new CustomEvent("scorm:score", { detail: { raw: 8, min: 0, max: 10 } }));
window.dispatchEvent(new CustomEvent("scorm:progress", { detail: 0.5 })); // 0..1
window.dispatchEvent(new CustomEvent("scorm:complete"));
The runtime maps these to cmi.score.*, sets success_status = passed/failed against mastery_score, and reports completion/progress. (dc:* event names are accepted as aliases.)
Question-level tracking (v2.3) β report each answer as a cmi.interactions record, so the LMS gradebook shows which questions were missed, not just the total:
window.SCORM2004.interaction({
id: "quiz1-q3", type: "choice",
description: "Which colour is the brand?",
learnerResponse: "Blue", correctResponse: "Red",
result: false, latencyMs: 12000,
});
// or, without touching the API:
window.dispatchEvent(new CustomEvent("scorm:interaction", { detail: { id: "q3", result: true } }));
Dialect-aware (2004 learner_response/timestamp vs 1.2 student_response/time, incorrect vs wrong) and best-effort by design: an LMS that refuses interaction writes gets a logged warning and the session carries on. Quizzes generated by the mobile-learning migration report their interactions automatically β one record per question, with the question text, the learner's answer, the expected answer and the latency.
SCORM 1.2, batch mode, CLI (v2.1)
SCORM 1.2 β pass scorm_version: "1.2" and you get a 1.2 manifest (validated
against the bundled 1.2 XSDs, with adlcp:masteryscore when mastery_score is
set). The injected runtime is adaptive: it speaks to whichever API the hosting
LMS exposes (API_1484_11 or API), maps the data model (single
lesson_status, 0-100 score, HH:MM:SS session time, 4096-char suspend data)
and never downgrades a passed status.
Batch β batch: true treats input_path as a directory of courses (each
sub-directory, .zip or .html = one course). One package per course, one
consolidated batch-report.json, and a broken course never sinks the others.
CLI β no MCP client required:
npx -y scorm-mcp-server ui # local drag & drop web UI
npx -y scorm-mcp-server pack course.html --title "My course"
npx -y scorm-mcp-server pack ./courses --batch --scorm-version 1.2
npx -y scorm-mcp-server validate pkg.zip # conformance-check an existing package
npx -y scorm-mcp-server selftest # 1-second health check
Web UI β ui opens a localhost page: drop an .html or .zip, pick the SCORM
edition and an optional pass mark, download the package. Runs entirely on your
machine; nothing is uploaded anywhere.
Library β buildPackage() is a public API for pipelines and SaaS backends:
import { buildPackage } from "scorm-mcp-server";
const r = await buildPackage({ html, title: "My course", scormVersion: "1.2", masteryScore: 0.6 });
// r.zip (Buffer) Β· r.fileName Β· r.warnings Β· r.milestoneIds β¦
Diagnostic β the scorm_selftest MCP tool packages a constant built-in HTML
and reports version, duration and output path: it separates "server broken"
from "input problem" in one second.
Validate any SCORM package (v2.3)
"Why does my LMS reject this zip?" β scorm_validate answers it for any SCORM package, not only those produced here, and the input is never modified:
npx -y scorm-mcp-server validate course.zip # human-readable report
npx -y scorm-mcp-server validate course.zip --json # machine-readable
Checks: zip readability, imsmanifest.xml at the ROOT (detects the classic "zipped the folder instead of its contents" mistake and says how to fix it), well-formed manifest, SCORM edition detection (2004/1.2), launchable organization/item/resource chain, launch file and every <file href> present in the archive (case-only mismatches flagged β they work on Windows and fail on Linux LMS servers), and full XSD validation against the official ADL schemas β using the package's own XSDs first and falling back to the embedded copies, so packages that ship without schemas validate too. Exit code 0/1 for CI pipelines; also exposed as the scorm_validate MCP tool and the validatePackage() library API.
Install
Option 0 β try it online, no install
https://scormpackager.vercel.app β drop a course, pick the SCORM edition, download the package. Files are processed in memory and never stored, but they do travel to a server; for real work use the local options below, where nothing leaves your machine (and there is no 4 MB limit).
Option A β one-click (recommended)
Download scorm-mcp-server-x.y.z.mcpb from the Releases, then in Claude Desktop β Settings β Extensions, drag-drop the .mcpb, pick an output folder, and enable it.
Option B β npm (any MCP client)
No install step: add this to your client's MCP config (~/Library/Application Support/Claude/claude_desktop_config.json for Claude Desktop):
{
"mcpServers": {
"scorm": {
"command": "npx",
"args": ["-y", "scorm-mcp-server"],
"env": { "SCORM_OUTPUT_DIR": "/ABSOLUTE/PATH/scorm-packages" }
}
}
}
Registry name: io.github.giacomomaria81/scorm-mcp-server (MCP registry).
Option C β from source (developer)
git clone <this-repo> && cd scorm-mcp-server
npm install # dist/ is prebuilt; npm run build is optional
Then point the config at node /ABSOLUTE/PATH/scorm-mcp-server/dist/index.js.
Restart Claude. The scorm_package tool is now available.
Usage
In a conversation: build your module with Claude Design, then say "package this module as SCORM." Claude calls scorm_package and returns the path to the .zip.
Progress & completion β it just works
You don't have to prepare anything: if your HTML declares no milestone, the packager auto-generates them from the document structure (sections β articles β headings, capped at 8, trigger view). Plain HTML gets meaningful progress out of the box. Disable with auto_milestones: false. Want success_status = passed on completion without touching the HTML? Pass success_on_completion: true.
Declarative milestones (recommended for fine control)
Mark the meaningful steps directly in your HTML β explicit milestones always take precedence over auto-generation. The runtime computes progress_measure = milestones_reached / total, and sets completion_status = "completed" once all are reached.
| Attribute | Effect |
|---|---|
data-jalon="unique-id" |
declares a milestone |
data-trigger="view" |
reached when scrolled into view (default) |
data-trigger="click" |
reached on click |
data-trigger="ended" |
reached when a video/audio ends |
<section data-jalon="intro" data-trigger="view">β¦</section>
<button data-jalon="read-pitch" data-trigger="click">I read it</button>
<video data-jalon="demo" data-trigger="ended">β¦</video>
Recommended: 4β8 milestones per micro-module. Resume is automatic (cmi.suspend_data + cmi.location); progress never regresses.
Programmatic milestones β window.SCORM2004.reach("quiz-passed") works even if the id has no data-jalon element: unknown ids are declared on the fly and count in the total. To register one before it's reached (accurate denominator), use window.SCORM2004.declare("quiz-passed") early. Both survive resume.
Success status (opt-in) β add data-scorm-success="on-completion" on any element (e.g. <body>) and the runtime also sets cmi.success_status="passed" when the module completes. Without it, success_status is never written.
Language β the tool's language (BCP-47, default fr-FR) is applied as <html lang="β¦"> when the source HTML doesn't declare one.
Security β asset references are confined to the module folder: ../ or absolute paths outside it are never inlined (a warning is emitted instead).
Test it without an LMS account
Open scorm-test-harness.html via a tiny local server and drop a generated .zip into it:
python3 -m http.server 8000 # then open http://localhost:8000/scorm-test-harness.html
You'll see live progress %, completion, and the full log of LMS API calls (0 errors expected).
Build & test
npm install
npm run build # tsc -> dist/
npm test # 102 checks: converter + runtime + mcp + schema + security + v2 (xmllint required)
# bonus: validate against a strict independent SCORM 2004 runtime
npm i -D scorm-again && node test/scorm-again.test.mjs
Requirements: Node β₯ 20, and xmllint (libxml2-utils) for the schema test.
Project structure
src/ index.ts (MCP server + CLI) Β· converter.ts (inlining + manifest + zip) Β· runtime.ts (injected SCORM runtime) Β· validate.ts (package conformance checker) Β· tom.ts (mobile-learning migration) Β· ui.ts (local web UI)
dist/ compiled output (shipped)
schemas/ 15 ADL XSD (SCORM 2004 4th Ed.) + schemas12/ (4 XSD SCORM 1.2), bundled into every package
test/ 17 suites (converter / runtime / mcp / schema / validation / interactions / migrationβ¦) + fixtures
ARCHITECTURE.md design decisions, data flow, testing strategy
scorm-test-harness.html local browser SCORM player (fake LMS, no account)
manifest.json MCPB manifest (for building the .mcpb desktop extension)
Privacy Policy
This extension runs entirely locally: no data collection, no telemetry, no third parties. The only network activity is downloading assets that your own HTML references, to embed them into the offline package. Full policy: PRIVACY.md.
License
Install
Add SCORM Packager (HTML β SCORM 2004) to your client. Pick the one you use.
claude mcp add scorm-mcp-server -- npx -y scorm-mcp-servercodex mcp add scorm-mcp-server -- npx -y scorm-mcp-serveramp mcp add scorm-mcp-server -- npx -y scorm-mcp-server{
"mcpServers": {
"scorm-mcp-server": {
"command": "npx",
"args": [
"-y",
"scorm-mcp-server"
]
}
}
}Add to `claude_desktop_config.json`, then restart Claude Desktop.
{
"mcpServers": {
"scorm-mcp-server": {
"command": "npx",
"args": [
"-y",
"scorm-mcp-server"
]
}
}
}Add to `~/.cursor/mcp.json`, or `.cursor/mcp.json` for a single project.
code --add-mcp '{"name":"scorm-mcp-server","command":"npx","args":["-y","scorm-mcp-server"]}'Or add the block manually to `.vscode/mcp.json` under `servers`.
{
"mcpServers": {
"scorm-mcp-server": {
"command": "npx",
"args": [
"-y",
"scorm-mcp-server"
]
}
}
}Add to `~/.codeium/windsurf/mcp_config.json`.
{
"mcpServers": {
"scorm-mcp-server": {
"command": "npx",
"args": [
"-y",
"scorm-mcp-server"
]
}
}
}Add to `cline_mcp_settings.json` via the MCP Servers panel.
{
"mcpServers": {
"scorm-mcp-server": {
"command": "npx",
"args": [
"-y",
"scorm-mcp-server"
]
}
}
}Add to `~/.gemini/settings.json`.
{
"mcpServers": {
"scorm-mcp-server": {
"type": "local",
"command": "npx",
"args": [
"-y",
"scorm-mcp-server"
],
"tools": [
"*"
]
}
}
}Add to `~/.copilot/mcp-config.json`, or run `/mcp add` inside the CLI.
{
"context_servers": {
"scorm-mcp-server": {
"command": {
"path": "npx",
"args": [
"-y",
"scorm-mcp-server"
]
}
}
}
}Add to your Zed `settings.json`.
npx -y scorm-mcp-serverRun `goose configure`, choose **Add Extension β Command-line Extension**, and paste this command.
Score
39 / 100
Incomplete
- Documentation25/25
- Maintenance25/25
- Trust13/20
- Capability0/15
- Install experience12/15
- Documents what it does and how to connect
- Has a resolvable package or endpoint
- Exposes at least one tool, prompt or resource
- README has substantive content
- Includes a code example
- Documents its configuration
- Mentions credentials or security posture
- Last commit 6 days ago
- Has a release history
- Repository is not archived
- Licensed MIT
- Namespace verified in the official MCP registry
- Claimed by its owner
- Published under an organisation
- 0 tool(s) documented
- Provides prompt templates
- Provides resources
- 12 documented install method(s)
- Published to a package registry
- Offers a hosted endpoint β no local install
Version history
| Versions | Published |
|---|---|
| 2.3.0Latest | Aug 25, 2026 |
| 2.2.1 | Aug 6, 2026 |
| 2.2.0 | Aug 2, 2026 |
| 2.1.0 | Aug 1, 2026 |
| 2.0.1 | Jul 25, 2026 |
| 2.0.0 | Jul 25, 2026 |