fub-mcp
# fub-mcp
A comprehensive [Model Context Protocol](https://modelcontextprotocol.io) server for
the [Follow Up Boss](https://www.followupboss.com/) real estate CRM API. Not
affiliated with or endorsed by Follow Up Boss.
Generates one MCP tool per FUB API operation (~130+ tools) directly from FUB's
published OpenAPI spec, plus a small set of hand-written extras for behavior that's
real but undocumented. Runs entirely on your machine — your API key never leaves it.
## Install
### Claude Desktop (recommended — no Terminal, no Node.js)
1. **Download** [`fub-mcp.mcpb`](https://github.com/gray-wilbee/fub-mcp/releases/latest/download/fub-mcp.mcpb)
and **double-click** it. Claude Desktop opens an install screen.
2. **Paste your Follow Up Boss API key** into the masked field (FUB → Admin → API),
then click **Install**. Claude Desktop stores the key in your system keychain
(macOS Keychain / Windows Credential Manager); it is never typed into a chat and
never sent anywhere except directly to Follow Up Boss.
3. **Turn it on.** Installing does not enable it: go to **Settings → Extensions**,
find **Follow Up Boss**, and switch the toggle **on**.
4. **Start a new chat** and try *"List my 3 most recently added contacts."*
Claude Desktop ships its own Node.js runtime, so nothing else needs installing.
Notes: the bundle isn't code-signed yet, so Claude Desktop may show an
unverified-developer caution; it has been tested on macOS, and Windows is supported
by Claude Desktop but not yet tested by the maintainer. To update, download the
newest `.mcpb` and install it over the old one.
### Claude Code, other MCP clients, or Terminal users
```bash
claude mcp add fub-mcp --env FUB_API_KEY=your-key -- npx -y fub-mcp
```
or add this to your MCP client's config (e.g. `claude_desktop_config.json`):
```json
{
"mcpServers": {
"fub-mcp": {
"command": "npx",
"args": ["-y", "fub-mcp"],
"env": {
"FUB_API_KEY": "your-fub-api-key"
}
}
}
}
```
Requires Node.js 18+. Get your API key from Follow Up Boss: **Admin → API**.
#### macOS guided setup (alternative to putting the key in a config file)
```bash
npx -y fub-mcp setup
```
Pops a native macOS dialog (masked input) for your key, validates it against the live
API, stores it in `~/.fub-mcp/.env` (permissions restricted to your user), and adds a
secret-free `mcpServers` entry to Claude Desktop's config. If you're using Claude
Desktop, the extension above is simpler and stores the key more securely.
### Optional environment variables
| Variable | Default | Purpose |
|---|---|---|
| `FUB_MCP_SYSTEM_NAME` | `fub-mcp` | Sent as `X-System` so FUB attributes actions to this tool and grants the better registered-system rate limit. |
| `FUB_MCP_SYSTEM_KEY` | unset | Only needed if you've separately [registered your own system](https://followupboss.com/2/api). |
| `FUB_MCP_ALLOW_DELETE` | `0` | Set to `1` to enable DELETE-verb tools at all. See **Delete safety** below. |
## Delete safety
Follow Up Boss DELETE calls are permanent. This server treats them as opt-in at two
layers:
1. **Server-level opt-in**: unless `FUB_MCP_ALLOW_DELETE=1` is set in the server's
environment, delete tools aren't registered at all — the model never sees them as
callable.
2. **Per-call confirmation**: even with that flag set, every delete tool requires a
`confirm: true` argument, and its description instructs the model to get explicit,
specific confirmation from the user before calling it — not to infer consent from
general intent.
Neither layer trusts the model alone; both must be satisfied.
## What's generated vs. hand-written
Most tools (`list_people`, `create_note`, `update_deal`, ...) are generated at build
time straight from FUB's OpenAPI spec (vendored in `src/openapi/fub-openapi.json` —
refresh it from https://docs.followupboss.com/openapi to pick up FUB API changes).
A few things needed hand-written overrides in `src/overrides/`:
- **`list_notes`** — FUB's docs only document `GET /notes/{id}`, but the plural
`GET /notes` endpoint works today and supports a `personId` filter. Confirmed
against the live API; treated as best-effort since it's unofficial.
- **`update_person` tag handling** — adding tags should pass `mergeTags=true`
(defaulted for you); removing a tag has no dedicated endpoint and requires a
fetch → filter → PUT-the-whole-array-back pattern (documented in the tool
description).
- **Notes vs. templates HTML handling** — notes need `isHtml: true` set explicitly
for HTML bodies; email templates take raw HTML directly with no such flag. These
are easy to mix up, so both tools' descriptions call it out.
- Two spec quirks fixed transparently by the generator: a couple of endpoints use
`:id` instead of `{id}` for path params, and the rate-limit endpoints' documented
paths double up the `/v1` prefix that's already in the base URL.
## Skills
Three [Claude Skills](./skills) ship alongside the server for common multi-step
workflows the tools alone don't capture:
- **`query-smart-list`** — resolve a Smart List by name (not just ID) before filtering
people by it.
- **`create-html-email-template`** — build and upload an HTML email template
correctly (see the HTML-handling gotcha above), including FUB's `%merge_field%`
syntax.
- **`create-text-template`** — build an SMS template with the same merge fields, plus
FUB's own texting-compliance guidance (opt-out language, carrier-filtering
avoidance).
## Using this outside Claude
- **ChatGPT Custom GPT**: see [`gpt/`](./gpt) for a trimmed, ≤30-operation OpenAPI
schema and setup instructions — each person builds their own GPT with their own
API key, no shared/hosted backend involved.
- **Claude web or mobile without the desktop app**: not currently supported.
Claude.ai's custom-connector UI only supports OAuth (or an org-admin-only static
header beta) for remote connectors, so there's no individual, bring-your-own-key
path there today the way there is for a Custom GPT. Reaching pure web/mobile users
would require a hosted, multi-tenant OAuth backend — out of scope for this repo for
now.
## Development
```bash
npm install
npm run build
npm run inspect # opens the MCP Inspector against the built server
```
`src/openapi/generate-tools.ts` does the spec → tool-schema conversion;
`src/overrides/index.ts` is where undocumented endpoints, description corrections,
and default overrides live. `src/tools.ts` merges the two and applies delete-gating.
## License
MIT
TDQS
Scored across 133 tools
Most tools map cleanly to a resource+action, but the sheer number (133) and similar names create real ambiguity: create_event vs. create_person, list_events vs. list_em_events, and the people/claim/ignore_unclaimed cluster are easy to confuse. Descriptions help, but the boundaries are not immediately evident from the names alone.
The dominant list_/get_/create_/update_ pattern is undermined by several post_/put_ prefixed tools (post_people_claim, put_inbox_apps_message) and inconsistent singular/plural forms (create_automations_person vs. list_automations_people). This mixes verb styles and noun forms within the same resource families, making the naming pattern unreliable.
133 tools is an extreme count for any MCP server; it far exceeds the 50+ threshold for a severe mismatch. While a full CRM API is inherently large, exposing every endpoint as a separate tool creates a heavy, unwieldy surface that is hard for agents to navigate.
The surface is remarkably broad, covering people, deals, pipelines, stages, notes, calls, tasks, appointments, templates, webhooks, teams, automations, and custom fields. However, there are notable gaps: no delete operation exists for any resource, events lack update, and there is no actual send capability for emails/texts (only template merge/render utilities).