Sentra — AI-Powered Mock Exam Generator (local-first MCP server)
Sentra is a local-first MCP server for university students. It lets you generate realistic mock exams from your lecture PDFs and previous exams.
OpenCode is the AI client, Sentra is the tool it calls. The MCP server does document extraction, validation, analysis prep, and local file operations. Your configured AI model (via OpenCode) does the reasoning and writes the questions. Model inference costs depend on your chosen provider — Sentra itself makes no model calls and costs nothing.
No hosted backend, no cloud database, no file storage, no auth service. Everything runs on your machine. Nothing you study is uploaded anywhere by Sentra.
Bilingual product site + docs: landing/ (English / Egyptian Arabic).
For AI agents: bootstrap contract (read this if the user pasted this repo's link)
The user wants Sentra installed and running. Do everything below yourself. Never ask the student to run commands or edit files. Everything stays on this machine — NEVER upload their files anywhere.
- Install: if
uvx sentra-mcp initworks, use it. Otherwisegit clonethis repo, thenuv syncinside it (installuvfirst viapip install uvif missing; create a Python 3.11 environment if no Python 3.11+ exists). Verify withuv run pytest -q(expect 30 passed). - Configure: add the
sentrablock fromopencode.jsonc.exampleundermcpin the user'sopencode.json(createmcpif missing, keep every other key). Prefer command["uvx", "sentra-mcp"]; from source use["uv", "--directory", "<ABSOLUTE_REPO_PATH>", "run", "sentra"]. SetSENTRA_COURSE_DIRto an absolute course path. - Course folder: create
OS-Course/{lectures,past_exams,output}ifinitdidn't (default: next to the repo or under Documents). - Verify the 5 tools respond: list_course_pdfs, extract_pdf_text, analyze_past_exams, prepare_exam_brief, save_exam_files.
- Tell the user (simply, in their language): the exact folder to drop PDFs into, and that they must RESTART OpenCode for the tools to appear.
- Making exams: for EACH exam requested, call
prepare_exam_briefwith its spec, write original questions (never copy past exams), thensave_exam_fileswith a DIFFERENT basename per exam (e.g. mock1, mock2). Never reuse a basename unless the user says overwrite. Every answer key stays in its separate*_answers.mdfile.
Fastest start: copy the link, OpenCode does the rest
- Copy this repo link: \https://github.com/mo22zy2/Sentra-MCP2. In OpenCode, paste it and say: \download and run this mcp3. Restart OpenCode so the sentra tools appear.
- Drop lecture PDFs into \lectures/\ and past exams into \past_exams/.
- Say: \make me 2 exams using the sentra mcp\ — collect both exams and both answer keys from \output/.
Prefer to run it yourself?
Prerequisite (once): install uv — Windows: winget install -e --id astral-sh.uv,
macOS/Linux or any Python: pip install uv.
uvx sentra-mcp init
init creates your course folder, adds Sentra to your opencode.json
(backing it up first, never deleting your other settings), and tells you
where to drop PDFs — in plain words. Then open OpenCode and paste:
Verify the 5 sentra tools work, then analyze my past exams and summarize the professor's question patterns.
Or skip the terminal entirely: paste this into OpenCode and the agent will run the setup for you:
Install Sentra on this computer: make sure `uv` is installed (install it if missing), then run `uvx sentra-mcp init` to configure OpenCode and create my course folder. Verify the 5 sentra tools are available, then tell me where to drop my lecture PDFs and past exams, in simple words. Never upload my files anywhere.
Then drop lecture PDFs into lectures/, past exams into past_exams/, and ask:
- "Analyze the previous exams and summarize the professor's question patterns."
- "Generate a two-hour Operating Systems mock exam with an answer key."
You get output/<name>_exam.md + output/<name>_answers.md, saved locally.
Manual install (developers)
Requires: Miniconda/Anaconda, Python 3.11.
git clone https://github.com/mo22zy2/Sentra-MCP.git
cd Sentra-MCP
conda create -n mcp python=3.11 -y
conda activate mcp
pip install uv
uv sync --python "$CONDA_PREFIX/bin/python" # Windows: uv sync --python %CONDA_PREFIX%\python.exe
Verify (tested on Python 3.11.17, MCP SDK 2.3.0, PyMuPDF 1.28.2):
uv run python -c "from mcp.server import MCPServer; import pymupdf; print('ok')"
uv run pytest -q # expect: 30 passed
OpenCode configuration
- Install OpenCode per https://opencode.ai/docs and configure any compatible provider/model. That provider bills you if paid.
- Copy
opencode.jsonc.exampleinto your OpenCode config (opencode.json), replacing<ABSOLUTE_PATH_TO_SENTRA_REPO>and<ABSOLUTE_PATH_TO_COURSE_FOLDER>with real absolute paths:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"sentra": {
"type": "local",
"command": ["uvx", "sentra-mcp"],
"environment": { "SENTRA_COURSE_DIR": "<ABSOLUTE_PATH_TO_COURSE_FOLDER>" },
"enabled": true,
"timeout": 30000
}
}
}
(uvx fetches sentra-mcp from PyPI on first run — no clone needed.
Developers running from source can use
["uv", "--directory", "<ABSOLUTE_PATH_TO_SENTRA_REPO>", "run", "sentra"]
instead.)
Verified against https://opencode.ai/docs/mcp-servers: type: "local"
command[]array, absolute--directory,environmentfor the course dir (not secrets),enabled,timeout. Never put API keys here.
Course folder
OS-Course/
├── lectures/ # lecture PDFs (primary content source)
├── past_exams/ # previous exam PDFs (style evidence)
└── output/ # generated *_exam.md + *_answers.md (auto-created)
Flat subfolders only — no reorganization needed. Supported format:
PDF only in this version (.txt/.docx are rejected with a clear error).
Tools (5, all local)
| Tool | What it does |
|---|---|
list_course_pdfs |
Lists lectures/ + past_exams/ PDFs, reports unreadable files. Never leaves the course dir. |
extract_pdf_text |
Page-preserving text extraction (50 pages / 60k chars per call). Flags scanned PDFs instead of returning silent empties. No OCR. |
analyze_past_exams |
Question types, wording templates, approx difficulty, marks — every finding cites file:page. Past patterns only; never claims to predict the real exam. |
prepare_exam_brief |
Validates your exam spec, returns a grounded brief + warnings for unsupported topics. The agent writes the questions. |
save_exam_files |
Validates exam/answer-key separation and saves output/<name>_exam.md + <name>_answers.md. Refuses silent overwrites. |
prompts/ holds the 5 agent workflow prompts (extract → knowledge base →
professor DNA → targets → predicted exam).
Privacy
- Sentra processes and saves everything on your machine and uploads nothing.
- If your OpenCode model is cloud-hosted, the content you ask about is sent to that provider — local processing does not guarantee content stays local.
- Scanned/image PDFs are flagged
insufficient_text: true. OCR is out of scope.
Limits & safety
- 50 MB per file; 50 pages / 60 000 chars per
extract_pdf_textcall; 12 000-char lecture budget per brief. - All paths resolve inside the course dir (
../escapes rejected). - PDFs are treated as untrusted data (never executed). Corrupt/empty PDFs return clear errors. No secrets in logs or config.
Troubleshooting
| Symptom | Fix |
|---|---|
Course directory does not exist |
Create it or set SENTRA_COURSE_DIR to an existing absolute folder. |
Access denied ... escapes the course directory |
Use lectures/x.pdf-style relative paths only. |
| Tools missing in OpenCode | opencode mcp list; check absolute --directory; re-run uv sync; restart OpenCode; bump timeout to 30000. |
... must sum to 100 |
Difficulty {easy,medium,hard} must total exactly 100. |
Refusing to overwrite |
New basename or overwrite: true. |
Unsupported file type |
This version reads PDFs only. |
insufficient_text: true |
Scanned PDF — use a text-based export. |
Unknown question types |
Allowed: MCQ, True/False, Short Answer, Essay, Numerical, Comparison, Diagram, Case Study, Application, Analysis, Problem Solving. |
Tests
conda activate mcp
uv run pytest -q
Covers extraction, empty/corrupt PDFs, page refs, dir validation, traversal
blocks, input/spec/output validation, key separation, filename collisions,
init config merge + backups, and MCP registration via in-memory Client(mcp).
Fixtures are synthetic — never commit private materials (see .gitignore:
course PDFs are excluded).
Contributing
Open an issue or pull request at https://github.com/mo22zy2/Sentra-MCP with your OS, Python version, the command you ran, and the full error message. Never attach private course materials.
Metadata
Release files for sentra-mcp 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sentra_mcp-1.0.0.tar.gz | 94.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sentra_mcp-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 114.7 kB
Release files / sentra_mcp-1.0.0.tar.gz
| Download URL | sentra_mcp-1.0.0.tar.gz |
|---|---|
| Size | 94.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88c72a66504c5ae54e27e1ef6d6386cbf41b4b5076a2833f4509932caa953177
|
|
BLAKE2b-256 checksum How to use checksums |
6623529f7706a8a5862b2c12e54fea6558fe970056ef86c16589f29758e81893
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sentra_mcp-1.0.0-py3-none-any.whl
| Download URL | sentra_mcp-1.0.0-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b0e10f1cfc1524a60123d86b512c3ee6c5275d392f81a22397490bdcc0875edd
|
|
BLAKE2b-256 checksum How to use checksums |
1d3c0d9da405d28be2e70ba0404dc50fd2e61d026114049f31cab9920d4544f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|