Skip to main content
Glama

pulpie-mcp

pulpie-mcp

An MCP server that gives AI agents their own tools for turning web pages into clean Markdown. It runs the Pulpie content extraction model locally, so tables, code blocks, links, and images come through intact instead of getting summarized away.

The agent can read a page inline, save it as a .md file, crawl a whole docs section into a folder, and search everything it saved later. Over time the library turns into a local reference collection you can reuse across projects.

Why I made it

I already had a little local UI for Pulpie that I used to pull docs and articles into Markdown, and it works really well. But I was still the one doing the pulling. Most agent fetch tools run pages through a small model that summarizes or trims them, which is not what you want when the agent needs the actual API reference.

So this gives the agent the same thing I was using. It can grab full documentation whenever it needs it and save it somewhere useful, and I don't have to go do it by hand.

Related MCP server: WebforAI Text Extractor

What it does

Tool

What it's for

fetch_markdown

Read a page right now. The Markdown comes back inline, cut off at max_chars (40,000 by default).

save_markdown

Save one page as a .md file. Returns the path and a heading outline instead of the whole page, so it doesn't eat the agent's context.

crawl_docs

Save a documentation section as a folder of .md files plus an index.md. Up to 500 pages per crawl, 50 by default.

list_library

List saved docs with their source URL and fetch time, optionally filtered by a search term.

search_library

Search saved docs by what they say and get back the matching sections, each with its heading path, source URL, and file path.

A few details worth knowing:

  • Where files go is up to the agent. For project work it passes a folder inside the project, like /path/to/project/DOCS/reference/uv. For general research it leaves directory empty and the file goes into the global library at ~/.pulpie/library/<site>/.

  • Every saved file has frontmatter with title, source, and fetched, so you (and the agent) can always tell where a file came from and how old it is.

  • Crawling checks the sitemap first. It looks at robots.txt, then <docs path>/sitemap.xml, then /sitemap.xml. If none of those exist, it follows links from the pages instead. It only crawls pages on the same host and under the starting path.

  • Search works on sections, not whole pages. Each page is split at its #, ##, and ### headings, so a search for useEffect cleanup returns the cleanup section instead of the whole hooks page. It searches the global library by default, or any folder you pass as directory.

  • Markdown and plain-text URLs pass straight through. If a URL already serves text/markdown or text/plain (like llms.txt), you get the file as is.

How it works

There are two pieces:

  1. The MCP server is what your agent launches. It's small and doesn't load the model.

  2. The backend is a local HTTP server that holds the Pulpie model in memory and does the actual fetching and extraction.

You never have to start the backend yourself. The first time a tool needs it, the MCP server starts it in the background and waits for the model to load. Every agent session shares that one backend, so you only ever have one copy of the model on your GPU. After 30 minutes with no requests it shuts itself down and frees the memory, and the next request starts it again.

The model is feyninc/pulpie-orange-small, a 210M parameter encoder. It uses around 420 MB of VRAM. On my RTX 4090 laptop, a cold start (including loading an already downloaded model) took about 10 seconds. After that, a single docs page saved in under a second, and an 8-page crawl of the uv docs took about 3 seconds. Most of that is network time.

Requirements

  • Python 3.10 or newer

  • uv (recommended) or pip

  • An NVIDIA GPU is nice but not required. Pulpie uses CUDA if it can, then Apple MPS, then falls back to CPU.

Heads up: this pulls in PyTorch, so the install is a few GB.

I've only tested this on Linux with an NVIDIA GPU so far. It should work on macOS, and Windows is untested.

Installation

Install it as a tool so the pulpie-mcp command is on your PATH:

uv tool install git+https://github.com/pinkpixel-dev/pulpie-mcp

Or from a local clone:

git clone https://github.com/pinkpixel-dev/pulpie-mcp
cd pulpie-mcp
uv tool install .

The model downloads from Hugging Face the first time the backend starts.

Adding it to your agent

Claude Code

claude mcp add --scope user pulpie -- pulpie-mcp

