rabbithole
Rabbithole is a local, infinite canvas for learning that lets an AI agent open, navigate, and answer questions about documents interactively in a browser — no account or API keys required.
Core tools:
open_rabbithole: Open a new document (from raw markdown, a.mdfile path, or a PDF ingest ID) or resume a saved hole by ID. Blocks until the human interacts, returningbranch_request,keep_listening, orsession_closed. Supports local image assets, relative link resolution, and PDF-ingested assets.answer_branch: Answer a pending branch request by streaming rich markdown chunks as a new child document on the canvas. Supports math, syntax-highlighted code,showfences for inline SVG/HTML diagrams, and local image assets. Final call blocks waiting for the next event.ingest_pdf: Extract a local PDF into page-render PNGs, embedded raster images, metadata, and per-page text. Returns an ingest ID to pass toopen_rabbithole.list_rabbitholes: List all saved holes (most recently updated first) with their ID, title, last-updated time, and node count, enabling easy session resumption.
Additional capabilities:
Questions asked while no agent is listening are saved and re-queued on resume, enabling durable recursive exploration.
Rich content support: GFM markdown, LaTeX math, code blocks, interactive diagrams, and light/dark theme-aware styling.
Fully local-first: data persists as JSON files on the MCP server with no external API calls.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@rabbitholeopen this document"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Rabbithole
An infinite canvas for learning. Open a document, ask at any point, and follow each answer into a new document.

