Back to MCP Servers

Pm Copilot

Triangulates HelpScout support tickets and ProductLift feature requests to generate prioritized product plans. Scores themes by convergence (same signal in both sources = 2x boost), scrubs PII, and accepts business metrics from other MCP servers via `kpi_context` for composable …

product-management
By dkships
289Updated 1 day agoTypeScriptMIT

Installation

npx -y pm-copilot

Configuration

{
  "mcpServers": {
    "pm-copilot": {
      "command": "npx",
      "args": ["-y", "pm-copilot"]
    }
  }
}

How to use

  1. Run the installation command above (if needed)
  2. Open your Claude Code settings file (~/.claude/settings.json)
  3. Add the configuration to the mcpServers section
  4. Restart Claude Code to apply changes

PM Copilot

An MCP server that triangulates customer support tickets, feature requests, and AI support agent conversations to help PMs decide what to build next.

TypeScript License: MIT MCP SDK Node.js


Real results: Analyzed 3,353 signals in one 30-day window — 1,678 support tickets, 276 feature requests, and 1,399 AI support agent conversations across 4 products. Top priority: Booking & Scheduling — 285 tickets + 74 feature requests + 347 chats pointing at the same problem, with the AI agent answering with low confidence in 48% of those chats.

The 1,399 chats are the point. None of them were visible to the analysis before v1.4.0, and they are 83% the volume of the ticket channel.

Read the full story: I built an MCP server that changed how I prioritize products — why I built this, how convergent signals work in practice, and what I learned building with Claude Code.


What Makes This Different

  • Signal triangulation. Matches support tickets against feature requests to find convergent themes, then scores them with a weighted formula that gives convergent signals a 2x priority boost.
  • The deflection blind spot. An AI support agent answers questions that never become tickets, so ticket-based prioritization undercounts every theme the bot handles — and the gap widens as the bot improves. Chatbase conversations are pulled in as a third signal class, with a per-theme self_serve_failure_rate showing where self-serve is failing.
  • Composability. Works alongside other MCP servers. Pass churn data from Metabase or traffic trends from Google Analytics into generate_product_plan via kpi_context, and the methodology adjusts priorities accordingly.
  • Built-in PM methodology. Opinionated scoring based on 7 years of product management across 9 products and 1M+ users. It's a real decision-making process exposed as an MCP resource, not a generic framework.
  • PII scrubbing. Customer data never reaches the LLM unfiltered. SSNs, credit cards (Luhn-validated), emails, and phone numbers are redacted before analysis. Agent responses are filtered out of quotes.

Architecture

graph TD
    A[Claude Desktop / Code] -->|stdio| B[pm-copilot]
    A -->|stdio| C[Metabase MCP]
    A -->|stdio| D[Google Analytics MCP]
    B -->|Reactive| E[HelpScout: tickets]
    B -->|Proactive| F[ProductLift: feature requests]
    B -->|Deflected| I[Chatbase: AI agent chats]
    C -->|Quantitative| G[Conversion, Churn, Revenue]
    D -->|Acquisition| H[Traffic, Channels, Trends]
    B -.->|kpi_context| A

Claude orchestrates multiple MCP servers. PM Copilot handles qualitative customer signals. Other servers provide quantitative business metrics. The kpi_context parameter is the integration point — no point-to-point integrations required.

Quick Start

git clone https://github.com/dkships/pm-copilot.git
cd pm-copilot
npm install
cp .env.example .env   # Edit with your credentials
npm run build

Credentials

HelpScout is required. ProductLift and Chatbase are both optional — configure either, both, or neither, and the analysis adapts.

VariableRequiredDescription
HELPSCOUT_APP_IDYesOAuth app ID from https://secure.helpscout.net/apps/custom/
HELPSCOUT_APP_SECRETYesOAuth app secret
PRODUCTLIFT_PORTALSNoMulti-portal: name|url|key,name2|url2|key2
PRODUCTLIFT_PORTAL_URLNoSingle portal URL
PRODUCTLIFT_API_KEYNoSingle portal Bearer token
PRODUCTLIFT_PORTAL_NAMENoPortal display name (default: default)
CHATBASE_API_KEYNoAccount-wide secret key from Chatbase → Settings → API keys
CHATBASE_AGENTSNoMulti-agent: name|agentId,name2|agentId2
CHATBASE_AGENT_IDNoSingle agent id
CHATBASE_AGENT_NAMENoSingle agent display name (default: default)

Chatbase API access needs a Chatbase Standard plan or higher. On a lower plan the API returns 403 and the deflection signal is reported as a warning rather than failing the whole analysis. One agent per product is the useful shape — agents give you product-level attribution that a shared support mailbox does not.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "pm-copilot": {
      "command": "node",
      "args": ["/absolute/path/to/pm-copilot/dist/index.js"]
    }
  }
}

Claude Code

claude mcp add pm-copilot -- node /absolute/path/to/pm-copilot/dist/index.js

Or use the .mcp.json already in the project root — Claude Code picks it up automatically.

Tools

synthesize_feedback

Cross-references HelpScout tickets, ProductLift feature requests, and Chatbase conversations, returns theme-matched analysis with priority scores.