Codex

In ~/.codex/config.toml:

[mcp_servers.pulpie]
command = "pulpie-mcp"

Other MCP clients

Most clients take a JSON config like this:

{
  "mcpServers": {
    "pulpie": {
      "command": "pulpie-mcp"
    }
  }
}

If you add environment variables (see below), put them in the client's env block for this server.

Using it

You don't need special prompts. Just ask for what you want:

  • "Pull the uv docs into this project's DOCS/reference folder."

  • "Read the asyncio queue docs and tell me how join() works."

  • "Do we already have the FastAPI docs saved somewhere?"

  • "Search the library for how FastAPI handles background tasks."

The server tells the agent to save project docs inside the project and general research in the global library, so it usually picks the right spot on its own.

Configuration

Everything is optional.

Variable

Default

What it does

PULPIE_URL

http://127.0.0.1:8787

Where the backend runs. Only local URLs get auto-started.

PULPIE_HOME

~/.pulpie

Holds the global library, the search index (search.db), and backend.log.

PULPIE_LIBRARY

$PULPIE_HOME/library

Where saved docs go when no directory is given.

PULPIE_ALLOW_PRIVATE

off

Set to 1 to allow localhost and LAN addresses.

PULPIE_IDLE_TIMEOUT

1800

Seconds without requests before the backend exits. 0 keeps it running.

PULPIE_START_TIMEOUT

600

How long to wait for the backend to start. The first run includes the model download.

Private addresses

By default the server won't fetch localhost, 127.0.0.1, LAN addresses like 192.168.x.x, or cloud metadata addresses. Agents follow links they find on the open web, so I'd rather block those than have a random page send the agent poking around your network. This is checked on every redirect too.

If you want to pull docs from a local dev server, set PULPIE_ALLOW_PRIVATE=1.

Commands

pulpie-mcp            # run the MCP server over stdio (your agent does this)
pulpie-mcp serve      # run the backend in the foreground, handy for debugging
pulpie-mcp status     # show whether the backend is running, and on which device
pulpie-mcp stop       # stop the backend

If something goes wrong with the backend, check ~/.pulpie/backend.log.

Limitations

  • Pages that render entirely in JavaScript come back mostly empty, because the backend fetches the HTML the server sends and doesn't run a browser. Most docs sites (Docusaurus, MkDocs, VitePress, Sphinx, Next.js) render on the server, so this hasn't been an issue for docs so far.

  • Code blocks are indented, not fenced. Pulpie converts HTML to Markdown with html2text, which writes code as 4-space indented blocks without a language tag. It's valid Markdown, just not as pretty.

  • Search is keyword search, not semantic search. It uses SQLite full-text search with stemming, so caching finds cache and readOnlyHint finds read_only_hint. A question phrased in totally different words than the docs use can still miss. If nothing matches every word, the results say they only match some of the words.

  • No PDFs. Non-HTML pages other than Markdown and plain text are rejected.

  • Saved pages are untrusted web content. Anything an agent reads from them is data, not instructions.

Model license

IMPORTANT

This project's code is Apache 2.0, but the Pulpie model it downloads,feyninc/pulpie-orange-small, is licensed CC BY-NC 4.0. That means non-commercial use only. The pulpie Python library itself is Apache 2.0. If you want to use this in a commercial product, check the model license with Feyn first.

pulpie-mcp doesn't bundle or redistribute the model weights. They're downloaded from Hugging Face on your machine.

Development

uv sync
uv run pytest

The integration test runs the real backend and model against a live page, so it's skipped unless you opt in:

PULPIE_INTEGRATION=1 uv run pytest tests/test_integration.py

License

Apache 2.0. See LICENSE.

Pulpie is made by Feyn.

Made with 💖 by Pink Pixel

Available Tools

5 tools
crawl_docsB

Crawl a documentation site and save every page as Markdown, plus an index.md.

