PM Context MCP Server
# PM Context MCP Server
A Python MCP server that gives Claude access to PM workflow data (sprints, roadmap, blockers, workload) so you can ask it questions a PM actually needs answered.
**No API keys required.** Runs entirely on synthetic fixture data representing a fictional product team ("Petal & Co"). Designed to be forked and connected to a real Linear or Jira workspace privately.
<img src="Demo-mcp.jpg" alt="Demo of Claude answering a sprint question using the MCP server" width="50%">
---
## The Problem
PMs spend a disproportionate amount of time context-switching: checking Linear for sprint status, Confluence for the roadmap, Slack for who's blocked. Each lookup is a tab, a search, a few seconds of reorientation.
The bigger problem is that the *questions* PMs ask are aggregate and cross-cutting ("what should I focus on today?", "who's overloaded?", "what's actually blocking us?") but the tools expose raw CRUD. You have to do the aggregation yourself.
This MCP server exposes PM-oriented tools to Claude so those questions get answered in one place, with actual data behind them.
---
## Architecture
```
Claude (Desktop or CLI)
│
│ MCP (stdio transport)
▼
pm-mcp-server (FastMCP)
│
│ loads
▼
data/fixture.json ← synthetic Petal & Co dataset
(or real Linear / Jira API in a private fork)
```
The server runs as a local subprocess. Claude calls tools over stdio; no network, no auth for the demo.
---
## Tools
| Tool | What Claude can ask |
|------|---------------------|
| `get_current_sprint_tool` | "What's in the current sprint?" / "How close are we to done?" |
| `get_my_issues_tool` | "What's on Priya's plate right now?" |
| `get_blockers_tool` | "What's blocking the team?" / "What should we unblock first?" |
| `search_issues_tool` | "Find all issues related to payments" |
| `get_roadmap_tool` | "How far along are we on each epic?" |
| `get_team_workload_tool` | "Who has the most issues assigned?" / "Show me the Growth team's workload" |
| `get_velocity_tool` | "What's our sprint velocity trend?" |
---
## How to Run
**Requirements:** Python 3.10+, [uv](https://docs.astral.sh/uv/)
```bash
# Clone and enter the repo
git clone https://github.com/jackhendon/pm-mcp-server
cd pm-mcp-server
# Install dependencies
uv sync
# Test a tool directly
uv run python -c "from tools.sprints import get_current_sprint; import json; print(json.dumps(get_current_sprint(), indent=2))"
# Run the MCP inspector (requires mcp[cli])
uv run mcp dev server.py
```
### Connect to Claude Desktop
Add this to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"pm-context": {
"command": "/Users/yourname/.local/bin/uv",
"args": ["--directory", "/path/to/pm-mcp-server", "run", "python", "server.py"]
}
}
}
```
> **Note:** Claude Desktop on macOS doesn't inherit your shell PATH, so `uv` must be an absolute path. Run `which uv` in your terminal to find it.
Config location:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
Restart Claude Desktop. You should see `pm-context` listed under connected tools.
### Connect to Claude Code (CLI)
```bash
claude mcp add pm-context uv run python server.py --cwd /path/to/pm-mcp-server
```
### Try these prompts
- "What's in the current sprint and how close are we to finishing?"
- "Who has the most work on their plate right now?"
- "What's blocking the team and what should we unblock first?"
- "How has our sprint velocity trended over the last few sprints?"
- "What's the roadmap looking like across all epics?"
- "Find all issues related to API authentication"
---
## Fixture Data: Petal & Co
The synthetic dataset represents a fictional gift-card startup's product team:
- **6 team members** across 2 teams (Growth, Core)
- **3 projects**: Checkout Redesign, API Platform v2, Gifting Suite
- **3 epics** at different stages of completion
- **17 issues** in the active sprint (Sprint 14) with realistic statuses and blockers
- **4 completed sprints** for velocity calculation
The data is rich enough that all 7 tools return genuinely interesting and differentiated results.
---
## Real API Mode
This repo is designed to be forked privately and connected to a real Linear or Jira workspace.
1. Fork the repo
2. Copy `.env.example` to `.env` and add your credentials
3. Implement `tools/integrations/linear.py` or `tools/integrations/jira.py` that returns data in the same shape as the fixture
4. Update `tools/__init__.py` to route to the real integration based on `DATA_SOURCE` env var
The tool signatures and return shapes stay the same. Claude doesn't know or care whether the data comes from a fixture or a live API.
TDQS
Scored across 7 tools
Each tool targets a distinct aspect of PM context: current sprint, assignee issues, blockers, keyword search, roadmap, workload, and velocity. There is no overlap that would cause an agent to select the wrong tool for a given query.
All tools follow a consistent [verb]_[noun]_tool pattern using snake_case. The only non-get verb is 'search', but it still fits the same structure, making the naming predictable and uniform.
With 7 tools, the server is well-scoped for its purpose of providing PM context. Each tool covers a distinct read-only query without unnecessary redundancy or bloat.
The server covers core PM context areas like sprint status, issues, blockers, roadmap, workload, and velocity. However, it lacks a direct way to fetch all issues for a specific sprint or retrieve a single issue by ID, requiring search instead. These are minor gaps but not fatal.