MCP: BizManager as a connector for Claude and ChatGPT

Owner's question (2026-10-11): can BizManager run an MCP server so it integrates with Claude and ChatGPT, since it already has an API? Answer: yes. The tools are thin wrappers over the API that already exists; the work is the sign-in (OAuth) that both assistants require, plus a rule for PHI.

Research (sources read 2026-10-11)

FindingSource
MCP's current revision is 2026-07-28: one HTTP endpoint that takes POST; each request carries its protocol version (header MCP-Protocol-Version and _meta); no sessions and no GET stream. Servers answer with plain JSON or a per-request SSE stream. Servers MUST check Origin and answer 403 to a bad onehttps://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http
Earlier clients use the initialize handshake (2025-03-26 to 2025-11-25). A "dual-era" server answers initialize for them and per-request metadata for modern clients, on the same endpointhttps://modelcontextprotocol.io/specification/2026-07-28/basic/versioning
Authorization: the MCP server is an OAuth 2.1 resource server; it MUST publish Protected Resource Metadata (RFC 9728), answer 401 with WWW-Authenticate: Bearer resource_metadata=..., accept only tokens issued for itself (audience = its URL, RFC 8707), never take tokens in the query string, and answer 403 insufficient_scope with the scopes needed. Client ID Metadata Documents are SHOULD; Dynamic Client Registration is MAY and deprecatedhttps://modelcontextprotocol.io/specification/latest/basic/authorization
Claude (claude.ai, Desktop, mobile, Cowork and Claude Code share one OAuth client stack) supports OAuth with DCR or CIMD, authless servers, and fixed API-key headers only in a limited beta. It needs a 401 to start sign-in, uses only the first authorization_servers entry, uses CIMD only when the authorization server advertises client_id_metadata_document_supported: true and none in token_endpoint_auth_methods_supported, sends PKCE S256 always, appends offline_access when listed, refreshes on 401 and up to 5 minutes early, expects refresh-token rotation for public clients and invalid_grant for a dead refresh token, gives discovery/registration/token endpoints 10 s (refresh 30 s), and takes form-encoded token requests. Redirects: https://claude.ai/api/mcp/auth_callback for the hosted apps; Claude Code uses a loopback http://localhost:<port>/callback or 127.0.0.1, matched without the port. No client_credentials grant. Traffic comes from 160.79.104.0/21https://claude.com/docs/connectors/building/authentication
A protected tool call must fail at the HTTP level (401 with the header), not as a 200 tool error, or Claude never shows the sign-in card. Claude caches discovery documents about 5 minuteshttps://claude.com/docs/connectors/building/lazy-authentication
Custom connectors by URL work on Claude Free (one connector), Pro, Max, Team and Enterprise; on Team and Enterprise an Owner adds it and members connect with their own accountshttps://claude.com/docs/connectors/custom/add-unlisted
ChatGPT: protected resource metadata and a 401 pointer; authorization server metadata with S256; CIMD with client_id https://chatgpt.com/oauth/client.json (auth method none or private_key_jwt), else DCR (once per connection) or a predefined client; resource echoed into the token's audience; iss returned in every authorization response (RFC 9207) and rejected when missing or different; redirect https://chatgpt.com/connector_platform_oauth_redirect (or a per-connector https://chatgpt.com/connector/oauth/{callback_id}). ChatGPT cannot present API keys and has no machine-to-machine grantshttps://developers.openai.com/plugins/build/auth
ChatGPT custom MCP apps with write actions run in developer mode on ChatGPT Business, Enterprise and Edu (web); admins publish them to the workspace; refresh tokens need offline_access advertised or users must sign in againhttps://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt
Anthropic's BAA does not cover connectors: "Your BAA doesn't cover any of them, even after an Owner turns them on", and data sent to third parties through MCP is not coveredhttps://privacy.claude.com/en/articles/8114513-business-associate-agreements-baa-for-commercial-customers
OpenAI signs BAAs for the API and ChatGPT Enterprise/Edu; whether custom MCP apps are covered is not stated on OpenAI's help page; secondary sources say third-party plugins are excludedhttps://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt, https://baagenerator.com/blog/does-openai-sign-a-baa

