Na Meetings

Created By
bmlt-enableda month ago
Search Narcotics Anonymous meetings worldwide via the BMLT directory.
Overview

bmlt-server-mcp

A streamable HTTP Model Context Protocol server that exposes BMLT (Basic Meeting List Toolbox — the Narcotics Anonymous meeting directory) as a set of read-only tools that AI assistants can call directly.

BMLT hosts approximately 85% of Narcotics Anonymous meetings worldwide; the default backend is the BMLT aggregator, which federates every public BMLT root server (server list) into a single search surface — effectively the authoritative AI-accessible source for finding NA meetings.

MCP is an open protocol, so any compatible client works: Claude (Code, Desktop, web), ChatGPT (Connectors and the Responses API), Google Gemini, Cursor, Windsurf, Zed, Cline, Continue, and others.

Unlike the npm bmlt-mcp-server (stdio-only, runs as a local subprocess), this server speaks MCP over HTTP and is meant to be hosted once and consumed remotely.

Built on Laravel + PHP 8.2+ using the official laravel/mcp package.

A live deployment runs at https://mcp.bmlt.app/ (landing page) with a tools reference at https://mcp.bmlt.app/reference.


Tools

All tools are read-only and idempotent. All tools accept an optional root_server_url argument; if omitted, the configured BMLT_ROOT_SERVER_URL is used.

ToolWhat it does
search_meetingsSearch meetings by address (geocoded server-side) or lat/lng + radius, filtered by weekday, time, format, venue type (in-person / virtual / hybrid), service body, and free text. Returns a curated summary by default (data_format=full for the raw BMLT response).
get_meetingFetch a single meeting by its BMLT id_bigint.
list_formatsList meeting format codes (Open, Closed, Speaker, Beginners, language tags, …) so callers can map names → IDs for search_meetings.
list_service_bodiesList zones / regions / areas / groups so callers can map names → IDs for search_meetings.
get_server_infoCapabilities, version, languages, and default coordinates for the configured root server.
list_root_serversPublic BMLT root servers known to the aggregator. Useful when the caller wants to switch roots.

Quick start

cp .env.example .env
docker compose up --build

The MCP endpoint is then live at http://localhost:8080/mcp over the Streamable HTTP transport.

Local PHP

composer install
cp .env.example .env
php artisan key:generate
php artisan serve     # http://localhost:8000/mcp

Verify with the MCP Inspector

php artisan mcp:inspector

Then connect to http://localhost:8000/mcp (or :8080 for Docker) and list tools.


Configuration

All configuration lives in .env (see .env.example). The interesting bits:

VariablePurpose
BMLT_ROOT_SERVER_URLRequired. Default BMLT root server, including /main_server path.
BMLT_ALLOWED_ROOTSComma-separated allowlist for the optional root_server_url tool argument. The default root is always implicitly allowed.
BMLT_ALLOW_ANY_ROOTtrue allows any URL via root_server_urlnot recommended in production (enables SSRF-style queries). Off by default.
BMLT_AGGREGATOR_URLAggregator queried by list_root_servers. Defaults to the public aggregator.
GEOCODERnominatim (default), google, or null. null rejects address inputs and requires lat/lng.
NOMINATIM_USER_AGENTIdentifies your deployment to OSM — required by Nominatim's ToS. Always set this in production.
GOOGLE_GEOCODER_API_KEYRequired when GEOCODER=google.

Why an allowlist?

The optional root_server_url tool argument lets a single deployment serve any BMLT root, but accepting arbitrary URLs would let callers turn the server into an SSRF probe against your network. The default is a strict allowlist (the configured default root, plus anything you add to BMLT_ALLOWED_ROOTS). Set BMLT_ALLOW_ANY_ROOT=true only when the server is isolated from anything sensitive.


Connecting AI clients

The endpoint of a deployed instance is https://your-host.example.com/mcp. Replace it below with your own host (or use https://mcp.bmlt.app/mcp to try the public instance).

Claude Code (CLI)

claude mcp add --transport http bmlt https://your-host.example.com/mcp

Claude Desktop — Custom Connector (newer builds)

Settings → Connectors → Add custom connector → paste the URL.

Claude Desktop — Config file (any version, needs Node.js)

{
  "mcpServers": {
    "bmlt": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://your-host.example.com/mcp"]
    }
  }
}

ChatGPT / OpenAI Responses API

{
  "tools": [
    {
      "type": "mcp",
      "server_label": "bmlt",
      "server_url": "https://your-host.example.com/mcp"
    }
  ]
}

In ChatGPT itself (Pro/Business/Enterprise): Settings → Connectors → Add, using the same URL.

Cursor / Windsurf / Zed / Cline / Continue