NameRequiredDescriptionDefault
urlYesWhere to start, usually the docs home page.
directoryNoAbsolute folder to save into. Use a folder inside the user's project for project reference docs. Leave empty to use the global library.
max_pagesNoStop after this many pages.
path_prefixNoOnly crawl URLs whose path starts with this, like /docs/. Defaults to the start URL's path, so pass a broader prefix when starting from a page deep inside the docs.

Output Schema

NameRequiredDescription
resultYes

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It discloses the output artifact (Markdown files plus index.md) but says nothing about rate limiting/politeness, robots handling, overwrite or failure behavior, or what happens on partial crawls — significant gaps for a tool that writes many files to disk.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence stating action and output with zero filler. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value explanation is correctly omitted, and the schema fully documents inputs. However, in a five-sibling docs/fetch/save library, the description omits the routing information (crawl-site vs fetch-single-page) and crawl-scope behavior that an agent needs to pick this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and every parameter (url, directory, max_pages, path_prefix) is well documented with defaults and rationale in the schema itself. The description adds nothing about parameters, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (crawl), a specific resource (a documentation site) and the concrete outcome (every page saved as Markdown plus index.md). It clearly distinguishes the action from the sibling names fetch_markdown/save_markdown/list_library, though it never explicitly contrasts itself with them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance, no alternatives, and no exclusions. It never tells the agent to prefer this over fetch_markdown for a single page, or when a crawl is inappropriate (e.g., huge sites, auth-protected docs). Usage is only loosely implied by the word 'crawl'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fetch_markdownA

Fetch a web page and return its main content as Markdown, without saving it.

NameRequiredDescriptionDefault
urlYesThe http(s) URL to read.
max_charsNoCut the Markdown off after this many characters.

Output Schema

NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses that the tool fetches and converts to Markdown without saving, but doesn't mention potential limitations such as handling of paywalls, authentication, rate limits, or the fact that only main content is extracted (implying some content may be omitted). The presence of an output schema means return format details are covered, but operational behavior remains underspecified.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that front-loads the core action and includes a key differentiator. Every part earns its place with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (2 parameters, output schema exists), the description is nearly complete. It covers the main purpose and the no-save behavior. A minor gap is the lack of explicit guidance on when to use this versus similar tools, but for a straightforward fetch operation this is acceptable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema fully documents the parameters (url and max_chars). The description adds no further parameter details. Baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb ('Fetch') and resource ('a web page'), and specifies the transformation ('return its main content as Markdown'). The contrast with sibling 'save_markdown' is evident from the phrase 'without saving it', making it unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly differentiates from 'save_markdown' by stating 'without saving it', which tells the agent this tool is for when the content is needed temporarily or for processing. However, it doesn't provide explicit when/when-not guidance or mention alternatives like 'crawl_docs'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_libraryB

List Markdown docs saved by pulpie, with their source URL and fetch time.

NameRequiredDescriptionDefault
queryNoOnly show docs whose title, URL, or path contains this.
directoryNoAbsolute folder to list. Leave empty to list the global library.

Output Schema

NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose the return payload (source URL and fetch time), which clarifies this is a read-only listing. However it says nothing about ordering, result limits, or that a query narrows results rather than replacing the list. Adequate but thin for a zero-annotation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence that identifies the actor (pulpie), the resource, and the returned fields with zero filler. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple (2 optional params, no nesting) and both an output schema and full parameter descriptions exist, so the description needn't explain returns. It is nearly complete, missing only a statement about result scope/ordering or how it relates to search_library.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both 'query' (title/URL/path substring match) and 'directory' (absolute folder vs global library) are already fully documented in the schema. The description adds no parameter meaning beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('List') and a specific resource ('Markdown docs saved by pulpie') and names the returned fields. It does not explicitly differentiate itself from the closely-named sibling search_library, leaving the list-vs-search boundary to inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance is given. The nearby sibling search_library handles filtered retrieval and the tool itself accepts a 'query' filter, but the description never says when to call this instead of search_library or whether this returns the entire library. The agent must infer usage from the name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

save_markdownB

