|
8 | 8 |
|
9 | 9 | from fastmcp import Context, FastMCP |
10 | 10 | from fastmcp.prompts.prompt import Message |
| 11 | +from mcp.types import PromptMessage, TextContent |
11 | 12 | from pydantic import Field |
12 | 13 |
|
| 14 | +from stocktrim_mcp_server.dependencies import get_services |
| 15 | +from stocktrim_mcp_server.logging_config import get_logger |
| 16 | + |
| 17 | +logger = get_logger(__name__) |
| 18 | + |
13 | 19 |
|
14 | 20 | async def _supplier_performance_review( |
15 | 21 | supplier_code: str | None, |
@@ -444,6 +450,263 @@ async def _forecast_accuracy_review( |
444 | 450 | return prompt |
445 | 451 |
|
446 | 452 |
|
| 453 | +async def _stockout_prevention( |
| 454 | + location_code: str, |
| 455 | + days_ahead: int, |
| 456 | + context: Context | None = None, |
| 457 | +) -> list[Message]: |
| 458 | + """Proactive stockout prevention workflow. |
| 459 | +
|
| 460 | + This prompt guides the AI through: |
| 461 | + 1. Risk Analysis: Identify products at risk |
| 462 | + 2. Gap Identification: Review current inventory levels |
| 463 | + 3. Forecast Review: Check forecasts for at-risk products |
| 464 | + 4. Preventive Action: Generate POs before stockouts occur |
| 465 | +
|
| 466 | + Expected duration: 2-4 minutes |
| 467 | +
|
| 468 | + Tools used: |
| 469 | + - review_urgent_order_requirements |
| 470 | + - generate_purchase_orders_from_urgent_items |
| 471 | + - forecasts_get_for_products |
| 472 | +
|
| 473 | + Resources: |
| 474 | + - stocktrim://reports/inventory-status |
| 475 | + - stocktrim://reports/urgent-orders |
| 476 | + - stocktrim://products/{code} |
| 477 | + """ |
| 478 | + |
| 479 | + # Fetch dynamic data if context provided |
| 480 | + # Note: Dynamic context fetching is not yet implemented but infrastructure is in place |
| 481 | + if context: |
| 482 | + try: |
| 483 | + _ = get_services( |
| 484 | + context |
| 485 | + ) # Validate services are available; result unused for now |
| 486 | + # Could optionally fetch location details, product count, etc. |
| 487 | + # Keep this fast (< 100ms) |
| 488 | + except Exception as e: |
| 489 | + logger.warning(f"Failed to fetch dynamic context: {e}") |
| 490 | + |
| 491 | + current_date = datetime.now().strftime("%Y-%m-%d") |
| 492 | + |
| 493 | + # MCP prompts use a single user message with embedded instructions |
| 494 | + prompt_msg = f"""# Stockout Prevention Analysis |
| 495 | +
|
| 496 | +You are an expert inventory management analyst conducting a proactive stockout prevention analysis. |
| 497 | +
|
| 498 | +## Analysis Parameters |
| 499 | +
|
| 500 | +- **Location:** {location_code} |
| 501 | +- **Forecast horizon:** {days_ahead} days |
| 502 | +- **Analysis date:** {current_date} |
| 503 | +
|
| 504 | +## Your Role |
| 505 | +
|
| 506 | +Execute a comprehensive stockout prevention workflow to: |
| 507 | +1. Analyze inventory risks and identify products at risk of stockout |
| 508 | +2. Review current inventory levels and forecast data |
| 509 | +3. Identify root causes (demand spikes, lead time issues, forecast gaps) |
| 510 | +4. Generate preventive purchase orders before stockouts occur |
| 511 | +5. Recommend safety stock or forecast adjustments |
| 512 | +
|
| 513 | +## Process Steps |
| 514 | +
|
| 515 | +### Step 1: Risk Analysis |
| 516 | +- Use `review_urgent_order_requirements` tool with days_ahead parameter of {days_ahead} |
| 517 | +- Review `stocktrim://reports/urgent-orders` resource for context |
| 518 | +- Identify products at risk of stockout within the {days_ahead}-day forecast horizon |
| 519 | +- Categorize by urgency: |
| 520 | + - **Critical:** < 7 days stock remaining |
| 521 | + - **Warning:** 7-14 days stock remaining |
| 522 | + - **Watch:** 14+ days stock remaining |
| 523 | +- Note any products with declining trends |
| 524 | +
|
| 525 | +### Step 2: Gap Identification |
| 526 | +- Review `stocktrim://reports/inventory-status` for current levels |
| 527 | +- Compare current stock against forecast demand |
| 528 | +- Identify gaps between stock and projected needs |
| 529 | +- Check for products with recent stockout history |
| 530 | +- Flag items with inadequate safety stock |
| 531 | +
|
| 532 | +### Step 3: Forecast Review |
| 533 | +- Use `forecasts_get_for_products` for at-risk products |
| 534 | +- Analyze demand patterns and trends |
| 535 | +- Check for seasonality or unusual spikes |
| 536 | +- Verify forecast accuracy based on historical data |
| 537 | +- Identify any forecast anomalies requiring attention |
| 538 | +
|
| 539 | +### Step 4: Preventive Action |
| 540 | +- Use `generate_purchase_orders_from_urgent_items` for each supplier |
| 541 | +- Group orders by supplier for efficiency |
| 542 | +- Consider lead times in order timing |
| 543 | +- Calculate order quantities to prevent stockouts |
| 544 | +- Flag products requiring immediate attention |
| 545 | +- Provide clear justification for each order |
| 546 | +
|
| 547 | +### Step 5: Recommendations |
| 548 | +- Identify products needing safety stock adjustments |
| 549 | +- Recommend forecast parameter changes |
| 550 | +- Suggest inventory policy improvements |
| 551 | +- Flag systematic issues (consistent under-ordering, lead time problems) |
| 552 | +- Provide cost analysis and budget impact |
| 553 | +
|
| 554 | +## Best Practices |
| 555 | +
|
| 556 | +- Always prioritize critical items (< 7 days stock) |
| 557 | +- Consider supplier lead times when calculating order urgency |
| 558 | +- Look for patterns indicating systematic issues |
| 559 | +- Balance prevention costs against stockout risks |
| 560 | +- Flag products with declining trends for special attention |
| 561 | +- Recommend proactive measures, not just reactive orders |
| 562 | +- Consider seasonal patterns in risk assessment |
| 563 | +- Verify supplier availability before recommending orders |
| 564 | +
|
| 565 | +## Tools Available |
| 566 | +
|
| 567 | +- `review_urgent_order_requirements`: Analyze reorder needs within time horizon |
| 568 | +- `generate_purchase_orders_from_urgent_items`: Create preventive POs |
| 569 | +- `forecasts_get_for_products`: Review forecast data for risk assessment |
| 570 | +
|
| 571 | +## Resources Available |
| 572 | +
|
| 573 | +- `stocktrim://reports/inventory-status`: Current inventory levels |
| 574 | +- `stocktrim://reports/urgent-orders`: Urgent reorder requirements |
| 575 | +- `stocktrim://products/{{code}}`: Individual product details |
| 576 | +- `stocktrim://suppliers/{{code}}`: Supplier information and lead times |
| 577 | +
|
| 578 | +## Output Format |
| 579 | +
|
| 580 | +Provide a structured markdown report with: |
| 581 | +1. **Executive Summary** (2-3 sentences on overall risk level) |
| 582 | +2. **Risk Categories Section:** |
| 583 | + - Critical Items (< 7 days) - immediate action needed |
| 584 | + - Warning Items (7-14 days) - preventive action recommended |
| 585 | + - Watch Items (14+ days) - monitoring needed |
| 586 | +3. **Root Cause Analysis** (common patterns identified) |
| 587 | +4. **Preventive Purchase Orders** (one section per supplier) |
| 588 | +5. **Inventory Policy Recommendations** (bulleted list) |
| 589 | +6. **Safety Stock Adjustments** (table format) |
| 590 | +7. **Action Items** (prioritized checklist) |
| 591 | +
|
| 592 | +Use tables for data, bullets for recommendations, and clear sections for easy scanning. |
| 593 | +Focus on prevention and proactive measures rather than reactive responses. |
| 594 | +
|
| 595 | +--- |
| 596 | +
|
| 597 | +**Start with Step 1: Risk identification for {location_code}.**""" |
| 598 | + |
| 599 | + return [Message(content=prompt_msg, role="user")] |
| 600 | + |
| 601 | + |
| 602 | +def product_lifecycle_review( |
| 603 | + category: str = "all", include_inactive: bool = False |
| 604 | +) -> list[PromptMessage]: |
| 605 | + """Review product portfolio, identify optimization opportunities, and configure products. |
| 606 | +
|
| 607 | + Guide AI through portfolio optimization and product configuration workflow: |
| 608 | + 1. Portfolio Overview: List products in category |
| 609 | + 2. Performance Analysis: Review sales, forecasts, inventory turns |
| 610 | + 3. Configuration Review: Check forecasting settings, supplier assignments |
| 611 | + 4. Optimization: Configure forecasts, update suppliers, flag for discontinuation |
| 612 | +
|
| 613 | + Analysis areas: |
| 614 | + - Slow-moving products (low turns) |
| 615 | + - Overstock risks (high inventory, low demand) |
| 616 | + - Forecast accuracy per product |
| 617 | + - Supplier consolidation opportunities |
| 618 | + - Missing configurations (no forecast, no supplier) |
| 619 | +
|
| 620 | + Args: |
| 621 | + category: Product category to review (default: 'all') |
| 622 | + include_inactive: Include discontinued/inactive products (default: False) |
| 623 | +
|
| 624 | + Returns: |
| 625 | + List of prompt messages guiding the workflow |
| 626 | + """ |
| 627 | + current_date = datetime.now().strftime("%Y-%m-%d") |
| 628 | + category_display = category if category != "all" else "all categories" |
| 629 | + |
| 630 | + # System message - guide AI through the workflow |
| 631 | + system_message = """You are a StockTrim inventory management expert conducting a product lifecycle review. |
| 632 | +
|
| 633 | +Your goal is to optimize the product portfolio through systematic analysis and configuration. |
| 634 | +
|
| 635 | +**Workflow Steps:** |
| 636 | +
|
| 637 | +1. **Portfolio Overview** |
| 638 | + - List all products in the category using `list_products` |
| 639 | + - Summarize total count, active vs inactive |
| 640 | + - Note any immediate concerns (e.g., many discontinued items) |
| 641 | +
|
| 642 | +2. **Performance Analysis** |
| 643 | + - For each product, review: |
| 644 | + * Sales history and trends |
| 645 | + * Current inventory levels vs demand |
| 646 | + * Inventory turnover rate |
| 647 | + * Forecast accuracy (if available) |
| 648 | + - Use `forecasts_get_for_products` to get forecast data |
| 649 | + - Access `stocktrim://reports/inventory-status` for inventory metrics |
| 650 | +
|
| 651 | +3. **Configuration Review** |
| 652 | + - Check each product's configuration: |
| 653 | + * Is forecasting enabled? (ignore_seasonality flag) |
| 654 | + * Are suppliers properly assigned? |
| 655 | + * Are lead times accurate? |
| 656 | + - Flag products with missing or incomplete configuration |
| 657 | +
|
| 658 | +4. **Optimization Recommendations** |
| 659 | + - Identify optimization opportunities: |
| 660 | + * **Slow movers**: Products with low turnover - consider discontinuation |
| 661 | + * **Overstock risks**: High inventory with declining demand - adjust forecast settings |
| 662 | + * **Forecast gaps**: Products without forecast configuration - enable forecasting |
| 663 | + * **Supplier consolidation**: Multiple suppliers for similar products - rationalize |
| 664 | + - Prioritize actions by business impact |
| 665 | +
|
| 666 | +5. **Execute Configuration Changes** |
| 667 | + - Use `configure_product` to update product settings |
| 668 | + - Use `update_forecast_settings` to adjust forecast parameters |
| 669 | + - Document all changes and rationale |
| 670 | +
|
| 671 | +**Analysis Focus Areas:** |
| 672 | +- Slow-moving products (inventory turnover < 4x per year) |
| 673 | +- Overstock situations (inventory > 90 days of demand) |
| 674 | +- Forecast accuracy issues (high variance between forecast and actual) |
| 675 | +- Supplier consolidation opportunities |
| 676 | +- Missing configurations (no forecast settings, no supplier mappings) |
| 677 | +
|
| 678 | +**Best Practices:** |
| 679 | +- Always review product details using `stocktrim://products/{code}` before making changes |
| 680 | +- Consider business context (seasonal products, new launches, etc.) |
| 681 | +- Document reasoning for configuration changes |
| 682 | +- Prioritize high-value or high-volume products |
| 683 | +- Be conservative with discontinuation recommendations""" |
| 684 | + |
| 685 | + # User message - specific request with parameters |
| 686 | + user_message = f"""Conduct product lifecycle review for {category_display}. |
| 687 | +
|
| 688 | +**Parameters:** |
| 689 | +- Category: {category} |
| 690 | +- Include inactive: {include_inactive} |
| 691 | +- Review date: {current_date} |
| 692 | +
|
| 693 | +**Your Task:** |
| 694 | +
|
| 695 | +1. Review product portfolio in category |
| 696 | +2. Analyze performance metrics |
| 697 | +3. Identify optimization opportunities |
| 698 | +4. Configure forecasts and suppliers as needed |
| 699 | +
|
| 700 | +Start with portfolio overview using the `list_products` tool.""" |
| 701 | + |
| 702 | + return [ |
| 703 | + PromptMessage( |
| 704 | + role="assistant", content=TextContent(type="text", text=system_message) |
| 705 | + ), |
| 706 | + PromptMessage(role="user", content=TextContent(type="text", text=user_message)), |
| 707 | + ] |
| 708 | + |
| 709 | + |
447 | 710 | def register_workflow_prompts(mcp: FastMCP) -> None: |
448 | 711 | """Register workflow prompts with FastMCP server. |
449 | 712 |
|
@@ -493,3 +756,17 @@ async def supplier_performance_review( |
493 | 756 | ) -> list[Message]: |
494 | 757 | """Comprehensive supplier performance review and analysis.""" |
495 | 758 | return await _supplier_performance_review(supplier_code, period_days, context) |
| 759 | + |
| 760 | + @mcp.prompt() |
| 761 | + async def stockout_prevention( |
| 762 | + location_code: str = Field(..., description="Location code to analyze"), |
| 763 | + days_ahead: int = Field( |
| 764 | + default=14, description="Days ahead to forecast (default: 14)" |
| 765 | + ), |
| 766 | + context: Context | None = None, |
| 767 | + ) -> list[Message]: |
| 768 | + """Proactive stockout prevention workflow: analyze inventory levels, identify gaps, and create preventive purchase orders.""" |
| 769 | + return await _stockout_prevention(location_code, days_ahead, context) |
| 770 | + |
| 771 | + # Register product_lifecycle_review prompt |
| 772 | + mcp.prompt()(product_lifecycle_review) |
0 commit comments