All of these read an mcpServers block. For Cursor, edit ~/.cursor/mcp.json (or the project-local .cursor/mcp.json); other clients use a similar config file.

{
  "mcpServers": {
    "bmlt": {
      "url": "https://your-host.example.com/mcp"
    }
  }
}

For per-tool parameter documentation and BMLT-API mappings, see the live reference page. For day-to-day commands on a deployed instance (log tailing, usage summaries, cache clears, upgrades), see docs/operations.md.


Adding authentication

The default config has no auth — anyone who can reach /mcp can call the tools. To gate it:

// routes/ai.php
use Laravel\Mcp\Facades\Mcp;

Mcp::oauthRoutes();                          // OAuth 2.1 (Laravel Passport)
Mcp::web('/mcp', BmltServer::class)
    ->middleware('auth:api');

Or add a simple bearer-token check via custom middleware. See the Laravel MCP docs for the full options.


Architecture

app/
├── Mcp/
│   ├── Servers/BmltServer.php           # Registers the 6 tools
│   └── Tools/
│       ├── SearchMeetingsTool.php
│       ├── GetMeetingTool.php
│       ├── ListFormatsTool.php
│       ├── ListServiceBodiesTool.php
│       ├── GetServerInfoTool.php
│       ├── ListRootServersTool.php
│       └── Concerns/ResolvesBmltClient.php
├── Services/
│   ├── Bmlt/
│   │   ├── BmltClient.php               # Wraps client_interface/json
│   │   ├── BmltClientFactory.php        # Allowlist enforcement
│   │   └── BmltException.php
│   └── Geocoding/
│       ├── Geocoder.php                 # Interface
│       ├── GeocoderManager.php          # Driver resolver
│       ├── NominatimGeocoder.php        # OSM (rate-limited, cached)
│       ├── GoogleGeocoder.php           # Google Geocoding API
│       ├── NullGeocoder.php             # Disabled
│       ├── GeocodingResult.php
│       └── GeocodingException.php
└── Providers/BmltServiceProvider.php

config/bmlt.php                          # All knobs
routes/ai.php                            # Mcp::web('/mcp', BmltServer::class)

The HTTP API wrapped by BmltClient is formally specified by the BMLT Semantic OpenAPI document (OpenAPI 3.1) — refer to it for every parameter, response shape, and field definition that BMLT itself supports, even if this MCP server doesn't yet expose it as a tool argument.


License

MIT

Server Config

{
  "mcpServers": {
    "bmlt": {
      "url": "https://mcp.bmlt.app/mcp"
    }
  }
}
Project Info
Created At
a month ago
Updated At
11 days ago
Author Name
bmlt-enabled
Star
-
Language
-
License
-
Category
Tags

Recommend Servers

View All
//beforeyouship — LLM Cost Modeling From Your Editor
@Indiegoing

Query realistic LLM cost models without leaving your editor. beforeyouship models the **true monthly cost** of an LLM app architecture — retries, prompt caching, batch discounts, infra overhead, and 3×/10× growth — across GPT-5.x, Claude, Gemini, DeepSeek, and more. Not a token calculator: a planning tool for the design phase, before you commit to a stack. **No API key needed to try it** — demo mode covers the six free-tier models. A Pro key from [beforeyouship.dev](https://beforeyouship.dev) unlocks the full 18-model catalog. ## What you can ask - "How much will a RAG chatbot cost at 10,000 requests/day?" - "Compare Claude Haiku vs Gemini Flash pricing for my workload" - "What's the cheapest model for a multi-step agent at scale?" - "Show me current per-token prices for Anthropic models" ## Tools ### `estimate_cost` Full cost model for an architecture at a given usage level. Returns Naive / Realistic / Worst Case monthly cost per model, 3×/10× growth scenarios, and an opinionated recommendation with reasoning. ### `get_model_prices` Current per-1M-token pricing — input, output, cached input, batch — with context windows and staleness metadata. ### `list_archetypes` Seven preset architecture patterns (simple chatbot, chatbot with history, RAG pipeline, multi-model router, coding assistant, document processor, multi-step agent) used as starting points for estimates. ## Setup **Claude Code:** ​```bash claude mcp add --transport http beforeyouship https://beforeyouship.dev/api/mcp ​``` **Cursor / other clients** — add a remote server: ​```json { "mcpServers": { "beforeyouship": { "type": "streamable-http", "url": "https://beforeyouship.dev/api/mcp" } } } ​``` Add an `Authorization: Bearer bys_...` header with a Pro key for the full catalog. ## Try it > Estimate the monthly cost of a RAG pipeline at 10,000 requests/day

13 hours ago
Shippo
@Shippo

21 hours ago