Fetch a web page and save its main content as a Markdown file. Returns the path and outline.

NameRequiredDescriptionDefault
urlYesThe http(s) URL to save.
filenameNoOptional file name. Defaults to one built from the URL path.
directoryNoAbsolute folder to save into. Use a folder inside the user's project for project reference docs. Leave empty to use the global library.

Output Schema

NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It correctly signals a two-part side effect (network fetch + file write) and mentions the return shape, but omits overwrite semantics, whether directories are created, and failure behavior for unreachable URLs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the primary action and followed by the return value. No filler whatsoever.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the brief return note is a bonus rather than a requirement, and the params are fully covered by the schema. The remaining gap is the absence of routing guidance relative to the four sibling tools for a write operation with no annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters (including the global-vs-project distinction for directory) are already documented. The description adds no parameter-level detail beyond the schema, which is the expected baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb (save) and resource (web page main content as Markdown file), plus a brief note on what it returns. It is distinguishable from fetch_markdown by the word 'save', but the description never explicitly contrasts the two, so an agent must infer the persistence difference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to use this versus fetch_markdown, crawl_docs, or the library tools, and no prerequisites or exclusions. Usage must be inferred entirely from the tool name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_libraryA

Search saved docs by content. Returns the best matching sections with their file paths.

NameRequiredDescriptionDefault
siteNoOnly search docs from this host, like react.dev.
limitNoMost sections to return.
queryYesWords to look for, like 'useEffect cleanup'.
directoryNoAbsolute folder to search, like a project's DOCS/reference. Leave empty to search the global library.

Output Schema

NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the return shape ('best matching sections with their file paths'), which hints at ranked/sectioned results, but says nothing about read-only semantics, ranking behavior, or result truncation beyond what the schema's limit already encodes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero waste, with the core action front-loaded and the return behavior second. Nothing is redundant or padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained in detail, and the annotations-less safety profile is low-risk for a search tool. The description is adequate, though it could note that results come from the previously saved/crawled library rather than the live web.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so site, limit, query, and directory are all documented in the schema with examples. The description adds no parameter-level detail, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource - searching saved docs by content - and adds scope via 'saved docs' versus the live-web sibling crawl_docs. It does not explicitly distinguish itself from list_library, but the 'by content' framing makes the retrieval style clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by 'search saved docs by content', and the schema note about leaving directory empty implies a global-library fallback. However, no alternative tool is named and no when-not-to-use condition is given, so an agent must infer that list_library covers enumeration and fetch_markdown covers retrieval.

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.

  1. 5 tool updatesv0.1.0
    • First observedcrawl_docs
    • First observedfetch_markdown
    • First observedlist_library
    • First observedsave_markdown
    • First observedsearch_library

TDQS

A3.7/5.0

Scored across 5 tools

Disambiguation4/5

fetch_markdown and save_markdown are the only pair with overlapping purposes, but the save/no-save distinction is clearly stated. list_library, search_library, and crawl_docs each target a distinct operation with no real ambiguity.

Naming Consistency5/5

All five tools follow a clean verb_noun snake_case pattern (fetch_markdown, save_markdown, crawl_docs, list_library, search_library). The convention is applied uniformly and reads predictably.

Tool Count5/5

Five tools is a tight, well-scoped set for a fetch/save/search docs server. Each tool earns its place with no redundancy.

Completeness4/5

The lifecycle covers fetch, persist, bulk-crawl, browse, and search. Minor gaps exist: no tool to delete or remove a saved doc, and no direct read of a specific saved file, but these are workaroundable.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    An MCP server for web content extraction that converts HTML pages into clean, LLM-optimized Markdown using Mozilla's Readability. It supports batch processing, intelligent multi-page crawling, and configurable caching while respecting robots.txt standards.
    32 npm
    -
  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    An MCP server that extracts clean, structured Markdown content from web page URLs using the WebforAI library. It simplifies feeding web content into AI models by removing HTML noise and intelligently processing tables and links.
    -