# Tutor Mcp

> An open-source MCP server that turns any LLM into an Intelligent Tutoring System. 50 years of cognitive science, MIT licensed.

- **Type:** MCP server
- **Install:** `agentstack add mcp-arnaudguiovanna-tutor-mcp`
- **Verified:** Pending review
- **Seller:** [ArnaudGuiovanna](https://agentstack.voostack.com/s/arnaudguiovanna)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [ArnaudGuiovanna](https://github.com/ArnaudGuiovanna)
- **Source:** https://github.com/ArnaudGuiovanna/tutor-mcp
- **Website:** https://tutor-mcp.dev/

## Install

```sh
agentstack add mcp-arnaudguiovanna-tutor-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Tutor MCP — Adaptive learning runtime for LLMs

> Turn any LLM into an **intelligent tutor**. Tutor MCP is an open-source [MCP](https://modelcontextprotocol.io/) server that gives an AI assistant durable learner state, cognitive-science scheduling, session memory, misconceptions, metacognition, and auditable pedagogical decisions. No item bank — the LLM generates content, Tutor MCP remembers and decides.

Tell the LLM what you want to learn — *Spanish for travel*, *Go for backend*, *medieval history* — and the runtime orchestrates the journey: what to study next, when to review, when you've mastered a concept, when you need a nudge. The next conversation starts from what the learner has mastered, forgotten, misunderstood, felt, and explicitly committed to do next.

**Status — alpha v0.4.0.** The full regulation pipeline (phase FSM + concept/action selectors + gate + threshold resolver) ships default-on; the fade controller is opt-in. Suitable for individual use, small groups, and classroom-scale (≤200 active learners). Single-tenant; runs single-node on SQLite + in-process scheduler by default, and now scales horizontally on an opt-in PostgreSQL backend (`DB_DRIVER=postgres`) with a distributed scheduler and shared rate-limit store for stateless multi-node deployments.

## Compatible clients

  
  &nbsp;&nbsp;
  
  &nbsp;&nbsp;
  
  &nbsp;&nbsp;
  

Claude (web + Desktop + Code), ChatGPT (Developer Mode), Le Chat, Gemini Enterprise / CLI. See the [client setup guide](#setup) below.

## Continuity model

The missing layer is not content. It is continuity.

LLMs can explain. Tutor MCP remembers and decides. The runtime owns the durable learner state and the pedagogical decisions; the LLM stays free to explain, reframe, question, generate exercises, and consolidate narrative memory from the traces it receives.

| Layer | Stored as | What it gives the tutor |
|---|---|---|
| **Algorithmic state** | SQLite domains, concept states, interactions, affect, calibration, transfer, intentions | Domains, prerequisites, phase, mastery, retention, ability, review timing, transfer readiness, active misconceptions |
| **Episodic memory** | Markdown `sessions/*.md` with YAML frontmatter | Affect, concepts touched, salient exchanges, mental-model observations, implementation intentions |
| **Narrative state** | Markdown `MEMORY.md`, `MEMORY_pending.md`, `concepts/*.md`, `archives/*.md` | Stable learner facts, pending observations, concept notes, medium-term trajectory, contradictions to verify |
| **Operator view** | Pedagogical snapshots + decision replay | Why an activity was selected, why a concept was held back, whether evidence was missing or noisy |

`get_next_activity` merges the algorithmic signals with `episodic_context`: stable memory, pending observations, recent sessions, archives, concept notes, and detected OLM inconsistencies. The LLM receives enough context to form a brief hypothesis about the learner's current cognitive state, but it does not own the schedule.

## How it works

The server sits between a learner and an LLM. It splits the job cleanly:

| Component | Owns | Does not own |
|---|---|---|
| **Deterministic engine — Tutor MCP** | Cognitive signals, phase control, evidence gates, session history, Markdown learner memory, audit trail | Learner-facing prose, examples, Socratic phrasing |
| **Generative coach — your LLM** | Content generation, natural language coaching, interpretation briefs, session summaries, memory consolidation | Durable mastery state, review timing, prerequisite gates |

Four loops run from the first session:

- **Learning loop** — Before and after every exchange, the LLM calls `get_next_activity` and `record_interaction`. The runtime updates BKT mastery, FSRS recall, IRT ability, Rasch/Elo exercise calibration, transfer evidence and misconception status — in real time, on every interaction. The LLM never picks scheduling itself.
- **Narrative memory loop** — `record_session_close` asks the LLM for a factual session trace; `update_learner_memory` stores stable memory, pending observations, concept notes, sessions and archives. The next `get_next_activity` call can use those traces to avoid a generic exercise.
- **Metacognitive loop** — Affect check-ins (`record_affect`), calibration tracking (`calibration_check` / `record_calibration_result`) and an autonomy score observe the learner's relationship to the system. A factual mirror surfaces consolidated dependency patterns — the system aims to make itself progressively unnecessary.
- **Motivation loop** — A brief engine selects one motivational angle per exercise (milestone, competence value, growth mindset, affect reframe, plateau recontext, utility value) and emits *signals + instruction* — never canned text. The LLM phrases it.

The pillars of an Intelligent Tutoring System map cleanly:

| ITS pillar | Owner |
|---|---|
| **Domain model** (concept graph, prerequisites) | Tutor MCP runtime — KST-validated |
| **Learner model** (mastery, ability, recall, transfer) | Tutor MCP runtime — BKT, IRT, Rasch/Elo, PFA |
| **Pedagogical model** (scheduling, regulation, alerts) | Tutor MCP runtime — FSRS, evidence gates, orchestrator |
| **Interface + content** | The LLM — Claude / ChatGPT / Le Chat / Gemini |

The cognitive science is rigid and measurable; the LLM is infinitely flexible. Together they ship an ITS that works on day one for any topic, without an editorial team.

## Quick start

### 1. Install or build

```bash
# Latest Linux release (no sudo: set TUTOR_MCP_INSTALL_DIR)
curl -fsSL https://tutor-mcp.dev/install.sh | sh

# Or build from source
go build -o tutor-mcp
```

### 2. Run

```bash
export JWT_SECRET="$(openssl rand -base64 32)"   # required — must be base64
export BASE_URL=https://your.domain              # public origin, no trailing slash
./tutor-mcp                                       # listens on :3000 by default
```

Verify: `curl $BASE_URL/health` → `{"status":"ok"}`.

For real use, put the runtime behind a public reverse proxy with TLS — see [OPERATIONS.md](./OPERATIONS.md). Web clients (Claude.ai, ChatGPT, Le Chat) require a public HTTPS endpoint; `http://localhost` is rejected by their cloud connectors.

### 3. Connect a client

Add `https://your.domain/mcp` as a custom MCP connector. OAuth 2.1 + PKCE with dynamic client registration: no client ID or secret to copy by hand. On the first connection the client opens `/authorize` — register (email + password) or log in. Subsequent launches reuse refresh tokens silently.

| Client | Path | Notes |
|---|---|---|
| **Claude.ai** | Settings → Connectors → + → URL `https://your.domain/mcp` | Pro, Max, Team, Enterprise |
| **ChatGPT** | Settings → Connectors → Advanced → Developer Mode → Create | Plus, Pro, Team, Enterprise, Edu |
| **Le Chat** | Connectors → + Add Connector → Custom MCP | Auto-detects OAuth |
| **Gemini Enterprise** | GCP Console → Custom MCP server data store | StreamableHTTP transport |
| **Gemini CLI** | [`geminicli.com/docs/tools/mcp-server/`](https://geminicli.com/docs/tools/mcp-server/) | Local CLI |
| **Claude Code** (CLI, local) | `.mcp.json` with `"url": "http://localhost:3000/mcp"` | No HTTPS needed |

## MCP tools (35)

All tools accept an optional `domain_id` for multi-domain learners; without it, the most recently active non-archived domain is used.

### Core learning loop (7)

| Tool | Purpose |
|---|---|
| `get_learner_context` | Session-start context: active domain, concept states, recent history, active misconceptions |
| `get_pending_alerts` | Learning + metacognitive alerts requiring action |
| `get_next_activity` | Next optimal activity + episodic context + reasoning request + tutor mode + motivation brief + mastery uncertainty + transfer profile + Rasch/Elo calibration |
| `record_interaction` | Persist outcome, update BKT/FSRS/IRT/Rasch-Elo; tracks hints, initiative, error type, misconception, rubric evidence, interpretation brief |
| `check_mastery` | Mastery-challenge readiness: BKT + evidence diversity + uncertainty + transfer status |
| `get_olm_snapshot` | Open Learner Model: per-concept mastery, retention, fringe membership |
| `get_dashboard_state` | Full dashboard: progress, retention, autonomy, calibration bias, affect history |

### Domain management (9)

| Tool | Purpose |
|---|---|
| `init_domain` | Create domain with concept graph, prerequisites, personal goal |
| `add_concepts` | Append concepts without resetting progress |
| `validate_domain_graph` | Audit graph: cycles, orphans, depth, disconnections |
| `archive_domain` / `unarchive_domain` / `delete_domain` | Lifecycle |
| `set_domain_priority` | Re-rank domains for scheduling weight |
| `set_goal_relevance` / `get_goal_relevance` | LLM-decomposed relevance vector over the concept graph (biases the concept selector) — gated by `REGULATION_GOAL` |

### Metacognition (5)

| Tool | Purpose |
|---|---|
| `record_affect` | Energy + confidence (start), satisfaction + difficulty + intent (end) |
| `calibration_check` / `record_calibration_result` | Self-prediction (1–5) + bias update |
| `get_autonomy_metrics` | Autonomy score 0–1 with 4 components (initiative, calibration, hint independence, proactive review) |
| `get_metacognitive_mirror` | Factual mirror message when a dependency pattern is consolidated over 3+ sessions |
| `update_learner_profile` | Persist learner metadata (objective, language, calibration bias, …) |

### Audit & replay (3)

| Tool | Purpose |
|---|---|
| `get_pedagogical_snapshots` | Before / observation / after / decision trace |
| `get_decision_replay_summary` | Offline audit: replay coverage, missing rubrics, transfer gaps, JSON issues |
| `get_misconceptions` | Per-concept misconceptions with status (active / resolved) and frequency |

### Transfer & negotiation (4)

| Tool | Purpose |
|---|---|
| `feynman_challenge` | Learner explains a mastered concept; LLM detects gaps for BKT injection |
| `transfer_challenge` / `record_transfer_result` | Structured probe in `near`/`far`/`debugging`/`teaching`/`creative` |
| `learning_negotiation` | Expose system plan + tradeoffs; learner can propose alternatives |

### Memory & session (5)

| Tool | Purpose |
|---|---|
| `update_learner_memory` / `read_raw_session` / `get_memory_state` | Markdown memory: sessions, concepts, stable memory, archives |
| `record_session_close` | Recap brief + optional Gollwitzer if-then implementation intention |
| `queue_webhook_message` | Queue a structured Discord nudge (`why_now`, `learning_gain`, `open_loop`, `next_action`) |

### Availability (1)

| Tool | Purpose |
|---|---|
| `get_availability_model` | Learner's time windows and session frequency |

### Alert engine

The scheduler detects nine alert types — learning (`FORGETTING`, `PLATEAU`, `ZPD_DRIFT`, `OVERLOAD`, `MASTERY_READY`) and metacognitive (`DEPENDENCY_INCREASING`, `CALIBRATION_DIVERGING`, `AFFECT_NEGATIVE`, `TRANSFER_BLOCKED`). Daily dedup, per-day frequency cap; archived/deleted domains are filtered out of reads and webhooks.

## Cognitive science engine

Pure-function algorithms running on every interaction, composed by the regulation orchestrator (`engine/orchestrator.go`; design notes in [`docs/regulation-design/`](./docs/regulation-design/)).

| Algorithm | Role |
|---|---|
| **BKT** + individualized BKT | Estimates mastery confidence per concept, not just whether the learner answered right today; recent-history profile individualizes `P(Learn)`, `P(Slip)`, `P(Guess)` — never tuned by the LLM |
| **FSRS** | Decides when to bring a concept back, using stability and difficulty curves |
| **IRT** | Tracks learner ability θ from response patterns so activity difficulty is calibrated to the current learner |
| **Rasch / Elo** | Keeps a deterministic learner-ability vs exercise-difficulty signal, exposed to the LLM and stored in snapshots |
| **PFA** | Weighs wins and losses on each concept to predict how the next attempt is likely to go |
| **KST** | Validates prerequisite graph; gates new concepts on mastery of ancestors |
| **Structured transfer** | Checks whether knowledge moves beyond the training pattern across `near`/`far`/`debugging`/`teaching`/`creative` probes |

The **regulation pipeline** runs as a 7-stage chain inside `get_next_activity`: threshold resolver → goal decomposer → phase FSM (`DIAGNOSTIC ↔ INSTRUCTION ↔ MAINTENANCE`) → concept selector → gate (anti-repeat / session-budget / no-fringe escape) → action selector → fade controller. Pure functions are unit-tested (~90 tests); the orchestrator integration is covered by SQLite in-memory + migration tests. Full design rationale in [`docs/regulation-design/`](./docs/regulation-design/).

## Configuration

Environment variables read at boot:

| Variable | Default | Effect |
|---|---|---|
| `JWT_SECRET` | — *(required)* | HS256 secret. Must be valid base64 (plain strings rejected at boot). Use `openssl rand -base64 32` — 32+ decoded bytes recommended for HS256. **Must be identical on every instance** in a multi-node deployment. |
| `PORT` | `3000` | HTTP listen port |
| `DB_DRIVER` | `sqlite` | `sqlite` (default, embedded, no external service) or `postgres` (horizontal multi-node). |
| `DB_PATH` | `./data/runtime.db` | SQLite path (ignored when `DB_DRIVER=postgres`) |
| `DATABASE_URL` | — | Postgres DSN, **required** when `DB_DRIVER=postgres` (e.g. `postgres://user:pass@host:5432/db?sslmode=require`). |
| `DB_MAX_CONNS` | `10` | Postgres connection-pool size per instance (ignored on SQLite). Keep `DB_MAX_CONNS × instances < Postgres max_connections`. |
| `SCHEDULER_MODE` | `inprocess` | `inprocess` (single-node cron) or `distributed` (per-run DB lease for exactly-once across a fleet). |
| `RATELIMIT_BACKEND` | `memory` | `memory` (per-instance, default) or `postgres`/`db` (shared, fleet-wide rate-limit + login-failure stores — required for coherent throttling across multiple instances). |
| `BASE_URL` | `http://localhost:$PORT` | Public origin (no trailing slash). Triggers HSTS when `https://`. |
| `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, `error` |
| `TRUSTED_PROXY_CIDRS` | — | Comma-separated CIDRs of trusted reverse-proxies. **Required behind a public proxy** — without it every IP-rate-limit collapses under the proxy's loopback bucket. |
| `MCP_RATE_LIMIT_PER_MIN` | `60` | Per-IP and per-learner cap on `/mcp` |
| `MCP_RATE_LIMIT_BURST` | `60` | Burst allowance |
| `TUTOR_MCP_MEMORY_ENABLED` | `on` | Markdown learner memory; set `off` for pre-memory contract |
| `TUTOR_MCP_MEMORY_ROOT` | `~/.tutor-mcp/` | Memory FS root |
| `REGULATION_THRESHOLD` | `on` | `off` reverts to legacy split thresholds (BKT 0.85 / KST 0.70 / Mid 0.80) |
| `REGULATION_GOAL` | `on` | `off` hides `set_goal_relevance` / `get_goal_relevance` and drops the goal-aware prompt section |
| `REGULATION_ACTION` / `_CONCEPT` / `_GATE` | `on` | `off` drops the system-prompt appendix only — the selector / gate logic always runs |
| `REGULATION_FADE` | **`off`** *(opt-in)* | Strict literal `on` enables the fade controller (verbosity reduction + webhook frequency + ZPD aggressiveness + proactive review). Any other value keeps it off. |

Auth endpoints are rate-limited at 10/min (`/authorize`, `/token`), 5/min (`/register`); the MCP endpoint applies the per-IP and per-learner caps configured above.

## Architecture

```
main.go              HTTP + MCP handler + OAuth + scheduler
auth/                OAuth 2.1 + JWT + PKCE + rate limiter
algorithms/          BKT / FSRS / IRT / Rasch-Elo / PFA / KST + thresholds
engine/              Orchestrator + phase FSM + selectors + gate + fade
                     + alert / motivation / mirror / replay / OLM
models/              Typed structs (learner, domain, interactions, regulation, …)
db/                  Store (SQLite default + Postgres) + dialect-aware schema + checksummed migrations
memory/              Markdown learner memory (stable / pending / sessions / concepts / archives)
tools/               MCP tool handler

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [ArnaudGuiovanna](https://github.com/ArnaudGuiovanna)
- **Source:** [ArnaudGuiovanna/tutor-mcp](https://github.com/ArnaudGuiovanna/tutor-mcp)
- **License:** MIT
- **Homepage:** https://tutor-mcp.dev/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-arnaudguiovanna-tutor-mcp
- Seller: https://agentstack.voostack.com/s/arnaudguiovanna
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