ParameterTypeDefaultDescription
timeframe_daysnumber30Days to look back (1-90)
top_voted_limitnumber50Top-voted requests per portal; recent requests in the timeframe are always included on top
mailbox_idstringHelpScout mailbox filter (raw ID)
mailbox_namestringHelpScout mailbox name (case-insensitive); auto-resolved to an ID. Run list_sources to see names
portal_namestringProductLift portal filter
agent_namestringChatbase agent filter. Run list_sources to see names
source_filterstringChatbase conversation source filter, comma-separated for multiple, e.g. Widget or Iframe or WhatsApp,API. Case-insensitive. Run list_sources for the valid values
detail_levelstring"summary""summary", "standard", or "full". Output size scales with data volume — roughly 20KB / 100KB / 600KB

Returns themes sorted by priority score, each with reactive/proactive counts, convergence flag, evidence summaries, and representative customer quotes.

generate_product_plan

Builds a prioritized product plan with evidence and customer quotes. Accepts external business metrics via kpi_context.

ParameterTypeDefaultDescription
timeframe_daysnumber30Days to look back (1-90)
top_voted_limitnumber50Top-voted requests per portal; recent requests in the timeframe are always included on top
mailbox_idstringHelpScout mailbox filter (raw ID)
mailbox_namestringHelpScout mailbox name (case-insensitive); auto-resolved to an ID. Run list_sources to see names
portal_namestringProductLift portal filter
agent_namestringChatbase agent filter. Run list_sources to see names
source_filterstringChatbase conversation source filter, comma-separated for multiple, e.g. Widget or Iframe or WhatsApp,API. Case-insensitive. Run list_sources for the valid values
kpi_contextstringBusiness metrics from other MCP servers
max_prioritiesnumber5Number of priorities to return (1-10)
preview_onlybooleanfalseAudit mode: show what data would be sent
detail_levelstring"summary""summary", "standard", or "full". Output size scales with data volume — for one 30-day mailbox, roughly 5KB / 21KB / 375KB
formatstring"json""json" (structured, composable) or "markdown" (ready-to-read product brief)

get_feature_requests

Raw ProductLift data access for browsing feature requests directly. Each request includes its public url.

ParameterTypeDefaultDescription
portal_namestringFilter to a specific portal
include_commentsbooleantrueInclude comments on each request
statusstringFilter to requests with this status (case-insensitive), e.g. open, planned, completed

list_sources

Lists the data sources the server is connected to — HelpScout mailboxes (id + name), ProductLift portals (name + url), and Chatbase agents (name + id) — so you can discover the names to pass to mailbox_name / portal_name / agent_name. When Chatbase is configured it also returns chatbase_conversation_sources, the values source_filter accepts (a fixed list from the Chatbase docs, not queried per account). Read-only; never returns API keys or customer data. Takes no parameters.

Signal classes

Three sources, three different things they tell you. Only the first two feed the convergence rule.

ClassSourceWhat it meansFeeds
ReactiveHelpScout ticketsSomething is brokenFrequency, severity, convergence
ProactiveProductLift requestsSomething is wantedFrequency, vote momentum, convergence
DeflectedChatbase conversationsSomething was asked, and self-serve either handled it or did notFrequency only

Deflected signals count toward frequency and carry two evidence fields per theme, but they do not enter the severity or vote-momentum terms and do not change the 2x convergence boost. The formula is unchanged from v2.1:

  • deflected_count — conversations matching the theme
  • self_serve_failure_rate — share of those conversations where the agent's lowest answer confidence fell below 0.5
  • mean_answer_confidence — mean of that same score

A theme with high deflected_count and a high self_serve_failure_rate is one customers keep asking about that self-serve does not resolve. Chatbase does not document what its min_score field measures, so it is reported as evidence for the LLM to weigh rather than folded into the priority score.

Conversations arrive from several channels (widget, WhatsApp, Messenger, API, …). The analysis reports a chatbase_sources count per channel, and the source_filter parameter narrows a run to one or more channels (comma-separated) — the filter is applied server-side by Chatbase. One catch: counts can include channels the filter list does not cover, like Playground or unknown (Chatbase omitted the source). A filter value outside the known list is passed through with a warning rather than rejected, since zero matches usually means the value is wrong, not that the channel went quiet.

Chatbase is optional. With no CHATBASE_API_KEY set, the deflection fields are simply absent and the analysis behaves exactly as before.

Example output

A trimmed synthesize_feedback response at the default summary detail level. Values are illustrative; note the PII scrubbing applied to the customer quote.

{
  "timeframe_days": 30,
  "detail_level": "summary",
  "portal_name": "all",
  "fetched_at": "2026-06-01T16:00:00.000Z",
  "pii_scrubbing_applied": true,
  "pii_categories_redacted": ["email", "phone", "credit_card"],
  "analysis": {
    "total_data_points": 612,
    "reactive_count": 548,
    "proactive_count": 64,
    "deflected_count": 312,
    "chatbase_sources": {
      "Widget or Iframe": 284,
      "WhatsApp": 23,
      "API": 5
    },
    "themes": [
      {
        "theme_id": "booking-scheduling",
        "label": "Booking & Scheduling",
        "category": "core",
        "priority_score": 87.1,
        "convergent": true,
        "signal_type": "convergent",
        "reactive_count": 211,
        "proactive_count": 19,
        "deflected_count": 96,
        "self_serve_failure_rate": 0.48,
        "mean_answer_confidence": 0.53,
        "evidence_summary": "326 signals (211 suppor

…
View source on GitHub