Back to the catalog

BMLT Meetings

Search Narcotics Anonymous meetings worldwide via the BMLT directory.

Open source Repository Open in the app JSON README (API)

About

Search Narcotics Anonymous meetings worldwide via the BMLT directory.

Details

Kind
MCP servers
Topic
Productivity
Publisher
bmlt-enabled
Origin
official
Category
ferramentas
Transport
http
Version
0.3.0
Last push
2026-05-18T03:36:07Z
Repository state
ativo
Language
Blade
Added
2026-08-29 03:02:31
Updated
2026-08-29 03:02:31
Origin id
io.github.bmlt-enabled/bmlt-server-mcp

README

# bmlt-server-mcp

A **streamable HTTP** [Model Context Protocol](https://modelcontextprotocol.io) server that exposes [BMLT](https://bmlt.app) (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](https://aggregator.bmltenabled.org/main_server/), which federates every public BMLT root server ([server list](https://raw.githubusercontent.com/bmlt-enabled/aggregator/refs/heads/main/serverList.json)) 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`](https://www.npmjs.com/package/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`](https://github.com/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)

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

The MCP endpoint is then live at `http://localhost:8080/mcp` over the [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#streamable-http).

### Local PHP

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

### Verify with the MCP Inspector

```bash
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_url` — **not 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)

```bash
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)

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

### ChatGPT / OpenAI Responses API

```json
{
  "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.

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

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

---

## Adding authentication

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

```php
// 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](https://laravel.com/docs/mcp) 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](https://aggregator.bmltenabled.org/main_server/api/v1/openapi-semantic.json)
(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

More