{
  "markdown": "# frugal\n\n**The open routing layer for AI tools.**\n\nFrugal is an MCP server that sits between your agent and its tool\nproviders. You describe the job — a search, an extraction, a render, or\njust an intent — and Frugal decides how to complete it, routing each call\nper policy: cheapest capable provider by default, fastest or premium when\nyou say so, pinned or denied when compliance says so, with automatic\nfailover when a provider errors or comes up empty. Every response carries\nthe decision — `provider_used`, `cost_usd`, and (via `frugal__execute`) a\none-line reason — so you can audit why each call went where it did.\n\nWorks with any model. One Go binary. Your keys. No account. Self-host\neverything, no lock-in. Source-available (BUSL 1.1 → Apache 2.0).\n\nInstall to first intelligently routed tool call: under five minutes.\n\n[frugal.sh](https://frugal.sh)\n\n## Install\n\n```bash\ncurl -fsSL https://frugal.sh/install | bash\nfrugal mcp install\n```\n\nThe first command drops the binary in your `$PATH`. The second auto-detects\nClaude Desktop, Cursor, AnythingLLM, and Claude Code and merges `frugal`\ninto each configured MCP server list.\n\n### AnythingLLM\n\n`frugal mcp install` finds AnythingLLM Desktop on its own and merges\n`frugal` into `<storage>/plugins/anythingllm_mcp_servers.json`. For a\nself-hosted or Docker AnythingLLM, point the installer at that instance's\nstorage directory (the same path its own `STORAGE_DIR` uses):\n\n```bash\nANYTHINGLLM_STORAGE_DIR=/path/to/anythingllm/storage frugal mcp install --client anythingllm\n```\n\nRestart AnythingLLM, then look for **frugal** under Agent Skills → MCP\nServers. The tools load for agent sessions, so call them from an `@agent`\nchat. In Docker, the `command` path must resolve *inside* the container —\nmount the `frugal` binary in, or run `frugal mcp serve --http` on the host\nand register it as a `streamable` server instead.\n\n## Try it now (no keys)\n\nSearch and extract work out of the box: **Marginalia** (free index of the\nindie / non-commercial web), **Wikipedia** (free Wikimedia REST search),\nand **go-readability** (free, pure-Go local extractor) ship enabled with\nzero configuration. This is the default `cheap` policy at work — free and\nlocal rungs first, failover when a provider comes up empty. Captured from\na live zero-key run:\n\n```\nfrugal__search {\"query\": \"AI agent framework comparison\", \"max_results\": 3}\n\n  stderr › search zero hits; falling back  provider=marginalia latency_ms=529\n  result › {\n    \"provider_used\": \"wikipedia\",\n    \"cost_usd\": 0,\n    \"latency_ms\": 954,\n    \"results\": [\n      {\"title\": \"Gemini Enterprise Agent Platform\", \"url\": \"https://en.wikipedia.org/wiki/Gemini_Enterprise_Agent_Platform\", ...},\n      {\"title\": \"Perplexity AI\", \"url\": \"https://en.wikipedia.org/wiki/Perplexity_AI\", ...},\n      {\"title\": \"Agentic commerce\", \"url\": \"https://en.wikipedia.org/wiki/Agentic_commerce\", ...}\n    ]\n  }\n```\n\nHonest limits: Marginalia is genuinely good for essays, docs, blogs, and\nniche technical writing, and weak on mainstream news and product pages;\nWikipedia covers entities and reference topics. Zero-key mode is a real\nworkflow for research and local extraction — it is not a Google-grade\nSERP. One env var changes that: `SEARXNG_URL` (free, self-hosted) or\n`SERPER_API_KEY` ($0.001/call) gives the chain a stronger rung to fall to.\n\n## Routing policies\n\nDeclare per capability how the provider chain is ordered, in\n`~/.frugal/config/models.yaml`:\n\n```yaml\nrouting:\n  search:\n    strategy: fast            # cheap (default) | fast | premium\n    deny: [youcom]            # never called — not by fallback, not even pinned\n  extract:\n    order: [firecrawl, goreadability]  # explicit preference; unlisted providers still fall back\n```\n\n- **cheap** (default) — effective cost ascending, quota-aware; automatic\n  failover up the ladder.\n- **fast** — ordered by your machine's own observed latency (from the\n  local usage ledger, successful calls only). Falls back to cost order\n  until enough history exists. Not a live probe.\n- **premium** — prefers your premium-priced providers, list price\n  descending.\n- **order** — an explicit preference list. It's a prefix, not a\n  whitelist: unlisted providers still serve as fallback.\n- **deny** — providers that must never be called. Enforced on pinned\n  calls too; this is the honest privacy knob (e.g. deny every paid\n  provider and nothing leaves your free/local rungs).\n\nEvery call chain logs which policy ran, and `frugal__execute` returns it\nin the response.\n\n## Spend caps and rate-limit cooldown\n\nTwo guardrails cap what a provider can cost you, enforced in the routing\nlayer alongside the policy above:\n\n```yaml\nsearch_providers:\n  youcom:\n    api_key_env: YDC_API_KEY\n    cost_per_call: 0.005\n    daily_budget_usd: 2.50   # skip youcom once it has spent $2.50 today\n\nrouting:\n  cooldown: 90s              # after a 429, skip that provider for 90s (default 60s)\n```\n\n- **daily_budget_usd** (per provider, any of the three tables) — once a\n  provider's spend for the current UTC day reaches this cap, the router\n  skips it and falls through to the next provider in the chain; a call\n  that pins it by name errors. Counters reset at UTC midnight. Zero or\n  absent means no cap. The same provider name under two capability tables\n  gets an independent budget.\n- **cooldown** (top level under `routing:`) — when a provider returns a\n  rate limit (HTTP 429), it is fenced off for this long so the chain\n  stops hammering it. A Go duration string like `90s` or `2m`; an invalid\n  value warns at startup and falls back to the 60s default. Applies to\n  every provider, capped or not.\n\nWhen a guardrail skips a provider it is noted in the routing trace\n(`; budget: skipped youcom (...)`) and logged at Warn. If every provider\nin a chain is over budget or cooling down, the call fails with a clear\nmessage rather than silently doing nothing.\n\n## Describe the job: `frugal__execute`\n\nInstead of picking a tool, an agent can state the intent and a priority.\nFrugal classifies it onto a capability (URL and keyword cues —\ndeterministic, no model call) and routes under your policy. Captured from\na live zero-key run:\n\n```\nfrugal__execute {\"intent\": \"search for MCP server security best practices\"}\n\n  stderr › search zero hits; falling back  provider=marginalia latency_ms=273\n  result › {\n    \"capability\": \"search\",\n    \"provider_used\": \"wikipedia\",\n    \"cost_usd\": 0,\n    \"latency_ms\": 650,\n    \"reason\": \"routed to a web search; policy=cheap: effective cost ascending; provider=wikipedia won on attempt 2\",\n    \"results\": [\n      {\"title\": \"ChatGPT\", \"url\": \"https://en.wikipedia.org/wiki/ChatGPT\", ...},\n      ...\n    ]\n  }\n```\n\n`priority: \"cheap\" | \"balanced\" | \"premium\"` maps onto the policies above\n(`balanced` defers to your configured strategy). A URL intent runs an\nextract and falls forward to a headless render when the page needs JS,\nwith the costs summed. The `reason` field is the receipt: what was\ndecided, under which policy, and which provider won on which attempt.\nThe direct tools (`frugal__search`, `frugal__extract`, `frugal__browse`)\nremain for callers that already know the capability.\n\n## See what you kept\n\nCost is Frugal's flagship policy, and the receipt is its proof. Every\ncall lands in a local ledger (`~/.frugal/usage`, JSONL, never leaves\nyour machine; `FRUGAL_STATS=off` disables it). `frugal stats` prints the\nmonth's receipt:\n\n```\nfrugal receipt · July 2026 (UTC)\n────────────────────────────────────────────────\ntool      provider            calls         paid\nsearch    marginalia              1      $0.0000\nsearch    wikipedia               1      $0.0000\nextract   goreadability           1      $0.0000\n────────────────────────────────────────────────\ntotal                             3      $0.0000\n\nsame calls at premium rack rate*         $0.0060\nyou paid                                 $0.0000\n────────────────────────────────────────────────\nyou saved                      $0.0060   (100%)\n────────────────────────────────────────────────\n* rack rate = list price of each capability's premium\n  provider, snapshotted at call time. failed calls excluded.\n```\n\nOnly the call that actually produced your result earns rack credit —\nfallback attempts and zero-hit whiffs don't inflate the number.\n\n## Set your keys (optional)\n\nAdd keys to unlock stronger paid providers. Frugal reads them from your\nenvironment and only registers tools whose providers are configured:\n\n```bash\n# Search — frugal__search\nexport SEARXNG_URL=...           # free, self-hosted (Marginalia + Wikipedia need no key)\nexport SERPER_API_KEY=...        # cheap paid\nexport YDC_API_KEY=...           # premium paid (You.com)\n\n# Extract — frugal__extract (goreadability is free, no key)\nexport FIRECRAWL_API_KEY=...     # premium paid (JS-rendered pages)\n\n# Browse — frugal__browse\nexport BROWSERLESS_TOKEN=...     # headless render\n```\n\nThat's it. Restart your agent. Only the tools whose providers are\nconfigured get registered.\n\n## The routing table\n\nTool prices haven't fallen the way model prices have. You.com at $0.005/call\nis 5× Serper at $0.001/call. SearXNG, running on your own machine, is free.\n\n| Capability | Free / local | Cheap paid | Premium paid | Status |\n|---|---|---|---|---|\n| Search | **SearXNG** · **Marginalia** · **Wikipedia** | **Serper** $0.001/call | **You.com** $0.005/call | **shipping** |\n| Extract | **go-readability** (local) | — | **Firecrawl** $0.001/page | **shipping** |\n| Browse | local Playwright *(deferred)* | **Browserless** $0.002/render | Browserbase *(planned)* | *partial* |\n| Code exec | local Docker | E2B ~$0.10/hr (2 vCPU) | Modal | planned |\n| Embeddings | nomic-embed-text, bge-large | text-embedding-3-small $0.02/1M tok | 3-large, Voyage-3, Cohere | planned |\n| Transcription | whisper.cpp | Deepgram Nova $0.0043/min | OpenAI Whisper $0.006/min | planned |\n\nUnder the `cheap` policy Frugal walks the columns left to right and you\nkeep the gap; `fast` and `premium` reorder the walk; `deny` fences\ncolumns off entirely. Cost is one policy among several — but it's the\none with a receipt.\n\n## What ships today\n\nOne MCP server, four tools, eight providers:\n\n- **`frugal__execute`** — **shipping**. Describe the job (`intent`,\n  optional `priority`); heuristic classification onto a capability, then\n  policy-routed. Returns the full routing trace (`capability`,\n  `provider_used`, `cost_usd`, `reason`).\n- **`frugal__search`** — **shipping**. Routed across **SearXNG** (free,\n  self-hosted), **Marginalia** (free, public), **Wikipedia** (free,\n  public), **Serper** (`$0.001/call`), and **You.com** (`$0.005/call`).\n  When a free provider returns zero hits the chain falls through to the\n  next rung; a paid provider returning zero hits ends the chain (the\n  query has no hits — no point paying a pricier provider to confirm).\n- **`frugal__extract`** — **shipping**. Routed across **go-readability**\n  (free, pure-Go local Readability) and **Firecrawl** (`~$0.001/page`,\n  JS-rendered).\n- **`frugal__browse`** — *partial*. **Browserless** (`~$0.002/render`,\n  headless Chrome) shipping; local Playwright deferred.\n- **Routing policies** — **shipping**. Per-capability `strategy`\n  (cheap / fast / premium), explicit `order`, `deny` lists.\n- **`frugal stats`** — the local savings receipt (see above).\n- Stdio + Streamable HTTP transports.\n- HTTP transport supports bearer-token auth (`FRUGAL_AUTH_TOKEN`),\n  per-IP rate limiting, and a `/metrics` endpoint (Prometheus text:\n  `frugal_calls_total{tool=,provider=}` etc.).\n- `frugal mcp install` writes the right config into Claude Desktop,\n  Cursor, AnythingLLM, and Claude Code.\n\n## Roadmap\n\n- **Phase 3** — embeddings, transcription, code execution, local chat\n  models, semantic cache.\n- **Phase 4 — Frugal Cloud** *(not shipped — waitlist open)*. The binary\n  stays local and self-hostable; Cloud adds the team layer on top:\n  - Hosted policy management (edit routing policies in a dashboard,\n    deploy to every app)\n  - Team workspaces and shared policy templates\n  - Usage analytics and cost reporting across the org\n  - Provider health monitoring and routing traces\n  - Org-wide API key management\n\n  Everything in Phase 4 is roadmap, not product. The open router never\n  requires it — no lock-in.\n  [Join the waitlist](mailto:sparker@hey.com?subject=Frugal%20Cloud%20waitlist)\n\n## From source\n\n```bash\ngit clone https://github.com/brainsparker/frugal.git && cd frugal && make build\n```\n\n## License\n\n[BUSL 1.1](./LICENSE) — self-hosting and internal commercial use are\npermitted. Each release converts to Apache 2.0 four years after publication.\nPlain-English summary in [LICENSE-BUSL-FAQ.md](./LICENSE-BUSL-FAQ.md).\n\n## Security\n\nPrivate vulnerability reports via [GitHub Security\nAdvisories](https://github.com/brainsparker/frugal/security/advisories/new).\nFull policy in [SECURITY.md](./SECURITY.md).\n",
  "bytes": 12865,
  "sha": "eeaf969c2a642fa53ca2a689eada0211443a3765244545ad27611c7c3241fb12",
  "repo_slug": "brainsparker/frugal",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_brainsparker_frugal_95ba3740/readme"
}