MCP server for the CRM-to-Reporting pipeline. Implements a minimal Model Context Protocol stdio server (JSON-RPC 2.0 over newline-delimited stdin/stdout) for syncing CRM data to a reporting layer, managing borrower portfolios, facilities, KPIs, covenant compliance, and reconciliation.
16 tools with clear verb-noun naming (run_sync, list_borrowers, get_kpi_movements). All have descriptions (avg ~120 chars, within baseline 34-392). Input schemas present with type declarations and parameter descriptions. However, output schemas are NOT documented, responses are inferred from code inspection only. No enum constraints on filter parameters (stage, owner, severity, report_type). Error handling is minimal; no recovery guidance or actionable error messages visible. Tool descriptions lack WHEN/WHY context and dependency hints. No tool annotations (readOnlyHint/destructiveHint). Pagination present (limit params with max bounds) but no cursor/offset or total_count fields documented. Missing: output field documentation, error classification, confirmation patterns for destructive ops.
Get detailed information about a specific borrower company.
Get detailed information about a specific facility/deal.
Return period-over-period revenue movements for each borrower. This is the core 'what moved this quarter?' question a PM would ask before drafting an LP letter.
Return the most recent sync run with full metrics.
Get all reporting metrics for a specific company across all periods.
Get detailed information about a specific sync run including extracted, transformed, loaded, and rejected counts.
List borrowers (portfolio companies) in the reporting layer. Optional filters: stage, owner, reporting_period.
Output schemas not documented. Tool descriptions state what is returned (e.g. 'Return the most recent sync run with full metrics') but do not specify field names, types, or structure. LLMs cannot plan downstream tool calls or extract data reliably without knowing response shape.
Filter parameters lack enum constraints. Tools like list_borrowers (stage, owner, reporting_period), list_facilities (stage, owner), list_reports (report_type), and list_reconciliation_breaks (severity) accept free-form strings. LLMs will hallucinate invalid values. Enums are self-documenting and prevent invalid queries.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 50 | <=2025-11-25 | v2 |
List detected covenant breaches for facilities.
List facilities / deals in the pipeline, optionally filtered by stage.
List numeric covenants attached to credit facilities.
List detected differences between CRM and fund admin records.
List records that failed validation and are in quarantine.
List generated investor/internal reports.
List recent sync runs for audit trail review.
Identify borrowers on a credit watch list based on covenant KPIs. A borrower goes on the watch list if any of these are true for the latest reporting period: EBITDA margin is negative, Burn multiple > 2.0, Revenue declined period-over-period, or Latest metrics missing entirely for a portfolio company.
Trigger a fresh sync run from CRM source → reporting layer.
No error handling guidance. Tool implementations return plain dicts with no error classification, recovery hints, or actionable messages. If a sync fails or a company_external_id is not found, the LLM receives no guidance on what to do next (retry, ask user, abort).
No tool annotations. Tools lack readOnlyHint, destructiveHint, or idempotentHint metadata. run_sync is destructive (triggers a fresh sync) but is not marked as such. LLMs cannot distinguish safe reads from risky writes without explicit hints.
Descriptions lack WHEN/WHY context and dependency hints. E.g. 'List borrowers (portfolio companies) in the reporting layer' does not explain when to call this vs get_company_details, or that it should be called first to discover available companies. Descriptions should guide tool selection and multi-step planning.