# GrowSurf MCP Server [![npm version](https://img.shields.io/npm/v/@growsurfteam/growsurf-mcp)](https://www.npmjs.com/package/@growsurfteam/growsurf-mcp) [![npm downloads](https://img.shields.io/npm/dm/@growsurfteam/growsurf-mcp)](https://www.npmjs.com/package/@growsurfteam/growsurf-mcp) [![license](https://img.shields.io/npm/l/@growsurfteam/growsurf-mcp)](./LICENSE) [![node](https://img.shields.io/node/v/@growsurfteam/growsurf-mcp)](https://nodejs.org) The **official GrowSurf command-line interface (CLI) and open-source Model Context Protocol (MCP) server** for implementing **GrowSurf referral and affiliate programs** with guided steps and safe REST API wrappers. Connect it to an AI agent and, in plain language, the agent can create a referral or affiliate program, configure rewards, install tracking, add and manage participants, and read analytics, all backed by the GrowSurf REST API. MCP is optional. Any action-capable agent that can send HTTPS requests can start with GrowSurf's client-neutral REST workflow at https://growsurf.com/agent-start.md. - Learn more about GrowSurf at https://growsurf.com - Start with direct REST at https://growsurf.com/agent-start.md - Read the OpenAPI contract at https://growsurf.com/openapi.json - Read the Arazzo workflow at https://growsurf.com/arazzo.yaml - Learn about optional MCP setup at https://docs.growsurf.com/build-with-ai#optional-connect-mcp ## Who is this for This MCP server is for: - Developers using MCP-compatible tools (Claude Code, Codex, Cursor, Copilot, and other MCP clients) - Teams that want guided, AI-assisted GrowSurf integrations This MCP server is NOT for: - Browser-only users who want a local stdio install. ChatGPT web and Claude.ai use the hosted remote connector at `https://mcp.growsurf.com`. Claude Desktop can use either the local stdio server or the hosted connector. See the full client list and setup at https://docs.growsurf.com/build-with-ai#optional-connect-mcp. ## What you get - **Guided Integration**: - Universal Code install - Native iOS/Android and React Native SDK implementation guidance - Native GrowSurf Window guidance - Signup flow - Qualifying action flow - Affiliate sale / transaction tracking - Webhooks - **Agent Recipes**: - MCP prompts for creating referral programs, creating affiliate programs, advising on program design, troubleshooting referral tracking, embedding the widget, listing and fetching programs and participants, configuring rewards, wiring webhooks, and reading analytics - Prompts use details from your conversation and ask only for missing information needed for the next step. No form inputs are needed. Existing prompt names and direct arguments remain supported. - Installable Agent Skill bundle at `skills/growsurf-agent-toolkit` - Steering to review starter Design, Emails, Options, Installation, rewards, and GrowSurf Window content before patching - One-shot program-creation eval prompts and acceptance checks for starter content and configuration review - **Happy‑Path REST API Wrappers**: - Create an account and get an API key with no existing credentials - Read and rename the bound team, request team verification, and resend the team owner's verification email - List and get campaigns - Get campaign analytics (totals, time series, email metrics, participant engagement activity, and activation cohorts) - Create, update, and clone programs (campaigns) - List, create, update, and delete campaign rewards - List, create, update, and delete Program Resources, including a safe one-time FILE preparation flow - Get/update Design, Emails, Options, and Installation config - Capture temporary GrowSurf preview screenshots so the user can see a draft program - List, create, update, delete, and test program webhooks - List, get, and add participants - Update a participant, email a participant, and get a participant's analytics and activity logs - Trigger referral credit (for referral programs), with optional delayed award (1-90 days) - Cancel a pending delayed referral trigger (for referral programs) - Record affiliate sale/transaction (for affiliate programs) - Create mobile participant tokens for signed-in native app users - **Official API Library Snippets**: - TypeScript - Python - PHP - Ruby - Java - **Helpers**: - Compute participant auto-auth HMAC hash - Normalize webhook payloads - Generate best‑effort idempotency keys for webhook deduplication ## Choosing a tool Use program and participant tools to read or change records. Guidance tools return advice or code for you to apply: | Task | Tool | | --- | --- | | Choose a program design and reward structure | `growsurf_program_design_advisor` | | Plan a web integration | `growsurf_integration_guide` | | Get browser JavaScript examples | `growsurf_client_snippets` | | Get one embeddable element's HTML | `growsurf_embeddable_element_snippet` | | Generate page-level participant auto authentication code | `growsurf_grsf_config_snippet` | | Get backend REST API library examples | `growsurf_api_library_snippets` | | Integrate a native iOS, Android, or React Native app | `growsurf_mobile_sdk_guide` | | Diagnose a program problem | `growsurf_troubleshoot_referral_tracking` | | Generate checks for an agent's program-creation workflow | `growsurf_agent_program_creation_eval` | Published tool names and fields use `campaign` for a program, including `campaignId`. These identifiers remain supported. Display titles use program terminology; Campaign Reward remains the name for a reward configuration. To delete one participant, pass one ID or email in `participants` to `growsurf_bulk_delete_participants`. The same permanent-deletion warnings apply. A separate single-participant tool is not needed. Program deletion and explicit reward fulfillment are outside this MCP tool set; completing a program is not deletion, and configuring a reward is not proof that it was delivered. ## Optional compact connection The default connection lists all 63 tools. Add `--compact` to select 32 tools for program setup, installation, participant management, referral tracking, rewards, and analytics. Your credential permissions can reduce the visible set further. ```bash npx -y @growsurfteam/growsurf-mcp --compact ``` In a stdio client configuration, append `"--compact"` to the package's `args` array. Server integrations can call `createGrowSurfMcpServer({ toolSurface: "compact" })`. Omit the option to keep the full catalog. Compact combines related guidance and settings tools: | Tool | Selection | Arguments | | --- | --- | --- | | `growsurf_get_guidance` | `topic`: `integration`, `browser`, `api_libraries`, `mobile_sdk`, `embeddable_element`, `participant_auto_auth`, or `program_creation_checks` | Put the selected guide's existing arguments under `input`. Use `{}` for defaults. | | `growsurf_get_program_settings` | `section`: `design`, `emails`, `options`, or `installation` | Put `campaignId` under `input`, or use the configured default. | | `growsurf_update_program_settings` | The same `section` values | Put `campaignId` and the `fields` patch under `input`. Read the section first. | For example, read a program's installation settings: ```json { "name": "growsurf_get_program_settings", "arguments": { "section": "installation", "input": { "campaignId": "YOUR_PROGRAM_ID" } } } ``` Program recommendations and troubleshooting keep their own tools. Participant reads, updates, deletion, referral actions, and sale or refund actions remain separate. Compact prompts, resources, guidance, and proposed configuration calls use the compact tool names and arguments. Use the full connection for account creation, team administration, program cloning, participant resources, webhook creation/updates/deletion/tests, participant emails, payout destinations, and webhook normalization. Remove `--compact` and reconnect. These operations remain available with their existing contracts on the full connection; compact rejects calls to tools outside its catalog. The tool-selection table above describes the full connection. ## Requirements - Node.js 22+ - A GrowSurf account for hosted OAuth - A GrowSurf **API key** for local stdio setup or manual API-key remote setup. A scoped key works as long as it has access to the tools and programs you want the agent to use. - A **campaign (program) ID** for campaign-scoped tools. Set `GROWSURF_CAMPAIGN_ID` as the default, pass a `campaignId` argument to target a specific program, or call `growsurf_list_campaigns` to find available programs. For a newly created program, pass the `id` returned by `growsurf_create_campaign` to the other tools. - Static guidance/snippet tools can run without credentials - Exception: `growsurf_create_account` needs **no** API key. Call it only after the authorized owner approves account creation and accepts GrowSurf's Terms of Service and Privacy Policy. The account starts a 14-day Business trial without a credit card and returns its API key once. A lost key cannot be recovered through the API, so use this only if you can store a secret past the current conversation; otherwise have the owner connect `https://mcp.growsurf.com` and sign in. Pause for owner email verification before protected calls. Unverified accounts are deleted after 7 days. Team-level tools do not need a campaign ID. - Every listed tool publishes standard MCP read-only, destructive, idempotent, and open-world safety hints. Scoped business actions stay available; API-key rotation is intentionally not an MCP tool. Rotate keys in GrowSurf Settings or through a direct REST/SDK client. ## Official CLI The npm package installs the `growsurf-mcp` command. Run it without a global install: ```bash npx -y @growsurfteam/growsurf-mcp ``` The CLI starts GrowSurf's local stdio MCP server. Set `GROWSURF_API_KEY` for API-backed actions and `GROWSURF_CAMPAIGN_ID` for a default program. Public developer resources and static integration guidance work without credentials. Inspect the installed command without starting the stdio server: ```bash npx -y @growsurfteam/growsurf-mcp --help npx -y @growsurfteam/growsurf-mcp --version ``` ## Supported MCP Hosts For an MCP-compatible host, use GrowSurf's hosted OAuth endpoint at `https://mcp.growsurf.com` when the host supports remote Streamable HTTP with OAuth. Use the local `npx` server when the host needs a stdio process or manual API-key setup. No GrowSurf account yet? After owner approval, an agent can connect to `https://mcp.growsurf.com/onboard` with no credentials and call `growsurf_create_account`. The GrowSurf MCP server works with any MCP-compatible host. The examples below cover a few config-based and CLI hosts. For the complete, current list of supported clients (including ChatGPT web, Claude.ai, Claude Desktop, GitHub Copilot, Gemini CLI, Devin Desktop, and Cline) with step-by-step setup, see https://docs.growsurf.com/build-with-ai#optional-connect-mcp. - Cursor - Claude Code (CLI-based) - Antigravity - Codex (CLI-based) ### Cursor 1. Open or create Cursor's global MCP configuration at `~/.cursor/mcp.json`. 2. Add a server named `growsurf` with the hosted OAuth endpoint: ```json { "mcpServers": { "growsurf": { "type": "http", "url": "https://mcp.growsurf.com" } } } ``` For local stdio instead, use: ```json { "mcpServers": { "growsurf": { "command": "npx", "args": ["-y", "@growsurfteam/growsurf-mcp"], "env": { "GROWSURF_API_KEY": "YOUR_API_KEY", "GROWSURF_CAMPAIGN_ID": "YOUR_CAMPAIGN_ID" } } } } ``` ### Claude Code (CLI-based) Open your terminal and connect Claude Code to the hosted OAuth endpoint: ```bash claude mcp add --transport http --scope user growsurf https://mcp.growsurf.com claude mcp login growsurf ``` For local stdio instead, install the server directly into Claude Code: ```bash claude mcp add growsurf \ -e GROWSURF_API_KEY=your_api_key \ -e GROWSURF_CAMPAIGN_ID=your_campaign_id \ -- npx -y @growsurfteam/growsurf-mcp ``` ### Antigravity 1. Open Antigravity. 2. Click the **…** menu in the panel to the right and select **MCP Servers**. 3. Click **Manage MCP Servers > View raw config**. 4. Recommended: in the `mcp_config.json` file, add the hosted OAuth endpoint: ```json { "mcpServers": { "growsurf": { "serverUrl": "https://mcp.growsurf.com" } } } ``` 5. Save the config, open **Settings > Customizations**, and select **Authenticate** for GrowSurf. For local stdio instead, use: ```json { "mcpServers": { "growsurf": { "command": "npx", "args": ["-y", "@growsurfteam/growsurf-mcp"], "env": { "GROWSURF_API_KEY": "YOUR_API_KEY", "GROWSURF_CAMPAIGN_ID": "YOUR_CAMPAIGN_ID" } } } } ``` ### Codex Recommended: connect Codex to the hosted OAuth endpoint: ```bash codex mcp add growsurf --url https://mcp.growsurf.com codex mcp login growsurf ``` Or create or edit `~/.codex/config.toml`: ```toml [mcp_servers.growsurf] url = "https://mcp.growsurf.com" ``` For local stdio instead, add the following: ```toml [mcp_servers.growsurf] command = "npx" args = ["-y", "@growsurfteam/growsurf-mcp"] [mcp_servers.growsurf.env] GROWSURF_API_KEY = "YOUR_API_KEY" GROWSURF_CAMPAIGN_ID = "YOUR_CAMPAIGN_ID" ``` Or configure local stdio from the CLI: ```bash codex mcp add growsurf \ --env GROWSURF_API_KEY=YOUR_API_KEY \ --env GROWSURF_CAMPAIGN_ID=YOUR_CAMPAIGN_ID \ -- npx -y @growsurfteam/growsurf-mcp ``` ## Configuration Set the following environment variables when running the MCP server: - `GROWSURF_API_KEY` (optional for startup; required for API-calling tools. Use a key with the scopes and program access those tools need) - `GROWSURF_CAMPAIGN_ID` (optional; the default program for campaign-scoped tools. A tool's `campaignId` argument overrides it, so a single server can operate on any of your programs) - `GROWSURF_API_BASE_URL` (optional; defaults to `https://api.growsurf.com/v2`. Useful for local or hosted MCP gateways that should call a different GrowSurf API origin) - `GROWSURF_UPLOAD_ALLOWED_ORIGINS` (required only for FILE Resource uploads; a comma-separated private allowlist of exact HTTPS origins accepted from GrowSurf upload tickets. Wildcards and URL paths are rejected) The hash helper requires an explicit `participantAuthSecret` argument and never uses `GROWSURF_PARTICIPANT_AUTH_SECRET`. Use a test secret for MCP examples; authenticate users and sign with production secrets on your backend. For webhooks, configure a signing `secret` and verify `GrowSurf-Signature` on your backend. `GROWSURF_WEBHOOK_TOKEN` is no longer used; keep secrets out of webhook URLs. ## Run with npx After publishing this package, customers can run: ```bash npx @growsurfteam/growsurf-mcp ``` For local development in this repo: ```bash npm install npm run build node dist/cli.js ``` ## MCP tools Every tool declares an MCP output schema and returns `structuredContent`, so hosts know each tool's result shape. REST tools return the API response (plus a JSON text block for older clients); the guidance and snippet tools return their markdown document under `markdown`. Program, reward-configuration, options, and participant reads also include a `rewardEvidence` object in `structuredContent`. It records what this response establishes about approval policy and automatic fulfillment marking. Delivery remains unknown without the relevant fulfillment records. This assessment applies to this response only; combine it with other evidence. The API fields and original JSON text remain unchanged. ### Guided Integration - `growsurf_integration_guide` Step-by-step guidance for implementing a GrowSurf referral or affiliate program. - `growsurf_mobile_sdk_guide` Native iOS/Android or React Native SDK guidance for attribution, `shareUrl`, `trackShare`, and the native GrowSurf Window. Set `platform` to `react_native` for the React Native SDK. - `growsurf_api_library_snippets` Official REST API library snippets for TypeScript, Python, PHP, Ruby, and Java. - `growsurf_list_integrations` List every integration the program can connect, each with `connected`, `enabled`, `autoDisabled`, and the dashboard `connectUrl`. Check this before acting on an integration. - `growsurf_get_integration_connect_link` Get a dashboard link that opens a specific integration's connect panel (Stripe, PayPal, Tango Card, Mailchimp, and many more). Hand it to the user when they want to connect one. The program is checked first, and the result reports whether the integration is already connected. Connecting happens in the dashboard, not through the API. ### Program design and troubleshooting - `growsurf_program_design_advisor` Returns a short first draft by default. Set `detail: "full"` for the complete report, including reward, sharing, and integration figures. `benchmarkFacts` carries complete statements with each ratio's unit, median, quartiles, sample, and source. Quote these statements together so a referral ratio cannot be mistaken for the percentage of people who refer. Recommend a qualifying action, reward structure, fulfillment path, safeguards, share channels, and integrations. The result includes `markdown`, a `configurationPlan` with exact tool arguments, and `decisions` with the qualifying action and unresolved customer choices. Call it before proposing rewards. Preserve the returned call shapes; the advisor and program-creation tools use different `goal` enums. Replace each `` with the `id` returned by program creation. Drafts leave reward amounts and commission terms open until the customer chooses them; a budget is a limit, not an incentive. Set `salesMotion` to `sales_led` for demos or negotiated contracts, or `self_service` for direct purchases. When the host supplies insights, advice includes aggregate figures; without insights it uses documentation. Non-USD advice and budget comparisons omit dollar reward bands because the data mixes dollar currencies. - `growsurf_troubleshoot_referral_tracking` Symptom-first diagnosis: referrals not credited, participant emails not sending, rewards not issued, participants not added, Universal Code not detected, integrations not syncing, Zapier errors, fraud flags, dashboard numbers that look wrong, and more. Returns the checks to run in order (with the read tool and field for each), the likely causes most common first, fixes, and doc links. Pass a `symptom` key, or a `description` that names the symptom. ### Client & UI Snippets - `growsurf_client_snippets` JavaScript SDK, GrowSurf Window, and embeddable examples. Includes a reminder to use a frontend design workflow when placing or styling embeddable UI. - `growsurf_embeddable_element_snippet` HTML snippet for a specific GrowSurf embeddable element. - `growsurf_grsf_config_snippet` `` snippet for configuring `window.grsfConfig` and participant auto-auth. ### Account onboarding - `growsurf_create_account` Create a GrowSurf account and get an API key. This is the only tool that does not require `GROWSURF_API_KEY`. The returned key is shown once and locked (`403` `EMAIL_NOT_VERIFIED_ERROR`) until the owner verifies their email; verification unlocks that same key, so keep it and retry. It is replaced only on the owner's first dashboard sign-in. Creating an account agrees, on the account holder's behalf, to GrowSurf's [Terms of Service](https://growsurf.com/terms) and [Privacy Policy](https://growsurf.com/privacy). ### Team - `growsurf_get_team` Fetch the team bound to the API key or OAuth connection, including its GrowSurf verification state. - `growsurf_update_team` Update the bound team's display name. - `growsurf_request_team_verification` Ask GrowSurf to verify the bound team, which is required before a program can email participants. - `growsurf_resend_team_owner_verification_email` Resend the verification email to the bound team's owner without revealing their email address. ### API & Tracking - `growsurf_get_campaign` Fetch campaign configuration. - `growsurf_list_campaigns` List programs available to the credential. Use this to find a `campaignId` before calling campaign-scoped tools. - `growsurf_get_campaign_analytics` Fetch program analytics, with optional per-period `series`, comparison, status, rate, email metrics via `include=email`, and participant activity-period engagement via `include=engagement`. - `growsurf_get_campaign_activation_analytics` Fetch eligible-participant activation cohorts with a fixed 7- or 30-day observation window. Referral programs group by `enrolledAsAdvocateAt`; affiliate programs group by `approvedAsAffiliateAt`. Read `coverageStartAt`, `state`, and `reason` before interpreting zeroes or nulls. - `growsurf_create_campaign` Create a new program (campaign) with type-appropriate starter content and optional inline rewards (only needs `GROWSURF_API_KEY`, not `GROWSURF_CAMPAIGN_ID`). Review the seeded Design, Emails, Options, Installation, rewards, and GrowSurf Window content before patching. - `growsurf_agent_program_creation_eval` Generate one-shot program-creation eval prompts and acceptance checks for starter content, conservative rewards, configuration review, frontend install proof, and clean public copy. - `growsurf_update_campaign` Update the program's identity and lifecycle: name, company branding, and status (only the fields you send are changed). - `growsurf_clone_campaign` Clone the program into a new `DRAFT` program (integrations and credentials are not copied). - `growsurf_list_campaign_rewards` List the program's configured rewards. - `growsurf_create_campaign_reward` Create a campaign reward. - `growsurf_update_campaign_reward` Update a campaign reward by its reward key. - `growsurf_delete_campaign_reward` Delete a campaign reward by its reward key. - `growsurf_list_program_resources` / `growsurf_create_program_resource` / `growsurf_update_program_resource` / `growsurf_delete_program_resource` Manage ordered participant resources. LINK uses HTTPS and TEXT uses plain text. - `growsurf_prepare_program_resource_file` Request a one-time ticket and upload an allowed file up to 10 MB to the exact host-allowlisted destination selected by GrowSurf. Pass the returned ticket and signed result unchanged to create/update. The tool accepts no upload URL or credential and never retries an upload. - `growsurf_get_campaign_design` / `growsurf_update_campaign_design` Read or patch design configuration, including the Program Editor Design tab and payout-destination confirmation page copy. - `growsurf_get_campaign_emails` / `growsurf_update_campaign_emails` Read or patch the Program Editor Emails tab config. - `growsurf_get_campaign_options` / `growsurf_update_campaign_options` Read or patch the Program Editor Options tab config, including the program's `languages`. - `growsurf_get_campaign_installation` / `growsurf_update_campaign_installation` Read or patch the Program Editor Installation tab config. - `growsurf_capture_referral_flow_screenshots` Capture temporary GrowSurf preview screenshots for the current program, after a draft is saved or when the user asks to see it. This returns the controlled referrer Window and referred-friend experience; use browser automation instead to prove the user's installed site. - `growsurf_list_campaign_webhooks` List the program's webhooks (secrets are never returned). - `growsurf_create_campaign_webhook` Add a webhook to the program (with events and a write-only signing secret). - `growsurf_update_campaign_webhook` Update a webhook by id (`primary` for the program's primary webhook). - `growsurf_delete_campaign_webhook` Remove a webhook by id. - `growsurf_test_campaign_webhook` Send a live test event to a webhook using its stored URL and secret. - `growsurf_add_participant` Add a participant (or referred participant) during signup. - `growsurf_list_participants` List participants in the current program, paginated by `nextId`. Pass `metadata` (up to 3 keys) to return only participants whose metadata matches exactly, such as looking someone up by your own customer ID. Use this to find a participant ID before calling participant-scoped tools. - `growsurf_get_participant` Fetch one participant by GrowSurf participant ID or email address. - `growsurf_update_participant` Update a participant by ID or email (including internal `notes` and the participant's `language`). - `growsurf_bulk_delete_participants` — Check each row outcome. `analyticsErasure.status: "pending"` means analytics erasure is still pending; do not repeat successful rows. Permanently delete up to 200 participants (by ID and/or email, mixed lists allowed) in one request, with per-row `DELETED`/`NOT_FOUND`/`DUPLICATE`/`ERROR` results. Irreversible. Successful rows lose participant access immediately; related record cleanup completes automatically, subject to required financial record retention. - `growsurf_email_participant` Email a participant using a configured template or a free-form subject/body. - `growsurf_get_participant_analytics` Fetch one participant's engagement, rank, share, affiliate revenue, commission, payout, optional email metrics, and covered first milestones. Use `include=activation` for milestones such as `firstPortalViewedAt` and `firstShareChannel`; add `series` for covered `portalViews` and `shareActions`. An unavailable null is unknown, not proof that the action never happened. - `growsurf_get_participant_activity_logs` List a participant's activity logs (offset/limit paginated). - `growsurf_trigger_referral` Trigger referral (for referral programs only). Optionally pass `delayInDays` (1-90) to hold the credit for N days before awarding it (e.g. to cover a refund window). - `growsurf_cancel_delayed_referral` Cancel a pending delayed referral trigger before the delay elapses (e.g. on refund/cancellation). - `growsurf_get_participant_payout_destination` Get a participant's payout-destination status across every provider enabled for the program (PayPal and/or Wise): per-provider status, confirmed payout email, legal recipient type, and repair reason. - `growsurf_request_participant_payout_destination_confirmation` Ask a participant to confirm their payout destination for a provider — sends them a one-time confirmation link (only the participant can confirm). - `growsurf_record_sale` Record affiliate sales or transactions (for affiliate programs only). - `growsurf_refund_transaction` Record an amendment (refund, partial refund, or chargeback) against a recorded transaction; reverses or adjusts the referrer's commission (for affiliate programs only). The inverse of `growsurf_record_sale`. - `growsurf_create_mobile_participant_token` Create or fetch a participant, then create a participant-scoped mobile SDK token for a signed-in mobile user. ### Helpers - `growsurf_participant_auth_hash` Generate participant auto-auth HMAC hashes (to authenticate participants automatically). - `growsurf_webhook_normalize` Normalize webhook payloads and generate idempotency keys (to deduplicate webhook deliveries). ## Webhooks GrowSurf webhooks notify your server when important referral or affiliate events occur, such as when new objects like participants, referrals, rewards, or transactions are created. Here are common use-cases: - Fulfill rewards automatically - Maintain internal points or credit systems - Sync participant and referral data into your database ### Duplicate Delivery Handling Webhook handlers should be idempotent because the same event can arrive more than once. Store an idempotency key before changing anything in your system. ### Webhook Security & Idempotency GrowSurf signs webhook deliveries when the webhook has a `secret` configured: each delivery includes a `GrowSurf-Signature` HMAC header computed with that secret (the secret is write-only and never returned). To securely use webhooks, we recommend the following: - Set a `secret` on the webhook and verify the `GrowSurf-Signature` header on receipt - Validate the payload shape and expected event type - Deduplicate webhook events using an idempotency key, because the same event can arrive more than once The GrowSurf MCP server provides a helper tool (`growsurf_webhook_normalize`) that normalizes webhook payloads and generates a best-effort idempotency key to simplify safe webhook processing. ## Development and Testing ```bash npm run dev npm test ``` ## Additional Resources Read developer docs at the following: - JavaScript SDK reference: https://docs.growsurf.com/developer-tools/javascript-sdk/api-reference - REST API reference: https://docs.growsurf.com/developer-tools/rest-api/api-reference - REST API libraries: https://docs.growsurf.com/developer-tools/rest-api/api-libraries - Native mobile guide: https://docs.growsurf.com/getting-started-for-mobile - iOS SDK: https://docs.growsurf.com/developer-tools/ios-sdk - Android SDK: https://docs.growsurf.com/developer-tools/android-sdk - React Native SDK: https://docs.growsurf.com/developer-tools/react-native-sdk - Getting Started with GrowSurf: https://docs.growsurf.com/getting-started The GrowSurf MCP server helps GrowSurf customers implement referral programs and affiliate programs quickly.