Na Meetings

by bmlt-enabled

133 downloads
Not rated
GitHub

About

Search Narcotics Anonymous meetings worldwide via the BMLT directory.

Details

Author
bmlt-enabled
Downloads
133
Categories
Other

- Six read‑only, idempotent tools: search_meetings, get_meeting, list_formats, list_service_bodies, get_server_info, list_root_servers.
- Supports geocoding (Nominatim, Google, or lat/lng) and filtering by weekday, time, format, venue type, service body, free text.
- Optional root_server_url argument lets callers query any allowed BMLT root server.
- Strict allowlist for root_server_url prevents SSRF; default permits only the configured root.
- Built on Laravel + PHP 8.2+ and designed for hosted, remote consumption (not local subprocess).

Setting up with Highlight

This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:

  1. Download and install Highlight from highlightai.com/download
  2. Navigate to the plugins tab and select "Add Custom Plugin"
  3. Configure the plugin with the settings below
    Plugin Name Na Meetings
    Command (node, npx, python, etc.)

    Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.

  4. Enable "Start Automatically" if you want the plugin to start when Highlight launches

From the repository

Deploy via Docker (docker compose up --build) or local PHP (composer install && php artisan serve), then configure .env with BMLT_ROOT_SERVER_URL. Any MCP‑compatible client (Claude, ChatGPT, Google Gemini, Cursor, Windsurf, Zed, Cline, Continue) can connect to the endpoint at http://localhost:8080/mcp (or your hosted URL) and call the six built‑in tools.

Claude Desktop / Cursor

Paste into your MCP client config file to install this server.

{
    "mcpServers": {
        "na meetings": {
            "bmlt": {
                "url": "https://mcp.bmlt.app/mcp"
            }
        }
    }
}

McpServers

{
    "bmlt": {
        "url": "https://mcp.bmlt.app/mcp"
    }
}

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.

| Tool | What it does |
| --- | --- |
| search_meetings | Search 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_meeting | Fetch a single meeting by its BMLT id_bigint. |
| list_formats | List meeting format codes (Open, Closed, Speaker, Beginners, language tags, …) so callers can map names → IDs for search_meetings. |
| list_service_bodies | List zones / regions / areas / groups so callers can map names → IDs for search_meetings. |
| get_server_info | Capabilities, version, languages, and default coordinates for the configured root server. |
| list_root_servers | Public BMLT root servers known to the aggregator. Useful when the caller wants to switch roots. |

---

Quick start

Docker (recommended)

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:

| Variable | Purpose |
| --- | --- |
| BMLT_ROOT_SERVER_URL | Required. Default BMLT root server, including /main_server path. |
| BMLT_ALLOWED_ROOTS | Comma-separated allowlist for the optional root_server_url tool argument. The default root is always implicitly allowed. |
| BMLT_ALLOW_ANY_ROOT | true allows any URL via root_server_urlnot recommended in production (enables SSRF-style queries). Off by default. |
| BMLT_AGGREGATOR_URL | Aggregator queried by list_root_servers. Defaults to the public aggregator. |
| GEOCODER | nominatim (default), google, or null. null rejects address inputs and requires lat/lng. |
| NOMINATIM_USER_AGENT | Identifies your deployment to OSM — required by Nominatim's ToS. Always set this in production. |
| GOOGLE_GEOCODER_API_KEY | Required 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

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.