Files
hermes-mcp/docs/getting-started.html
Garfield 61dab40585 feat(saas): SquareMCP v2 — multi-tenant MCP platform complete
Steps 0–10 of the v2 plan, 194 tests passing.

Core infrastructure
- Shared Redis client (src/redis.ts); all four Redis consumers migrated
- Vitest test harness with vitest.config.ts and npm test/test:watch scripts

Billing & invoicing (Steps 1–2)
- Monthly invoice generation with idempotency (MySQL uq_customer_period unique key)
- Cron job with Redis distributed lock (Lua compare-delete, 1-hr TTL)
- Invoice emailer via nodemailer (FETCHERPAY SMTP)
- Billing middleware: checkLimit gate in handleToolCall; platform attribution fix

Email multi-tenancy (Step 3)
- EmailCtx = Account | EmailCredentials; imap.ts + smtp.ts accept both
- resolveEmailCtx helper in tools.ts; all email tools use customer credentials

Analytics + platform health (Steps 4–5)
- Chart.js bar charts for platform breakdown and daily activity
- Token expiry check in getCredential with dynamic import refresh
- platform-health.ts: per-platform health probe with 10-min Redis cache
- GET /api/health/platforms; "Token expired" amber badge in dashboard

Tool schema filtering (Step 6)
- stripAccountParam deep-clones tool schemas; multi-tenant sessions never
  see the internal account enum

OAuth hardening (Step 7)
- Atomic auth code consumption: UPDATE SET used=TRUE, check affectedRows
- customer_id threaded through oauth_auth_codes → oauth_tokens
- getTokenCustomer(); requireAuth resolves req.customer from Bearer token
- Consent page requires authenticated session; redirect_uri validated
  against registered URIs; http://localhost:* loopback wildcard

DCR browser flow (Step 8)
- ensureOAuthAppRegistered() upserts pre-registered SquareMCP OAuth app
  on startup with redirect URIs for mcp-callback, localhost:*, claude-desktop,
  opencode
- GET /oauth/connect-mcp → server-side redirect (client_id off frontend)
- GET /oauth/mcp-callback → exchanges code, renders config snippet page
  with copy buttons for Claude Desktop and Codex CLI

Webhooks (Step 9)
- webhook_url + webhook_secret columns on customers
- deliverWebhook(): HMAC-SHA256 signing, 3× exponential retry (1s/4s/16s),
  Redis DLQ with 7-day TTL on total failure
- isValidWebhookUrl(): SSRF protection (blocks RFC-1918, localhost, .local)
- POST /api/webhooks/config (secret returned once), GET, DELETE
- GET /api/admin/webhooks/dlq/:customerId
- WhatsApp POST route uses express.raw() for raw body preservation
- Dashboard Webhooks tab with secret-once display and copy button

Developer docs (Step 10)
- docs/ static HTML site (GitHub Pages, no build pipeline)
- index.html: landing page with client + platform overview
- getting-started.html: tabbed MCP config for Claude Desktop, Codex CLI, opencode
- platforms.html: LinkedIn, TikTok, WhatsApp, Instagram, Twitter, Telegram guides
- agent-tutorial.html: complete Node.js agent (Anthropic SDK + MCP SDK),
  LinkedIn posting loop, extensions for multi-platform + inbound webhook reaction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 23:43:56 -04:00

