Product Manager MCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GITHUB_TOKEN | No | Your own GitHub personal access token. Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| LINEAR_API_KEY | No | Your own Linear personal API key. Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| NOTION_API_KEY | No | Your own Notion integration secret (ntn_…). Then share the pages it should see with the integration. Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| STRIPE_API_KEY | No | Your own Stripe secret or restricted key. Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| TAVILY_API_KEY | No | Your own Tavily API key. Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| GRANOLA_API_KEY | No | Your own Granola API key, from the Granola app: Settings → Connectors → API keys (Business plan or above). Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| SLACK_BOT_TOKEN | No | A bot token (xoxb-…) from your own Slack app. Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| GOOGLE_CLIENT_ID | No | OAuth client ID for Google browser sign-in over your own OAuth client. | |
| FIRECRAWL_API_KEY | No | Your own Firecrawl API key. Can alternatively be stored in the OS keychain with `product-manager-mcp login`. | |
| GOOGLE_CLIENT_SECRET | No | OAuth client secret for Google browser sign-in over your own OAuth client. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| granola_notes_listA | List meeting notes, filtered by when they were created or last updated and optionally narrowed to one folder and its subfolders. Returns each note's id, title, owner and timestamps, not its content. Fetch that with notes_get. Only notes that already have a generated AI summary appear here. |
| granola_notes_getA | Read one meeting note: its AI summary, the people who attended, the calendar event it was taken against, and the folders it belongs to. Pass include='transcript' to get the transcript inline as well. A transcript too large to inline answers 413 TRANSCRIPT_TOO_LARGE. Read it with notes_transcript_get instead. |
| linear_search_issuesA | Search issues by text, across titles and descriptions. Set |
| linear_issue_createA | Create an issue. |
| slack_chat_post_messageA | Send a message to a Slack channel, private group, or DM. Provide |
| linear_customers_listC | List customers — the companies whose requests Linear tracks against issues. |
| linear_customer_need_createA | Record a customer request, optionally attached to an issue or project. This is the one Linear mutation whose reply carries no object — it answers only with whether it worked. |
| granola_notes_transcript_getA | Read a meeting transcript one page at a time. Use this for any long transcript, and whenever notes_get answers 413 TRANSCRIPT_TOO_LARGE. Each item is one line of speech with who said it and when. |
| gdocs_documents_createA | Create a blank document with a title. Only the title is honoured — the document is created empty. To add content, call this and then documents_batch_update with the returned documentId. |
| gdocs_documents_batch_updateA | Apply a list of edits to a document. Each request sets exactly one kind of edit — insert_text, replace_all_text, update_text_style, insert_table and so on. Edits apply in order against a document that shifts as they do: when inserting at several indices, order the requests back-to-front so earlier insertions do not move the positions later ones refer to. |
| gdocs_documents_getA | Read a document's full structural content. The document ID is the long string in its URL, between '/d/' and '/edit'. Pass include_tabs_content=true for a document with several tabs, since the default response covers only the first. |
| linear_project_createA | Create a project. |
| linear_project_milestone_createC | Create a milestone inside a project. |
| notion_pages_retrieve_markdownA | Get a page's whole content as Markdown, rendered by Notion. One call instead of recursing through |
| notion_comments_createA | Comment on a page or block, or reply to an existing discussion with its |
| linear_project_getB | Get one project with its content, milestones and members. Accepts the project's UUID or the slug from its URL. |
| linear_issues_listA | List issues, optionally filtered. Conditions on one filter object combine with AND. To find a team's open work, filter on team.key and state.type. |
| github_pulls_listA | List pull requests. Filter by |
| linear_project_update_createA | Post a status update on a project, optionally reporting health as 'onTrack', 'atRisk' or 'offTrack'. This writes a note; to change the project itself, use |
| linear_projects_listB | List projects in the workspace, with their status and progress. |
| linear_project_milestones_listA | List project milestones. Filter by project to get one project's. |
| gsheets_spreadsheets_values_updateC | Sets values in a range of a spreadsheet. |
| gforms_forms_responses_listA | List a form's submitted responses, newest page first, up to 5000 per page. The only supported filter is on submission time: pass filter='timestamp >= 2026-01-01T00:00:00Z' to read what has arrived since a point in time. Answers come back keyed by questionId. |
| gsheets_spreadsheets_values_appendC | Appends values to a spreadsheet. |
| slack_conversations_historyB | Fetch recent messages from a Slack channel. |
| slack_reactions_addC | Add an emoji reaction to a Slack message. |
| firecrawl_monitor_createB | Create a scheduled monitor for scrape, crawl, or search targets. |
| firecrawl_monitor_checks_listC | List checks for a monitor. |
| linear_cycle_getB | Get one cycle with the issues in it. |
| gcalendar_events_insertC | Create a calendar event; returns details of the event. |
| gforms_forms_createA | Create a new form from a title. Only the title and the document title are honoured: the form is created with no description, no items and default settings. To add questions, call this and then forms_batch_update with the returned formId. Pass unpublished=true to create a form that does not yet accept responses. |
| gmail_messages_sendC | Send an email via the Gmail API. |
| granola_folders_listA | List the folders this key can reach, sorted alphabetically. The listing is flat and each folder names its parent in parent_folder_id, so a hierarchy is reassembled from a full walk. Use it to find the folder_id that narrows a note listing or a webhook endpoint's deliveries. |
| notion_pages_createA | Create a page — as a subpage of another page, or as a row of a database by giving its |
| linear_customer_needs_listA | List customer requests. Filter by issue to see what a piece of work is wanted for, or by customer to see everything one company has asked for. |
| stripe_customers_listA | List customers, most recently created first. Filter by email to find one. |
| stripe_subscriptions_listB | List subscriptions. Filter by customer or status. |
| linear_customer_createB | Create a customer. Only |
| linear_customer_updateC | Update a customer's name, owner, tier, revenue or size. |
| linear_customer_getC | Get one customer by its UUID. |
| gmail_drafts_createC | Save an email draft to Gmail. |
| slack_conversations_createB | Create a channel. Slack refuses a name that is already taken. |
| slack_conversations_inviteA | Add people to a channel. With |
| tavily_research_createA | Create an async research task that searches, analyzes sources, and generates a cited report. Poll results with research_get. |
| tavily_research_getA | Retrieve the status and results of a research task by request_id. HTTP 202 means still running; poll until HTTP 200. |
| linear_document_createA | Create a document. Only |
| github_releases_generate_notesA | Generate release-note text from the pull requests merged since a previous tag. This creates nothing — GitHub returns a name and a markdown body and saves neither — so it is safe to call for a draft changelog. Pass the result to |
| linear_users_listA | List workspace members. Use this to resolve a person's name or email to the UUID that assignment expects. |
| slack_users_listA | List members of the workspace. Use this to resolve a person's name to the user ID that Slack mentions and filters expect. |
| connectA | Connect one app this server uses. For an app that issues keys, says where to get one and the terminal command that stores it. For Google, once the user's own OAuth client is set, starts the browser sign-in and returns at once: the user approves in the browser and the next call works. To see which apps are connected, call |
| connection_statusA | See which apps this server is connected to, and how to connect each one that is not. Changes nothing. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| setup | Connect every app this server uses, the quickest way each one allows. |
| call_notes_to_deduped_linear_issues | Feature requests from yesterday's calls land as issues, matched against what already exists, and #product sees the list. |
| customer_requests_attached_to_the_issue_they_ask_for | The roadmap gets ranked by who asked, not by who spoke loudest in planning. |
| discovery_calls_to_prd_draft | A first PRD drafted from five interviews, with quotes, before the PM opens a blank doc. |
| prd_doc_to_linear_project_milestones_and_issues | The spec turns into a plan in one pass instead of an afternoon of copy-paste. |
| notion_spec_to_linear_issues_linked_back | Teams that write in Notion and ship in Linear stop keeping two lists. |
| weekly_project_update_written_from_the_work | The update reports what merged and what slipped, with health set from evidence rather than optimism. |
| roadmap_sheet_that_keeps_itself_true | Leadership keeps its spreadsheet and the spreadsheet stops lying. |
| feedback_form_to_triaged_customer_needs | Every response is either attached to an issue or logged as new, never left in a tab. |
| feedback_channel_to_linear | Feedback posted in Slack gets an issue and a checkmark, so nobody wonders if it was seen. |
| competitor_changelog_watch | A competitor ships something and a scoped issue exists before the sales team asks about it. |
| cycle_review_doc_and_retro_booking | Planned vs. done vs. carried over, written up and on the calendar before the retro. |
| customer_interview_program | Screener, scheduling and confirmations for ten interviews without a scheduling tool. |
| research_synthesis_from_a_folder_of_calls | Twenty calls become one synthesis page with every claim traceable to a note. |
| requests_ranked_by_revenue | Each feature request carries the MRR of the customers behind it. |
| linear_customers_synced_from_stripe | Linear's customer tiers and revenue reflect billing, so prioritisation uses real numbers. |
| shipped_to_tell_everyone_who_asked | The loop gets closed with every requester, which is the cheapest retention there is. |
| launch_room_in_one_go | Checklist page, launch-day event and channel with the right people, from the project. |
| problem_space_research_brief | A cited brief lands in the project's docs before the kickoff meeting. |
| release_notes_for_customers | Engineering's release notes rewritten for users, from the issues that actually closed. |
| linear_digest_to_slack | What moved, what's stuck, who owns it, with people actually @-mentioned. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 51 tools
Most tools are clearly distinguished by service prefix and resource/action naming (e.g., linear_issues_list vs linear_search_issues, slack_chat_post_message vs slack_conversations_history). However, linear_project_update_create is misleading: it posts a status update on a project, not updates the project itself, and its description references a non-existent `project_update` tool, causing confusion.
Tool names consistently use snake_case with a service prefix and action verb at the end (e.g., linear_issue_create, slack_conversations_invite, gdocs_documents_get). Minor deviations exist: connect and connection_status lack a service prefix, and notion_pages_retrieve_markdown uses 'retrieve_markdown' while other read tools use 'get'.
With 51 tools spanning 14 different services, the set is far too large for a focused product manager server. While the breadth of integrations explains some volume, many tools are single-operation (e.g., only list or create) and could be consolidated, making the surface feel bloated and unwieldy.
Core CRUD operations are missing across nearly all resources: no update or delete for issues, projects, documents, Slack messages, or Gmail drafts. Several tools referenced in descriptions (linear_teams_list, linear_workflow_states_list, linear_project_update, gforms_forms_batch_update, github_releases_create) are absent, which will cause agent failures when following documented workflows.