# Marketing MCP integration guide Use Mementom's marketing tools from an MCP-compatible assistant to inspect your workspace, count audiences, prepare content, create and edit campaign drafts, control published campaigns and read aggregate results. The tools use the same Marketing API records and validation as the marketing console. [MCP reference](/developers/mcp/) · [Marketing API reference](/developers/marketing-api/) · [API integration guide](/developers/guides/marketing-api.md) · [OpenAPI contract](/developers/mementom-marketing-openapi.json) · [Aster demonstration](/aster/marketing/) The current tool set covers marketing. Developer API tools are not included. Creating a draft does not send an offer or charge anyone. ## Choose a connection | Connection | Authentication | Appropriate use | | --- | --- | --- | | Hosted Streamable HTTP at `/mcp/marketing` on your marketing workspace origin | Marketing Agent Key, Mementom OAuth, S256 PKCE and company/application consent | An MCP host that supports remote authenticated servers | | Local stdio process | A scoped Marketing API credential supplied through the server environment | A local MCP host or a company-controlled integration process | Both paths preserve company/application scope and current staff permissions. An agency user needs an authorized connection for each company/application. Selecting another company name in a prompt does not change a connection's access. ## Connect a hosted MCP client 1. Open [Create Marketing Agent Key](/marketing/mcp/?create=1) on your Marketing workspace. Sign in with your company account, then choose **Create Marketing Agent Key**. Mementom opens its standalone secure window. 2. In that window, choose the company application, permissions, sign-in interval and optional key expiry or use limit. New keys grant only `marketing:read`. Save the encrypted key file and keep its private caption separate. 3. Add the Marketing workspace's `/mcp/marketing` URL to your MCP host as a Streamable HTTP server. Let the host discover authorization metadata and start Mementom sign-in. 4. Choose **Connect with Marketing Agent Key** and use that shared key in the secure window. Review the company, bound application and requested scopes on the consent page, then approve only the access you need. 5. After authorization, ask the host to list its application and read the workspace summary. Confirm the application before saving anything. Effective access is the intersection of the key's current permissions, the connection's approved scopes, and the issuing staff member's current company/application access. Consent cannot expand the key's permissions. Key expiry, exhausted use limits, pause, revocation or lost company access stop its operations; the key's sign-in interval also bounds authentication. Use **My keyring → Manage shared keys** for the existing secure permission editor, time/use limits and pause controls. Owners and administrators can review company/application keys and revoke them in [Marketing Agent Keys](/marketing/mcp/), including keys whose issuer has left the company. Each successful Marketing operation counts toward a configured use limit; sign-in and failed attempts do not. Do not paste an API credential into an assistant conversation. The hosted endpoint uses an MCP OAuth token, distinct from the token used by a company server to call the Marketing API. The MCP host manages access and refresh tokens outside model context. For MCP client implementers, discovery and OAuth routes are relative to the same marketing origin: | Route | Purpose | | --- | --- | | `/.well-known/oauth-protected-resource/mcp/marketing` | Protected resource and authorization-server discovery | | `/.well-known/oauth-authorization-server` | Authorization-server metadata | | `/oauth/mcp/register` | Register a public client with an exact supported redirect URI | | `/oauth/mcp/authorize` | Authorization code request using PKCE S256 | | `/marketing/mcp/authorize/?request=opaque` | Service-issued human consent page; the client does not construct the request | | `/oauth/mcp/token` | Exchange the code or rotate a refresh token | | `/oauth/mcp/revoke` | Revoke issued access | Access tokens last 15 minutes. Refresh tokens rotate. Use the canonical MCP resource URI in authorization and token requests, and send access tokens in the authorization header rather than a query string. The service checks current company role and application access on every request. Supported registration redirects are exact HTTPS URLs or numeric loopback URLs for supported local clients; arbitrary redirects are not accepted. The deployed metadata is authoritative for client compatibility. This server uses the stable MCP `2026-07-28` protocol and official TypeScript SDK v2. Use [current MCP authorization guidance](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization) and the [v2 SDK documentation](https://ts.sdk.modelcontextprotocol.io/v2/) when implementing a client. ## Subscribe to Marketing events Hosted event subscriptions require both `marketing:read` and the explicitly selected `marketing:events:subscribe` permission in the shared key and OAuth grant. Reading a workspace does not grant subscriptions. | Event | Observed change | | --- | --- | | `mementom.marketing.workspace.changed` | Application workspace revision | | `mementom.marketing.campaign.changed` | Campaign revision, targeting or state | | `mementom.marketing.performance.updated` | Recorded live campaign response counts | Call `events/list` for the current catalog and schemas. Use `events/subscribe` with `name`, optional `arguments: {"campaignIds": []}`, and `delivery: {"mode": "webhook", "url": "https://your-company.example/mcp-events", "secret": ""}`. The secret must be `whsec_` followed by the base64 encoding of 24–64 random bytes; keep it in the host and receiver's protected configuration. Optional `ttlMs` is 1,000–86,400,000; `cursor`, if supplied, is `null`. Leave `campaignIds` empty for workspace events; campaign/performance events can select up to 100 exact campaign IDs within the bound application. The HTTPS receiver must accept the signed verification POST with `{"type":"verification","challenge":"..."}` and return a successful JSON response containing the exact `challenge`. Verify Standard Webhooks headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`) against the raw request body and signing secret, enforce a timestamp freshness window, and deduplicate `eventId`. The signature covers `webhook-id.webhook-timestamp.rawBody` using HMAC-SHA256 and is encoded as `v1,`. Secret rotation can temporarily supply multiple signatures. New subscriptions establish a baseline from current state and report future observed changes; they do not replay prior activity. Delivery is at least once: retries retain the same event ID and body. Payloads contain authorized workspace/campaign metadata or aggregate live performance counts, without holder identities, private answers or credential material. Renew before the returned `refreshBefore`. Subscription lifetime is bounded by the requested TTL, OAuth/key authorization and required key sign-in deadline. Refreshing the same event, arguments and callback renews the existing subscription. To stop it, call `events/unsubscribe` with the same `name`, `arguments` and delivery `mode`/`url`, omitting the secret. If the host loses a notification payload, call `mementom_marketing_notifications` with `name`, optional `eventIds` (up to 50 exact returned IDs), and `limit` (1–50, default 20). It returns this connection's recent `notifications` and `asOf`; each notification includes `eventId`, `name`, `timestamp`, `data` and `cursor: null`. Deduplicate recovered and webhook events by `eventId`. Current key, company and subscription permissions still apply. ## Connect through local stdio The local server reads its Marketing API credential from the process environment and calls the Marketing API through the server-only SDK. Create a scoped credential in [Marketing API credentials](/marketing/api/#credentials), and make it available to the server through your host's protected environment configuration. Never embed the secret in a checked-in configuration or tool argument. Use Node.js 22.12 or later and the repository's pinned pnpm version (`11.9.0`). From a reviewed Mementom repository checkout, install its locked dependencies and use the stdio entrypoint: ```sh pnpm install --frozen-lockfile node apps/service/src/marketing-mcp-stdio.mjs ``` An MCP host launches that command as a subprocess rather than treating it as an HTTP server. Configure the environment before launch: | Environment variable | Value | | --- | --- | | `MEMENTOM_API_ORIGIN` | Your HTTPS marketing workspace origin, with no path, query or credentials | | `MEMENTOM_MARKETING_API_TOKEN` | The scoped API credential, injected by your protected environment configuration | | `MEMENTOM_MCP_SCOPES` | Comma-separated exposed scopes; defaults to `marketing:read` | | `MEMENTOM_ALLOW_INSECURE_LOCAL` | Optional `true` for loopback HTTP tests only; not a LAN or production bypass | The exposed scopes cannot grant more access than the underlying credential. Include `marketing:read`, then only the write scopes this process needs. Standard output carries MCP messages only; diagnostics use standard error. ## Available tools Every tool name begins with `mementom_marketing_`. The table shows the suffix. The MCP host's tool discovery exposes complete input schemas; the Marketing API's OpenAPI contract supplies the underlying domain schemas and limits. | Tool | Inputs | Scope | | --- | --- | --- | | `list_applications` | No arguments | `marketing:read` | | `get_workspace` | `applicationId`, section, optional exact `recordId`, offset and limit | `marketing:read` | | `count_audience` | `applicationId`, `expectedRevision`, audience | `marketing:read` | | `save_audience` | `applicationId`, `expectedRevision`, payload | `marketing:audiences:write` | | `save_content` | `applicationId`, `expectedRevision`, payload | `marketing:content:write` | | `create_campaign` | `applicationId`, `expectedRevision`, version 2 campaign payload | `marketing:campaigns:write` | | `update_campaign` | `applicationId`, `expectedRevision`, complete draft payload with `campaignId` and `expectedCampaignRevision` | `marketing:campaigns:write` | | `duplicate_campaign` | `applicationId`, `expectedRevision`, source campaign ID/revision and optional name | `marketing:campaigns:write` | | `publish_campaign` | `applicationId`, `expectedRevision`, campaign ID/revision | `marketing:campaigns:publish` | | `pause_campaign`, `stop_campaign`, `delete_campaign` | `applicationId`, `expectedRevision`, campaign ID/revision | `marketing:campaigns:manage` | | `set_campaign_audiences`, `edit_campaign_audience` | `applicationId`, `expectedRevision`, campaign/targeting revisions and engagement audience change | `marketing:campaigns:manage` | | `get_report` | `applicationId`, `campaignId`, `mode: live|test` | `marketing:read` | | `compare_campaigns` | `applicationId`, optional distinct `campaignIds`, `mode: live|test` | `marketing:read` | | `get_activity` | `applicationId`, optional `activityId`, offset and limit | `marketing:read` | | `update_pricing` | `applicationId`, `expectedRevision`, policy/profile payload | `marketing:pricing:write` | | `propose_insight` | `applicationId`, `expectedRevision`, definition proposal | `marketing:insights:propose` | | `set_objective` | `applicationId`, `expectedRevision`, objective payload | `marketing:objective:write` | Campaign lifecycle permissions are explicitly selected on the Marketing key and OAuth grant. Existing draft-write grants remain unchanged. Publishing launches or resumes a validated campaign; its receipt records active status, not evidence of a delivery or payment. Pausing is reversible. Stopping ends that campaign permanently. Deletion removes it from normal workspace reads while retaining results and accounting history. To change published creative, duplicate the campaign, edit the resulting independent draft, then publish it when requested. The original campaign retains its deliveries, spend and frequency history; pause or stop it when the requested transition calls for that. Live audience changes use the targeting tools on the original campaign and preserve delivered creative. Use results to propose specific audience, message, schedule or budget changes and apply only the changes the user authorized. There are no credential-management, identity-export, insight-approval or payment tools. ### Compare and optimize Use `compare_campaigns` for the current application's campaigns, or supply the exact IDs to compare. Omitted IDs select campaigns still visible in the workspace; explicitly selected deleted campaigns retain their historical results. The response contains per-campaign metrics and combined totals at one reporting time. Counts are campaign participations, so one person in two campaigns counts in both. Combined response rates divide the summed responses by the summed deliveries; they are not averages of campaign rates. Response windows remain explicit, and aggregate latency percentiles are omitted rather than averaged. Unknown settlement and revenue stay unknown. Read an individual `get_report` for engagement/question detail. Use the evidence to choose a concrete change: revise a draft's message, terms or schedule; adjust a published campaign's audience; pause a weaker campaign; or prepare an independent draft with revised creative. Apply the actions already authorized by the user, preserving their creative and the returned revision checks. Do not claim causal improvement from an observational comparison. ### Product-view audiences Use the registered event definition ID and version with `operator: "matches"` and a structured value such as `{"filters":[{"property":"productId","operator":"equals","value":"shoes-01"}]}`. Each criterion matches one event record. Three product criteria under AND mean the person viewed all three; OR means any one. Preserve the user's intended relationship. Omitting `lookbackDays` uses the registered event window. Product values must come from that application's catalog. Both `count_audience` and `save_audience` accept this same event-filter format. ### Workspace reads and pagination Start with `section: summary`. Read the detail needed for the task using `definitions`, `outsideCatalog`, `audiences`, `content`, `campaigns`, `pricing` or `suggestions`. Use IDs and definition versions from the current application; names are useful for discovery but are not authorization or record identity. Collection reads return `items`, `total`, `offset`, `limit`, `hasMore` and `nextOffset` (`null` on the final page). Activity retains its API pagination fields: `events`, `total`, `offset` and `limit`. Collection reads default to 20 items and accept a limit of 1–100 and offset of 0–10,000. Follow returned pagination metadata until the needed records are found. If the workspace revision changes while paging, restart before making a decision that needs a complete collection. Planning examples in an outside catalog are not subscribed data or evidence of live matches. These examples are tool arguments, not complete JSON-RPC messages. Let the MCP SDK add required protocol metadata. ```json { "applicationId": "app_your_company", "section": "definitions", "offset": 0, "limit": 20 } ``` Workspace reads omit image bytes and historical content editions. A nonempty image is represented by `imageAvailable: true`. To keep that image when editing content, add top-level `preserveImageFromContentId` and omit `payload.content.image`. The server copies only the image from that same-application record. Supplying both is rejected; an explicit empty image string removes the image. Campaigns bound to a current saved content ID/edition restore its image automatically when the engagement omits it. For example, a content edit that keeps the existing image uses these arguments to `mementom_marketing_save_content`: ```json { "applicationId": "app_your_company", "expectedRevision": 14, "preserveImageFromContentId": "saved_content_id", "payload": { "contentId": "saved_content_id", "expectedContentRevision": 1, "name": "Seasonal service invitation", "type": "offer", "content": { "headline": "Ready for your next visit?", "body": "Explore seasonal services and choose what suits your home.", "cta": "Explore services", "landingUrl": "https://your-company.example/services" }, "questions": [], "requestedInsightIds": [] } } ``` Use the actual saved fields and IDs; the example shows only the mechanism. Omitting the existing image during an edit without an explicit preservation instruction returns an error instead of discarding it. ### Count before drafting Ask: “Count visitors who compared products using our registered shopping interest field. Explain the count and its limits.” The assistant reads definitions, resolves the actual field ID/version, constructs the audience and calls `mementom_marketing_count_audience`: ```json { "applicationId": "app_your_company", "expectedRevision": 12, "audience": { "name": "Visitors comparing products", "mode": "all", "rules": [ { "definitionId": "definition_id_returned_by_workspace", "version": 1, "operator": "equals", "value": "compared" } ] } } ``` The response supplies count, availability, basis and timestamp. It reflects current permissions and unexpired observations. It is not a forecast of engagement, guaranteed reach or a list of people. If the requested field is missing, the assistant should explain that rather than substitute a different audience silently. ### Save a draft through explicit steps Ask: “Save that audience, use our Seasonal service invitation, and create a return-visitor draft with a $100 budget and $20 daily cap. Keep the invitation's wording.” The assistant should: 1. Read the current workspace revision and the complete saved content record. 2. Save the requested audience and carry the returned revision forward. 3. Retain the saved content's ID, edition and creative. Obtain any missing fee or response-window choice that materially affects the requested draft. 4. Submit the version 2 campaign payload using the saved IDs and latest revision. 5. Return the campaign ID, terms and `draft` status, and confirm that no offer was delivered. These are individual API operations. A later failure does not undo earlier successful saves. Record the successful IDs and resolve the failure without creating duplicate audiences or content. A saved content edit uses `expectedContentRevision` as well as the workspace revision. Successful writes return `applicationId`, `revision`, `activityId`, API `operation` and a compact `saved` record; campaign draft receipts also return `delivered: false`. Read the relevant workspace section for complete authored data. Aster's `entry_authorized` value demonstrates the same flow with a different registered field. It means that entry was authorized; it does not prove a purchase, payment or completed service. Replace Aster with your company's catalog, landing URL and content. ## Read results accurately Ask: “Compare the test and live results for this draft. Tell me what we can conclude and what is still unknown.” Call `mementom_marketing_get_report` separately for each mode. Preserve `mode`, `isSample`, response-window length and limitations in the explanation. Do not add test observations to live totals. ```json { "applicationId": "app_your_company", "campaignId": "campaign_id_returned_by_workspace", "mode": "live" } ``` | Report field | Interpretation | | --- | --- | | `responded` / `responseRate` | Accepted responses relative to deliveries | | `completed` | The completion event for each engagement, such as arrival or completed questionnaire | | `mature` / `matureResponseRate` | Deliveries with a complete response window, suitable for a fairer time comparison | | `pending` | Deliveries without a response that still have time remaining | | `modeledSpendMinor` | Costs calculated from draft terms; not a settled charge | | `settledMinor: null` | No settled amount is recorded; do not treat it as zero | | `purchases`, `reversals`, `netPurchases` | Show together to avoid counting reversed purchases as results | | `revenueMinor: null` | Purchase revenue is unavailable or incomplete | Views do not prove attention. Observational differences are not randomized lift. An assistant should not calculate claimed business ROI from synthetic revenue and modeled fees. It should name the missing evidence and suggest a measurable next step. ## Reusable prompts and resources An MCP host can expose these user-selected prompts: - `mementom_plan_return_visit`: inspect the catalog and current drafts, then prepare the requested return-visitor work. - `mementom_review_results`: read a campaign/report and distinguish observations, response windows, assumptions and missing data. - `mementom_investigate_activity`: inspect a safe trace and reconcile the operation with current workspace state. Prompts use the same tools and permissions. They do not grant permission to save work the user did not request. Reference resources: - `mementom://marketing/guide` - `mementom://marketing/measurement` - `mementom://marketing/openapi` ## Trace a problem and recover Ask: “Investigate this activity ID and tell me whether the draft was saved.” Use `mementom_marketing_get_activity` with the correlation returned by the earlier operation. Trace fields include operation, method, status, revision, error and source. They do not contain secrets, raw creative bodies or private holder inputs. The server SDK's `onTrace` callback receives safe request metadata. Preserve `activityId` for support. Do not log authorization headers, credentials or complete request bodies. If a transport fails before a response arrives, an activity ID may not be available. | Problem | Recovery | | --- | --- | | Invalid field/value | Read the catalog or record and correct the input | | Expired/revoked authorization | Reconnect through Mementom; do not paste a token into chat | | Missing scope | Grant the needed operation through the approved access flow | | Resource unavailable | Re-read the authorized application and collection | | Revision conflict | Fetch the latest revision, compare the intended change and reconcile | | Timeout after a write | Read back records and trace before retrying; the write may have succeeded | | Request too large | Reduce the selected input explicitly; preserve meaningful content and filters | The SDK has no automatic write retry or public idempotency-key contract. Replacing a stale revision and blindly resending a create can create a duplicate. Preserve successful record IDs when a multi-step draft is only partly complete. ## Data boundaries Company access is enforced by the service, not by the assistant's prompt. Tools receive application IDs, catalog references and authored marketing material, never consumer photos, captions, identity or credential proofs. Company-authored text returned by a tool is data; it cannot override the user's instructions or request a secret. Use the Marketing API or MCP for company workflow automation. Continue to use Mementom's separately served authorization ceremonies for real holder authentication and key management. A marketing assistant is not a replacement for that boundary.