What it means for BizManager

How to connect

Copy the connector address from Business > Integrations or My account: your BizManager address followed by /mcp, for example https://bizmanager.autosecurelogin.com/mcp.

Signing in opens BizManager's consent screen: pick the business (when you belong to several) and tick what the assistant may do. It never gets more than your role allows. End a connection in My account; owners and admins can end anyone's in Business > Integrations.

Claude Code sign-in and the ASL web firewall (resolved 2026-10-11)

Found on the live server after the 0.7.0 release: Claude Code signs in with a loopback callback (http://localhost:<port>/callback), and the LurkerLock-managed web firewall (OWASP Core Rule Set 4.25.0, paranoia level 1, GET and HEAD only) refused any GET argument holding a localhost or IP-address URL: rule 934110 (server-side request forgery list) and rule 931100 (URL with an IP address). claude.ai, Claude Desktop and ChatGPT were not affected (https callbacks).

With the owner's approval, BizManager's nginx site file (deploy/nginx/bizmanager.autosecurelogin.com.conf) gained a location = /oauth/authorize whose ModSecurity rule removes only ARGS:redirect_uri from those two rules on that path; everything else is still inspected. It was applied on 2026-10-11 at 23:38 UTC as a signed LurkerLock platform-edge change (LurkerLock repo, docs/BIZMANAGER-OAUTH-WAF-20261011.md, PR sasysolutions1/lurkerlock#43). Afterwards Claude Code's request reaches the consent screen, and the same localhost values in any other argument or path are still refused.

What it can do (tools)

AreaToolsPermission
Businessget_business (name, time zone, tax rates)any
Clientssearch_clients, get_client, create_client, add_noteread:clients, write:clients (notes also write:requests)
Price listlist_servicesread or write of clients, quotes or jobs
Requestslist_requests, get_request, add_request, update_requestread:requests, write:requests
Scheduleget_schedule, get_visit, reschedule_visitread:schedule, write:schedule
Jobslist_jobs, get_job, create_job (one-off, price as a job line)read:jobs, write:jobs
Quoteslist_quotes, get_quote, create_quote (draft), send_quote (contacts the client)read:quotes, write:quotes
Invoiceslist_invoices, get_invoiceread:invoices
Paymentsrecord_paymentwrite:payments
Reportsbusiness_summary (the dashboard)read:reports

Each tool is a call to a documented API route (docs/API.md), so validation, tenancy and audit are the route's own. Read tools carry readOnlyHint; send_quote carries openWorldHint.

Design

PieceFileWhat
Authorization serversrc/modules/mcp/oauth.mjsdiscovery, clients, consent, codes, tokens, connections
MCP endpointsrc/modules/mcp/server.mjsPOST /mcp, JSON-RPC, tool dispatch, audit tagging
Toolssrc/modules/mcp/tools.mjsthe 24 tools, their schemas, hints and routes
Modulesrc/modules/mcp/index.mjstables, public routes, console routes, the sweep job
Guard hooksrc/api.mjsctx.internal: an in-process call with a verified caller
Consolepublic/assets/app/views/mcp/consent screen #/connect/:token, the "AI assistants" card
Teststest/mcp.test.mjsthe full flow, every tool, step-up, refresh, PHI, tenancy, keys

**Public routes.** /.well-known/oauth-protected-resource (and /mcp suffixed), /.well-known/oauth-authorization-server, GET /oauth/authorize, POST /oauth/token, POST /oauth/register, POST /oauth/revoke, POST /mcp (GET and DELETE answer 405), /docs/mcp.

**Authorization.**

**Endpoint.**

**Console routes.** GET|POST /api/mcp/consent/:token, GET /api/mcp/connections, DELETE /api/mcp/connections/:id (yours), GET /api/mcp/business, DELETE /api/mcp/business/:id (settings.manage). /api/mcp is closed to API keys and assistants.

**LurkerLock.** No reviewed file changed. The local session guard covers the console cookie (so the consent screen); bearer tokens on /mcp are checked by BizManager, as API keys are.