Skip to main content

MCP Server

Produktly provides a Model Context Protocol (MCP) server that lets you connect AI assistants like Claude, Cursor, Windsurf, and others directly to your Produktly data.

With the MCP server you can query your widgets, responses and cross-feature usage stats through natural language — and have your AI assistant build them for you. Product tours, onboarding checklists, smart tips, announcements, micro surveys, NPS widgets, feedback widgets and changelog posts can all be created and edited through the server.

Working in a codebase with a coding agent? See the Produktly agent skill, which teaches Claude Code, Cursor, and similar tools the whole flow: installing the snippet, identifying users, picking stable selectors, and authoring widgets.

Endpoint

https://api.produktly.com/api/mcp

The server uses the Streamable HTTP transport (stateless mode).

Authentication

The MCP server authenticates using your Produktly API key as a Bearer token.

  1. Go to Settings > API keys in your Produktly dashboard
  2. Generate a new key (give it a name like "MCP")
  3. Use the key as a Bearer token in your MCP client configuration

Treat the key like a password: it can read and write all of your Produktly data. It is a different token from the Client Auth Token in your install snippet, which is public by design.

Setup

Claude Code (CLI)

Run this command in your terminal:

claude mcp add produktly --transport http --url https://api.produktly.com/api/mcp --header "Authorization: Bearer YOUR_PRIVATE_KEY"

Or add it manually to your Claude Code MCP settings:

{
"mcpServers": {
"produktly": {
"type": "streamable-http",
"url": "https://api.produktly.com/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_PRIVATE_KEY"
}
}
}
}

Cursor / Windsurf

Add to your MCP configuration file:

{
"mcpServers": {
"produktly": {
"url": "https://api.produktly.com/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_PRIVATE_KEY"
}
}
}
}

GitHub Copilot / VS Code

In VS Code, open the Command Palette and run MCP: Add Server. Select HTTP as the transport type, then enter the URL https://api.produktly.com/api/mcp.

Or add it manually to your .vscode/mcp.json:

{
"servers": {
"produktly": {
"type": "http",
"url": "https://api.produktly.com/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_PRIVATE_KEY"
}
}
}
}

The Produktly tools will be available in Copilot's Agent mode.

Other MCP clients

Any MCP client that supports the Streamable HTTP transport can connect. Set the URL to https://api.produktly.com/api/mcp and include the Authorization: Bearer YOUR_PRIVATE_KEY header.

ChatGPT / Gemini

ChatGPT and Gemini require OAuth-based authentication for MCP servers, which is not yet supported. We're working on adding OAuth support — stay tuned.

Targeting

Every widget type only shows where you tell it to. Pass exactly one of these three forms:

{ "showOnAllPages": true }
{
"rules": [
{ "type": "url", "comparisonOperator": "contains", "value": "/dashboard" },
{ "type": "custom::::plan", "comparisonOperator": "one_of", "value": ["pro", "enterprise"] }
],
"logicalOperator": "AND"
}
{ "userSegmentIds": [3, 7] }

Rule types include url, device_type, language, location, screen_width, screen_height, current_time, produktly_user_created_at, and custom::::<attribute> for any attribute you send with identifyUser. See Targeting rules for the full list.

caution

A widget with no targeting never shows anywhere. Publishing requires targeting to be set.

Publishing

Widgets created through the API are drafts by default. Drafts never render on your site.

To publish, pass active: true. The widget must be publishable: targeting is always required, plus whatever that type needs to render.

WidgetAlso needs
Product tourat least one step
Checklistat least one item
Smart tipsettings.cssSelector
Announcementtitle, plus content for popup and toast
Micro surveyat least one question
Feedback widgetat least one option
NPS widgetnothing further

If anything is missing, the widget stays a draft and the response note explains why — the work is never lost, it just waits for the missing piece.

Once a widget is live, the API rejects updates that would introduce a new publishing problem: clear a live feedback widget's options, or drop the targeting from a live tour, and you get a not_publishable error instead of a silently broken widget. Set active: false first if you want to take it down.

