MCP servers for apfel

Give apfel web access.
One tool call.

⚡ Built for the 4096-token context window

Three MCP servers that plug into apfel (Apple's on-device LLM CLI) and give it the one thing the 3B model can't do on its own: read the live web. Token-budget optimized, aggressively truncated, one brew install.

MIT Open Source 3 Python stdio servers macOS 26 Tahoe Works with apfel
vs. chaining separate tool calls

One call. Not three.

Most MCP bundles give you a search and a fetch tool and expect the model to chain them. In apfel's 4096-token context window, every extra tool call costs schema and conversation tokens you can't afford. apfel-mcp ships a compound search_and_fetch that does the whole round in a single call.

apfel-mcp separate search + fetch
Tool-call round-trips per answer 1 2-3
Schema tokens per turn (2 schemas vs 1) ~200 ~450
Tool-result hard cap (fits the context) 5000 chars unbounded
Readability article extraction
SSRF blocklist (private networks) ?
Tolerates model arg-key hallucinations
Works with apfel out of the box ?

Numbers are from real measurements in apfel's 4096-token budget. Each MCP tool schema costs ~200-250 tokens in the prompt every turn; chaining two separate tools means the model pays that cost twice, plus the intermediate tool-call JSON in conversation history. The compound tool collapses the whole thing into one round-trip.

Real sessions

Seven recorded runs. Zero edits.

Every terminal below is a real apfel --chat session I ran before publishing. Tool calls, raw tool output, model answers - all copied verbatim. No cloud. No cherry-picked best-of-N. The compound tool handles it in one round-trip.

How it works

Install, attach, ask.

Three binaries on your PATH. Attach one (or all three) to apfel with --mcp and the 3B model picks up the tools automatically.

1

brew install

One tap, one install. Three console scripts land on your PATH: apfel-mcp-url-fetch, apfel-mcp-ddg-search, apfel-mcp-search-and-fetch.

2

Attach to apfel

Pass the binary path with apfel --mcp $(which apfel-mcp-search-and-fetch). apfel launches the MCP as a stdio subprocess and discovers its tools.

3

Ask anything

The on-device 3B model decides when to call the tool, reads the truncated result, and answers. One round-trip. No cloud. Your question stays on your Mac. Only the target URLs get fetched.

What you get

Three MCP servers.

Each one ships as a standalone binary and a Python module. Attach one, two, or all three. Shared infrastructure for caching, arg-tolerance, SSRF guards, and token-budget truncation.

Fetch

apfel-mcp-url-fetch

Fetch an http(s) URL, extract the main article body with Readability, drop navigation and ads with BeautifulSoup, convert to Markdown, return the cleaned result.

Readability + BS4 SSRF blocklist 6000-char cap 2 MB download limit
Search

apfel-mcp-ddg-search

DuckDuckGo web search via a direct httpx + BeautifulSoup HTML scrape. No API key. Unofficial and experimental - see the README for the honest caveats.

httpx + BS4 60s cache 2000-char cap Rate-limit aware
Flagship

apfel-mcp-search-and-fetch

Search DDG AND fetch the top N result pages in ONE tool call. Saves ~500 tokens of schema/state overhead vs chaining separate tools. Declared as search and web_search so the 3B model's hallucinated names still route.

Compound tool 5000-char cap Partial-failure OK Default 2 results
Before you install

Requirements

apfel-mcp plugs into apfel. You need apfel working first.

apfel installed

Install apfel with brew install Arthur-Ficial/tap/apfel. Requires macOS 26 Tahoe, Apple Silicon, Apple Intelligence enabled.

macOS 26 (Tahoe)

Required by apfel for Apple Intelligence. apfel-mcp itself runs on any macOS with Python 3.10+.

Internet access (at call time)

The MCPs hit the open web when the model calls them. apfel itself still runs 100% on-device. Your prompts never leave your Mac.

Privacy note: apfel-mcp never sees your prompts. It only receives the URL or search query the model decides to pass. The URL target gets a normal HTTP request from your Mac. No proxy, no third party, no telemetry.
Install

Get apfel-mcp

Free. MIT-licensed. One brew install installs all three MCPs.

Homebrew (recommended)

Installs three console-script binaries to /opt/homebrew/bin. One formula, all three MCPs.

brew install Arthur-Ficial/tap/apfel-mcp

Updates with brew upgrade apfel-mcp. Formula source lives in Arthur-Ficial/homebrew-tap.

After installing

  1. Confirm the binaries are on your PATH: which apfel-mcp-url-fetch
  2. Attach one to apfel: apfel --mcp $(which apfel-mcp-search-and-fetch)
  3. Ask a question that needs the web: "use the search tool to find what macOS Tahoe is"
  4. apfel launches the MCP as a stdio subprocess automatically
  5. The 3B model calls the tool, reads the result, and answers
  6. Attach multiple --mcp flags to stack tools in one session
Other install options

Pip

pip install apfel-mcp

From source: git clone + pip install -e .. Requires Python 3.10+.

Python -m

python -m apfel_mcp.url_fetch_server

Run directly without a console script. Useful for MCP Inspector.

MCP Inspector

npx @modelcontextprotocol/inspector \
  apfel-mcp-search-and-fetch

Official interactive testing UI for MCP servers.

Under the hood

Built for apfel's 4096-token window.

apfel-mcp exists because apfel's context budget is 4,096 tokens, most of which is already consumed by the system prompt, tool schemas, and conversation history. Every tool result has to earn its place. These MCPs are engineered from the ground up to return small, useful output - not to truncate afterward.

What we optimize

  • Hard caps per tool. url-fetch: 6000 chars. ddg-search: 2000 chars. compound: 5000 chars. The model's budget never gets blown by a single tool result.
  • Readability + BS4 tag-strip. Two-pass extraction drops nav, footer, script, and form tags before Markdown conversion. We keep the 4000 chars that matter.
  • Arg-key tolerance. The 3B model invents argument names constantly. A shared extractor accepts query, q, term, topic, or any reasonable string under any key that isn't clearly a count.
  • Dual tool-name declaration. The compound tool appears as both search and web_search in tools/list so the model's hallucinated names still dispatch correctly.
  • 60s in-memory cache. Repeated queries in a session don't re-hit DDG.

Honest limitations

  • DDG is unofficial. DuckDuckGo has no public web-search API. We scrape the HTML endpoint. Expect occasional rate-limit or bot-challenge errors. Same framing as OpenClaw's DDG extension.
  • JS-heavy sites. Readability only sees the initial HTML. Pages that render content via JavaScript after load return thin extracts. No headless browser.
  • English results bias. DDG's region is set to wt-wt but the result quality varies by topic.
  • No authentication. url-fetch does not attach cookies or auth headers. Public URLs only.
  • SSRF blocklist is opt-out-able. Private networks (10.0.0.0/8, 127.0.0.0/8, etc.) are blocked by default. Set URL_FETCH_ALLOW_PRIVATE_NETWORKS=1 for local dev.
Open for contributions

Build more apfel-optimized MCPs.

apfel-mcp is designed as a home for token-budget-aware MCPs. If you have an idea for one that fits apfel's 4096-token window, open an issue or a PR. The shared common/ module gives you budget enforcement, JSON-RPC stdio, SSRF-safe fetch, arg tolerance, and a test harness to build on.

#agentswelcome

AI agent contributions welcome.

Claude Code, Codex, Cursor, Aider, any autonomous coding agent - if you can read CLAUDE.md, run pytest, and open a pull request, you can ship an apfel-mcp. The contribution rules below were written to be unambiguous enough for an agent to follow without human translation. Credit your tool in the commit trailer (Co-Authored-By: Claude Sonnet 4.6 <[email protected]>), include a passing test suite, and submit. Humans and agents review on the same bar: token budget first, tests second, honesty about limits third.

Ideas we'd love to see

None of these exist yet. All welcome as issues or PRs. Each one should land with tests, a hard token cap, and honest documentation of its limits.

Data

sqlite-query

Read-only SQL query over a local SQLite file. Result row count capped, output truncated.

Code

git-log

Query a local git repo: recent commits, file blame, branch info. Read-only, no writes.

Docs

man-page

Fetch a section of a man page or built-in help text. 3000-char hard cap.

Files

fs-read

Read a bounded slice of a local file with path allowlist, byte cap, and no writes.

Time

datetime

Current date, timezone conversion, relative date parsing. Tiny, fast, always useful.

Shell

safe-shell

Allowlisted read-only shell commands (df, uname, uptime, ps) with output truncation.

Propose an MCP

Contribution rules

  1. Token budget first. Pick a hard cap before writing code. 2000-6000 chars is the sweet spot for apfel.
  2. Test-driven. Write failing tests before the implementation. Mock all network and subprocess calls.
  3. Use common/. Reuse budget.truncate_to, mcp_protocol.run_server, arg_tolerance.extract_string. Don't reinvent.
  4. Honest limits. Document exactly where the MCP stops being useful, in the tool description and the README.
  5. One tool, one purpose. Don't build multi-tool mega-servers. Compound tools are the exception - they exist to save round-trips, not to add features.
  6. No persistence. In-memory caches are fine. SQLite databases are not.

Free and open source.

MIT-licensed. Use it, fork it, ship it. Bug reports, pull requests, and new MCP ideas all welcome.