MCP server for brutal, evidence-based screenplay analysis via retrieval over a reference database of real scripts.
Project description
๐ฌ slugline-mcp
Brutal, evidence-based screenplay analysis โ grounded in real produced scripts.
Mood, next-action suggestions, and "X meets Y" comparisons, backed by retrieval over ~2,200 real screenplays. One MCP server. Zero vibes-based feedback.
Under the hood: a full Retrieval-Augmented Generation (RAG) pipeline โ chunking, vector embeddings, semantic search, and local zero-shot classification โ exposed entirely as Model Context Protocol (MCP) tools, with zero LLM calls from the server itself.
slugline-mcp doesn't write or judge your scene itself โ it retrieves real produced scenes similar to yours (or matching a mood you're chasing) so your own connected Claude can ground its feedback in evidence instead of guessing. It's the retrieval half of RAG, full stop: parse, embed, index, and semantically search real screenplays, then hand that grounded evidence to Claude over MCP.
โญ Star this repo if you find it useful.
Try it once it's runnable end-to-end (see the roadmap below):
- ๐ฆ Clone it โ
git clone https://github.com/NalluriTanavreddy/slugline-mcp.git && cd slugline-mcp && uv sync- ๐ Add it to Claude Desktop โ see
docs/claude_desktop.mdfor the config- ๐ฌ Ask about your scene โ "Find me real scenes similar to this one: [paste a scene]" and Claude answers grounded in actual retrieved screenplay text, not general knowledge
๐ฅ Demo
A screen recording is still coming (see the roadmap below), but
docs/demo_walkthrough.md has a full text walkthrough with real
tool output โ including both the precise tag-matched and semantic-fallback paths of
find_mood_reference_scenes โ captured against an actual local test index, not fabricated.
๐ฏ What is this?
slugline-mcp is an MCP (Model Context Protocol) server for screenwriters. It's a retrieval-only RAG pipeline: it parses a reference database of real movie screenplays into scenes, embeds them, and exposes semantic search over that index as MCP tools. The LLM doing the actual writing and judgment is your own Claude, connected locally โ this server never calls out to an LLM itself, it just supplies the evidence.
Two engineering ideas this project is built around:
- RAG, done properly: real chunking (screenplay scenes, not arbitrary token windows), a purpose-fit embedding model, a persistent vector store, and metadata filtering (mood tags computed once at index time) layered on top of semantic similarity โ not just "stuff everything into a prompt."
- MCP, done properly: five tools with schemas an LLM can actually reason about
(
Annotated[..., Field(description=...)]throughouttools/), including a dedicatedget_analysis_styletool whose whole job is steering how the calling LLM uses the other four โ prompt engineering expressed as a callable tool, not a static system prompt.
Reference data comes from rohitsaxena/MovieSum, a public Hugging Face dataset of ~2,200 movie screenplays, pre-structured into scenes with dialogue and stage directions.
๐ง How the RAG Pipeline Works
Index time (once, offline, in indexing/build_index.py):
- Parse โ MovieSum's screenplay XML (or a user's raw pasted script, via a separate plain-text splitter) is split into scenes, not arbitrary chunks โ a scene is the natural retrieval unit for screenplay feedback.
- Embed โ each scene's flattened text is encoded with
sentence-transformers/all-MiniLM-L6-v2into a 384-dim vector. - Classify โ each scene is also run once through a local zero-shot classifier
(
facebook/bart-large-mnli) against a fixed mood taxonomy, so mood becomes a stored metadata field instead of something re-inferred on every query. - Store โ vectors + text + metadata land in a persistent Chroma collection.
Query time (every MCP tool call, in retrieval.py):
- The incoming query (a scene, or a target mood) is embedded with the same model.
- Chroma runs approximate nearest-neighbor search over the stored vectors โ optionally
pre-filtered by metadata (e.g.
mood == "paranoid") before ranking by similarity. - Results are formatted into a canonical scene shape and returned as MCP tool output โ raw evidence, not a generated answer.
Retrieval and generation are fully decoupled here: this server only ever does the retrieval half, and the MCP tool boundary is exactly where that handoff happens.
โจ Features
๐ Evidence Retrieval
search_similar_scenesโ semantic search for real produced scenes structurally or tonally similar to a scene you're writingget_scene_detailsโ fetch the full text and metadata for one indexed scene by idlist_indexed_moviesโ enumerate every movie currently in the reference indexfind_mood_reference_scenesโ find scenes that strongly hit a target mood (e.g. "paranoid"), for when you want to rewrite toward a mood your scene doesn't have yet โ a hybrid search: free-text moods close to a precoded tag get precise tag-filtered results, anything else falls back to raw semantic search, with the method used reported back for transparency
๐ฃ๏ธ Analysis Guidance
get_analysis_styleโ instructs the connected LLM to be direct rather than encouraging, to gather evidence before writing anything, and to structure its feedback around mood, next action, and an "X meets Y" comparison โ each one cited against specific retrieved scenes
โ๏ธ Under the Hood
- MovieSum's screenplay XML is parsed into structured
Sceneobjects (slugline, action lines, dialogue, parentheticals); a separate plain-text splitter handles a user's own pasted script, which has no such structure - Every reference scene is run once through a local, free zero-shot classifier
(
facebook/bart-large-mnli) at indexing time to tag its dominant mood โ no per-query cost, no external API - Embeddings use
sentence-transformers/all-MiniLM-L6-v2, stored in a local Chroma index - End users never build the index themselves: a
bootstrapmodule downloads a prebuilt index from a Hugging Face Hub dataset repo on first run, falling back to clear "no index available" behavior (never a crash) if that fails
๐งฐ Tech Stack
| Layer | Choice |
|---|---|
| Architecture pattern | RAG (retrieval-augmented generation), exposed entirely as MCP tools |
| Language | Python 3.11+ |
| MCP framework | Official mcp Python SDK (FastMCP) |
| Embeddings / vector search | sentence-transformers (all-MiniLM-L6-v2) + Chroma ANN search |
| Vector database | Chroma (persistent, local) |
| Mood classification | Local zero-shot transformers pipeline (facebook/bart-large-mnli), index-time only |
| Reference dataset | rohitsaxena/MovieSum (~2,200 screenplays) |
| Prebuilt index hosting | Hugging Face Hub dataset repo, via huggingface-hub |
| Build backend | Hatchling (src layout) |
| Package manager | uv |
| Testing | pytest |
โ๏ธ Getting Started
Prerequisites
- Python 3.11+
- uv
Install
From PyPI: not yet published โ see the roadmap below (Phase 8).
From source (works today):
git clone https://github.com/NalluriTanavreddy/slugline-mcp.git
cd slugline-mcp
uv sync
Run the server
uv run python -m slugline_mcp
Add it to Claude Desktop
See docs/claude_desktop.md for the full config example (dev
mode today; a simpler uvx slugline-mcp config once published).
Build or fetch a reference index
The server needs a populated Chroma index to retrieve from. See
docs/dataset.md for building one locally from MovieSum, and
src/slugline_mcp/indexing/bootstrap.py for how published builds will fetch a prebuilt
one automatically.
Development setup
uv sync --extra index # adds datasets + transformers, needed only for indexing
uv run --with pytest pytest tests/
See docs/testing.md for testing tools interactively with the MCP
Inspector.
๐ Usage
Once slugline-mcp is connected (see Add it to Claude Desktop above), just talk to Claude normally โ paste a scene, describe what you're stuck on, or ask for a comparison. Claude decides which tools to call; you never call them directly.
Typical workflow
- Paste a scene and ask for feedback. Claude calls
get_analysis_stylefirst (it's designed to steer the whole interaction), thensearch_similar_sceneswith your scene's text to pull real comparable scenes from the reference index. - Claude cites specific movies and scenes, not vague genre talk โ if it says "this reads
like a beat from 8MM," that's because
search_similar_scenesactually returned that scene. - Ask to see the full match. "Show me that whole scene" prompts Claude to call
get_scene_detailswith the id from the earlier search result. - Ask for a mood rewrite. "Make this scene feel more paranoid" prompts
find_mood_reference_scenes("paranoid")โ Claude gets back real scenes that strongly hit that mood, plus whether the match was precise (tag_matched) or a broader semantic guess (semantic_fallback). - Ask what's in the reference set. "What movies do you have indexed?" calls
list_indexed_movies.
Example prompts
| You ask Claude... | Tool(s) it calls |
|---|---|
| "Here's my opening scene โ what does this actually read like?" | get_analysis_style, search_similar_scenes |
| "Show me the full text of that Iron Lady scene you mentioned" | get_scene_details |
| "I want this argument to feel more like dread building, not just tense" | find_mood_reference_scenes |
| "What films are actually in your reference database?" | list_indexed_movies |
| "Give me an 'X meets Y' comparison for this whole script" | get_analysis_style, search_similar_scenes (called repeatedly across scenes) |
Tools reference
| Tool | Purpose | Key parameters |
|---|---|---|
get_analysis_style |
Tone/structure instructions for the calling LLM | none |
search_similar_scenes |
Semantic search for structurally/tonally similar produced scenes | query (scene text), n_results |
get_scene_details |
Full text + metadata for one scene by id | scene_id |
list_indexed_movies |
Every movie currently in the index | none |
find_mood_reference_scenes |
Scenes that strongly hit a target mood, hybrid tag/semantic search | target_mood, top_k |
If retrieval comes back empty
Every tool degrades gracefully instead of erroring if no reference index is available yet
(see retrieval.py) โ you'll get empty results rather than a crash. If that happens:
- Confirm a Chroma index exists at
~/.slugline-mcp/chroma(or whereverSLUGLINE_MCP_PERSIST_DIRpoints). - If not, either wait for
bootstrap.pyto fetch the prebuilt index, or build one yourself (seedocs/dataset.md).
๐๏ธ Project Structure
src/slugline_mcp/
โโโ server.py # FastMCP instance, tool registration
โโโ __main__.py # `python -m slugline_mcp` entry point
โโโ config.py # env var loading
โโโ retrieval.py # Chroma-backed retrieval (search, get, mood filter)
โโโ tools/
โ โโโ search_similar_scenes.py
โ โโโ get_scene_details.py
โ โโโ list_indexed_movies.py
โ โโโ get_analysis_style.py
โ โโโ find_mood_reference_scenes.py
โ โโโ _formatting.py # shared scene response shape
โโโ indexing/
โโโ parser.py # MovieSum XML -> Scene objects
โโโ plaintext_scene_splitter.py # raw pasted scripts -> scenes
โโโ embeddings.py # sentence-transformers wrapper
โโโ mood_tagging.py # local zero-shot mood classifier
โโโ chroma_client.py # Chroma persistent client/collection
โโโ build_index.py # maintainer script: parse + embed + tag + store
โโโ bootstrap.py # download prebuilt index from HF Hub
tests/ # pytest suite, one file per tool/module
docs/ # dataset, MCP Inspector testing, Claude Desktop config
๐บ๏ธ Roadmap
- Phase 0 โ Repo setup: README, license,
pyproject.toml, package structure - Phase 1 โ Indexing pipeline: MovieSum XML parser, plain-text splitter,
embeddings, Chroma,
build_index, local mood tagging, HF Hub bootstrap - Phase 2 โ MCP server core: FastMCP scaffold, entry point, config, retrieval logic
- Phase 3 โ Tools: all five tools implemented, registered, and tested
- Phase 4 โ Local testing: MCP Inspector docs, schema fixes, graceful empty results, Claude Desktop config, this README
- Phase 5 โ Packaging: console entry point, versioning,
uvxsupport - Phase 6 โ CI/CD: GitHub Actions build/test + PyPI publish workflows
- Phase 7 โ Docs & release: full usage guide, CONTRIBUTING, demo walkthrough, v0.1.0
- Phase 8 โ Publish: TestPyPI, then PyPI
See TASKS.md for the full task-by-task build checklist.
๐ License
MIT โ see LICENSE.
๐ค Author
Built by NalluriTanavreddy.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slugline_mcp-0.1.0.tar.gz.
File metadata
- Download URL: slugline_mcp-0.1.0.tar.gz
- Upload date:
- Size: 306.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ef204a2d742ea3633ad1a959e74bd698abd059c28bb79ff3d15352b8bd25615
|
|
| MD5 |
716eae8f4b680366cb68b112243385a9
|
|
| BLAKE2b-256 |
31cbe1605a4ee6d95bf0c89580beff8da819d15cc481d0552e1d31293e7d761f
|
File details
Details for the file slugline_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: slugline_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 27.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3734b93adfdc7627ce48ea7a3ce1da9417a78bb5eea3f706dfc10326b751a0da
|
|
| MD5 |
8678631b7b935c0058ae4f0200a54b06
|
|
| BLAKE2b-256 |
3c4663df883dfa26f55118e85b8c32feaf343e802a38826a855f18f9b82798dd
|