Claude.ai's MCP auth callback requires a state parameter. Generate a random
state in /oauth/connect-claude-ai and preserve it through the consent form
and login redirect so it is echoed back to claude.ai.
Add https://claude.ai/api/mcp/auth_callback to the pre-registered OAuth
client redirect_uris so the new /oauth/connect-claude-ai route works.
ensureOAuthAppRegistered uses ON DUPLICATE KEY UPDATE so the DB row is
updated on the next server startup.
- Replace single 'Connect to Claude / ChatGPT' button with a modal picker
offering Claude.ai web, Claude Desktop, Codex CLI, and ChatGPT/GPT Actions.
- Add /oauth/connect-claude-ai backend route that redirects to Anthropic's
official https://claude.ai/api/mcp/auth_callback OAuth callback.
- Update MCP callback result page with browser-specific instructions for
Claude.ai web, Claude Desktop, ChatGPT/GPT Actions, and Codex CLI.
- Deploy new app and hermes images to K8s.
Addresses claude.ai accessibility flagging: all 11 platform Connect buttons now
have aria-label="Connect [Platform]" and title="Connect [Platform]"; all form
inputs have aria-label; modal close button has aria-label="Close".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The global express.json() middleware at line 77 was parsing the body
into a JS object before the route-level express.raw() could capture
the raw Buffer. When WHATSAPP_APP_SECRET is set and a signature is
present, crypto.createHmac().update(req.body) received an Object
instead of Buffer, throwing TypeError and crashing the process.
Fix: register app.use('/webhook/whatsapp', express.raw({ type: '*/*' }))
before app.use(express.json()) so the raw body is preserved for HMAC.
Post-deploy verification: all 7 webhook tests pass, pod 0 restarts.
Related: SquareMCP/2026-06-10-twilio-whatsapp-webhook-deployment.md
Add POST /webhook/twilio/whatsapp for the pilot approval loop — Alex
replies 1/2/3 to the Twilio number to approve post drafts. Includes
HMAC-SHA1 signature validation, Redis dedup (wa_msg_seen:MessageSid),
pilot_owner_phone allowlist, staleness check (7d), tracking link
creation, and draft status update.
Also fix two security bugs in the existing Meta webhook handler:
fail-open when WHATSAPP_APP_SECRET unset (now 503), and missing length
guard before timingSafeEqual (was RangeError → 500, now 403).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- src/tracking-links.ts — create, get, record click, validate URL, bot detection
- src/tracking-links.test.ts — 20 tests, all passing
- src/db.ts — tracking_links table, post_drafts table, 6 pilot columns on customers
- src/index.ts — public GET /t/:token redirect route (no auth)
Analytics (click count) is fire-and-forget after redirect.
MySQL is source of truth; redirect never depends on Redis.
Related: SquareMCP/2026-06-09-tracking-links-deployment.md
- product/site/squaremcp-broker-demo.mp4 — 45s mortgage broker demo video
served at squaremcp.com/squaremcp-broker-demo.mp4, sent to Ferrari Lending
- .gitignore: add .runner (Gitea Actions runner token, should not be committed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces direct Poste.io SMTP (mail.squaremcp.com:30587, port 25 blocked)
with Azure Communication Services relay (smtp.azurecomm.net:587).
All sqcp_* accounts share a single ACS credential; FROM addresses unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CRITICAL: forgot-password no longer returns token in response; sends email via info@squaremcp.com instead
- Rate limit: login 10/15min, forgot-password 5/hr, chat 30/hr (Redis, per IP)
- express.json() capped at 100kb
- WhatsApp webhook HMAC verification (activates when WHATSAPP_APP_SECRET is set)
- JWT_SECRET now explicitly set in K8s (was falling back to CREDENTIAL_ENCRYPTION_KEY)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Customers who haven't connected WhatsApp in the dashboard now
automatically use the SquareMCP default number (+19547385805 via Twilio)
instead of throwing 'WhatsApp not connected'. Routing flag usingDefault
replaces the !customer check so OAuth sessions get the same Twilio path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ChatGPT regenerates its GPT ID (and callback URL) every time the GPT
is saved, making exact redirect_uri matching impossible. Added support
for the registered URI pattern https://chat.openai.com/aip/*/oauth/callback
which matches any valid ChatGPT GPT callback via regex.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drops obsidian (5 ops) and whatsapp/templates list (1 op) to stay
under ChatGPT's 30-operation cap. Served at /openapi-chatgpt.json.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The SquareMCP number (+19547385805) is registered under Twilio's BSP,
so direct Meta API sends were blocked with #200 permission errors.
Default account now routes through Twilio's REST API; customer-owned
accounts still use Meta's Cloud API directly.
- twilioSend(): POST to api.twilio.com with Basic auth
- resolveTemplateText(): fetches template body from Meta, substitutes
{{1}}/{{}} parameters, so templates render correctly via Twilio
- Bumped WHATSAPP_API_VERSION to v21.0
- Added TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_WHATSAPP_NUMBER,
WHATSAPP_DEFAULT_BUSINESS_ACCOUNT_ID to K8s deployment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WHATSAPP_DEFAULT_PHONE_NUMBER_ID, WHATSAPP_DEFAULT_ACCESS_TOKEN,
and WA_VERIFY_TOKEN (hermes-wa-2026) added to K8s deployment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
POST /webhook/twilio/voice returns TwiML that says the number doesn't
accept voice calls and hangs up — needed for Twilio number config.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- notifications/slack.ts: added sendChatEscalationAlert (fires when visitor
asks about pricing, demo, help, or a human) and sendSupportEmailAlert
- email-poller.ts: polls support@squaremcp.com every 5 min via IMAP,
deduplicates with Redis (support📧alerted_uids), fires Slack alert
for each new unseen message
- index.ts: detectEscalation() scans last user message for trigger phrases;
chat endpoint fires alert fire-and-forget after responding; startEmailPoller()
called on server boot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- chat.ts: system prompt now includes step-by-step ChatGPT Custom GPT
setup (openapi.json import + OAuth), Claude/Cursor/Windsurf config,
and mortgage broker guidance — bot no longer incorrectly says ChatGPT
is unsupported
- smtp.ts: all sqcp_* accounts now route to mail.squaremcp.com (SQCP_SMTP_HOST)
instead of the fetcherpay server
- tools.ts: ACCOUNT_PARAM description now lists all 14 mailboxes including
the 7 squaremcp.com accounts so Claude picks the right one without guessing
- package.json: postinstall hook runs imapflow patch script after npm install
- hermes-k8s.yaml: updated image digest to current production build
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move client.connect() inside try/catch in withClient
- Add logImapError() writing full stack to /vaults/imap-errors.log for diagnosis
- Extend patch-imapflow.cjs to guard this.remainder.trim() in parser-instance.js
- Root cause of reported crash was undefined args.q (callers passing 'query' not 'q')
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New accounts: sqcp_garfield, sqcp_info, sqcp_sales, sqcp_support,
sqcp_founder, sqcp_contact, sqcp_admin
- All use same poste.io mail server as fetcherpay.com (IMAP 30993, SMTP 30587)
- Password: onelove for all accounts
- Updated: imap.ts, smtp.ts, tools.ts, manifest.ts, hermes-k8s.yaml
Chat widget now runs a live tool-use loop via Claude Haiku. Exposes
slack, discord, and telegram demo tools — bot can actually send messages
and read channels to prove the platform works in real time. Widget shows
a purple pill with tool names when the agent calls a live platform.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Slack as customer-facing messaging platform (client, 4 MCP tools, dashboard card)
- Add /api/chat endpoint powered by Claude Haiku with SquareMCP system prompt
- Add embeddable chat-widget.js injected into all 3 sites (docs, app, www)
- Add ANTHROPIC_API_KEY, serve product/ as static files
- Update Platform type to include slack
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
16s landscape (1920x1080): shows SquareMCP chat prompt triggering an
animated cURL call to the Business Management API creating a message
template (HEADER/BODY/FOOTER components with variables), then the right
panel renders a WhatsApp phone UI previewing the template bubble with
variable placeholders highlighted and a PENDING status badge.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>