certifico-mark
v0.2.0
Published
MCP server (stdio) for the Certifico assessment marking API
Readme
certifico-mark
MCP server that drives the Certifico assessment marking API from Claude Code / Claude Cowork. It runs in two modes:
- Local (stdio, default): runs on your machine via
npx. Authenticate via a device-code flow, point it at a folder of assessment files, spend credits through the existing API, and get marked result PDFs downloaded locally. - Remote (Streamable HTTP): a hosted Docker service at
https://mcp.certifico.com.au/mcp. Stateless: every request must carry your Certifico access token as a bearer header; nothing is stored server-side.
Everything also stays visible in the Certifico web dashboard, because the MCP uses the exact same API as the frontend.
Local (stdio) - default
claude mcp add certifico-mark -- npx -y certifico-markInstall in Claude Desktop
For a point-and-click install (no terminal needed): download the .mcpb extension from certifico.com.au/claude, then double-click the downloaded file (or drag it into Claude Desktop > Settings > Extensions) to install it. Open a chat and ask it to sign you in: the login tool opens the approval page in your browser with the code already filled in, and sign-in completes by itself as soon as you press Confirm.
Remote (Streamable HTTP)
claude mcp add --transport http certifico-mark https://mcp.certifico.com.au/mcpEvery request needs Authorization: Bearer <certifico access token> (configure it as a header in your MCP client). Without a valid header the server answers 401 with instructions for the device flow. In HTTP mode:
login/login_complete/logout/whoamiare not exposed: auth comes entirely from the header.mark_folderanddownload_results(which need your local disk) are replaced bymark_files(upload files as base64, same 200-file / 50 MB caps) andget_download_links(authenticated per-assessment PDF URLs + the batch ZIP URL).- Tokens are never auto-refreshed and never stored on the server. When your access token expires, the API's 401 is surfaced to you; obtain a fresh token via the device flow.
Running the remote server
certifico-mark serve --port 8080 # or: MCP_TRANSPORT=http PORT=8080 certifico-markEndpoints: POST /mcp (MCP Streamable HTTP), GET /healthz → ok.
Docker (image built from the included Dockerfile), joining the vetass-api production network:
services:
certifico-mark-mcp:
build: ./certifico-mark
restart: unless-stopped
environment:
CERTIFICO_API_URL: http://api:3000/api
networks:
- production-api-network
networks:
production-api-network:
external: trueThen expose port 8080 as https://mcp.certifico.com.au via your TLS reverse proxy.
Security notes
- Auth is a per-request bearer token; the server keeps no credential files, refresh tokens, sessions, or any cross-request state. A fresh MCP server instance is built per request around that request's token, so users cannot leak into each other.
- Uploaded files are streamed straight to the Certifico API as a multipart batch; nothing is written to the service's disk.
Configuration
| Env var | Default | Description |
|---|---|---|
| CERTIFICO_API_URL | https://api.certifico.com.au/api | Base URL of the Certifico API. Defaults to production; override for the dev environment (https://dev.api.certifico.com.au/api) or a local stack. |
Credentials are stored at ~/.certifico/mark/credentials.json (mode 0600): { apiUrl, accessToken, refreshToken, email }. Tokens refresh automatically; logout deletes the file.
Privacy Policy
Full policy: certifico.com.au/privacy.
Student files are uploaded to Certifico only when a mark tool (mark_folder or mark_files) is called; nothing is uploaded before then. The refresh token that keeps you signed in is stored locally at ~/.certifico/mark/credentials.json and is never sent anywhere except the Certifico API. This MCP server collects no analytics and reports no telemetry.
Tools
| Tool | Purpose |
|---|---|
| login | Starts the device flow: opens the approval page in the default browser (disable with the "Open the sign-in page automatically" setting) and returns the verification URL, user code and a deviceCode. |
| login_complete | Call immediately after login: waits up to ~45s for the browser approval, then saves tokens. If it reports "still pending", call it again with the same deviceCode - no need for the teacher to confirm anything. |
| whoami | Shows the signed-in email and API URL. |
| logout | Revokes the session and deletes local credentials. |
| get_credits | Current credit balance (1 credit = one assessment group). |
| buy_credits | Creates a checkout session; returns a checkoutUrl to pay. |
| mark_folder | The main workflow: scans a folder for .pdf/.doc/.docx, auto-groups by "Student Name - UNITCODE - Part N.ext", pre-checks credits, uploads the batch, waits for marking (up to 30 min) and downloads result PDFs. wait: false returns the batchId immediately. |
| get_batch_status | Per-assessment state/outcome of a batch. |
| list_batches | Lists past batches. |
| download_results | Downloads all completed PDFs of a batch to a folder. |
| retry_assessment | Retries a FAILED assessment (charges 1 credit; fails if input files were purged after 24h). |
HTTP mode replaces the filesystem/login tools with:
| Tool (HTTP mode only) | Purpose |
|---|---|
| mark_files | Uploads files: [{ name, contentBase64 }] (max 200 files, 50 MB each), auto-groups by the naming convention, pre-checks credits and creates the batch. Returns the batchId immediately. |
| get_download_links | Authenticated download URLs: /assessments/:id/download per completed assessment plus the batch ZIP. Fetching them requires the same bearer token. |
File naming convention
<Student Name> - <UNITCODE> - <Part N>.<pdf|doc|docx>: files sharing student + unit code form one group = one assessment = 1 credit. Names without a recognizable unit code (3 letters then 3+ letters/digits, e.g. BSBXCM501) fall back to a unitless group per student.
Limits (validated locally before upload, and enforced server-side): max 200 files, max 50 MB per file, non-recursive scan.
Example prompts
login
- "Sign me in to Certifico"
- "Log in to my Certifico account so I can start marking"
- "Connect this to Certifico, start the sign-in flow"
login_complete (normally called by Claude on its own, straight after login)
- "Complete my Certifico login now"
- "Keep waiting, I'm approving it in the browser"
whoami
- "Which Certifico account am I signed in as?"
- "Show me who's logged in and which API URL is in use"
- "Am I currently signed in to Certifico?"
logout
- "Sign me out of Certifico"
- "Log out and delete my local credentials"
- "I'm done for today, log me out of Certifico"
get_credits
- "How many credits do I have left?"
- "Check my Certifico credit balance"
- "Do I have enough credits to mark 10 assessments?"
buy_credits
- "Buy 50 more credits"
- "I'm running low, top up 20 credits"
- "Create a checkout session for 100 credits"
mark_folder
- "Mark the assessments in ~/Marking/BSB40120"
- "Mark ~/Downloads/submissions and save results to ~/Marking/results"
- "How much will marking ~/Marking/CHC33021 cost before you run it?"
get_batch_status
- "What's the status of batch abc123?"
- "Is batch abc123 finished marking yet?"
- "Show me the per-student outcome for batch abc123"
list_batches
- "Show me my past marking batches"
- "List the batches I've run this month"
- "What batches have I submitted so far?"
download_results
- "Download the results for batch abc123 into ~/Marking/results"
- "Get the finished PDFs from batch abc123 and save them to my Desktop"
- "Save the completed marking PDFs for batch abc123 to ~/Marking/CHC33021/done"
retry_assessment
- "Retry the failed assessment in batch abc123, assessment id xyz789"
- "That assessment failed, please retry it: assessment xyz789 in batch abc123"
- "Re-run assessment xyz789 since it failed the first time"
mark_files (HTTP mode only)
- "Mark these three uploaded files as one batch"
- "Here are base64-encoded submissions for Jane Doe, mark them"
- "Upload and mark these assessment files for BSBXCM501"
get_download_links (HTTP mode only)
- "Give me the download links for batch abc123"
- "What are the authenticated URLs for the completed PDFs in batch abc123?"
- "Get me the ZIP download link for batch abc123"
Development
Against the local stack (./scripts/dev-stack.sh in the monorepo root; API on plain HTTP :3000; prefer it over the TLS proxy so you never need to disable certificate checks):
npm install
npm test # vitest
npm run typecheck # tsc --noEmit
npm run build # tsup → dist/index.js (single minified file)
claude mcp add certifico-mark-dev --env CERTIFICO_API_URL=http://localhost:3000/api -- node "$(pwd)/dist/index.js"Never set NODE_TLS_REJECT_UNAUTHORIZED=0 against production.
Publishing
Only the bundled, minified dist/ and this README are published (files in package.json); source code is not included in the npm tarball.
