An MCP (Model Context Protocol) server that exposes product-management tools for AI agents. Built with the MCP Python SDK using FastMCP.
Tools
| Tool | Description |
|---|---|
prioritize_backlog |
Rank backlog items using RICE, value/effort, or customer-signal scoring |
analyze_feedback |
Extract and rank themes from customer feedback |
assess_capacity |
Calculate per-engineer sprint capacity with carry-over and skill-fit checks |
map_dependencies |
Trace dependency chains via BFS and surface risks |
Project Structure
ProductNerveCenter/
├── server.py # MCP server — data loading + tool wrappers
├── olympics.json # Evaluation agent configuration
├── tools/
│ ├── __init__.py # Package exports
│ ├── prioritize_backlog.py # RICE / value-effort / customer-signal scoring
│ ├── analyze_feedback.py # Theme extraction & grouping logic
│ ├── assess_capacity.py # Sprint capacity calculation
│ └── map_dependencies.py # BFS dep traversal & risk analysis
├── data/
│ ├── product_backlog.json # 35 backlog items
│ ├── customer_feedback.json # 90 customer feedback entries
│ ├── team_roster.json # 8 engineers across 2 squads
│ ├── dependencies.json # Dependency graph edges
│ └── sprint_history.json # 6 sprint history records
├── oracle_connection/
│ └── README.md # Discovery process documentation
├── TECHNICAL_DECISIONS.md # Design decisions log
├── data_dictionary.md # Field definitions for all data files
├── requirements.txt
├── agent_config.json
└── env_vars.json
Prerequisites
- Python 3.11 or 3.12
- pip
Setup
# Set Python version (if using pyenv)
pyenv local 3.11.11 # or 3.12.3
# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
Running the Server
stdio mode (for Claude Desktop / evaluation agent)
python3 server.py
HTTP mode (for browser/network clients)
python3 server.py http 8000
This starts a Streamable HTTP server at http://127.0.0.1:8000.
Connecting to the Server
From Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"devpulse": {
"command": "python3",
"args": ["/full/path/to/ProductNerveCenter/server.py"],
"env": {
"PM_AGENT_DATA": "/full/path/to/ProductNerveCenter/data",
"MCP_DATA_URL": "https://co-mcp-server-dev.apps-internal.lrl.lilly.com/mcp"
}
}
}
}
From another MCP client (HTTP mode)
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession
async with streamablehttp_client("http://127.0.0.1:8000/mcp") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("prioritize_backlog", {"method": "rice"})
print(result)
Environment Variables
| Variable | Purpose | Default |
|---|---|---|
PM_AGENT_DATA |
Path to the data/ folder with JSON files |
./data |
MCP_DATA_URL |
Remote MCP server URL for team roster & dependency map | https://co-mcp-server-dev.apps-internal.lrl.lilly.com/mcp |
Quick Test (no remote server needed)
The server gracefully handles the remote MCP server being unreachable — it logs a warning and continues with empty roster/deps. You can run it locally right away:
source .venv/bin/activate
python3 server.py http 8000
You'll see:
[MCP] ... WARNING MCP server unreachable (...) — roster and deps will be empty
The 4 tools will still work using the local JSON files in data/.
Tool Details
prioritize_backlog
| Parameter | Type | Default | Description |
|---|---|---|---|
method |
string | "value_effort" |
Scoring method: "rice", "value_effort", "customer_signal" |
filters |
dict | null |
Filter by squad, status, or tags |
include_dependency_check |
bool | true |
Flag items with unresolved blockers |
analyze_feedback
| Parameter | Type | Default | Description |
|---|---|---|---|
time_range |
dict | null |
{"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"} |
customer_tier |
string | null |
"enterprise", "mid_market", or "startup" |
source |
string | null |
"support_ticket", "nps_survey", "sales_call", "user_interview" |
group_by |
string | "theme" |
"theme", "customer", or "source" |
assess_capacity
| Parameter | Type | Default | Description |
|---|---|---|---|
sprint_id |
string | null |
Target sprint ID (uses latest if null) |
squad |
string | "all" |
Filter by squad name |
include_carry_over |
bool | true |
Subtract in-progress points from capacity |
check_skill_fit |
bool | false |
Flag skill mismatches on assigned items |
map_dependencies
| Parameter | Type | Default | Description |
|---|---|---|---|
item_ids |
list | null |
Item IDs to trace (null = all in-progress/planned) |
include_external |
bool | true |
Include external dependencies |
max_depth |
int | 3 |
Maximum BFS traversal depth |