diff --git a/hermes-k8s.yaml b/hermes-k8s.yaml index 1c018d8..2a96a24 100644 --- a/hermes-k8s.yaml +++ b/hermes-k8s.yaml @@ -22,7 +22,7 @@ spec: fsGroup: 1000 containers: - name: hermes-mcp - image: localhost:32000/hermes-mcp@sha256:17f1f7ce059f0f87d9c34c39e2ea0fb1f25cf72f9279341c5912e6c35690f43a + image: localhost:32000/hermes-mcp@sha256:54488f625b5a065f3cfb30d9d0afe269dac65aadd8206652d27da034daf1dee4 imagePullPolicy: Always securityContext: allowPrivilegeEscalation: false diff --git a/package.json b/package.json index c1d0cc8..d66fee8 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "test:product-site:cleanup": "node product/site/cleanup-test-submissions.mjs", "deploy:product-site:verify": "bash product/site/deploy-and-verify.sh", "test": "vitest run", - "test:watch": "vitest" + "test:watch": "vitest", + "postinstall": "node scripts/patch-imapflow.cjs" }, "dependencies": { "@anthropic-ai/sdk": "^0.96.0", diff --git a/src/chat.ts b/src/chat.ts index 1dfd5cd..d6a19d1 100644 --- a/src/chat.ts +++ b/src/chat.ts @@ -10,16 +10,54 @@ You have real tools connected to live platforms. When a visitor asks "can it sen What SquareMCP does: - Connects AI coding assistants to social platforms: LinkedIn, TikTok, WhatsApp, Instagram, Twitter/X, Facebook, Telegram, Discord, Slack, and Email - Works with any MCP-compatible client: Claude Desktop, Claude Code, Cursor, Windsurf, opencode, Codex CLI +- Also works with ChatGPT via Custom GPT (uses the REST API + OAuth, not MCP protocol directly) - Provides a multi-tenant SaaS platform where each customer securely stores their own platform credentials - Plans: Free (100 calls/month), Pro, Business +How to connect — by AI client: + +CHATGPT (chatgpt.com): +SquareMCP works with ChatGPT via a Custom GPT with Actions. Steps: +1. Go to chatgpt.com → Explore GPTs → Create → Actions → Import from URL +2. Import the OpenAPI schema: https://hermes.squaremcp.com/openapi.json +3. Set Authentication to OAuth: + - Authorization URL: https://hermes.squaremcp.com/oauth/authorize + - Token URL: https://hermes.squaremcp.com/oauth/token + - Register your OAuth client first at: https://hermes.squaremcp.com/oauth/register +4. Connect your social accounts in the SquareMCP dashboard at https://app.squaremcp.com +5. Ask your Custom GPT: "Send a WhatsApp to my top 3 clients" — it just works. +Full guide: email support@squaremcp.com for the ChatGPT setup walkthrough. + +CLAUDE (claude.ai or Claude Desktop): +1. In claude.ai → Settings → Integrations → Add MCP server +2. Server URL: https://hermes.squaremcp.com/mcp +3. Authenticate via OAuth +4. Connect social accounts at https://app.squaremcp.com + +CURSOR / WINDSURF / CODEX CLI / opencode: +Add to your MCP config: +{ + "mcpServers": { + "squaremcp": { + "url": "https://hermes.squaremcp.com/mcp", + "apiKey": "your-api-key-from-dashboard" + } + } +} + +For mortgage brokers specifically: +- ChatGPT Custom GPT is often the easiest starting point — no install required, works in the browser +- WhatsApp rate blast: one command sends updates to hundreds of clients +- Multi-channel: handle WhatsApp, email, LinkedIn, and Facebook from a single AI conversation +- Compliance: we can scope the setup to stay within RESPA/TILA guidelines + When using tools: - For demo sends (Slack, Telegram, Discord), send a short, friendly message that explains this is a live SquareMCP demo - After a tool succeeds, explain what just happened and how easy it was - If a tool fails (missing credentials), explain what credential the customer would set up instead - Never expose tokens or internal IDs in your reply -Keep replies concise. If you don't know something, say so and suggest emailing support@squaremcp.com.`; +Keep replies concise and practical. If you don't know something, say so and suggest emailing support@squaremcp.com.`; // Tools the public demo agent is allowed to use (no customer auth needed — uses env var creds) const DEMO_TOOL_NAMES = new Set([ diff --git a/src/smtp.ts b/src/smtp.ts index df20c1f..52c7d1b 100644 --- a/src/smtp.ts +++ b/src/smtp.ts @@ -5,6 +5,9 @@ import type { EmailCredentials } from './multitenancy/credential-store.js'; const FETCHERPAY_SMTP_HOST = process.env['FETCHERPAY_SMTP_HOST'] ?? 'mail.fetcherpay.com'; const FETCHERPAY_SMTP_PORT = parseInt(process.env['FETCHERPAY_SMTP_PORT'] ?? '30587'); +const SQCP_SMTP_HOST = process.env['SQCP_SMTP_HOST'] ?? 'mail.squaremcp.com'; +const SQCP_SMTP_PORT = parseInt(process.env['SQCP_SMTP_PORT'] ?? '30587'); + function fetcherpaySmtpTransport(user: string, pass: string) { return nodemailer.createTransport({ host: FETCHERPAY_SMTP_HOST, @@ -15,6 +18,16 @@ function fetcherpaySmtpTransport(user: string, pass: string) { }); } +function sqcpSmtpTransport(user: string, pass: string) { + return nodemailer.createTransport({ + host: SQCP_SMTP_HOST, + port: SQCP_SMTP_PORT, + secure: false, + auth: { user, pass }, + tls: { rejectUnauthorized: false }, + }); +} + function getEnvSmtpTransport(account: Account = 'yahoo') { switch (account) { case 'fetcherpay': @@ -28,19 +41,19 @@ function getEnvSmtpTransport(account: Account = 'yahoo') { case 'founder': return fetcherpaySmtpTransport(process.env['FOUNDER_EMAIL']!, process.env['FOUNDER_PASSWORD']!); case 'sqcp_garfield': - return fetcherpaySmtpTransport(process.env['SQCP_GARFIELD_EMAIL']!, process.env['SQCP_GARFIELD_PASSWORD']!); + return sqcpSmtpTransport(process.env['SQCP_GARFIELD_EMAIL']!, process.env['SQCP_GARFIELD_PASSWORD']!); case 'sqcp_info': - return fetcherpaySmtpTransport(process.env['SQCP_INFO_EMAIL']!, process.env['SQCP_INFO_PASSWORD']!); + return sqcpSmtpTransport(process.env['SQCP_INFO_EMAIL']!, process.env['SQCP_INFO_PASSWORD']!); case 'sqcp_sales': - return fetcherpaySmtpTransport(process.env['SQCP_SALES_EMAIL']!, process.env['SQCP_SALES_PASSWORD']!); + return sqcpSmtpTransport(process.env['SQCP_SALES_EMAIL']!, process.env['SQCP_SALES_PASSWORD']!); case 'sqcp_support': - return fetcherpaySmtpTransport(process.env['SQCP_SUPPORT_EMAIL']!, process.env['SQCP_SUPPORT_PASSWORD']!); + return sqcpSmtpTransport(process.env['SQCP_SUPPORT_EMAIL']!, process.env['SQCP_SUPPORT_PASSWORD']!); case 'sqcp_founder': - return fetcherpaySmtpTransport(process.env['SQCP_FOUNDER_EMAIL']!, process.env['SQCP_FOUNDER_PASSWORD']!); + return sqcpSmtpTransport(process.env['SQCP_FOUNDER_EMAIL']!, process.env['SQCP_FOUNDER_PASSWORD']!); case 'sqcp_contact': - return fetcherpaySmtpTransport(process.env['SQCP_CONTACT_EMAIL']!, process.env['SQCP_CONTACT_PASSWORD']!); + return sqcpSmtpTransport(process.env['SQCP_CONTACT_EMAIL']!, process.env['SQCP_CONTACT_PASSWORD']!); case 'sqcp_admin': - return fetcherpaySmtpTransport(process.env['SQCP_ADMIN_EMAIL']!, process.env['SQCP_ADMIN_PASSWORD']!); + return sqcpSmtpTransport(process.env['SQCP_ADMIN_EMAIL']!, process.env['SQCP_ADMIN_PASSWORD']!); case 'gmail': return nodemailer.createTransport({ host: 'smtp.gmail.com', diff --git a/src/tools.ts b/src/tools.ts index 5f008e2..34d29f1 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -20,7 +20,7 @@ const ACCOUNT_PARAM = { account: { type: 'string', enum: ['yahoo', 'fetcherpay', 'garfield', 'sales', 'leads', 'founder', 'gmail', 'sqcp_garfield', 'sqcp_info', 'sqcp_sales', 'sqcp_support', 'sqcp_founder', 'sqcp_contact', 'sqcp_admin'], - description: 'Which mailbox to use: "yahoo" (gheron01@yahoo.com), "fetcherpay" (garfield.heron@fetcherpay.com), "garfield" (garfield@fetcherpay.com), "sales" (sales@fetcherpay.com), "leads" (leads@fetcherpay.com), "founder" (founder@fetcherpay.com), or "gmail" (Gmail account). Defaults to "yahoo".', + description: 'Which mailbox to use: "yahoo" (gheron01@yahoo.com), "fetcherpay" (garfield.heron@fetcherpay.com), "garfield" (garfield@fetcherpay.com), "sales" (sales@fetcherpay.com), "leads" (leads@fetcherpay.com), "founder" (founder@fetcherpay.com), "gmail" (garfield.heron@gmail.com), "sqcp_garfield" (garfield@squaremcp.com), "sqcp_info" (info@squaremcp.com), "sqcp_sales" (sales@squaremcp.com), "sqcp_support" (support@squaremcp.com), "sqcp_founder" (founder@squaremcp.com), "sqcp_contact" (contact@squaremcp.com), "sqcp_admin" (admin@squaremcp.com). Defaults to "yahoo".', }, };