A good habit with AI assistants is to ask for drafts by default and publish yourself from the dashboard after reviewing — every create and update response includes a dashboardUrl for exactly this.

Available tools

AreaTools
Setup guidanceget_setup_guide
Product tourslist_product_tours, get_product_tour, create_product_tour, update_product_tour
Checklistslist_checklists, get_checklist, create_checklist, update_checklist
Smart tipslist_smart_tips, get_smart_tip, create_smart_tip, update_smart_tip
Announcementslist_announcements, get_announcement, create_announcement, update_announcement
Micro surveyslist_micro_surveys, get_micro_survey, create_micro_survey, update_micro_survey
NPS widgetslist_nps_widgets, get_nps_widget, create_nps_widget, update_nps_widget, get_nps_score, get_nps_responses
Feedback widgetslist_feedback_widgets, get_feedback_widget, create_feedback_widget, update_feedback_widget, get_feedback_responses
Changelogslist_changelogs, get_changelog_posts, create_changelog_post, update_changelog_post, list_tags
Roadmapslist_roadmaps, get_roadmap
Statsget_widget_stats, get_stats_summary

Widgets you create through the API start as drafts — see Publishing.

get_setup_guide

Get the official Produktly setup guide, written for AI agents. Read the relevant topic before installing Produktly or creating your first widget.

ParameterTypeRequiredDescription
topicenumYesOne of install, identify, selectors, widgets
  • install — the script snippet, per-framework instructions (React, Next.js, Vue, GTM, WordPress), CSP hosts, and how to verify the install.
  • identify — the identifyUser signature and when to call it.
  • selectors — how to choose CSS selectors that survive a redesign.
  • widgets — every widget type you can create, what each one needs before it can be published, targeting, and the draft → review → publish flow.

list_product_tours

List all product tours (id, name, active status, dates, folder).

get_product_tour

Get one tour with its full steps, settings, and targeting rules. Fetch a tour before updating it — updates replace steps wholesale.

ParameterTypeRequiredDescription
productTourIdnumberYesThe ID of the product tour

create_product_tour

Create a product tour. Saved as a draft unless active: true is passed.

ParameterTypeRequiredDescription
namestringYesTour name (internal)
stepsobject[]NoSteps in order — see Step types
targetingobjectNoWhere the tour shows — see Targeting
settingsobjectNoTour behavior (start trigger, button labels, colors, …)
themeIdnumberNoAttach an existing theme
folderIdnumberNoFile the tour into a folder
activebooleanNoPublish immediately. The tour must have at least one step and targeting set

The response includes a dashboardUrl — open it to review the tour in the builder.

update_product_tour

Update a tour. Only the fields you provide are changed, but steps and targeting replace their stored values wholesale: fetch with get_product_tour first, and keep the existing step id values so analytics stay intact. settings are merged.

ParameterTypeRequiredDescription
productTourIdnumberYesThe ID of the tour to update
name, steps, targeting, settings, themeId, folderId, activeNoSame as create_product_tour

Tours that are already live can be edited, but the API rejects an update that would leave a live tour unpublishable — see Publishing.

Step types

Every step has a type. Cards accept title (plain text) and content (HTML), plus optional width, height, button labels (nextBtnText, backBtnText, finishBtnText), and a secondary action button.

TypePurposeRequired fields
welcomeCentered intro card
highlightSpotlights an element on the pagedomQuery (CSS selector)
modalCentered card
toastSmall card in the bottom-right corner
redirectNavigates the user, renders nothingredirectUrl

Highlight steps also accept direction (auto, top, right, bottom, left), highlight, allowClickEvents, skipIfNotFound, and actionListeners for auto-advancing when the user interacts with the element. Call get_setup_guide with topic: "selectors" for guidance on choosing a reliable domQuery.

list_checklists

List all checklists (id, name, active status, dates, folder).

get_checklist

Get one checklist with its full items, settings, and targeting rules.

ParameterTypeRequiredDescription
checklistIdnumberYesThe ID of the checklist

create_checklist

Create an onboarding checklist. Saved as a draft unless active: true is passed.