186 lines
7.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Getting Started — SquareMCP Docs</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<nav class="site-nav">
<div class="nav-inner">
<a href="index.html" class="nav-logo"><span class="nav-logo-mark">S</span> SquareMCP</a>
<div class="nav-links">
<a href="getting-started.html" class="active">Getting started</a>
<a href="platforms.html">Platform guides</a>
<a href="agent-tutorial.html">Agent tutorial</a>
<a href="https://hermes.squaremcp.com/openapi-social.json" target="_blank">API reference ↗</a>
</div>
<a href="https://squaremcp.com" class="nav-cta" target="_blank">Open app</a>
</div>
</nav>
<div class="page">
<div class="hero">
<h1>Getting started</h1>
<p>Connect your AI assistant to SquareMCP in five minutes. Choose your client below.</p>
</div>
<h2>Step 1 — Create your account</h2>
<ol class="steps">
<li>
<div>
<strong>Sign up at squaremcp.com</strong>
Open the <a href="https://squaremcp.com" target="_blank">SquareMCP dashboard</a>, create an account, and verify your email.
</div>
</li>
<li>
<div>
<strong>Get your access token</strong>
Click <strong>Connect MCP Client</strong> in the dashboard. This opens a short OAuth flow that issues a Bearer token bound to your account.
Copy the token shown on the confirmation page — it won't be displayed again.
</div>
</li>
<li>
<div>
<strong>Connect at least one platform</strong>
Go to <strong>Platforms</strong> and connect LinkedIn, TikTok, WhatsApp, or any other service. See <a href="platforms.html">Platform guides</a> for step-by-step instructions per platform.
</div>
</li>
</ol>
<h2>Step 2 — Configure your MCP client</h2>
<div class="tabs">
<button class="tab active" onclick="switchTab(this,'claude')">Claude Desktop</button>
<button class="tab" onclick="switchTab(this,'codex')">Codex CLI</button>
<button class="tab" onclick="switchTab(this,'opencode')">opencode</button>
</div>
<div id="tab-claude" class="tab-content tab-panel active">
<pre><code><span class="cmt">// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)</span>
<span class="cmt">// %APPDATA%\Claude\claude_desktop_config.json (Windows)</span>
{
<span class="str">"mcpServers"</span>: {
<span class="str">"squaremcp"</span>: {
<span class="str">"type"</span>: <span class="str">"http"</span>,
<span class="str">"url"</span>: <span class="str">"https://hermes.squaremcp.com/mcp"</span>,
<span class="str">"headers"</span>: {
<span class="str">"Authorization"</span>: <span class="str">"Bearer YOUR_TOKEN_HERE"</span>
}
}
}
}</code></pre>
<p>Restart Claude Desktop after saving. You should see SquareMCP tools in the tool picker (hammer icon).</p>
</div>
<div id="tab-codex" class="tab-content tab-panel">
<pre><code><span class="cmt"># ~/.codex/config.json</span>
{
<span class="str">"mcpServers"</span>: {
<span class="str">"squaremcp"</span>: {
<span class="str">"type"</span>: <span class="str">"http"</span>,
<span class="str">"url"</span>: <span class="str">"https://hermes.squaremcp.com/mcp"</span>,
<span class="str">"headers"</span>: {
<span class="str">"Authorization"</span>: <span class="str">"Bearer YOUR_TOKEN_HERE"</span>
}
}
}
}</code></pre>
<p>Or pass inline per command:</p>
<pre><code>codex --mcp-server squaremcp=https://hermes.squaremcp.com/mcp \
--mcp-header squaremcp:Authorization="Bearer YOUR_TOKEN_HERE" \
"Post a LinkedIn update about today's product launch"</code></pre>
<div class="callout">
<strong>PKCE flow (optional)</strong>
Codex CLI supports the full OAuth PKCE flow. Run <code>codex auth squaremcp</code> and follow the browser prompt — no token copy-paste required.
</div>
</div>
<div id="tab-opencode" class="tab-content tab-panel">
<pre><code><span class="cmt"># ~/.config/opencode/config.json</span>
{
<span class="str">"mcp"</span>: {
<span class="str">"servers"</span>: {
<span class="str">"squaremcp"</span>: {
<span class="str">"type"</span>: <span class="str">"http"</span>,
<span class="str">"url"</span>: <span class="str">"https://hermes.squaremcp.com/mcp"</span>,
<span class="str">"headers"</span>: {
<span class="str">"Authorization"</span>: <span class="str">"Bearer YOUR_TOKEN_HERE"</span>
}
}
}
}
}</code></pre>
<p>Save the file and restart opencode. The SquareMCP tools will appear in the tool list automatically.</p>
</div>
<h2>Step 3 — Verify the connection</h2>
<p>Ask your AI assistant:</p>
<pre><code>What social platforms do I have connected?</code></pre>
<p>It should call <code>get_profile</code> or <code>linkedin_get_profile</code> and return your account details. If you see a "Platform not connected" error, revisit the <a href="platforms.html">Platform guides</a>.</p>
<h2>Available tools</h2>
<p>SquareMCP exposes tools across every connected platform. A few highlights:</p>
<div class="card-grid">
<div class="card">
<h4>linkedin_create_post</h4>
<p>Publish text, image, or video to your LinkedIn feed.</p>
</div>
<div class="card">
<h4>tiktok_create_video</h4>
<p>Upload a video file and publish it to TikTok.</p>
</div>
<div class="card">
<h4>whatsapp_send_message</h4>
<p>Send a WhatsApp message to any number via Business API.</p>
</div>
<div class="card">
<h4>twitter_create_tweet</h4>
<p>Post a tweet with optional media attachment.</p>
</div>
<div class="card">
<h4>instagram_create_reel</h4>
<p>Publish a reel to your Instagram Business account.</p>
</div>
<div class="card">
<h4>send_email</h4>
<p>Send email from any connected IMAP/SMTP account.</p>
</div>
</div>
<p>See the full list in the <a href="https://hermes.squaremcp.com/openapi-social.json" target="_blank">API reference</a>.</p>
<h2>Troubleshooting</h2>
<h3>Tools not appearing in Claude</h3>
<p>Restart Claude Desktop after editing <code>claude_desktop_config.json</code>. If tools still don't appear, open the Claude Desktop developer console and look for MCP connection errors.</p>
<h3>"Platform not connected" errors</h3>
<p>The tool was called but the platform isn't linked to your account. Open the dashboard and connect the platform under <strong>Platforms</strong>.</p>
<h3>"Token expired" badge in dashboard</h3>
<p>OAuth tokens for LinkedIn, TikTok, and Instagram expire. SquareMCP attempts an automatic refresh — if that fails, reconnect the platform. WhatsApp, Telegram, and Discord use long-lived bot tokens that don't expire.</p>
<h3>Rate limit errors</h3>
<p>Each SquareMCP plan has a monthly tool-call limit. Check <strong>Usage</strong> in the dashboard. Upgrade your plan if you're consistently hitting the limit.</p>
<div class="callout callout-warn">
<strong>Keep your Bearer token secret</strong>
Your Bearer token has full access to every connected platform. Treat it like a password. Rotate it from the dashboard if you suspect it's been exposed.
</div>
</div>
<script>
function switchTab(btn, id) {
btn.closest('.page').querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
btn.closest('.page').querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
btn.classList.add('active');
document.getElementById('tab-' + id).classList.add('active');
}
</script>
</body>
</html>