sentra-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sentra_mcp-0.1.0/.github/workflows/publish.yml +18 -0
- sentra_mcp-0.1.0/.gitignore +22 -0
- sentra_mcp-0.1.0/.python-version +1 -0
- sentra_mcp-0.1.0/LICENSE +21 -0
- sentra_mcp-0.1.0/OS-Course/lectures/.gitkeep +0 -0
- sentra_mcp-0.1.0/OS-Course/output/.gitkeep +0 -0
- sentra_mcp-0.1.0/OS-Course/past_exams/.gitkeep +0 -0
- sentra_mcp-0.1.0/PKG-INFO +196 -0
- sentra_mcp-0.1.0/README.md +172 -0
- sentra_mcp-0.1.0/landing/.gitignore +24 -0
- sentra_mcp-0.1.0/landing/README.md +24 -0
- sentra_mcp-0.1.0/landing/index.html +30 -0
- sentra_mcp-0.1.0/landing/package-lock.json +1820 -0
- sentra_mcp-0.1.0/landing/package.json +28 -0
- sentra_mcp-0.1.0/landing/public/favicon.svg +8 -0
- sentra_mcp-0.1.0/landing/src/App.tsx +31 -0
- sentra_mcp-0.1.0/landing/src/components/Closing.tsx +82 -0
- sentra_mcp-0.1.0/landing/src/components/CodeBlock.tsx +66 -0
- sentra_mcp-0.1.0/landing/src/components/DemoChat.tsx +124 -0
- sentra_mcp-0.1.0/landing/src/components/Faq.tsx +57 -0
- sentra_mcp-0.1.0/landing/src/components/Features.tsx +64 -0
- sentra_mcp-0.1.0/landing/src/components/Hero.tsx +133 -0
- sentra_mcp-0.1.0/landing/src/components/HowItWorks.tsx +58 -0
- sentra_mcp-0.1.0/landing/src/components/Install.tsx +167 -0
- sentra_mcp-0.1.0/landing/src/components/Navbar.tsx +127 -0
- sentra_mcp-0.1.0/landing/src/components/QuickStart.tsx +39 -0
- sentra_mcp-0.1.0/landing/src/components/Section.tsx +57 -0
- sentra_mcp-0.1.0/landing/src/components/WhatIs.tsx +50 -0
- sentra_mcp-0.1.0/landing/src/config.ts +46 -0
- sentra_mcp-0.1.0/landing/src/i18n/ar.ts +166 -0
- sentra_mcp-0.1.0/landing/src/i18n/en.ts +166 -0
- sentra_mcp-0.1.0/landing/src/i18n/index.tsx +41 -0
- sentra_mcp-0.1.0/landing/src/index.css +71 -0
- sentra_mcp-0.1.0/landing/src/main.tsx +10 -0
- sentra_mcp-0.1.0/landing/src/motion/variants.ts +20 -0
- sentra_mcp-0.1.0/landing/tsconfig.json +25 -0
- sentra_mcp-0.1.0/landing/vite.config.ts +7 -0
- sentra_mcp-0.1.0/opencode.jsonc.example +14 -0
- sentra_mcp-0.1.0/prompts/Extracting_Text_from_PDF.md +95 -0
- sentra_mcp-0.1.0/prompts/exam_targets_prompt.md +313 -0
- sentra_mcp-0.1.0/prompts/knowledge_base_prompt.md +298 -0
- sentra_mcp-0.1.0/prompts/predicted_exam_prompt.md +176 -0
- sentra_mcp-0.1.0/prompts/professor_dna_prompt.md +369 -0
- sentra_mcp-0.1.0/pyproject.toml +48 -0
- sentra_mcp-0.1.0/src/sentra/__init__.py +3 -0
- sentra_mcp-0.1.0/src/sentra/analysis_prep.py +180 -0
- sentra_mcp-0.1.0/src/sentra/course_store.py +74 -0
- sentra_mcp-0.1.0/src/sentra/exam_files.py +80 -0
- sentra_mcp-0.1.0/src/sentra/exam_spec.py +112 -0
- sentra_mcp-0.1.0/src/sentra/init_cmd.py +136 -0
- sentra_mcp-0.1.0/src/sentra/pdf_reader.py +101 -0
- sentra_mcp-0.1.0/src/sentra/server.py +154 -0
- sentra_mcp-0.1.0/src/sentra/settings.py +31 -0
- sentra_mcp-0.1.0/tests/__init__.py +0 -0
- sentra_mcp-0.1.0/tests/conftest.py +55 -0
- sentra_mcp-0.1.0/tests/test_analysis.py +56 -0
- sentra_mcp-0.1.0/tests/test_course_store.py +39 -0
- sentra_mcp-0.1.0/tests/test_exam_output.py +118 -0
- sentra_mcp-0.1.0/tests/test_init.py +62 -0
- sentra_mcp-0.1.0/tests/test_pdf_reader.py +49 -0
- sentra_mcp-0.1.0/tests/test_tools.py +74 -0
- sentra_mcp-0.1.0/uv.lock +743 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: astral-sh/setup-uv@v5
|
|
17
|
+
- run: uv build
|
|
18
|
+
- run: uv publish
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
.venv/
|
|
3
|
+
dist/
|
|
4
|
+
build/
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.pyc
|
|
7
|
+
*.pyo
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
|
|
10
|
+
# Student materials — never commit private PDFs
|
|
11
|
+
OS-Course/**/*.pdf
|
|
12
|
+
OS-Course/**/*.PDF
|
|
13
|
+
|
|
14
|
+
# Frontend
|
|
15
|
+
landing/node_modules/
|
|
16
|
+
landing/dist/
|
|
17
|
+
|
|
18
|
+
# OS / editors
|
|
19
|
+
.DS_Store
|
|
20
|
+
Thumbs.db
|
|
21
|
+
.vscode/
|
|
22
|
+
.idea/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
sentra_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mo22zy2
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sentra-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sentra — local-first MCP server for mock exam generation
|
|
5
|
+
Project-URL: Homepage, https://github.com/mo22zy2/Sentra-MCP
|
|
6
|
+
Project-URL: Issues, https://github.com/mo22zy2/Sentra-MCP/issues
|
|
7
|
+
Author: mo22zy2
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: education,mcp,mock-exam,opencode,study
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Education
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: <3.14,>=3.11
|
|
19
|
+
Requires-Dist: anyio>=4.9
|
|
20
|
+
Requires-Dist: mcp<3,>=2
|
|
21
|
+
Requires-Dist: pydantic>=2.12
|
|
22
|
+
Requires-Dist: pymupdf>=1.26
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Sentra — AI-Powered Mock Exam Generator (local-first MCP server)
|
|
26
|
+
|
|
27
|
+
Sentra is a local-first **MCP server** for university students. It lets you
|
|
28
|
+
generate realistic mock exams from your lecture PDFs and previous exams.
|
|
29
|
+
|
|
30
|
+
**OpenCode is the AI client, Sentra is the tool it calls.** The MCP server
|
|
31
|
+
does document extraction, validation, analysis prep, and local file
|
|
32
|
+
operations. Your configured AI model (via OpenCode) does the reasoning and
|
|
33
|
+
writes the questions. Model inference costs depend on your chosen provider —
|
|
34
|
+
Sentra itself makes no model calls and costs nothing.
|
|
35
|
+
|
|
36
|
+
No hosted backend, no cloud database, no file storage, no auth service.
|
|
37
|
+
Everything runs on your machine. Nothing you study is uploaded anywhere
|
|
38
|
+
by Sentra.
|
|
39
|
+
|
|
40
|
+
Bilingual product site + docs: [`landing/`](landing/) (English / Egyptian Arabic).
|
|
41
|
+
|
|
42
|
+
## Fastest start: two commands, OpenCode does the rest
|
|
43
|
+
|
|
44
|
+
Prerequisite (once): install `uv` — Windows: `winget install -e --id astral-sh.uv`,
|
|
45
|
+
macOS/Linux or any Python: `pip install uv`.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uvx sentra-mcp init
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`init` creates your course folder, adds Sentra to your `opencode.json`
|
|
52
|
+
(backing it up first, never deleting your other settings), and tells you
|
|
53
|
+
where to drop PDFs — in plain words. Then open OpenCode and paste:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
Verify the 5 sentra tools work, then analyze my past exams and summarize the professor's question patterns.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or skip the terminal entirely: paste this into OpenCode and the agent will
|
|
60
|
+
run the setup for you:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
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.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then drop lecture PDFs into `lectures/`, past exams into `past_exams/`, and ask:
|
|
67
|
+
|
|
68
|
+
- "Analyze the previous exams and summarize the professor's question patterns."
|
|
69
|
+
- "Generate a two-hour Operating Systems mock exam with an answer key."
|
|
70
|
+
|
|
71
|
+
You get `output/<name>_exam.md` + `output/<name>_answers.md`, saved locally.
|
|
72
|
+
|
|
73
|
+
## Manual install (developers)
|
|
74
|
+
|
|
75
|
+
Requires: Miniconda/Anaconda, Python 3.11.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
git clone https://github.com/mo22zy2/Sentra-MCP.git
|
|
79
|
+
cd Sentra-MCP
|
|
80
|
+
conda create -n mcp python=3.11 -y
|
|
81
|
+
conda activate mcp
|
|
82
|
+
pip install uv
|
|
83
|
+
uv sync --python "$CONDA_PREFIX/bin/python" # Windows: uv sync --python %CONDA_PREFIX%\python.exe
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Verify (tested on Python 3.11.17, MCP SDK 2.3.0, PyMuPDF 1.28.2):
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv run python -c "from mcp.server import MCPServer; import pymupdf; print('ok')"
|
|
90
|
+
uv run pytest -q # expect: 30 passed
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### OpenCode configuration
|
|
94
|
+
|
|
95
|
+
1. Install OpenCode per https://opencode.ai/docs and configure any
|
|
96
|
+
compatible provider/model. That provider bills you if paid.
|
|
97
|
+
2. Copy `opencode.jsonc.example` into your OpenCode config (`opencode.json`),
|
|
98
|
+
replacing `<ABSOLUTE_PATH_TO_SENTRA_REPO>` and
|
|
99
|
+
`<ABSOLUTE_PATH_TO_COURSE_FOLDER>` with real absolute paths:
|
|
100
|
+
|
|
101
|
+
```jsonc
|
|
102
|
+
{
|
|
103
|
+
"$schema": "https://opencode.ai/config.json",
|
|
104
|
+
"mcp": {
|
|
105
|
+
"sentra": {
|
|
106
|
+
"type": "local",
|
|
107
|
+
"command": ["uvx", "sentra-mcp"],
|
|
108
|
+
"environment": { "SENTRA_COURSE_DIR": "<ABSOLUTE_PATH_TO_COURSE_FOLDER>" },
|
|
109
|
+
"enabled": true,
|
|
110
|
+
"timeout": 30000
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
(`uvx` fetches `sentra-mcp` from PyPI on first run — no clone needed.
|
|
117
|
+
Developers running from source can use
|
|
118
|
+
`["uv", "--directory", "<ABSOLUTE_PATH_TO_SENTRA_REPO>", "run", "sentra"]`
|
|
119
|
+
instead.)
|
|
120
|
+
|
|
121
|
+
Verified against https://opencode.ai/docs/mcp-servers: `type: "local"`
|
|
122
|
+
+ `command[]` array, absolute `--directory`, `environment` for the course dir
|
|
123
|
+
(not secrets), `enabled`, `timeout`. Never put API keys here.
|
|
124
|
+
|
|
125
|
+
### Course folder
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
OS-Course/
|
|
129
|
+
├── lectures/ # lecture PDFs (primary content source)
|
|
130
|
+
├── past_exams/ # previous exam PDFs (style evidence)
|
|
131
|
+
└── output/ # generated *_exam.md + *_answers.md (auto-created)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Flat subfolders only — no reorganization needed. Supported format:
|
|
135
|
+
**PDF only** in this version (`.txt`/`.docx` are rejected with a clear error).
|
|
136
|
+
|
|
137
|
+
## Tools (5, all local)
|
|
138
|
+
|
|
139
|
+
| Tool | What it does |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `list_course_pdfs` | Lists `lectures/` + `past_exams/` PDFs, reports unreadable files. Never leaves the course dir. |
|
|
142
|
+
| `extract_pdf_text` | Page-preserving text extraction (50 pages / 60k chars per call). Flags scanned PDFs instead of returning silent empties. No OCR. |
|
|
143
|
+
| `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. |
|
|
144
|
+
| `prepare_exam_brief` | Validates your exam spec, returns a grounded brief + warnings for unsupported topics. The agent writes the questions. |
|
|
145
|
+
| `save_exam_files` | Validates exam/answer-key separation and saves `output/<name>_exam.md` + `<name>_answers.md`. Refuses silent overwrites. |
|
|
146
|
+
|
|
147
|
+
`prompts/` holds the 5 agent workflow prompts (extract → knowledge base →
|
|
148
|
+
professor DNA → targets → predicted exam).
|
|
149
|
+
|
|
150
|
+
## Privacy
|
|
151
|
+
|
|
152
|
+
- Sentra processes and saves everything on your machine and uploads nothing.
|
|
153
|
+
- If your OpenCode model is cloud-hosted, the content you ask about is sent
|
|
154
|
+
to that provider — local processing does not guarantee content stays local.
|
|
155
|
+
- Scanned/image PDFs are flagged `insufficient_text: true`. OCR is out of scope.
|
|
156
|
+
|
|
157
|
+
## Limits & safety
|
|
158
|
+
|
|
159
|
+
- 50 MB per file; 50 pages / 60 000 chars per `extract_pdf_text` call;
|
|
160
|
+
12 000-char lecture budget per brief.
|
|
161
|
+
- All paths resolve inside the course dir (`../` escapes rejected).
|
|
162
|
+
- PDFs are treated as untrusted data (never executed). Corrupt/empty PDFs
|
|
163
|
+
return clear errors. No secrets in logs or config.
|
|
164
|
+
|
|
165
|
+
## Troubleshooting
|
|
166
|
+
|
|
167
|
+
| Symptom | Fix |
|
|
168
|
+
|---|---|
|
|
169
|
+
| `Course directory does not exist` | Create it or set `SENTRA_COURSE_DIR` to an existing absolute folder. |
|
|
170
|
+
| `Access denied ... escapes the course directory` | Use `lectures/x.pdf`-style relative paths only. |
|
|
171
|
+
| Tools missing in OpenCode | `opencode mcp list`; check absolute `--directory`; re-run `uv sync`; restart OpenCode; bump `timeout` to 30000. |
|
|
172
|
+
| `... must sum to 100` | Difficulty `{easy,medium,hard}` must total exactly 100. |
|
|
173
|
+
| `Refusing to overwrite` | New `basename` or `overwrite: true`. |
|
|
174
|
+
| `Unsupported file type` | This version reads PDFs only. |
|
|
175
|
+
| `insufficient_text: true` | Scanned PDF — use a text-based export. |
|
|
176
|
+
| `Unknown question types` | Allowed: MCQ, True/False, Short Answer, Essay, Numerical, Comparison, Diagram, Case Study, Application, Analysis, Problem Solving. |
|
|
177
|
+
|
|
178
|
+
## Tests
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
conda activate mcp
|
|
182
|
+
uv run pytest -q
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Covers extraction, empty/corrupt PDFs, page refs, dir validation, traversal
|
|
186
|
+
blocks, input/spec/output validation, key separation, filename collisions,
|
|
187
|
+
`init` config merge + backups, and MCP registration via in-memory `Client(mcp)`.
|
|
188
|
+
Fixtures are synthetic — never commit private materials (see `.gitignore`:
|
|
189
|
+
course PDFs are excluded).
|
|
190
|
+
|
|
191
|
+
## Contributing
|
|
192
|
+
|
|
193
|
+
Open an issue or pull request at
|
|
194
|
+
https://github.com/mo22zy2/Sentra-MCP with your OS, Python version, the
|
|
195
|
+
command you ran, and the full error message. Never attach private course
|
|
196
|
+
materials.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Sentra — AI-Powered Mock Exam Generator (local-first MCP server)
|
|
2
|
+
|
|
3
|
+
Sentra is a local-first **MCP server** for university students. It lets you
|
|
4
|
+
generate realistic mock exams from your lecture PDFs and previous exams.
|
|
5
|
+
|
|
6
|
+
**OpenCode is the AI client, Sentra is the tool it calls.** The MCP server
|
|
7
|
+
does document extraction, validation, analysis prep, and local file
|
|
8
|
+
operations. Your configured AI model (via OpenCode) does the reasoning and
|
|
9
|
+
writes the questions. Model inference costs depend on your chosen provider —
|
|
10
|
+
Sentra itself makes no model calls and costs nothing.
|
|
11
|
+
|
|
12
|
+
No hosted backend, no cloud database, no file storage, no auth service.
|
|
13
|
+
Everything runs on your machine. Nothing you study is uploaded anywhere
|
|
14
|
+
by Sentra.
|
|
15
|
+
|
|
16
|
+
Bilingual product site + docs: [`landing/`](landing/) (English / Egyptian Arabic).
|
|
17
|
+
|
|
18
|
+
## Fastest start: two commands, OpenCode does the rest
|
|
19
|
+
|
|
20
|
+
Prerequisite (once): install `uv` — Windows: `winget install -e --id astral-sh.uv`,
|
|
21
|
+
macOS/Linux or any Python: `pip install uv`.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
uvx sentra-mcp init
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`init` creates your course folder, adds Sentra to your `opencode.json`
|
|
28
|
+
(backing it up first, never deleting your other settings), and tells you
|
|
29
|
+
where to drop PDFs — in plain words. Then open OpenCode and paste:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
Verify the 5 sentra tools work, then analyze my past exams and summarize the professor's question patterns.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or skip the terminal entirely: paste this into OpenCode and the agent will
|
|
36
|
+
run the setup for you:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
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.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then drop lecture PDFs into `lectures/`, past exams into `past_exams/`, and ask:
|
|
43
|
+
|
|
44
|
+
- "Analyze the previous exams and summarize the professor's question patterns."
|
|
45
|
+
- "Generate a two-hour Operating Systems mock exam with an answer key."
|
|
46
|
+
|
|
47
|
+
You get `output/<name>_exam.md` + `output/<name>_answers.md`, saved locally.
|
|
48
|
+
|
|
49
|
+
## Manual install (developers)
|
|
50
|
+
|
|
51
|
+
Requires: Miniconda/Anaconda, Python 3.11.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git clone https://github.com/mo22zy2/Sentra-MCP.git
|
|
55
|
+
cd Sentra-MCP
|
|
56
|
+
conda create -n mcp python=3.11 -y
|
|
57
|
+
conda activate mcp
|
|
58
|
+
pip install uv
|
|
59
|
+
uv sync --python "$CONDA_PREFIX/bin/python" # Windows: uv sync --python %CONDA_PREFIX%\python.exe
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Verify (tested on Python 3.11.17, MCP SDK 2.3.0, PyMuPDF 1.28.2):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv run python -c "from mcp.server import MCPServer; import pymupdf; print('ok')"
|
|
66
|
+
uv run pytest -q # expect: 30 passed
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### OpenCode configuration
|
|
70
|
+
|
|
71
|
+
1. Install OpenCode per https://opencode.ai/docs and configure any
|
|
72
|
+
compatible provider/model. That provider bills you if paid.
|
|
73
|
+
2. Copy `opencode.jsonc.example` into your OpenCode config (`opencode.json`),
|
|
74
|
+
replacing `<ABSOLUTE_PATH_TO_SENTRA_REPO>` and
|
|
75
|
+
`<ABSOLUTE_PATH_TO_COURSE_FOLDER>` with real absolute paths:
|
|
76
|
+
|
|
77
|
+
```jsonc
|
|
78
|
+
{
|
|
79
|
+
"$schema": "https://opencode.ai/config.json",
|
|
80
|
+
"mcp": {
|
|
81
|
+
"sentra": {
|
|
82
|
+
"type": "local",
|
|
83
|
+
"command": ["uvx", "sentra-mcp"],
|
|
84
|
+
"environment": { "SENTRA_COURSE_DIR": "<ABSOLUTE_PATH_TO_COURSE_FOLDER>" },
|
|
85
|
+
"enabled": true,
|
|
86
|
+
"timeout": 30000
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
(`uvx` fetches `sentra-mcp` from PyPI on first run — no clone needed.
|
|
93
|
+
Developers running from source can use
|
|
94
|
+
`["uv", "--directory", "<ABSOLUTE_PATH_TO_SENTRA_REPO>", "run", "sentra"]`
|
|
95
|
+
instead.)
|
|
96
|
+
|
|
97
|
+
Verified against https://opencode.ai/docs/mcp-servers: `type: "local"`
|
|
98
|
+
+ `command[]` array, absolute `--directory`, `environment` for the course dir
|
|
99
|
+
(not secrets), `enabled`, `timeout`. Never put API keys here.
|
|
100
|
+
|
|
101
|
+
### Course folder
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
OS-Course/
|
|
105
|
+
├── lectures/ # lecture PDFs (primary content source)
|
|
106
|
+
├── past_exams/ # previous exam PDFs (style evidence)
|
|
107
|
+
└── output/ # generated *_exam.md + *_answers.md (auto-created)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Flat subfolders only — no reorganization needed. Supported format:
|
|
111
|
+
**PDF only** in this version (`.txt`/`.docx` are rejected with a clear error).
|
|
112
|
+
|
|
113
|
+
## Tools (5, all local)
|
|
114
|
+
|
|
115
|
+
| Tool | What it does |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `list_course_pdfs` | Lists `lectures/` + `past_exams/` PDFs, reports unreadable files. Never leaves the course dir. |
|
|
118
|
+
| `extract_pdf_text` | Page-preserving text extraction (50 pages / 60k chars per call). Flags scanned PDFs instead of returning silent empties. No OCR. |
|
|
119
|
+
| `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. |
|
|
120
|
+
| `prepare_exam_brief` | Validates your exam spec, returns a grounded brief + warnings for unsupported topics. The agent writes the questions. |
|
|
121
|
+
| `save_exam_files` | Validates exam/answer-key separation and saves `output/<name>_exam.md` + `<name>_answers.md`. Refuses silent overwrites. |
|
|
122
|
+
|
|
123
|
+
`prompts/` holds the 5 agent workflow prompts (extract → knowledge base →
|
|
124
|
+
professor DNA → targets → predicted exam).
|
|
125
|
+
|
|
126
|
+
## Privacy
|
|
127
|
+
|
|
128
|
+
- Sentra processes and saves everything on your machine and uploads nothing.
|
|
129
|
+
- If your OpenCode model is cloud-hosted, the content you ask about is sent
|
|
130
|
+
to that provider — local processing does not guarantee content stays local.
|
|
131
|
+
- Scanned/image PDFs are flagged `insufficient_text: true`. OCR is out of scope.
|
|
132
|
+
|
|
133
|
+
## Limits & safety
|
|
134
|
+
|
|
135
|
+
- 50 MB per file; 50 pages / 60 000 chars per `extract_pdf_text` call;
|
|
136
|
+
12 000-char lecture budget per brief.
|
|
137
|
+
- All paths resolve inside the course dir (`../` escapes rejected).
|
|
138
|
+
- PDFs are treated as untrusted data (never executed). Corrupt/empty PDFs
|
|
139
|
+
return clear errors. No secrets in logs or config.
|
|
140
|
+
|
|
141
|
+
## Troubleshooting
|
|
142
|
+
|
|
143
|
+
| Symptom | Fix |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `Course directory does not exist` | Create it or set `SENTRA_COURSE_DIR` to an existing absolute folder. |
|
|
146
|
+
| `Access denied ... escapes the course directory` | Use `lectures/x.pdf`-style relative paths only. |
|
|
147
|
+
| Tools missing in OpenCode | `opencode mcp list`; check absolute `--directory`; re-run `uv sync`; restart OpenCode; bump `timeout` to 30000. |
|
|
148
|
+
| `... must sum to 100` | Difficulty `{easy,medium,hard}` must total exactly 100. |
|
|
149
|
+
| `Refusing to overwrite` | New `basename` or `overwrite: true`. |
|
|
150
|
+
| `Unsupported file type` | This version reads PDFs only. |
|
|
151
|
+
| `insufficient_text: true` | Scanned PDF — use a text-based export. |
|
|
152
|
+
| `Unknown question types` | Allowed: MCQ, True/False, Short Answer, Essay, Numerical, Comparison, Diagram, Case Study, Application, Analysis, Problem Solving. |
|
|
153
|
+
|
|
154
|
+
## Tests
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
conda activate mcp
|
|
158
|
+
uv run pytest -q
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Covers extraction, empty/corrupt PDFs, page refs, dir validation, traversal
|
|
162
|
+
blocks, input/spec/output validation, key separation, filename collisions,
|
|
163
|
+
`init` config merge + backups, and MCP registration via in-memory `Client(mcp)`.
|
|
164
|
+
Fixtures are synthetic — never commit private materials (see `.gitignore`:
|
|
165
|
+
course PDFs are excluded).
|
|
166
|
+
|
|
167
|
+
## Contributing
|
|
168
|
+
|
|
169
|
+
Open an issue or pull request at
|
|
170
|
+
https://github.com/mo22zy2/Sentra-MCP with your OS, Python version, the
|
|
171
|
+
command you ran, and the full error message. Never attach private course
|
|
172
|
+
materials.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea
|
|
19
|
+
.DS_Store
|
|
20
|
+
*.suo
|
|
21
|
+
*.ntvs*
|
|
22
|
+
*.njsproj
|
|
23
|
+
*.sln
|
|
24
|
+
*.sw?
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Sentra landing page (public site, not the exam app)
|
|
2
|
+
|
|
3
|
+
Bilingual (EN / Egyptian Arabic) product + docs site for the Sentra MCP server.
|
|
4
|
+
Lives in `landing/` so the Python MCP project at the repo root stays untouched.
|
|
5
|
+
|
|
6
|
+
## Run
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
cd landing
|
|
10
|
+
npm install
|
|
11
|
+
npm run dev # local preview
|
|
12
|
+
npm run build # production build → dist/
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Notes
|
|
16
|
+
|
|
17
|
+
- `src/config.ts` — `GITHUB_URL` is the single source of truth for the repo
|
|
18
|
+
link (currently `https://github.com/mo22zy2/Sentra-MCP`). The bootstrap
|
|
19
|
+
prompt (`BOOTSTRAP_PROMPT`) injects it automatically. Never hardcode the
|
|
20
|
+
URL elsewhere.
|
|
21
|
+
- Install commands and the OpenCode JSON mirror the root `README.md` and
|
|
22
|
+
`opencode.jsonc.example` verbatim. If those change, update `src/config.ts`.
|
|
23
|
+
- Stack: React + TypeScript + Tailwind v4 (`@tailwindcss/vite`) + motion +
|
|
24
|
+
lucide-react. No router (anchor navigation, single page).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" dir="ltr">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Sentra — Study smarter. Practice with purpose.</title>
|
|
8
|
+
<meta
|
|
9
|
+
name="description"
|
|
10
|
+
content="Sentra is a local-first MCP server that turns your lecture PDFs and previous exams into focused mock exams through AI agents like OpenCode."
|
|
11
|
+
/>
|
|
12
|
+
<meta property="og:title" content="Sentra — Study smarter. Practice with purpose." />
|
|
13
|
+
<meta
|
|
14
|
+
property="og:description"
|
|
15
|
+
content="Turn lecture PDFs and past exams into focused practice with a local-first MCP server built for AI-powered studying."
|
|
16
|
+
/>
|
|
17
|
+
<meta property="og:type" content="website" />
|
|
18
|
+
<meta name="twitter:card" content="summary" />
|
|
19
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
20
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
21
|
+
<link
|
|
22
|
+
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=IBM+Plex+Sans+Arabic:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap"
|
|
23
|
+
rel="stylesheet"
|
|
24
|
+
/>
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
<div id="root"></div>
|
|
28
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
29
|
+
</body>
|
|
30
|
+
</html>
|