ParameterTypeRequiredDescription
namestringYesShown as the checklist panel header
itemsobject[]NoChecklist items — see below
targetingobjectNoWhere the checklist shows — see Targeting
settingsobjectNoPosition, display mode, colors, button text
themeIdnumberNoAttach an existing theme
folderIdnumberNoFile the checklist into a folder
activebooleanNoPublish immediately. The checklist must have at least one item and targeting set

Each item needs a title, a type (start-tour, open-url, or custom), and a completionType:

completionTypeCompletes whenAlso required
manual-clickThe user ticks it off
page-eventA DOM event fires on your sitepageEventElementSelector, optionally eventType (click, hover, element-visible)
tour-completeA product tour is finishedtourToCompleteId

Items with type: "start-tour" need a tourId; items with type: "open-url" need a redirectToUrl.

update_checklist

Update a checklist. Same replace-vs-merge rules as update_product_tour: items and targeting replace wholesale (preserve item id values — completion state is keyed on them), settings merge.

ParameterTypeRequiredDescription
checklistIdnumberYesThe ID of the checklist to update
name, items, targeting, settings, themeId, folderId, activeNoSame as create_checklist

list_smart_tips / get_smart_tip

List all smart tips, or fetch one with its full settings and targeting rules. Fetch before updating: settings merge, targeting replaces.

create_smart_tip

Create a smart tip: a small contextual card anchored to one element on the page.

ParameterTypeRequiredDescription
namestringYesInternal name
settings.cssSelectorstringYesThe element the tip anchors to. Without it nothing renders
title / contentstringNoCard title (plain text) and body (HTML)
settingsobjectNoTrigger (displayOn), beacon style and offsets, card placement, actions, colors
targetingobjectNoSee Targeting
themeId, folderId, activeNoAs with other widgets

displayOn accepts click, hover, focus, beacon_click and beacon_hover. Turning the beacon off with displayBeacon: false while using a beacon trigger is rejected, since the tip would have nothing to open it.

update_smart_tip

Update a smart tip. settings merge, targeting replaces wholesale.

ParameterTypeRequiredDescription
smartTipIdnumberYesThe ID of the smart tip
name, title, content, settings, targeting, themeId, folderId, activeNoSame as create_smart_tip

list_announcements / get_announcement

List all announcements, or fetch one with its full settings and targeting rules.

create_announcement

Create an announcement: a topbar, popup or toast message.

ParameterTypeRequiredDescription
namestringYesInternal name
titlestringNoHeadline. The only text shown on topbar styles
contentstringNoHTML body. Rendered for popup and toast only
settings.typeenumNotopbar (default), topbar-hovering, popup, toast
settingsobjectNoAction buttons, dimensions, colors, display cadence
targetingobjectNoSee Targeting

Topbar styles render the title only, so content is stored but not displayed there; the response note tells you when that happens. Showing an action button requires giving it a destination, either actionLink or actionType: "tour" with actionTourId.

update_announcement

Update an announcement. settings merge, targeting replaces wholesale.

ParameterTypeRequiredDescription
announcementIdnumberYesThe ID of the announcement
name, title, content, settings, targeting, themeId, folderId, activeNoSame as create_announcement

list_micro_surveys / get_micro_survey

List all micro surveys, or fetch one with its full questions, settings and targeting rules.

create_micro_survey

Create a micro survey: a short in-app survey shown one question at a time.

ParameterTypeRequiredDescription
namestringYesInternal name
settings.questionsobject[]YesAt least one question, asked in order
settingsobjectNoTrigger, position, auto-close, colors, completion action
targetingobjectNoSee Targeting

Each question needs a question string and a type: emoji, thumbs, rating (fixed 1-5), text or multi-choice. Only emoji takes options (each with a name and emoji), and only multi-choice takes multiChoiceOptions. Questions run as a flat list with no branching.

Unless settings.displayTrigger is immediate, time_delay or manual, you must also supply settings.cssSelector, because the default click trigger needs an element to attach to.

update_micro_survey

Update a micro survey. Sending settings.questions replaces the whole question list.

