Skip to main content
Glama
README.md
# ๐Ÿ“š study-mcp

> A Model Context Protocol (MCP) server that turns video transcripts and study materials into a searchable, AI-powered knowledge base โ€” directly inside Claude Desktop.

[![CI](https://github.com/italoo97/study-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/italoo97/study-mcp/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.13-blue)](https://www.python.org)
[![Coverage](https://img.shields.io/badge/coverage-96%25-brightgreen)](#-development)
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)

---

## โœจ What it does

Paste a video transcript or point to a PDF, slide deck, DOCX, or image and instantly:

- ๐ŸŽฌ **Ingest video transcripts** โ€” paste raw text or load `.srt`/`.vtt` caption files; timestamps are preserved so you can jump back to the exact moment in the video
- ๐Ÿ” **Search semantically** โ€” ask questions in natural language across all your materials, powered by local embeddings (no API cost)
- ๐ŸŽฏ **Generate quizzes** โ€” sample representative context from any material so Claude can quiz you on it
- ๐Ÿง  **Summarize & create flashcards** โ€” saved directly to Notion
- ๐Ÿ“Š **Track your library** โ€” list materials, inspect overviews, view stats, delete what you no longer need

Everything runs locally by default (ChromaDB + HuggingFace embeddings). Set a single environment variable to switch to pgvector on Supabase/Postgres.

---

## ๐Ÿงฐ Tech Stack

| Layer | Technology |
|---|---|
| Language | Python 3.13 |
| MCP server | [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) (FastMCP) |
| Embeddings | [sentence-transformers](https://sbert.net) + HuggingFace models (local inference, PyTorch) |
| Vector stores | [ChromaDB](https://www.trychroma.com) (local) ยท [pgvector](https://github.com/pgvector/pgvector) on Supabase/Postgres (cloud) |
| Document parsing | [Docling](https://github.com/docling-project/docling) (PDF, DOCX, PPTX, HTML, images) + native SRT/VTT parser |
| Integrations | [Notion API](https://developers.notion.com) (`notion-client`) |
| Configuration | pydantic-settings (typed, env-based) |
| Tooling | Poetry ยท pytest (+coverage) ยท ruff ยท mypy `--strict` ยท pre-commit ยท commitizen |
| CI | GitHub Actions (lint, type check, tests on every push/PR) |

---

## ๐Ÿ—๏ธ Architecture

```
study-mcp/
โ”œโ”€โ”€ src/study_mcp/
โ”‚   โ”œโ”€โ”€ core/
โ”‚   โ”‚   โ”œโ”€โ”€ config.py       # Settings via environment variables (pydantic-settings)
โ”‚   โ”‚   โ”œโ”€โ”€ embeddings.py   # sentence-transformers, local inference, E5 prefixing
โ”‚   โ”‚   โ”œโ”€โ”€ chunker.py      # Heading โ†’ paragraph โ†’ sentence-aware chunking
โ”‚   โ”‚   โ””โ”€โ”€ transcript.py   # SRT/VTT parser with timestamp preservation
โ”‚   โ”œโ”€โ”€ db/
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py     # VectorRepository protocol + backend auto-detection
โ”‚   โ”‚   โ”œโ”€โ”€ chroma.py       # Local vector store (ChromaDB, zero setup)
โ”‚   โ”‚   โ””โ”€โ”€ pgvector.py     # Cloud vector store (Supabase/Postgres, HNSW index)
โ”‚   โ”œโ”€โ”€ tools/
โ”‚   โ”‚   โ”œโ”€โ”€ ingest.py       # File & raw-text ingestion (Docling + native parsers)
โ”‚   โ”‚   โ”œโ”€โ”€ search.py       # Semantic search
โ”‚   โ”‚   โ”œโ”€โ”€ materials.py    # Overview, quiz context, stats, deletion
โ”‚   โ”‚   โ”œโ”€โ”€ list_materials.py
โ”‚   โ”‚   โ””โ”€โ”€ notion.py       # Notion integration (summaries & flashcards)
โ”‚   โ””โ”€โ”€ server.py           # FastMCP server: tools, resource, prompt, lifespan
โ”œโ”€โ”€ tests/                  # 60 tests, ~96% coverage, no model download needed
โ””โ”€โ”€ docs/
    โ””โ”€โ”€ claude_desktop_config.json
```

**Design highlights:**

- **Repository pattern** โ€” both vector backends implement the same `VectorRepository` protocol; the backend is chosen at startup from `DATABASE_URL` with no code changes.
- **E5 query/passage prefixing** โ€” `intfloat/multilingual-e5-*` models are trained with `query:` / `passage:` prefixes; applying them measurably improves retrieval quality. Applied automatically when an E5 model is configured.
- **Sentence-aware chunking** โ€” text is split by heading, then paragraph, then grouped by whole sentences with sentence-level overlap. Chunks never cut a word or sentence in half.
- **Idempotent ingestion** โ€” `material_id` is a SHA-256 content hash, so re-ingesting the same material is a no-op (`already_indexed`) instead of a duplicate.
- **Timestamp-aware transcripts** โ€” SRT/VTT cues are grouped into paragraphs by speech pauses; search results on transcripts carry a `start_time` so you can jump back into the video.

---

## ๐Ÿ› ๏ธ Available Tools

| Tool | Description |
|---|---|
| `ingest_text_tool` | Ingest raw text โ€” e.g. a pasted video transcript โ€” into the vector store |
| `ingest_file_tool` | Convert and index a file: PDF, DOCX, PPTX, HTML, images, `.txt`, `.md`, `.srt`, `.vtt` |
| `search_tool` | Semantic search across all indexed materials (optionally scoped to one) |
| `list_materials_tool` | List all indexed materials |
| `get_material_overview_tool` | Preview the first chunks of a material before summarizing or quizzing |
| `generate_quiz_context_tool` | Sample chunks spread across a material so Claude can write quiz questions |
| `study_stats_tool` | Totals: materials, chunks, chunks per material |
| `delete_material_tool` | Remove a material and all of its chunks |
| `save_summary_tool` | Save a summary to Notion |
| `save_flashcards_tool` | Save Q&A flashcards to Notion |
| `create_quiz_tool` | Create an interactive quiz page in Notion (open or multiple-choice, answer in Notion then paste back for checking) |

The three Notion tools also accept `related_pages` (a list of
`notion_url` values from earlier saves in the same conversation) to
link a new page to related materials via Notion's native mentions -
see [`docs/NOTION_SETUP.md`](docs/NOTION_SETUP.md).

The server also exposes an MCP **resource** (`study://materials`, the current library as JSON) and a **prompt** (`study_prompt`, a ready-made study-plan workflow for any material).

---

## ๐Ÿš€ Quick Start

### 1. Clone and install

```bash
git clone https://github.com/italoo97/study-mcp.git
cd study-mcp
poetry install
```

### 2. Configure environment

```bash
cp .env.example .env
```

All variables have sensible defaults โ€” the server works out of the box with ChromaDB and no external services. See [`.env.example`](.env.example) for every option.

### 3. Configure Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (see [`docs/claude_desktop_config.json`](docs/claude_desktop_config.json) for a full example):

```json
{
  "mcpServers": {
    "study-mcp": {
      "command": "poetry",
      "args": [
        "--directory", "/absolute/path/to/study-mcp",
        "run", "python", "-m", "study_mcp.server"
      ],
      "env": {
        "CHROMA_PATH": "/absolute/path/to/study-mcp/chroma_db"
      }
    }
  }
}
```

> โš ๏ธ Claude Desktop launches the server from its own working directory, so relative paths (like the `.env` file or the default `./chroma_db`) won't resolve to the project folder. Set `CHROMA_PATH` to an absolute path as above, and pass any other variables (`NOTION_TOKEN`, `DATABASE_URL`, ...) in the `env` block โ€” see [`docs/claude_desktop_config.json`](docs/claude_desktop_config.json) for a complete example.

> **Vector backend is auto-detected:**
> - `DATABASE_URL` empty โ†’ ChromaDB locally (zero setup)
> - `DATABASE_URL` set โ†’ pgvector on Supabase/Postgres (free tier works; table and HNSW index are created automatically)

### 4. Restart Claude Desktop

The tools appear automatically.

---

## ๐ŸŽฌ Ingesting video transcripts

The main workflow this server was built for:

1. Open a video (YouTube, a recorded lecture, a course platform) and copy its transcript โ€” or download the captions as `.srt`/`.vtt`.
2. Paste it into Claude: *"Ingest this transcript as 'Linear Algebra โ€” Lecture 3': ..."* โ†’ Claude calls `ingest_text_tool`.
3. Ask anything: *"According to my lecture, what is an eigenvector?"* โ†’ `search_tool` returns the most relevant passages, each with a `start_time` when available, so you can jump back to that moment in the video.
4. Study actively: *"Quiz me on this lecture"* โ†’ `generate_quiz_context_tool` samples passages spread across the whole material and Claude writes the questions.

`.srt`/`.vtt` files are parsed natively: cue numbers and markup are stripped, consecutive cues are merged into paragraphs at natural speech pauses, and paragraph start times are preserved as metadata.

---

## ๐Ÿง  Embedding Models

Set `EMBEDDING_MODEL` to any [sentence-transformers](https://sbert.net) compatible model:

| Model | Languages | Dims |
|---|---|---|
| `intfloat/multilingual-e5-small` *(default)* | PT + EN + 90 more | 384 |
| `intfloat/multilingual-e5-base` | PT + EN + 90 more | 768 |
| `BAAI/bge-small-en-v1.5` | EN only | 384 |

> Update `EMBEDDING_DIM` to match โ€” the server validates the dimension at startup and fails fast on a mismatch.

---

## ๐Ÿ“‹ Notion Setup (optional)

Only needed for `save_summary_tool` and `save_flashcards_tool`. Full
walkthrough (including a script that creates the database for you)
in [`docs/NOTION_SETUP.md`](docs/NOTION_SETUP.md).

Quick version:

1. Create an integration at [notion.so/my-integrations](https://www.notion.so/my-integrations)
2. Create the database โ€” either run
   `poetry run python scripts/create_notion_database.py <parent_page_id>`
   (creates it with the right schema and shares it automatically), or
   create it by hand with these properties: `Name` (Title), `Type`
   (Select), `Material` (Rich text), `Tags` (Multi-select) โ€” then
   share it with your integration manually.
3. Set `NOTION_TOKEN` and `NOTION_DATABASE_ID` in the `env` block of
   your Claude Desktop config (**not** `.env` โ€” see
   [`docs/claude_desktop_config.json`](docs/claude_desktop_config.json)).

---

## ๐Ÿ’ก Example usage in Claude

```
"Ingest this transcript as 'ML Course โ€” Gradient Descent': [pasted transcript]"

"Ingest this file: /Users/me/Downloads/algorithms_lecture.pdf"

"Search my materials: what is dynamic programming?"

"Give me an overview of material a1b2c3d4"

"Quiz me with 10 questions about my gradient descent lecture"

"Summarize it and save to Notion with tags: ML, optimization"

"Show my study stats"
```

---

## ๐Ÿ”ง Development

```bash
poetry install

poetry run task lint        # ruff check
poetry run task format      # ruff format
poetry run task type_check  # mypy --strict
poetry run task test        # pytest (60 tests, coverage gate at 80%)
```

The test suite runs without downloading any embedding model โ€” embeddings are faked with deterministic vectors and the repository layer is tested against an in-memory double plus a real ChromaDB instance in a temp directory.

CI (GitHub Actions) runs lint, strict type checking, and the full test suite on every push and PR.

---

## ๐Ÿ“„ License

[MIT](LICENSE)