Quick start
The fastest path: clone, build, run, connect. You'll have your tutor reachable from your AI assistant in under ten minutes.
http://localhost:3000/mcp. No domain, no TLS, no public IP needed. For cloud connectors, set BASE_URL to your HTTPS origin.What you need
Tutor MCP is intentionally lean. A 2 GB VPS handles a small classroom; your laptop handles personal use.
localhost.Architecture in plain English
Tutor MCP sits between the assistant and the learner state. The assistant remains the conversational interface; Tutor MCP is the memory and decision runtime.
You talk to your AI
Ask for a goal, a review, a harder challenge, or a session close in natural language.
The AI calls MCP tools
It reads learner context, asks for the next activity, records outcomes, and saves session memory.
Tutor MCP updates state
The runtime updates mastery, retention, calibration, misconceptions, memory files, and audit traces.
Algorithmic state: domains, interactions, mastery, retention, calibration, affect, autonomy, OAuth tokens, scheduler data.
Narrative state: session summaries, concept notes, stable memory, pending observations, and long-term archives.
Install & build
Two paths to a running binary, pick the one that fits. The pre-built binary is the fastest; building from source is for contributors or anyone who wants to pin to a commit.
Install the latest binary
Single binary, no toolchain. The installer detects Linux or macOS plus amd64 or arm64, downloads the latest release asset, verifies it when SHA256SUMS is published, installs a tutor-mcp launcher, and creates a local instance folder.
By default it creates ~/tutor-mcp/.env, ~/tutor-mcp/data, ~/tutor-mcp/memory, and ~/tutor-mcp/backups. Existing .env files are preserved. runtime.db is created automatically on first start at DB_PATH.
==> Detected platform: linux/amd64
==> Creating config at ~/tutor-mcp/.env
==> Database path: ~/tutor-mcp/data/runtime.db
==> Memory root: ~/tutor-mcp/memory
==> Start with: tutor-mcp
Run tutor-mcp after install; the launcher loads ~/tutor-mcp/.env automatically. For public web clients, edit BASE_URL to your HTTPS origin. Override paths with TUTOR_MCP_HOME=/srv/tutor-mcp, TUTOR_MCP_INSTALL_DIR=/usr/local/bin, or TUTOR_MCP_PORT=3001. Full platform assets and SHA256SUMS remain available on the release page.
latest; use a tagged release URL such as v0.4.0 when you want deliberate upgrades.Build from source
The whole tree is one Go module; no Docker, no Node, no Python. Useful if you want to contribute or pin to a specific commit.
$ cd tutor-mcp
$ go build -o tutor-mcp
$ mkdir -p data backups memory
$ cat > .env <<EOF
JWT_SECRET=$(openssl rand -base64 32)
BASE_URL=http://localhost:3000
PORT=3000
DB_PATH=./data/runtime.db
BACKUP_DIR=./backups
TUTOR_MCP_MEMORY_ROOT=./memory
EOF
$ set -a
$ . ./.env
$ set +a
$ ./tutor-mcp
[info] tutor-mcp listening on :3000
[info] db opened at ./data/runtime.db
Environment & config
The binary reads its configuration from environment variables. JWT_SECRET is mandatory and must be base64. BASE_URL should be your public origin for web clients.
JWT_SECRET=$(openssl rand -base64 32)
BASE_URL=https://tutor.your-domain.com
DB_PATH=./data/runtime.db
BACKUP_DIR=./backups
BACKUP_RETENTION_DAYS=14
TUTOR_MCP_MEMORY_ENABLED=on
TUTOR_MCP_MEMORY_ROOT=./memory
TRUSTED_PROXY_CIDRS=127.0.0.1/32
MCP_RATE_LIMIT_PER_MIN=60
MCP_RATE_LIMIT_BURST=60
PORT=3000
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/… # optional
Reverse proxy & HTTPS
Web AI clients require HTTPS. Caddy gives you automatic Let's Encrypt with two lines:
tutor.your-domain.com {
reverse_proxy localhost:3000
}
Reload Caddy (caddy reload) and your tutor is live at https://tutor.your-domain.com/mcp. That's the URL you'll paste into your AI provider.
Run as a service
A user systemd unit keeps things running and ties cleanly into the documented backup timer.
$ systemctl --user enable --now tutor-mcp-backup.timer
$ journalctl --user -u tutor-mcp -f
Postgres & multi-node (optional)
SQLite is the default and handles up to ~200 active learners on a single node. v0.4.0 ships an opt-in Postgres backend that turns Tutor MCP into a stateless service you can run on multiple nodes behind a load balancer.
Single-node on Postgres
Point the binary at a Postgres database with DB_DRIVER=postgres and a DATABASE_URL. The schema is created and migrated on first start, guarded by a Postgres advisory lock so cold starts can't race. A checksum guard rejects boots against a drifted schema.
DB_DRIVER=postgres
DATABASE_URL=postgres://tutor:secret@db.example.com:5432/tutor?sslmode=require
DB_MAX_CONNS=20
Multi-node behind a load balancer
For horizontal scale, run several instances against the same Postgres. Three switches make the fleet behave as one logical server:
JWT_SECRETidentical on every node so OAuth tokens stay valid across the fleet.SCHEDULER_MODE=distributeduses database leasing so each scheduled job fires exactly once, no matter how many nodes are running.RATELIMIT_BACKEND=postgresmoves rate limits and login-failure counters into the shared store for fleet-wide throttling.
DB_DRIVER=postgres
DATABASE_URL=postgres://tutor:secret@db.example.com:5432/tutor?sslmode=require
JWT_SECRET=<base64 — same on every node>
SCHEDULER_MODE=distributed
RATELIMIT_BACKEND=postgres
DB_MAX_CONNS=20
SELECT … FOR UPDATE on concept_states and SKIP LOCKED on the webhook queue protect against lost updates when multiple nodes write at the same time. Full operator notes live in OPERATIONS.md.Plug into your AI
Once your server is reachable, registering it inside your assistant takes about a minute. The wording differs between providers; the moves don't.
Claude (claude.ai), Pro / Max / Team / Enterprise
- Open Settings → Connectors.
- Click the + next to Connectors.
- Fill in: Name =
Tutor MCP, Server URL =https://your.domain/mcp. - Click Add and complete the OAuth login.
ChatGPT, Plus / Pro / Team / Enterprise / Edu
- Profile menu → Settings → Connectors.
- Open Advanced at the bottom and toggle Developer mode.
- Back to Connectors → Create.
- Name =
Tutor MCP, Description =Adaptive learning brain, Server URL =https://your.domain/mcp. - Click Create and authenticate via OAuth.
Le Chat (Mistral)
- Open
chat.mistral.ai→ Connectors. - Click + Add Connector → Custom MCP Connector tab.
- Name =
tutor_mcp(no spaces), Server URL =https://your.domain/mcp. - Click Connect, complete OAuth.
Gemini
Consumer web Gemini doesn't expose custom MCP connectors yet. For now:
- Gemini Enterprise, register the runtime via Google Cloud Console as a custom MCP data store.
- Gemini CLI, use the command-line interface, which supports MCP integrations directly.
Plug into Claude Code
If you're using Claude Code in your terminal, drop a .mcp.json file in your project root (or ~/.claude/mcp.json globally) and you're connected.
"mcpServers": {
"tutor-mcp": {
"type": "http",
"url": "http://localhost:3000/mcp"
}
}
}
Swap localhost:3000 for your.domain if your server isn't local.
Local & alternative clients
The MCP protocol is open. Tutor MCP speaks plain HTTP MCP, so any client that supports custom MCP servers works, including those wired to local models.
- Cline, VS Code extension, supports MCP and local LLMs.
- Continue, IDE assistant with MCP support.
- OpenWebUI, self-hosted ChatGPT-style frontend.
- Custom client, any LLM that can call MCP tools (Ollama-backed, llama.cpp, vLLM…).
Test your setup
Once your provider is connected, send this prompt in a fresh chat. The assistant should call two MCP tools and reply with a short pedagogical brief.
Drop this into your chat
get_learner_contextget_next_activity (or sets up a domain first)If any step fails, jump to Troubleshooting below.
Learner memory
Tutor MCP stores two complementary layers. SQLite keeps algorithmic state: domains, interactions, BKT/FSRS/IRT/Rasch-Elo values, calibration, affect, autonomy, OAuth tokens, and scheduler data. Markdown memory keeps the narrative layer the LLM can read and update.
Timestamped summaries with affect, concepts touched, salient exchanges, and implementation intentions.
Current narrative state per concept, updated when a durable observation appears.
Learner preferences and durable facts, promoted only when confirmed or explicitly stated.
Monthly, quarterly, and annual consolidation written by the connected LLM through MCP.
The main tools are record_session_close, update_learner_memory, read_raw_session, and get_memory_state. The LLM authors the summaries; the server validates scopes and paths, writes files atomically, and exposes recent narrative context inside get_next_activity.
DB_PATH and TUTOR_MCP_MEMORY_ROOT.Backup & restore
Your algorithmic learner model lives in SQLite, and the narrative learner memory lives under TUTOR_MCP_MEMORY_ROOT. Back up both. Two systemd units handle online SQLite backups; add an off-host copy for the database and the memory directory.
$ systemctl --user start tutor-mcp-backup.service
For the Markdown memory directory, use your normal file backup path:
To restore from a snapshot:
$ mv ./data/runtime.db ./data/runtime.db.broken-$(date -u +%FT%TZ)
$ rm -f ./data/runtime.db-shm ./data/runtime.db-wal
$ cp ./backups/runtime-2026-05-05T03-30-00Z.db ./data/runtime.db
$ systemctl --user start tutor-mcp
Troubleshooting
The assistant never calls the tutor
Check the logs for missing pipeline decision entries:
If no decisions are logged, the LLM isn't calling get_next_activity, re-trigger explicitly with: « Use Tutor MCP get_next_activity. »
OAuth handshake fails
Make sure your domain has a valid TLS certificate. curl -I https://your.domain/mcp should return 200 with no warning. AI providers reject self-signed certs.
Repeated phase fallback (NoFringe)
Empty candidate pool, you haven't defined a domain yet, or the goal is too narrow. Run tutor.init_domain with a goal description and three to five concept names.