ParameterTypeRequiredDescription
microSurveyIdnumberYesThe ID of the micro survey
name, settings, targeting, themeId, folderId, activeNoSame as create_micro_survey

list_nps_widgets

List all your NPS widgets (id, name, active status, creation date).

get_nps_widget

Get one NPS widget with its full settings and targeting rules. Fetch before updating: settings merge, targeting replaces.

ParameterTypeRequiredDescription
npsWidgetIdnumberYesThe ID of the NPS widget

create_nps_widget

Create an NPS widget: a rating prompt with an optional follow-up question.

ParameterTypeRequiredDescription
namestringYesInternal name
settings.selectedScaleenumNoten (0-10, the standard NPS scale, default), five (1-5) or emojis (0-2)
settingsobjectNoQuestion text, email and comment collection, display style, trigger, cadence, colors
targetingobjectNoSee Targeting

Scores from get_nps_score are calculated per scale, so a five or emojis widget is scored on its own range rather than the 0-10 one.

update_nps_widget

Update an NPS widget. settings merge, targeting replaces wholesale.

ParameterTypeRequiredDescription
npsWidgetIdnumberYesThe ID of the NPS widget
name, settings, targeting, themeId, folderId, activeNoSame as create_nps_widget

get_nps_score

Get the NPS score and response breakdown for an NPS widget. NPS = % promoters (rating 9-10) − % detractors (rating 0-6); passives are 7-8.

ParameterTypeRequiredDescription
npsWidgetIdnumberYesThe ID of the NPS widget
startDatestringNoFilter responses from this date (ISO 8601)
endDatestringNoFilter responses until this date (ISO 8601)

Returns npsScore, totalResponses, and counts/percentages for promoters, passives, and detractors.

get_nps_responses

Get individual responses for an NPS widget.

ParameterTypeRequiredDescription
npsWidgetIdnumberYesThe ID of the NPS widget
startDatestringNoFilter responses from this date (ISO 8601)
endDatestringNoFilter responses until this date (ISO 8601)
latestCountnumberNoReturn only the latest X responses (max 100)

list_feedback_widgets

List all your feedback widgets (id, name, active status, creation date).

get_feedback_widget

Get one feedback widget with its full options, settings and targeting rules. Fetch before updating: options and targeting replace wholesale, settings merge.

ParameterTypeRequiredDescription
feedbackWidgetIdnumberYesThe ID of the feedback widget

create_feedback_widget

Create a feedback widget: a floating beacon that collects categorized feedback.

ParameterTypeRequiredDescription
namestringYesInternal name
optionsobject[]NoThe answer options. Each needs a name, optionally an emoji
optionsPresetnumberNoUse a built-in set instead of listing options: 1 issue/idea/other, 2 three emojis, 3 five emojis, 4 four emojis, 5 feelings, 6 issue/idea/happy/angry/other
settingsobjectNoQuestion text, beacon placement, email collection, screenshots, colors, text overrides
targetingobjectNoSee Targeting

Pass either options or optionsPreset, not both. Publishing needs at least one option plus targeting.

update_feedback_widget

Update a feedback widget. Sending options replaces the whole list.

ParameterTypeRequiredDescription
feedbackWidgetIdnumberYesThe ID of the feedback widget
name, options, optionsPreset, settings, targeting, themeId, folderId, activeNoSame as create_feedback_widget

get_feedback_responses

Get responses for a specific feedback widget.

ParameterTypeRequiredDescription
feedbackWidgetIdnumberYesThe ID of the feedback widget
startDatestringNoFilter responses from this date (ISO 8601)
endDatestringNoFilter responses until this date (ISO 8601)
latestCountnumberNoReturn only the latest X responses (max 100)

list_changelogs

List all your changelogs (id, name, active status, creation date).

get_changelog_posts

Get posts for a specific changelog.

ParameterTypeRequiredDescription
changelogIdnumberYesThe ID of the changelog
startDatestringNoFilter posts from this date (ISO 8601)
endDatestringNoFilter posts until this date (ISO 8601)
latestCountnumberNoReturn only the latest X posts (max 100)

create_changelog_post

Create a new changelog post. Posts default to draft (active: false) unless active: true is explicitly passed.

