{
  "markdown": "# espresso-mcp\n\n[![npm version](https://img.shields.io/npm/v/espresso-mcp?logo=npm&color=cb3837)](https://www.npmjs.com/package/espresso-mcp)\n[![npm downloads](https://img.shields.io/npm/dm/espresso-mcp?logo=npm)](https://www.npmjs.com/package/espresso-mcp)\n[![MCP Registry](https://img.shields.io/badge/MCP%20Registry-listed-3b82f6?logo=anthropic)](https://registry.modelcontextprotocol.io)\n[![code license](https://img.shields.io/badge/code-MIT-green)](LICENSE)\n[![data license](https://img.shields.io/badge/data-CC--BY--4.0-blueviolet)](data/LICENSE)\n\n> An MCP server that finds great espresso cafes — and codifies what makes them great.\n\n`espresso-mcp` is a [Model Context Protocol](https://modelcontextprotocol.io) server you can plug into Claude Desktop, Claude.ai, ChatGPT, Google Gemini, Cursor, Hermes, OpenClaw, and any other standard MCP host. It ships with a curated database of 100+ specialty-coffee shops, 75+ specialty roasters, and a transparent scoring algorithm that captures *why* a shop is good — sourcing, freshness, equipment, training — and *why* a shop is bad (the heaviest negative signal: menus dominated by flavored syrups).\n\nIt is **not** a Yelp clone. The data is hand-curated, the scoring is explicit, and the philosophy is \"if it's covering bad coffee with flavors, we don't want it.\"\n\n---\n\n## The bias\n\nespresso-mcp has an opinion. Shops that hide bad coffee behind flavored syrups are the failure pattern this tool is designed to filter out. The scoring algorithm gives `syrup_emphasis` the heaviest non-disqualifying penalty (−22) — heavier than any single positive signal. Mass-market chains (Starbucks, Dunkin', Costa, Tim Hortons, Peet's, Caribou) and \"looks third-wave but tastes flavored\" shops (the algorithm's `flavor-led-specialty` category) score in `avoid` or `fair` tier regardless of how good the signage looks.\n\nPositive credit goes to the signals great shops actually invest in:\n\n- In-house roasting, or named-partner sourcing from a known specialty roaster\n- Single-origin espresso (not just blends)\n- Roast date on retail bags (peak-freshness commitment)\n- Espresso + pour-over both offered — the \"complete program\"\n- Cortado on the menu — a confidence proxy; shops avoid small milk drinks when their espresso can't hold up\n- Competition involvement / SCA-certified staff\n- Equipment from the third-wave shortlist (Slayer, La Marzocco, Synesso, Decent, Victoria Arduino, Modbar)\n- Recognition from authoritative rankings (World's 100 Best, SCA championships, Coffee Review 95+, Good Food Awards)\n\nEvery signal is documented at [`src/scoring/weights.ts`](src/scoring/weights.ts) and surfaced to clients via the score breakdown on every result — you can see exactly *why* a cafe is recommended.\n\n---\n\n## See it in action\n\n```\nYou: I'm near Brandenburg Gate in Berlin. Find me 3 great espresso cafes \n     within walking distance.\n\nClaude: [resolves Brandenburg Gate → 52.5163, 13.3777]\n        [calls find_espresso_near with radius_km=2]\n\n  Found 3 specialty cafes within 2km of Brandenburg Gate, sorted by quality:\n\n  • The Barn (Mitte)         — 0.8km — score 95 (world-class) — World's #61\n    In-house roastery, single-origin focus, \"never blends beans.\" Founded \n    2010, one of Europe's leading third-wave roasters.\n\n  • Companion Coffee (Mitte) — 1.1km — score 83 (great)\n    Curated multi-roaster with rotating guest beans. Tea + coffee crossover \n    in a quiet Mitte design space.\n\n  • Westberlin (Mitte)       — 1.3km — score 82 (great)\n    Iconic third-wave anchor since ~2010. Magazine + coffee concept; pours \n    The Barn and rotating European roasters.\n```\n\n---\n\n## What it does\n\nOnce installed in your MCP client, you can ask things like:\n\n- *\"I'm at the Hotel Adlon Berlin — find me great espresso within walking distance.\"*\n- *\"I'm staying near the Brandenburg Gate. Recommend 3 cafes and rank by quality.\"*\n- *\"Search for cafes in Tokyo scoring above 80.\"*\n- *\"Tell me about Tim Wendelboe.\"*\n- *\"Score this cafe — they have a Slayer, in-house roasting, single-origin espresso, and no flavored syrups.\"*\n- *\"What are the world-class roasters in Denmark?\"*\n- *\"What should I avoid in Chicago? Show me an anti-pattern example.\"*\n\nThe model gets a structured score with reasoning, distance, awards, and per-signal contributions — enough to give you an honest recommendation rather than a popularity list.\n\n---\n\n## Quick install\n\n| Client | Section |\n|---|---|\n| Claude Desktop | [↓](#claude-desktop) |\n| Claude.ai (Browser MCP) | [↓](#claudeai-browser-mcp) |\n| ChatGPT | [↓](#chatgpt) |\n| Google Gemini CLI | [↓](#google-gemini-cli) |\n| Hermes (Nous Research) | [↓](#hermes-nous-research) |\n| OpenClaw | [↓](#openclaw) |\n| Cursor | [↓](#cursor) |\n| VS Code | [↓](#vs-code) |\n| Any standard stdio | [↓](#generic-stdio-client) |\n| From source | [↓](#from-source-development) |\n\n### Recommendation: use `@latest` while the project is iterating\n\nWhile we're still adding cafes and refining the algorithm, pin to the live npm tip:\n\n```jsonc\n\"args\": [\"-y\", \"espresso-mcp@latest\"]\n```\n\nOnce the data and scoring stabilize, you can drop `@latest` and pin a specific version for reproducibility.\n\n---\n\n## Per-client configuration\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows). If the file doesn't exist, create it:\n\n```json\n{\n  \"mcpServers\": {\n    \"espresso\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"espresso-mcp@latest\"]\n    }\n  }\n}\n```\n\nRestart Claude Desktop. The 🔌 menu should show 6 tools under \"espresso.\"\n\n### Claude.ai (Browser MCP)\n\nClaude.ai's web app supports MCP servers via OAuth and remote endpoints. For local installation, use Claude Desktop instead (above). To expose `espresso-mcp` to Claude.ai as a remote server, wrap it with `mcp-remote` (see the [ChatGPT](#chatgpt) section below — same approach).\n\n### ChatGPT\n\n⚠ **Important**: ChatGPT only supports **remote** MCP servers (HTTPS endpoints), not local stdio processes. You have two options:\n\n**Option 1: Use the hosted version (when available).** If we publish a hosted endpoint we'll list it here.\n\n**Option 2: Bridge `espresso-mcp` to HTTPS via `mcp-remote`.** Run a small bridge on a machine you control:\n\n```bash\nnpx -y mcp-remote bridge espresso-mcp \\\n  --port 8080 \\\n  --token \"your-shared-secret\"\n```\n\nThen expose port 8080 via a tunnel (Cloudflare Tunnel, Tailscale Funnel, or a small VPS) and use the resulting HTTPS URL.\n\n**Enabling MCP in ChatGPT** (Plus / Pro / Team / Enterprise plans only):\n\n1. Settings → **Connectors** → **Advanced** → toggle **Developer mode** on.\n2. Add a custom connector pointing at your bridge URL.\n\n[OpenAI's MCP docs](https://platform.openai.com/docs/mcp) have the latest connector setup.\n\n### Google Gemini CLI\n\nEdit `~/.gemini/settings.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"espresso\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"espresso-mcp@latest\"]\n    }\n  }\n}\n```\n\nRestart Gemini CLI. It will auto-connect at startup and show \"Connected\" if successful. See [Gemini CLI MCP docs](https://geminicli.com/docs/tools/mcp-server/) for the full reference.\n\n### Hermes (Nous Research)\n\nHermes uses YAML, not JSON. Edit `~/.hermes/config.yaml`:\n\n```yaml\nmcp_servers:\n  espresso:\n    command: \"npx\"\n    args: [\"-y\", \"espresso-mcp@latest\"]\n```\n\nOptional: filter to just the tools you want exposed:\n\n```yaml\nmcp_servers:\n  espresso:\n    command: \"npx\"\n    args: [\"-y\", \"espresso-mcp@latest\"]\n    tools:\n      include: [find_espresso_near, search_cafes, score_cafe]\n```\n\nRestart Hermes — it auto-discovers MCP tools at startup. See [Hermes MCP docs](https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp).\n\n### OpenClaw\n\nOpenClaw uses standard stdio MCP config. Install OpenClaw if you haven't:\n\n```bash\ncurl -fsSL https://openclaw.ai/install.sh | bash\n# or: npm install -g openclaw@latest\n```\n\nThen add to your OpenClaw config (typically `~/.openclaw/config.json` — check [OpenClaw MCP docs](https://docs.openclaw.ai/cli/mcp) for the current location):\n\n```json\n{\n  \"mcpServers\": {\n    \"espresso\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"espresso-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Cursor\n\nEdit `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"espresso\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"espresso-mcp@latest\"]\n    }\n  }\n}\n```\n\n### VS Code\n\nVS Code uses a dedicated `mcp.json` file (not `settings.json`). For workspace-scoped config, create `.vscode/mcp.json`. For user-wide, run the `MCP: Open User Configuration` command from the Command Palette.\n\n```json\n{\n  \"servers\": {\n    \"espresso\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"espresso-mcp@latest\"]\n    }\n  }\n}\n```\n\nNote: VS Code uses the key `servers` (not `mcpServers`) — this is the most common copy-paste mistake when migrating configs from other clients.\n\n### Generic stdio client\n\nFor any MCP-compatible host that spawns local processes:\n\n```jsonc\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"espresso-mcp@latest\"]\n}\n```\n\nThe server writes JSON-RPC to stdout and logs to stderr only — capture stderr if you want startup messages.\n\n### From source (development)\n\n```bash\ngit clone https://github.com/mattgierhart/espresso-mcp\ncd espresso-mcp\nnpm ci\nnpm run build\n\n# Point your client at:\n#   command: node\n#   args:    [\"/absolute/path/to/espresso-mcp/dist/index.js\"]\n```\n\nOr run the MCP Inspector against the local build:\n\n```bash\nnpm run inspect\n```\n\n---\n\n## Travel & address-based queries\n\nThe most common real-world question is *\"I'm at X, where should I get coffee?\"* Here's the pattern in practice.\n\n### Hotel-based recommendation\n\n```\nYou: I'm staying at the Hotel Adlon Berlin. Find me 3 great espresso cafes nearby.\n\n[Claude searches for the Adlon's coordinates: ~52.5163, 13.3795]\n[Claude calls find_espresso_near with those lat/lon]\n[Returns ranked Berlin cafes within walking distance]\n```\n\nThe model resolves the address to coordinates (using its built-in knowledge or a web search), then calls `find_espresso_near`. No extra config needed.\n\n### Address-based query\n\n```\nYou: I'm walking around Millennium Park in Chicago. What's the closest specialty espresso?\n\n[Claude resolves the landmark → ~41.882, -87.622]\n[Calls find_espresso_near with radius_km: 2]\n[Ranks results by quality, then distance]\n```\n\n### Multi-city trip planning\n\n```\nYou: I have trips coming up to Tokyo, Berlin, and Hong Kong. Build me a coffee plan —\n     top 2 cafes per city, plus the one roaster I should buy beans from in each.\n\n[Claude calls search_cafes for each city, sorts by score]\n[Calls list_great_roasters filtered by country]\n[Composes a per-city itinerary]\n```\n\n### Score what you're looking at right now\n\n```\nYou: I'm at a cafe with a Slayer machine, they roast on-site, single-origin espresso \n     option, roast date on bags, and they only have plain milk drinks — no syrups. \n     Score it.\n\n[Claude calls score_cafe with those signals]\n[Returns 95/100 (\"world-class\") with per-signal contributions]\n```\n\n### Hotel coffee-walkability comparison (manual, until v0.4)\n\nYou can do this today with multiple tool calls:\n\n```\nYou: Compare these Berlin hotels by walkable specialty coffee:\n     - Hotel Adlon (Mitte)\n     - Soho House Berlin (Mitte)\n     - 25hours Hotel Bikini (Charlottenburg)\n\n[Claude calls find_espresso_near three times, one per hotel]\n[Composes a comparison table]\n```\n\nA dedicated `score_hotel_coffee_access` tool is on the [roadmap](https://github.com/mattgierhart/espresso-mcp/issues) for v0.5.\n\n### Best-effort with cities not yet in the database\n\nIf you query a city we haven't curated yet (e.g., Lisbon, Seoul, Mexico City), `find_espresso_near` returns no curated matches. The model can still combine its own knowledge with `score_cafe` to evaluate any cafe you describe. We're filling in cities one batch at a time — open an issue if you want yours prioritized.\n\n---\n\n## Tools\n\n### `find_espresso_near`\n\nFind ranked specialty espresso cafes within a radius of coordinates.\n\n```jsonc\n{ \"lat\": 35.6855, \"lon\": 139.6904, \"radius_km\": 3, \"min_score\": 60, \"limit\": 10 }\n```\n\nReturns cafes from the curated database sorted by espresso-quality score, with per-cafe distance and reasoning.\n\n### `search_cafes`\n\nSearch the curated database by query, city, country, roaster, or minimum score.\n\n```jsonc\n{ \"query\": \"natural wine\", \"country\": \"DE\", \"min_score\": 70, \"limit\": 20 }\n```\n\n### `get_cafe_details`\n\nFull record for a cafe by id, including the score breakdown signal-by-signal and a few related/nearby cafes.\n\n```jsonc\n{ \"id\": \"tim-wendelboe-oslo\" }\n```\n\n### `score_cafe`\n\nThe codified algorithm exposed directly. Pass in signals you've observed (from a website, a review, a photo) and get a 0-100 score with a per-signal contribution breakdown. **No database lookup required.**\n\n```jsonc\n{\n  \"name\": \"Hypothetical Shop\",\n  \"observed_signals\": {\n    \"roasting\": \"in-house\",\n    \"brew_methods\": [\"espresso\", \"pour-over\"],\n    \"single_origin_espresso\": true,\n    \"roast_date_on_bags\": true,\n    \"cortado_on_menu\": true,\n    \"syrup_emphasis\": false\n  }\n}\n```\n\n### `list_great_roasters`\n\nCurated specialty roasters by country and reputation tier.\n\n```jsonc\n{ \"country\": \"DK\", \"min_reputation\": \"regional-leader\", \"limit\": 25 }\n```\n\n### `list_anti_patterns`\n\nCurated shops that exemplify what to **avoid** — the contrast set for the algorithm. Two flavors:\n\n- **`mass-market-chain`** — Starbucks, Dunkin', Costa, Tim Hortons, Peet's, Caribou. Generic dark roasts, flavored-drink menus, low sourcing transparency.\n- **`flavor-led-specialty`** — shops that display third-wave signage (in-house roasting, single-origin signs, roast dates) but in practice serve a syrup-forward menu. *Looks specialty, drinks flavored.* Useful contrast when explaining why a recommended shop is the real thing.\n\n```jsonc\n{ \"category\": \"flavor-led-specialty\", \"limit\": 10 }\n```\n\nAnti-patterns are stored separately in [`data/anti-patterns.json`](data/anti-patterns.json) so they never bleed into `find_espresso_near` or `search_cafes` results.\n\n---\n\n## How scoring works\n\nThe full weight table is the source of truth at [`src/scoring/weights.ts`](src/scoring/weights.ts). In short:\n\n**Positive signals** (the things great shops do):\n- In-house or named-partner roasting from a known specialty roaster\n- Single-origin espresso\n- Roast date on retail bags (peak-freshness commitment)\n- Espresso + pour-over both offered (\"complete program\")\n- Cortado on the menu (confidence in espresso)\n- Competition involvement / SCA-certified staff\n- Quality espresso machines (Slayer, La Marzocco, Synesso, Decent, Victoria Arduino, Modbar)\n- Awards (World's 100 Best, SCA championships, Coffee Review 95+, Good Food Awards)\n\n**Negative signals** (the cover-up patterns):\n- **`syrup_emphasis` (−22)** — menu dominated by flavored-syrup drinks. The strongest avoid-signal. Great shops don't hide behind syrups.\n- `flavored_drink_share > 0.5` (additional −7)\n- `no_grinder_visible` (−25) — effectively disqualifying\n- `only_dark_roast` (−8) — masks bean defects\n- `no_origin_info` (−7) — they don't know or don't care\n\n**Roaster reputation bonus**: cafes that roast in-house or partner with a known roaster get +25 (world-class), +15 (regional-leader), or +8 (notable) on top of structural signals.\n\nNull/unknown signals are skipped, not penalized. The score includes a `confidence` value proportional to how many signals were actually observed.\n\nScore tiers:\n\n| Score | Tier |\n|---|---|\n| ≥ 85 | World-class |\n| ≥ 70 | Great |\n| ≥ 55 | Good |\n| ≥ 40 | Fair |\n| < 40 | Avoid |\n\nThe \"looks specialty but isn't\" pattern is tricky — a cafe with genuine third-wave structural signals plus a flavored-drink menu will score in the \"good\" range despite the syrup penalty. For those cases, the explicit `category: flavor-led-specialty` flag in [`data/anti-patterns.json`](data/anti-patterns.json) is the authoritative human override.\n\n---\n\n## Curated coverage (v0.2.0)\n\nThe database is hand-curated. Coverage skews toward cities where we (or trusted curated guides) have actual recent visits. We add cities batch-by-batch — open an issue if you want yours prioritized.\n\n| Region | Cafes | Districts represented |\n|---|---:|---|\n| Berlin | 15 | Mitte, Kreuzberg, Neukölln, Charlottenburg |\n| London | 15 | Holborn, Shoreditch, City, Marylebone, Bishopsgate, Hammersmith (incl. Workshop × 3) |\n| NYC (Manhattan + Brooklyn) | 17 | East Village, Nolita, Noho, Flatiron, FiDi, NoMad, Williamsburg, Bushwick, Park Slope |\n| Dallas / DFW | 18 | Design District, Lower Greenville, Oak Cliff / Bishop Arts, Deep Ellum, Knox-Henderson, Plano |\n| Denver metro | 18 | Capitol Hill, RiNo, LoHi, Tennyson, Edgewater, Aurora, Lone Tree, Littleton |\n| Hong Kong | 10 | Causeway Bay, Sheung Wan, Tsim Sha Tsui, Tai Hang |\n| Tokyo / Osaka | 6 | Omotesando, Nakameguro, Kuramae, Shimokitazawa, Sangubashi |\n| Guangzhou | 8 | Tianhe, Yuexiu, Liwan |\n| Other | ~9 | Oslo, Copenhagen, Dublin, Galway, Vienna, Singapore, Santa Ana SV, Rogers AR |\n\nPlus 8 deliberately-flagged anti-pattern entries (Starbucks, Dunkin', Costa, Tim Hortons, Peet's, Caribou, plus two \"looks specialty but tastes flavored\" examples).\n\n**Gaps worth filling next**: SF, LA, Seattle, Portland, Melbourne, Sydney, Stockholm, Amsterdam, Paris, Taipei, Seoul, Mexico City.\n\n---\n\n## Contributing a cafe\n\nOpen a PR against [`data/cafes.json`](data/cafes.json):\n\n1. Add the entry in alphabetical order by city, then name.\n2. Use exact coordinates when possible (`\"coord_precision\": \"exact\"`). Look them up on Google Maps.\n3. Set `last_verified` to today's ISO date.\n4. Only include signals you've personally observed or can cite.\n5. If you're naming a new roaster, add it to [`data/roasters.json`](data/roasters.json) with a reasonable reputation tier (`notable`, `regional-leader`, or `world-class`).\n6. Run `npm test` and `npm run validate-data` before opening the PR.\n\nSee [`data/README.md`](data/README.md) for the full schema reference.\n\n### Suggesting an anti-pattern\n\nAnti-patterns belong in [`data/anti-patterns.json`](data/anti-patterns.json) with a `category` field set. Strong candidates are shops you've personally verified as either mass-market or \"looks specialty but drinks flavored.\" Include a `notes` field explaining the gap between signage and experience.\n\n### Reporting feedback\n\nOpen an [issue](https://github.com/mattgierhart/espresso-mcp/issues) with what you tested, what worked, what surprised you, and what's missing. We track the roadmap (community contribution tool, automated address geocoding, live data fallback, hotel-proximity scoring) as open issues.\n\n---\n\n## License\n\n- **Code** is MIT — see [`LICENSE`](LICENSE).\n- **Data** (`data/*.json`) is CC-BY 4.0 — see [`data/LICENSE`](data/LICENSE). Attribution required.\n\nIf you redistribute the data, please link back to this repository.\n\n---\n\n## Sources we trained the patterns on\n\nThe curated cafe roster, the signal weight table, and the anti-pattern category framing were built by reading and cross-referencing the people who already do this work well. Credit and links:\n\n**City and region guides**\n- [World's 100 Best Coffee Shops](https://worlds100bestcoffeeshops.com) — annual industry-voted ranking; the backbone of the world-class tier\n- [European Coffee Trip](https://europeancoffeetrip.com/city-guides/) — 6,229+ curated European specialty cafes; used heavily for the London and Berlin batches\n- [D Magazine — Best Dallas Coffee Shops and Roasters](https://www.dmagazine.com/guides/best-dallas-coffee-shops-and-roasters/) — the canonical DFW specialty guide\n- [Drips of God — New York](https://www.dripsofgod.com/new-york) — Manhattan + Brooklyn curation\n- [Bee An Coffee — Best Specialty Coffee in NYC 2026](https://beeancoffee.com/city-guides/best-specialty-coffee-in-nyc-2026/) — Brooklyn roastery focus\n- [Grounds Club — Hong Kong Specialty Coffee Guide](https://www.groundsclub.com/the-guide) — HK-specific\n- [Asian Coffee Map](https://asiancoffeemap.com) — Asia regional anchor\n\n**Awards and rankings**\n- [Sprudgie Awards](https://sprudge.com/sprudgies) — Sprudge's annual community awards\n- [Good Food Awards: Coffee](https://goodfoodfdn.org/awards) — US specialty roaster recognition\n- [Coffee Review (95+ scores)](https://www.coffeereview.com) — exceptional roast quality\n- [SCA World Barista Championship](https://worldbaristachampionship.org) — competition involvement is a high-signal indicator\n\n**Frameworks and taxonomies**\n- [Sprudge](https://sprudge.com) — long-form specialty coffee journalism; the original \"signal taxonomy\" intuition came from years of Sprudge reading\n- [Specialty Coffee Association — Barista Skills curriculum](https://sca.coffee) — equipment shortlist and certification framework\n- [SCA Certified Commercial Equipment list](https://sca.coffee/sca-certified/commercial-equipment) — what \"quality espresso machine\" means\n\n**A lot of time spent in cafes.** Fieldwork. Probably not tax-deductible. The most honest entry on this list — every weight in [`src/scoring/weights.ts`](src/scoring/weights.ts) was calibrated by someone who has been personally disappointed by a Slayer-equipped shop that turned out to lean syrup-forward.\n\n**Built on**\n- [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) — the official MCP TypeScript SDK\n- [Zod](https://zod.dev), [tsup](https://tsup.egoist.dev), [Vitest](https://vitest.dev), [Firecrawl](https://firecrawl.dev) (for scraping city guides during curation)\n",
  "bytes": 21473,
  "sha": "5fe08d941149f291a86267334522e01abf6e7c0227e007d4616b10a1d149d71d",
  "repo_slug": "mattgierhart/espresso-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_mattgierhart_espresso_mcp_741c1bc2/readme"
}