Skip to content

Commit 3a687a8

Browse files
authored
feat(mcp): Implement supplier_performance_review prompt (#109)
* feat(mcp): implement supplier_performance_review prompt Implement comprehensive supplier performance review prompt with: - Optional supplier_code parameter (defaults to None for all suppliers) - period_days parameter (defaults to 90 days) - Dynamic current date injection - Comprehensive system instructions for supply chain analysis - Guided multi-step workflow (overview, analysis, trends, recommendations) - Full test coverage (10 tests passing) - Token size validation (under 5KB)
1 parent 3e9b436 commit 3a687a8

3 files changed

Lines changed: 275 additions & 6 deletions

File tree

stocktrim_mcp_server/src/stocktrim_mcp_server/prompts/workflows.py

Lines changed: 170 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,164 @@
44
inventory management tasks.
55
"""
66

7-
from fastmcp import FastMCP
7+
from datetime import datetime
88

9-
from stocktrim_mcp_server.logging_config import get_logger
9+
from fastmcp import Context, FastMCP
10+
from fastmcp.prompts.prompt import Message
11+
from pydantic import Field
1012

11-
logger = get_logger(__name__)
13+
14+
async def _supplier_performance_review(
15+
supplier_code: str | None,
16+
period_days: int,
17+
context: Context | None = None,
18+
) -> list[Message]:
19+
"""Comprehensive supplier performance review and analysis.
20+
21+
This prompt guides the AI through:
22+
1. Supplier overview and details
23+
2. Performance analysis (PO history, delivery times, costs)
24+
3. Trend analysis (improving/declining performance)
25+
4. Recommendations (consolidation, risk mitigation, contracts)
26+
27+
Expected duration: 3-5 minutes
28+
29+
Tools used:
30+
- list_purchase_orders
31+
- get_supplier
32+
33+
Resources:
34+
- stocktrim://reports/supplier-directory
35+
- stocktrim://suppliers/{code}
36+
"""
37+
# Get current date for context
38+
current_date = datetime.now().strftime("%Y-%m-%d")
39+
40+
# Determine supplier scope
41+
supplier_specific_or_all = (
42+
f"Specific supplier: {supplier_code}" if supplier_code else "All suppliers"
43+
)
44+
45+
prompt_content = f"""You are an expert supply chain analyst conducting a comprehensive supplier performance review.
46+
47+
# Analysis Parameters
48+
49+
- {supplier_specific_or_all}
50+
- Analysis period: {period_days} days
51+
- Review date: {current_date}
52+
53+
# Your Task
54+
55+
Conduct a thorough supplier performance review by:
56+
57+
1. Analyzing supplier performance metrics
58+
2. Identifying optimization opportunities
59+
3. Providing actionable recommendations
60+
4. Highlighting risk mitigation strategies
61+
62+
# Process Steps
63+
64+
## Step 1: Supplier Overview
65+
- Use stocktrim://reports/supplier-directory resource to get supplier list
66+
- If specific supplier, use stocktrim://suppliers/{{code}} for details
67+
- Review supplier basic information (contact, terms, lead times)
68+
- Identify active vs inactive suppliers
69+
70+
## Step 2: Performance Analysis
71+
- Use list_purchase_orders tool filtered by supplier and time period
72+
- Calculate key performance indicators:
73+
- On-time delivery rate
74+
- Order accuracy
75+
- Average lead time vs promised lead time
76+
- Cost trends over time
77+
- Order frequency and consistency
78+
79+
## Step 3: Trend Analysis
80+
- Identify improving performance patterns
81+
- Identify declining performance patterns
82+
- Compare suppliers against each other (if reviewing all)
83+
- Flag any concerning trends (cost increases, delays)
84+
- Note seasonal patterns if evident
85+
86+
## Step 4: Recommendations
87+
- **Consolidation Opportunities**: Identify suppliers that could be consolidated
88+
- **Risk Mitigation**: Flag suppliers with declining performance or single-source risks
89+
- **Contract Renegotiation**: Suggest where better terms could be negotiated
90+
- **Supplier Development**: Identify suppliers worth investing in
91+
- **Alternative Sources**: Recommend backup suppliers for critical items
92+
93+
# Metrics to Analyze
94+
95+
## Delivery Performance
96+
- On-time delivery rate (% of orders delivered on or before promised date)
97+
- Average delay in days for late orders
98+
- Lead time consistency (standard deviation)
99+
100+
## Cost Performance
101+
- Price trends over analysis period
102+
- Cost per unit trends
103+
- Total spend by supplier
104+
- Cost competitiveness compared to alternatives
105+
106+
## Order Accuracy
107+
- Correct quantities received
108+
- Correct products received
109+
- Quality issues or returns
110+
111+
## Relationship Quality
112+
- Communication responsiveness
113+
- Problem resolution effectiveness
114+
- Flexibility with urgent orders
115+
- Payment terms favorability
116+
117+
# Best Practices
118+
119+
- Always analyze data for the full period specified
120+
- Compare current performance to historical baselines
121+
- Provide quantitative metrics whenever possible
122+
- Be objective in assessments
123+
- Prioritize recommendations by impact and feasibility
124+
- Consider both cost and risk in recommendations
125+
126+
# Tools Available
127+
128+
- **list_purchase_orders**: Get PO history filtered by supplier and date range
129+
- **get_supplier**: Get detailed supplier information
130+
131+
# Resources Available
132+
133+
- **stocktrim://reports/supplier-directory**: Complete supplier directory
134+
- **stocktrim://suppliers/{{code}}**: Individual supplier details
135+
136+
# Output Format
137+
138+
Provide a structured markdown report with:
139+
140+
1. **Executive Summary** (2-3 sentences)
141+
2. **Supplier Overview Section**
142+
- Number of suppliers reviewed
143+
- Total spend in period
144+
- Key statistics
145+
3. **Performance Analysis Section**
146+
- Top performers (with metrics)
147+
- Bottom performers (with metrics)
148+
- Detailed metrics by supplier
149+
4. **Trend Analysis Section**
150+
- Improving suppliers
151+
- Declining suppliers
152+
- Emerging patterns
153+
5. **Recommendations Section** (prioritized bulleted list)
154+
- Consolidation opportunities
155+
- Risk mitigation actions
156+
- Contract renegotiation targets
157+
- Supplier development investments
158+
6. **Action Items** (specific next steps)
159+
160+
Use tables for metrics, bullets for recommendations, and clear sections for easy scanning.
161+
162+
Start with the supplier overview step."""
163+
164+
return [Message(content=prompt_content, role="user")]
12165

13166

14167
def register_workflow_prompts(mcp: FastMCP) -> None:
@@ -17,5 +170,17 @@ def register_workflow_prompts(mcp: FastMCP) -> None:
17170
Args:
18171
mcp: FastMCP server instance
19172
"""
20-
# Individual prompts will be added here in follow-up PRs
21-
pass
173+
174+
@mcp.prompt()
175+
async def supplier_performance_review(
176+
supplier_code: str | None = Field(
177+
default=None,
178+
description="Specific supplier to review (optional, if None reviews all)",
179+
),
180+
period_days: int = Field(
181+
default=90, description="Historical period to analyze (default: 90 days)"
182+
),
183+
context: Context | None = None,
184+
) -> list[Message]:
185+
"""Comprehensive supplier performance review and analysis."""
186+
return await _supplier_performance_review(supplier_code, period_days, context)

stocktrim_mcp_server/tests/test_prompts/test_workflows.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
"""Tests for workflow prompts."""
22

3+
import pytest
4+
5+
from stocktrim_mcp_server.prompts.workflows import _supplier_performance_review
6+
37

48
class TestWorkflowPrompts:
59
"""Tests for workflow prompt registration and structure."""
@@ -15,3 +19,103 @@ def test_workflow_prompts_module_exists(self):
1519
from stocktrim_mcp_server.prompts.workflows import register_workflow_prompts
1620

1721
assert callable(register_workflow_prompts)
22+
23+
24+
class TestSupplierPerformanceReview:
25+
"""Tests for supplier_performance_review prompt."""
26+
27+
@pytest.mark.asyncio
28+
async def test_supplier_performance_review_structure(self):
29+
"""Test prompt returns correct message structure."""
30+
messages = await _supplier_performance_review(None, 90, None)
31+
32+
assert len(messages) == 1
33+
assert messages[0].role == "user"
34+
assert hasattr(messages[0].content, "text")
35+
36+
@pytest.mark.asyncio
37+
async def test_supplier_performance_review_content(self):
38+
"""Test prompt contains expected content."""
39+
messages = await _supplier_performance_review(None, 90, None)
40+
41+
content = messages[0].content.text.lower()
42+
assert "supply chain analyst" in content
43+
assert "supplier performance review" in content
44+
assert "list_purchase_orders" in content
45+
assert "get_supplier" in content
46+
assert "stocktrim://reports/supplier-directory" in content
47+
assert "stocktrim://suppliers/{code}" in content
48+
49+
# Check for key process steps
50+
assert "supplier overview" in content
51+
assert "performance analysis" in content
52+
assert "trend analysis" in content
53+
assert "recommendations" in content
54+
55+
# Check for key metrics
56+
assert "on-time delivery" in content
57+
assert "cost" in content or "costs" in content
58+
assert "lead time" in content
59+
60+
# Check for parameters
61+
assert "90" in content
62+
assert "all suppliers" in content
63+
64+
@pytest.mark.asyncio
65+
async def test_supplier_performance_review_specific_supplier(self):
66+
"""Test prompt correctly uses specific supplier parameter."""
67+
messages = await _supplier_performance_review("SUP-001", 90, None)
68+
69+
content = messages[0].content.text
70+
assert "SUP-001" in content
71+
assert "Specific supplier: SUP-001" in content
72+
73+
@pytest.mark.asyncio
74+
async def test_supplier_performance_review_all_suppliers(self):
75+
"""Test prompt correctly handles all suppliers mode."""
76+
messages = await _supplier_performance_review(None, 90, None)
77+
78+
content = messages[0].content.text
79+
assert "All suppliers" in content
80+
81+
@pytest.mark.asyncio
82+
async def test_supplier_performance_review_parameters(self):
83+
"""Test prompt correctly uses parameters."""
84+
messages = await _supplier_performance_review("SUP-002", 60, None)
85+
86+
content = messages[0].content.text
87+
assert "SUP-002" in content
88+
assert "60" in content
89+
90+
@pytest.mark.asyncio
91+
async def test_supplier_performance_review_token_size(self):
92+
"""Test prompt stays within token budget."""
93+
messages = await _supplier_performance_review(None, 90, None)
94+
95+
content_size = len(messages[0].content.text)
96+
97+
# Keep under 5KB total
98+
assert content_size < 5000, f"Prompt too large: {content_size} bytes"
99+
100+
@pytest.mark.asyncio
101+
async def test_supplier_performance_review_contains_metrics(self):
102+
"""Test prompt mentions key performance metrics."""
103+
messages = await _supplier_performance_review(None, 90, None)
104+
105+
content = messages[0].content.text.lower()
106+
# Check for important metrics
107+
assert "delivery" in content
108+
assert "accuracy" in content
109+
assert "consolidation" in content
110+
assert "risk" in content
111+
112+
@pytest.mark.asyncio
113+
async def test_supplier_performance_review_output_format(self):
114+
"""Test prompt specifies output format."""
115+
messages = await _supplier_performance_review(None, 90, None)
116+
117+
content = messages[0].content.text.lower()
118+
# Check for output format guidance
119+
assert "executive summary" in content
120+
assert "markdown" in content or "report" in content
121+
assert "recommendations" in content

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)