MCP Server
The Business Dash MCP (Model Context Protocol) server lets AI coding assistants — Claude, Cursor, ChatGPT, Goose, VSCode, and others — interact with your organization's data directly. The assistant can read your business profile, browse your catalog, search services, check your booking link, and even submit quote requests, all through structured tool calls.
How It Works
Each organization's published site hosts its own MCP endpoint at
/.well-known/mcp.json. AI clients that support MCP discovery find it
automatically when pointed at your site URL.
The server implements the Streamable HTTP Transport specification (JSON-RPC 2.0 over HTTP POST).
Before the MCP endpoint responds, the organization must opt in by enabling the MCP App feature in the dashboard settings.
Enabling MCP
- Go to Settings → AI & Integrations in the organization dashboard
- Toggle MCP App to enabled
- Optionally configure which write tools are allowed (see below)
Once enabled, the MCP endpoint is live at your published site's URL:
https://<your-site>.businessdash.us/.well-known/mcp.json
Or on your custom domain:
https://<your-domain>/.well-known/mcp.json
SDK-Hosted Sites (your own Next.js app)
The host-resolved endpoint above exists only on platform-served sites. If your domain hosts your own app built with the SDK, mount the proxy and your domain gains the identical connector surface:
// app/api/mcp/route.ts
import { mcpHandler } from '@businessdash/sdk/mcp'
export const { POST, GET } = mcpHandler({
siteId: process.env.BD_SITE_ID!,
baseUrl: process.env.NEXT_PUBLIC_BD_APP_URL!, // https://www.businessdash.us
})
// app/.well-known/mcp.json/route.ts
import { mcpManifestHandler } from '@businessdash/sdk/mcp'
export const GET = mcpManifestHandler({
siteId: process.env.BD_SITE_ID!,
baseUrl: process.env.NEXT_PUBLIC_BD_APP_URL!,
})
The proxy forwards verbatim to /api/public/mcp/{siteId} on the platform —
the org's MCP opt-in and per-tool write gates are enforced there, so the
proxy can't widen anything.
Connecting an AI Assistant
Claude Cowork / claude.ai (custom connector)
Cowork and claude.ai use the same connector system. The org's MCP endpoint is a standard remote connector URL:
- Open Settings → Connectors in Claude (or Cowork)
- Choose Add custom connector
- Paste the connector URL:
https://<your-domain>/api/mcp
Claude can then read the business profile, browse and search the catalog, fetch the booking link, and file quote requests straight into the CRM — using the same per-tool gating configured in the dashboard. Write tools stay off unless the org enables them.
The dashboard shows this URL pre-filled with the org's verified domain under Site Builder → SEO + AI discoverability once the MCP App is enabled.
The endpoint answers only on a verified custom domain — verify the domain before handing the URL to Claude.
ChatGPT
ChatGPT's connectors are MCP too. In Settings → Connectors (enable developer mode if the option is hidden), choose Add connector and paste the same URL:
https://<your-domain>/api/mcp
Deep Research and chat can then call the read tools; write tools follow the same per-tool dashboard gating as every other client.
Gemini CLI / Gemini Code Assist
The consumer Gemini app doesn't take custom connectors yet, but Google's
agent surfaces do. For Gemini CLI, add to ~/.gemini/settings.json:
{
"mcpServers": {
"bd": {
"httpUrl": "https://<your-domain>/api/mcp"
}
}
}
Gemini Code Assist reads the same mcpServers shape. For the org connector
(https://www.businessdash.us/api/mcp/org), Gemini CLI's remote-MCP OAuth support
walks the same authorization flow Claude and ChatGPT use — run /mcp auth
if it doesn't prompt automatically.
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"bd": {
"type": "streamable-http",
"url": "https://<your-site>.businessdash.us/api/mcp"
}
}
}
Claude Code / Cursor / VSCode
No dedicated config needed — these clients auto-discover MCP via the
.well-known/mcp.json endpoint when pointed at your site URL. Just give your
assistant the site URL and it will find the tools.
Goose
Use the Streamable HTTP transport type:
# In your Goose session config
mcp_servers:
bd:
type: streamable-http
url: https://<your-site>.businessdash.us/api/mcp
Available Tools
Read Tools (always on)
| Tool | Description |
|---|---|
get_business_info | Returns name, address, hours, contact info |
get_company_profile | Full profile — about, SEO metadata, JSON-LD, OG tags |
list_services | Services catalog with title, price, price type |
list_products | Products catalog |
search_catalog | Search products and services by keyword |
request_quote | Submit a quote request (creates a CRM lead) |
book_meeting_link | Returns the public scheduling/booking page URL |
Write Tools (disabled by default)
| Tool | Description |
|---|---|
update_company_profile | Patch website, phone, email, about text, share image |
generate_blog_image | Generate AI blog-cover image variations |
generate_blog_image_dark_companion | Generate dark-theme companion for a light image |
Write tools are gated per-tool. Enable them in Settings → AI & Integrations → MCP App Tools.
Write Tool Configuration
Write tools are individually gated through mcp_app_tools_config. To enable a
write tool:
- Navigate to Settings → AI & Integrations → MCP App
- Toggle the specific write tool you want to allow
- Changes take effect immediately — no restart needed
An AI assistant calling a disabled write tool receives:
{ "ok": false, "error": "tool_disabled" }
This gives you fine-grained control. For example, you might allow
update_company_profile for onboarding assistance while keeping blog image
generation off.
Tool Examples
Get business info
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_business_info"
}
}
Search catalog
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search_catalog",
"arguments": {
"q": "water heater"
}
}
}
Submit a quote request
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "request_quote",
"arguments": {
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "555-0123",
"message": "Looking to install a tankless water heater"
}
}
}
Protocol Details
- Transport: Streamable HTTP (JSON-RPC 2.0)
- Endpoint:
https://<your-site>/api/mcp - Discovery:
https://<your-site>/.well-known/mcp.json - Methods supported:
initialize,tools/list,tools/call,resources/list,resources/read,ping - Auth: Phase 2 (planned) — currently gated by organization opt-in + hostname resolution
Security
- The MCP endpoint only responds for organizations that have explicitly enabled the feature
- Requests are resolved per-hostname — only your published site's domain can reach your MCP endpoint
- Write tools are individually gated and disabled by default
- Every write action is logged with an audit trail (source, timestamp, changed fields)
- No authentication token is required in Phase 1 — security relies on hostname resolution and the opt-in gate
Org Connector (assistant acts as staff)
Everything above is the public connector — the assistant sees what a site visitor sees. The org connector is the private counterpart: Claude or ChatGPT operates inside the workspace, holding a revocable credential an org admin explicitly approved.
https://www.businessdash.us/api/mcp/org
Adding that URL as a custom connector triggers a standard OAuth flow:
- The client discovers the authorization server via RFC 9728 resource
metadata (
/.well-known/oauth-protected-resource/api/mcp/org) and registers itself (RFC 7591 dynamic client registration — open, grants nothing by itself). - The admin lands on
/oauth/authorize, signed into their org, and approves — read scope always, write scope only via an explicit switch on the consent screen. - The token exchanged (authorization code + PKCE S256) is minted as an
agent credential— the same table auth.md agents live in, so it shows up in the org's credential list and revokes the same way.
Org-only tools on top of the full public catalog:
| Tool | Description |
|---|---|
get_org_overview | Org name, sites, verified domains, distribution counts |
get_site_traffic | Pageviews + visitors for a window (human traffic only) |
get_ai_visibility | Which AI crawlers fetched which pages (AEO signal) |
list_ai_distribution_items | The resolved answer-engine distribution list |
Public write tools (update_company_profile, blog image generation) become
callable only when the approval included write scope — and each still passes
through the org's per-tool mcp_app_tools_config gate. An OAuth approval
never bypasses the org's own switches.
Mounting it on your framework
mcpHandler returns a Web-standard (Request) => Promise<Response>, which is
exactly what Next's App Router, Astro, Remix and TanStack Start want — and
exactly what SvelteKit, Nuxt, Qwik City and Express do not. Those four get
adapters:
import {
sveltekitMcpHandler, // also astroMcpHandler
nitroMcpHandler, // Nuxt / Nitro
qwikMcpHandler, // Qwik City
expressMcpHandler, // Express, Angular SSR, Analog
} from '@businessdash/sdk/mcp-adapters'
SvelteKit — src/routes/api/mcp/+server.ts:
export const { POST, GET } = sveltekitMcpHandler({ siteId, baseUrl })
Nuxt / Nitro — server/routes/api/mcp.post.ts:
export default defineEventHandler(nitroMcpHandler({ siteId, baseUrl }))
Qwik City — src/routes/api/mcp/index.ts. Qwik answers by calling send()
rather than returning, which the adapter handles:
const mcp = qwikMcpHandler({ siteId, baseUrl })
export const onPost = mcp.onPost
export const onGet = mcp.onGet
Express / Angular SSR:
const mcp = expressMcpHandler({ siteId, baseUrl })
app.post('/api/mcp', mcp)
app.get('/.well-known/mcp.json', expressMcpManifestHandler({ siteId, baseUrl }))
Each adapter is a shape-change over the same handler — none reimplements the proxy, the error mapping or the manifest caching.
Mount the manifest route too. It is what tells the platform which domain to
advertise, so the connector URL an org hands to Claude or ChatGPT points at
their site. On Node the origin is rebuilt from the Host header and
x-forwarded-proto — behind a proxy that does not set them, the published URL
will be wrong.