Follow Up Boss MCP is a production-grade Python 3.12+ repository that combines:
- a typed async Follow Up Boss SDK/client built on
httpx - a layered domain service package built with
pydanticv2 models - a production-ready MCP server built with the official Python MCP SDK and
FastMCP
The repository uses only official Follow Up Boss API documentation and official MCP documentation as design authority. It includes a real Follow Up Boss doc-ingestion step, an explicit API coverage matrix, strict static typing, deterministic tests, and enforced 100% line and 100% branch coverage for all production code under src/followupboss_mcp.
- Follow Up Boss API docs: https://docs.followupboss.com/reference/getting-started
- MCP build-server docs: https://modelcontextprotocol.io/docs/develop/build-server
- MCP Inspector docs: https://modelcontextprotocol.io/docs/tools/inspector
- MCP debugging docs: https://modelcontextprotocol.io/docs/tools/debugging
- Official MCP Python SDK: https://github.com/modelcontextprotocol/python-sdk
The repository is intentionally layered:
config.py,auth.py,constants.py, andlogging.pyhandle configuration, auth, and safe logging.retry.py,rate_limits.py,pagination.py, andhttp_client.pycentralize transport behavior.models/*andservices/*provide typed Follow Up Boss operations.webhooks.pycontains reusable webhook signature verification and fast-ack helpers.mcp_tools.py,mcp_registration.py,mcp_server.py, andcli.pyexpose the typed client through a predictable MCP surface.hosted_auth.py,hosted_oauth.py,hosted_rate_limits.py, andhosted_reference.pyprovide the shared hosted deployment path.battle_tests.pyencodes prompt-level MCP routing scenarios and read-only API-oracle checks for intent hardening.
More detail is in docs/architecture.md.
- API key authentication with HTTP Basic auth using the API key as the username and an empty password
- OAuth Bearer token support
- Configurable
X-SystemandX-System-Keyrequest headers - Configurable base URL with Follow Up Boss v1 as the default
- JSON request and response handling
- 429 handling with
Retry-After - truncated exponential backoff with jitter for retryable 5xx failures and transport errors
- reusable pagination helpers supporting both
nexttoken flow andoffsetfallback - typed services for Identity, People, People Relationships, Person Attachments, Events, Users, Custom Fields, Deals, Deal Custom Fields, Deal Attachments, Email Marketing, Groups, Inbox Apps, Pipelines, Ponds, Reactions, Smart Lists, Stages, Action Plans, Appointments, Appointment Outcomes, Appointment Types, Automations, Calls, Tasks, Team Inboxes, Teams, Templates, Text Messages, Threaded Replies, Timeframes, Notes, Webhook Events, and Webhooks
- current-user profile lookup with MCP-side redaction of secret-like fields
- people duplicate checks plus unclaimed-lead list, claim, and ignore helpers
- explicit webhook signature verification using the exact raw request body
- MCP tools, one resource, and one lead-event composition prompt
- stdio and streamable HTTP transports
- hosted OAuth authorization-server routes for dynamic client registration, Follow Up Boss browser consent delegation, and MCP-scoped bearer tokens
- hosted branding metadata with a packaged Follow Up Boss logo served from
/assets/follow-up-boss-logo.png, advertised aslogo_uri, and mirrored as the issuer-host favicon at/favicon.ico - read-only battle-test scenario models for vague chatbot prompts, selected MCP tool routes, forbidden tools, and typed API-oracle comparison
src/followupboss_mcp: production packagescripts/ingest_followupboss_docs.py: official Follow Up Boss crawler and manifest generatorscripts/validate_api_coverage.py: explicit API coverage matrix generatordocs/followupboss-endpoint-manifest.json: machine-readable Follow Up Boss manifestdocs/api-coverage-matrix.md: implementation matrix across discovered official endpointssrc/followupboss_mcp/assets: packaged hosted branding assets, including the Follow Up Boss logo and favicon used by OAuth metadata and issuer-host discoverysrc/followupboss_mcp/battle_tests.py: reusable read-only battle-test scenario and oracle evaluator codeexamples: runnable examples for health checks, event submission, and server transportstests: unit, integration, contract, and MCP test suites
uv syncThis installs the package plus the default development group defined in pyproject.toml.
| Variable | Required | Default | Notes |
|---|---|---|---|
FOLLOWUPBOSS_API_KEY |
For api_key auth |
None | API key used as the HTTP Basic username. The legacy alias FOLLOW_UP_BOSS_API_KEY is also accepted. |
FOLLOWUPBOSS_ACCESS_TOKEN |
For oauth auth |
None | OAuth access token used as a Bearer token. The legacy alias FOLLOW_UP_BOSS_ACCESS_TOKEN is also accepted. |
FOLLOWUPBOSS_AUTH_MODE |
No | api_key |
Valid values: api_key, oauth. The legacy alias FOLLOW_UP_BOSS_AUTH_MODE is also accepted. |
FOLLOWUPBOSS_SYSTEM_NAME |
No | None | Sent as X-System when configured. Recommended for external integrations. Legacy aliases FOLLOW_UP_BOSS_SYSTEM_NAME and FOLLOW_UP_BOSS_X_SYSTEM are also accepted. |
FOLLOWUPBOSS_SYSTEM_KEY |
No | None | Sent as X-System-Key when configured. Required for Follow Up Boss webhook verification and webhook admin scenarios. Legacy aliases FOLLOW_UP_BOSS_SYSTEM_KEY and FOLLOW_UP_BOSS_X_SYSTEM_KEY are also accepted. |
FOLLOWUPBOSS_BASE_URL |
No | https://api.followupboss.com/v1 |
Override for alternate environments or proxies. The legacy alias FOLLOW_UP_BOSS_BASE_URL is also accepted. |
FOLLOWUPBOSS_TIMEOUT_SECONDS |
No | 10.0 |
Per-request timeout. Must be greater than zero. The legacy alias FOLLOW_UP_BOSS_TIMEOUT_SECONDS is also accepted. |
FOLLOWUPBOSS_MAX_RETRIES |
No | 3 |
Retry budget for retryable failures. Must be zero or greater. The legacy alias FOLLOW_UP_BOSS_MAX_RETRIES is also accepted. |
FOLLOWUPBOSS_LOG_LEVEL |
No | INFO |
One of DEBUG, INFO, WARNING, ERROR, CRITICAL. The legacy alias FOLLOW_UP_BOSS_LOG_LEVEL is also accepted. |
FOLLOWUPBOSS_DEFAULT_TIMEZONE |
No | Account timezone | Optional IANA timezone override (such as America/Denver) used to interpret naive appointment and task datetimes. By default the server auto-detects the authenticated account's timezone from Follow Up Boss /me, so no configuration is needed. Follow Up Boss stores times in UTC and does not honor a timezone offset suffix on the wire, so the server converts datetimes to UTC before sending: naive values are interpreted in the resolved zone, and aware values are converted from their offset. Set this variable only to force a specific zone. The legacy alias FOLLOW_UP_BOSS_DEFAULT_TIMEZONE is also accepted. |
SENTRY_DSN |
No | None | Enables Sentry error monitoring when set. The DSN identifies the Sentry project but does not grant access to project data. |
SENTRY_ENVIRONMENT |
No | local |
Sentry environment name. The hosted MCP deployment uses production. |
SENTRY_RELEASE |
No | None | Sentry release identifier, such as followupboss-mcp@0.1.0+<git-sha>. |
SENTRY_SAMPLE_RATE |
No | 1.0 |
Error-event sample rate between 0.0 and 1.0. |
SENTRY_TRACES_SAMPLE_RATE |
No | None | Optional transaction trace sample rate between 0.0 and 1.0; tracing is disabled when unset. |
SENTRY_PROFILES_SAMPLE_RATE |
No | None | Optional profiling sample rate between 0.0 and 1.0; profiling is disabled when unset. |
SENTRY_ENABLE_LOGS |
No | false |
Set true to send supported Python logging events to Sentry. |
SENTRY_DEBUG |
No | false |
Enables verbose Sentry SDK diagnostics; avoid in stdio MCP sessions unless debugging startup. |
Run the exact quality gates enforced locally and in CI:
make validateRun only the docs and markdown validation checks with:
make docs-checkFor the explicit underlying commands:
uv sync
uv export --format requirements.txt --all-groups --locked --no-editable --no-emit-project --output-file /tmp/followupboss-mcp-requirements.txt
uvx --from pip-audit pip-audit -r /tmp/followupboss-mcp-requirements.txt --strict --disable-pip --no-deps
uv run python scripts/validate_docs_links.py
uv run ruff format --check .
uv run ruff check .
uv run mypy src tests
uv run pytest
uv run coverage run --branch -m pytest
uv run coverage report --fail-under=100
uv run python -m followupboss_mcp.cli --helpBuild and validate the distribution artifacts with:
make build-smokeRun the optional live checks only when sandbox credentials are available:
FOLLOWUPBOSS_RUN_LIVE_TESTS=1 make live-identity-check
FOLLOWUPBOSS_RUN_LIVE_TESTS=1 make live-contract-checklive-identity-check is the quick auth and transport smoke path. live-contract-check
adds a broader suite across identity, users, people, timeframes, MCP-layer /me
redaction, note reactions, registered-system person attachments when configured,
and disposable person-centered note, task, and appointment write-and-rollback flows.
Both targets auto-load a repository-local .env when present, so manual export is optional for the common local workflow.
uv run python -m followupboss_mcp.cli stdiouv run python -m followupboss_mcp.cli streamable-http --host 127.0.0.1 --port 8000 --path /mcpHosted multi-tenant operator guidance lives in
docs/hosted-deployment-guide.md and docs/customer-onboarding-flow.md.
Treat the local commands above as developer workflows, not as the production
recipe for the shared hosted deployment. The repository now also ships
followupboss-mcp-hosted as the reference hosted entrypoint described in the
hosted deployment guide. Hosted deployments can expose OAuth authorization
server routes that let Cursor delegate browser consent to Follow Up Boss and
receive MCP-scoped hosted bearer tokens.
The current production deployment is served at:
https://fub.theperry.group/mcp
The same issuer host also serves OAuth discovery and branding endpoints:
https://fub.theperry.group/.well-known/oauth-authorization-server
https://fub.theperry.group/.well-known/openid-configuration
https://fub.theperry.group/assets/follow-up-boss-logo.png
https://fub.theperry.group/favicon.ico
The hosted OAuth metadata includes logo_uri so MCP clients can discover the
packaged Follow Up Boss logo without hard-coding an asset path. The same logo is
also exported as /favicon.ico so clients that infer branding from the issuer
domain receive the MCP-specific icon rather than a generic domain icon.
The production GitHub Actions workflow is .github/workflows/deploy-production.yml.
It deploys automatically on pushes to main and can also be started manually
with workflow_dispatch. The workflow builds the hosted image, pushes it to
ECR, renders the ECS task definition from the production environment variables, and
updates the followupboss-mcp-hosted ECS service.
Pushing to a non-main branch does not deploy production unless that branch is
merged into main or the workflow is manually dispatched for the desired ref.
Identity-based health check:
uv run python examples/identity_check.pyCanonical lead ingestion via POST /events:
uv run python examples/send_lead_event.pyRun the MCP server directly from example scripts:
uv run python examples/run_mcp_stdio.py
uv run python examples/run_mcp_streamable_http.pyThe official MCP docs recommend using MCP Inspector during development. From the repository root:
npx @modelcontextprotocol/inspector uv run followupboss-mcp stdioFor a streamable HTTP server, start the server first and then connect Inspector to the HTTP endpoint you exposed.
- docs/architecture.md
- CONTRIBUTING.md
- docs/followupboss-doc-ingestion.md
- docs/api-coverage-matrix.md
- docs/hosted-deployment-guide.md
- deploy/ecs/README.md
- docs/customer-onboarding-flow.md
- docs/mcp-usage.md
- docs/mcp-validation-checklist.md
- docs/testing.md
- docs/security.md
- docs/security-incident-playbook.md
- docs/release-checklist.md
- docs/final-validation-report.md
FOLLOWUPBOSS_API_KEY must be provided: setFOLLOWUPBOSS_API_KEYor switch toFOLLOWUPBOSS_AUTH_MODE=oauthwithFOLLOWUPBOSS_ACCESS_TOKEN.401or403errors: verify the credential, the integration user permissions, and whether the API key owner has access to the endpoint you are calling.429errors: Follow Up Boss returned a rate limit. The client respectsRetry-After, but sustained rate limiting usually means the caller should reduce request volume.- Note or call mutations immediately after person creation can fail if the person is not visible yet. Use the event-ingestion path or the service wait helper for eventual-consistency-sensitive flows.
- Custom field writes must use the Follow Up Boss field
namesuch ascustomBirthday, not the UI label. - In stdio mode, never write operational logs to stdout. The server uses Python logging rather than printing MCP diagnostics to stdout.
- Secrets are loaded through environment variables and represented as
SecretStrinside settings. - Authorization and
X-System-Keyvalues are redacted in logs and object representations. - Caller-supplied overrides for
Authorization,X-System,X-System-Key, andContent-Typeare rejected at the HTTP client boundary. - Webhook verification uses HMAC-SHA256 over the base64-encoded raw request body with
X-System-Key. - Webhook receivers should acknowledge with a fast
2xxresponse and move longer processing off the request thread. - CI now includes dependency audit and secret-scanning automation without a temporary vulnerability exception in the current lockfile state.
- Successful HTTP responses now emit method, path, status, and elapsed-time logs through the existing stderr-safe logger.
More detail is in docs/security.md.
This repository enforces:
mypy --strictruff checkruff format --check- passing
pytest coverage run --branch -m pytestcoverage report --fail-under=100
The coverage gate is scoped to all production code in src/followupboss_mcp, and both line coverage and branch coverage must remain at 100.00%.