ParameterTypeRequiredDescription
changelogIdnumberYesThe ID of the changelog to add the post to
titlestringYesPost title
descriptionstringNoPost description as HTML (e.g. <p>, <ul>, <strong>)
datestringNoPost date (ISO 8601). Defaults to now
activebooleanNoWhether the post is live. Defaults to false
tagNamesstring[]NoTag names to attach. Must match existing tags (case-insensitive)

Unknown tagNames return an error listing the unresolved names — use list_tags first.

update_changelog_post

Update an existing changelog post. Only the fields you provide are changed.

ParameterTypeRequiredDescription
changelogItemIdnumberYesThe ID of the post to update
titlestringNoNew title
descriptionstringNoNew HTML description
datestringNoNew post date (ISO 8601)
activebooleanNoWhether the post is live
tagNamesstring[]NoReplacement tag names. Omit to leave tags unchanged; pass [] to clear

list_tags

List all tags in the company (id, name, colors). Useful for looking up tag names to pass to create_changelog_post and update_changelog_post.

list_roadmaps

List all your roadmaps with their sections (id, name, public name, active status, sections).

get_roadmap

Get a full roadmap with all sections and items. Supports search and tag filtering within the roadmap.

ParameterTypeRequiredDescription
roadmapIdnumberYesThe ID of the roadmap
startDatestringNoFilter items updated from this date (ISO 8601)
endDatestringNoFilter items updated until this date (ISO 8601)
latestCountnumberNoReturn latest X items per section (max 100)
querystringNoCase-insensitive substring match on item name or description
tagNamesstring[]NoFilter items whose tag name matches any of these (case-insensitive exact match)

get_widget_stats

Get event counts and unique users per widget for a given widget type. Returns one entry per widget with a breakdown by event type. Useful for comparing widgets of the same type (e.g. "which tours have the best completion rate?") or inspecting a single widget when entityId is provided.

ParameterTypeRequiredDescription
entityTypeenumYesOne of tour, checklist, smartTip, announcement, changelog, npsWidget, roadmap
entityIdnumberNoFilter to a single widget
startDatestringNoStart date (ISO 8601). Defaults to 30 days ago
endDatestringNoEnd date (ISO 8601). Defaults to today

Max range 90 days. uniqueUsers is a per-day sum approximation — it may double-count users active across multiple days.

get_stats_summary

Get a company-wide stats summary across all widget types. Returns primary and secondary metrics (completion rate, open rate, action rate), event counts, period-over-period comparison, and a trend series for each widget type.

ParameterTypeRequiredDescription
startDatestringNoStart date (ISO 8601). Defaults to 7 days ago
endDatestringNoEnd date (ISO 8601). Defaults to today

The trend series is daily when the range is 21 days or less, weekly otherwise. Max range 90 days.

Example usage

Once connected, you can ask your AI assistant things like:

  • "What are our latest changelog posts?"
  • "Show me feedback from the last week"
  • "What items are on our product roadmap?"
  • "Search the roadmap for items about 'integration' tagged as 'New Feature'"
  • "What's our NPS score this quarter, and what are the detractors saying?"
  • "Which product tour has the best completion rate over the last month?"
  • "How did our overall engagement change this week vs last week?"
  • "Summarize the feedback we got this month"
  • "Draft a changelog post about the webhook improvements we shipped this week, tag it as Improvement, leave it as a draft"
  • "Build a 4-step welcome tour for our dashboard and show it on all pages — leave it as a draft for me to review"
  • "Create an onboarding checklist: take the welcome tour, invite a teammate, connect an integration"
  • "Our NPS detractors keep mentioning the export flow. Draft a smart onboarding checklist that walks new users through it"
  • "Add a fifth step to the welcome tour highlighting the new Reports button"
  • "Add a smart tip on the billing page pointing at the invoice download button"
  • "Announce Tuesday's maintenance window as a topbar on every page, as a draft"
  • "Create a 2-question micro survey asking why people visited the pricing page"
  • "Set up an NPS widget on a five-point scale, shown once a quarter to users on the Pro plan"