Open the web app · Explore the offline architecture tour
Rabbithole has two hosts and one canvas:
The static web app uses your chosen model endpoint or the coding-agent subscription already signed in on your machine.
The MCP server lets Claude Code, Codex, and other MCP clients answer while the canvas, storage, and local transport stay on your machine.
No account, telemetry, or hosted document store. Web documents live in your browser. MCP documents live under ~/.rabbithole/ unless RABBITHOLE_DIR overrides it.
Web
Visit rabbithole.ing, then paste a question or URL, drop Markdown or PDF, or import a Rabbithole file.
The web app supports OpenRouter, local and custom OpenAI-compatible endpoints, and the optional subscription bridge:
npx @shlokkhemani/rabbithole bridgeThe bridge prints a private pairing link and connects the page to an installed, signed-in Claude Code or Codex CLI. It binds only to loopback.
Related MCP server: MCP RAG Server
MCP quick start
Requires Node 18+ and a browser.
Claude Code:
claude mcp add rabbithole -- npx -y github:shlokkhemani/rabbitholeCodex:
codex mcp add rabbithole -- npx -y github:shlokkhemani/rabbitholeThen start a fresh agent session and say:
Open this document in Rabbithole.
The tool call stays pending while the agent listens for canvas asks. If a client enforces a short MCP tool timeout, raise that client's timeout; saved asks survive disconnects and resume.
Develop
git clone https://github.com/shlokkhemani/rabbithole.git
cd rabbithole
npm install
npm run build
npm testUseful references:
The canvas and frozen snapshots remain self-contained HTML. The browser bundles in dist/ are committed so the package can run without an install-time build.
License
MIT. See LICENSE.
Available Tools
4 toolsanswer_branchA
Answer one pending branch request from an open Rabbithole. Called after open_rabbithole or answer_branch returns status='branch_request'. Write a focused, well-formatted markdown answer to the human's question about their selection - use selected_text, parent_node_title, and lineage for context (you already hold the documents you authored). If selected_text is empty, answer conversationally about the parent document as a whole. If the request has a 'lens', match that style.
Authoring vocabulary:
Base notation: GFM markdown, $...$/$$...$$ and (...)/[...] math, and highlighted language-tagged code fences.
If the answer is content fetched from a URL or repo, pass its document URL as base_url so relative images and links resolve.
If the answer uses a local image, pass assets: [{ name, file_path }] and reference it as
; use this for screenshots, generated diagrams, and other non-web images.Use ```show when a concept is spatial or structural: architecture, memory layout, relationships.
show dialect: HTML/CSS/inline-SVG only; no scripts. Scripts and unsafe attributes are stripped.
show craft: prefer HTML/CSS layout with flexbox/grid over absolute SVG coordinates.
Design visuals for about 380px card width; make them fluid and keep labels short.
Use theme tokens, never hardcoded colors, so visuals match light and dark themes: --fg, --fg-bold, --fg-dim, --fg-faint, --node-bg, --bar-bg, --border, --border-focus, --accent, --accent-contrast, --code-bg, --hl, --hl-strong, --warn, --font-ui, --font-doc, --font-mono.
Example show:
<style>.flow{display:grid;gap:8px}.box{border:1px solid var(--border);padding:8px;border-radius:6px}</style>
<div class='flow'><div class='box'>Parse</div><div class='box' style='background:var(--hl)'>Render</div></div>Streaming choreography: send prose in 1-3 sentence chunks as usual.
Emit each visual fence contiguously, ideally in one chunk; readers see a placeholder until the fence closes.
Interleave prose -> visual -> prose when useful. Use a visual only when it genuinely carries the explanation.
Finish streaming by sending the remaining final chunk in a normal call with a short 'title'. Partial chunks concatenate verbatim: include your own spacing/newlines and never repeat text already sent. The final call blocks and returns the next event. If it returns status='keep_listening', immediately call open_rabbithole { hole_id }; if the host reports a tool timeout (e.g. timed out awaiting tools/call), do the same. Do not re-send content; asks are saved.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Short label for the new node (a few words; required on the final call) | |
| assets | No | Local image files to attach to this hole; reference them in markdown as asset:name.png images | |
| content | Yes | Markdown chunk (partial) or the remaining markdown (final call) | |
| partial | No | true = stream this chunk into the pending answer and return immediately; omit/false = finish the answer and block for the next event | |
| base_url | No | Document URL used to resolve relative markdown links/images; absolute http(s) only | |
| request_id | Yes | The request_id of the branch_request being answered | |
| session_id | Yes | Active session ID from open_rabbithole |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so the description fully discloses behavior: streaming chunks, final blocking call, concatenation rules, authoring vocabulary, asset handling, and timeout recovery. It covers safety (don't re-send content) and formatting expectations comprehensively.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but well-structured with clear sections (authoring vocabulary, streaming choreography). It is front-loaded with purpose. Could be slightly more concise, but the detail is warranted given tool complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite no output schema, the description covers all aspects: usage triggers, parameter details, streaming protocol, error handling, formatting rules, and asset management. No gaps for agent execution.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 100% coverage but description adds deep semantics: explains streaming protocol, chunk vs final, asset referencing, title requirement on final call, and content formatting. Goes far beyond schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Answer one pending branch request from an open Rabbithole' and specifies the trigger condition. It differentiates from sibling tools (ingest_pdf, list_rabbitholes, open_rabbithole) by focusing on answering branch requests.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to call this tool (after open_rabbithole or answer_branch returns status='branch_request') and provides handling for various scenarios (empty selected_text, lens, keep_listening status, timeout). No ambiguity about usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ingest_pdfA
Extract a local PDF into Rabbithole image assets and per-page text. Produces 2x page render PNGs named page-001.png, page-002.png, etc. plus opportunistic embedded rasters named embed-p001-01.png when the PDF contains extractable images. The agent should compose markdown itself, using page renders as the dependable figure source and embedded rasters when they are cleaner, then call open_rabbithole with the returned ingest_id (or pass hole_id here to attach assets directly to an existing hole). For arXiv links, prefer fetching the HTML version and opening that markdown with base_url instead of ingesting the PDF.
| Name | Required | Description | Default |
|---|---|---|---|
| pages | No | Optional page or range such as "3" or "1-20"; default processes the first 40 pages | |
| hole_id | No | Existing hole id to attach assets to directly; omit to stage assets for open_rabbithole | |
| file_path | Yes | Local path to a PDF file | |
| include_text | No | Whether to return per-page extracted text; defaults to true |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description explains output formats (PNG naming), opportunistic embedded rasters, and the agent's role in composing markdown. Lacks mention of error handling or prerequisites.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is detailed but each sentence adds value. It front-loads the core purpose and avoids redundancy with the schema. Could be slightly more concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers input, output naming, usage patterns, and alternatives. Lacks explicit return value structure (beyond ingest_id), but given no output schema, it is mostly complete for an extraction tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline 3. The description adds context on default pages range, hole_id usage, and includes a note on arXiv preference, enhancing parameter understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool extracts a local PDF into image assets and per-page text, with specific naming conventions. It is distinct from siblings like answer_branch or open_rabbithole.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance on using open_rabbithole with the returned ingest_id or passing hole_id for direct attachment, and advises against PDF ingestion for arXiv links. Does not exhaustively cover all scenarios but is helpful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_rabbitholesA
List saved Rabbitholes (most recently updated first) so you can resume one by hole_id via open_rabbithole. Returns id, title, last-updated time, and node count for each.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided; description carries full burden. States sorting order and return fields but does not explicitly declare read-only nature or any other behavioral traits. Adequate for a simple list tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose, no wasted words. Efficiently conveys essential information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Sufficient for a zero-parameter tool with no output schema. Mentions return fields and ordering; missing pagination details but likely unnecessary given simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters exist, so baseline is 4. Description adds no parameter information, but none is needed as schema coverage is 100%.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists saved Rabbitholes sorted by last updated, specifies return fields (id, title, last-updated time, node count), and distinguishes from sibling open_rabbithole by indicating it enables resumption.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear context: use to list rabbitholes for subsequent resume via open_rabbithole. Does not explicitly state when not to use or compare to other siblings, but the purpose is straightforward.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_rabbitholeA
Open a document on an infinite canvas so the human can read it and dive down rabbit holes. Start a NEW hole with { title, content } (or { title, file_path }), or RESUME a saved one with { hole_id } (use list_rabbitholes to find it). When opening content fetched from a URL or repo, pass the document's own URL as base_url so relative images and links resolve. For local images that are not on the web, pass assets and reference them as
. For a PDF already processed with ingest_pdf, pass ingest_id when starting the new hole and reference the returned asset names as
. The canvas opens in the browser and this call BLOCKS until the human acts. It returns status='branch_request' when the human selects text and asks a question — answer it with answer_branch. A branch_request with EMPTY selected_text is a follow-up question about the parent document as a whole (a chat reply beneath it) — answer conversationally in that document's context. A branch_request may carry a 'lens' (explain | eli5 | example | deeper) — the question text spells out the style the human tapped; honor it. One marked saved=true was asked while no agent was listening — answer it like any other. On a resumed hole the first branch_request carries a 'rehydration' field with the whole tree (and any saved_asks); read it to reload your context. Long waits periodically return status='keep_listening' with hole_id; immediately call open_rabbithole { hole_id } to keep listening, and do not re-send content. If the host reports a tool timeout (e.g. timed out awaiting tools/call), also re-call open_rabbithole { hole_id }; nothing is lost and asks are saved. It returns status='session_closed' when the human clicks Done or closes the tab.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Document title (required for a new hole) | |
| assets | No | Local image files to attach to this hole; reference them in markdown as asset:name.png images | |
| content | No | Raw markdown for the root document | |
| hole_id | No | Resume a saved hole instead of starting a new one | |
| base_url | No | Document URL used to resolve relative markdown links/images; absolute http(s) only | |
| file_path | No | Path to a .md file (alternative to content) | |
| ingest_id | No | Staged PDF assets returned by ingest_pdf; only valid when starting a new hole |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavior: the tool blocks until human action, returns statuses like branch_request, keep_listening, and session_closed, and explains how to handle timeouts by re-calling with hole_id. It details branch_request semantics including selected_text, lens, and rehydration.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but necessary due to the tool's complexity. It is well-structured: starts with purpose, then parameter usage, then return behavior. Every sentence adds value, though a minor trim could improve conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the 7 parameters, no output schema, and complex interaction patterns, the description covers all scenarios: new hole vs resume, branch_request handling, keep_listening, timeout recovery, and rehydration. It is fully complete for an AI agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description adds significant context beyond parameter names: e.g., base_url resolves relative links, assets are referenced as asset:name.png, and ingest_id is for staged PDF assets. This enriches the schema's baseline descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool opens a document on an infinite canvas for reading and exploration. It distinguishes between starting a new hole (with title and content or file_path) and resuming a saved hole (with hole_id), which differentiates it from sibling tools like list_rabbitholes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use each parameter combination, such as using base_url for URL-sourced content, assets for local images, and ingest_id for PDFs. It also explains when to use list_rabbitholes to find saved holes and how to handle branch requests and keep_listening responses.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v0.1.0- First observed
answer_branch - First observed
ingest_pdf - First observed
list_rabbitholes - First observed
open_rabbithole
TDQS
Each tool has a clear, distinct purpose: opening/resuming rabbitholes, answering branch requests, ingesting PDFs, and listing saved ones. No overlap in functionality.
All tool names follow the `verb_noun` pattern (e.g., list_rabbitholes, open_rabbithole, answer_branch, ingest_pdf), providing a consistent and predictable interface.
With 4 tools, the set is tightly scoped to the rabbithole interaction domain—opening, answering, ingesting, and listing. No tool feels redundant, and the number is appropriate for the focused purpose.
The tools cover core workflows well, but missing explicit update/delete functionality for rabbitholes. However, the blocking nature of open_rabbithole and the branch-answer loop cover most user interactions adequately.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Self-hosted AI-native knowledge workspace with hybrid search, GraphRAG, and MCP.
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
Query your own PDFs and documents from any MCP client. Every answer cites the page it came from.
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceA local MCP server that gives AI coding assistants retrieval access to your personal knowledge base of books, standards, and docs, grounding their answers in sources you trust.MIT
- FlicenseNot gradedqualityDmaintenanceA local RAG server using the Model Context Protocol (MCP) to allow AI assistants to query private documents with persistent memory and support for many file formats.1-
- AlicenseAqualityBmaintenanceA local-first MCP server that ingests PDFs, extracts structure, and provides semantic search and sequential navigation tools for AI clients to query and learn from documents.10MIT
- AlicenseNot gradedqualityAmaintenanceMCP server for local RAG over personal notes, PDFs, and documents, enabling plain-English querying and hybrid search with multi-hop context expansion.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/shlokkhemani/rabbithole'
If you have feedback or need assistance with the MCP directory API, please join our Discord server