emf-bar-mcp

emf-bar-mcp

MCP server for the EMF Camp bar API that enables fuzzy drink discovery by one or two keywords, showing the bar and live stock for each drink.

Category
Visit Server

README

emf-bar-mcp

A small, public MCP server over the EMF Camp bar API, built for a low‑context voice model: fuzzy drink discovery by one or two keywords, the bar each drink is served at, and live stock — while touching the upstream API as little as possible.

  • Discovery is free. The whole menu (124 drinks) and which bar carries each one is pulled in one call to /api/stocktypes.json at container start, then refreshed slowly in the background. find_drinks and list_bars never hit the network.
  • Live checks are cheap and targeted. check_stock reads one drink via /api/stocktype/<id>.json; whats_on_tap reads the two on‑tap endpoints. Both sit behind short TTL caches, so a burst of voice traffic collapses to one upstream request.

The paste‑into‑a‑prompt guide for the voice model is PROMPT.md.

Live instance: https://emf-bar-mcp-37viybmxjq-ew.a.run.app/mcp — Cloud Run (llm-voice, europe‑west1), public, scale‑to‑zero. Health: /health.

Quick start

npm install
npm start                 # HTTP server on http://0.0.0.0:8787/mcp  (default)
# or
npm run stdio             # stdio transport, for desktop MCP clients

Health check: curl localhost:8787/health

Docker

docker build -t emf-bar-mcp .
docker run -p 8787:8787 emf-bar-mcp

Connecting a client

Streamable HTTP (remote / public) — point your MCP client at http://<host>:8787/mcp.

stdio (e.g. Claude Desktop claude_desktop_config.json):

{
  "mcpServers": {
    "emf-bar": { "command": "node", "args": ["/abs/path/to/emf-bar-mcp/src/index.js"], "env": { "MCP_TRANSPORT": "stdio" } }
  }
}

Tools

Tool Args Live call? Returns
list_bars — no The 3 bars (slug, name, drink count, map link)
find_drinks query (1–2 keywords), bar?, category?, include_unavailable?, limit? no Ranked drinks: id, name, abv, price, category, bars, dietary flags
check_stock drink (name or id), bar? 1 status (on_sale/in_stock_not_on_sale/out_of_stock), onSale, inStock, level, servingsRemaining+servingUnit, percentRemaining, containerPercentRemaining (cask/keg), price, bars, plus source/live/checkedAt freshness
whats_on_tap bar? 1 (cached) Casks/kegs/ciders pouring now, each with remainingPct / level
opening_hours bar? 1 (cached) open, closesAt/nextOpen, upcoming schedule. Site-wide schedule (EMF publishes no per-bar hours)

Every tool returns a short spoken‑style content string and machine‑readable structuredContent. check_stock returns a candidates list when a name is ambiguous.

On sale vs in stock. EMF only serves some draught beers/ciders at a time ("not all draught beers and ciders are on sale at the same time"). The API models this: a product is on sale when it has a stockline (a place to buy it), and in stock when base_units_remaining > 0. So a cask in the cellar can be in stock but not on sale. check_stock.status surfaces the three cases — on_sale, in_stock_not_on_sale, out_of_stock — and find_drinks hides not‑on‑sale drinks unless include_unavailable: true.

Bar names are fuzzy: robotarms/"Robot Arms"/"main bar", cybar/"Cybar"/"Null Sector", spacebar/"SpaceBAR"/"space bar" all resolve.

Configuration (env vars)

Var Default Purpose
MCP_TRANSPORT http http or stdio
PORT / HOST 8787 / 0.0.0.0 HTTP bind
EMF_BAR_BASE https://bar.emf.camp Upstream API base
CATALOG_REFRESH_MS 900000 (15 min) Background catalog refresh interval
STOCK_TTL_MS 20000 Per‑drink live‑stock cache TTL
ONTAP_TTL_MS 30000 On‑tap cache TTL
SESSIONS_TTL_MS 300000 Opening‑times cache TTL
HTTP_TIMEOUT_MS 8000 Upstream request timeout

How it works

                 startup + every CATALOG_REFRESH_MS
  /api/stocktypes.json ───────────────► catalog cache (drinks, tags, bar placement, Fuse index)
                                              │
  find_drinks / list_bars  ◄──────────────────┘   (0 upstream calls)

  check_stock   ──► /api/stocktype/<id>.json      (TTL STOCK_TTL_MS)
  whats_on_tap  ──► /api/on-tap.json + /api/cybar-on-tap.json  (TTL ONTAP_TTL_MS)

Discovery matching is deterministic (keyword/synonym/style/flavour tags derived from each drink, including "hoppy"/"gluten free"/"alcohol free"), with a Fuse.js fuzzy fallback for typos and mis‑transcriptions. The HTTP transport is stateless (a fresh MCP server per request; the catalog cache is a shared singleton), so it scales and hosts simply.

The upstream /api/stocktypes.json is flagged expensive — do not poll; this server honours that by pulling it only at start‑up and on the slow refresh timer, never per request.

Notes

  • Not affiliated with EMF; uses the public read‑only bar API. Data © EMF.
  • Node ≥ 18 (uses global fetch). MIT licensed.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured