MCP server for commercial loan document verification, KYC, fraud detection, and GST intelligence
This server demonstrates strong definition quality with well-structured tool definitions, comprehensive descriptions, and proper schema usage. All 9 tools have explicit registrations with Zod schemas and descriptive titles. Descriptions are detailed (194-500+ chars) and include context about when/why to use each tool, which exceeds the baseline of 194 chars average. Tool naming follows verb_noun convention (doc_parse, fraud_query, gst_verify, kyc_validate) and is consistent across the domain. Input schemas use Zod with proper type definitions and descriptions for all parameters. However, there are gaps: output schemas are documented in prose within tool descriptions but not formalized in the tool definitions themselves; some parameters could accept human-friendly identifiers rather than requiring structured references; and no explicit error recovery guidance in descriptions. The server shows awareness of domain-specific patterns (e.g., risk_verdict enums, confidence thresholds, tampering signals) and proper composition (tools chain logically via document_id, entity_type references).
Verify a dentist's BDS/MDS registration with the Dental Council of India. Critical for dental clinic loans — fake credentials are a major fraud vector. Args: - registration_number: DCI registration number from the degree certificate - dentist_name: Full name as on the loan application - degree_type: "BDS" | "MDS" | "BOTH" Returns: { "registration_status": "active"|"suspended"|"revoked"|"not_found", "credential_verified": boolean, "dentist_name": string, // Name on DCI records "practice_years": number, "council_name": string, "risk_flags": string[], // e.g. ["BORROWED_CREDENTIAL", "REVOKED_ELSEWHERE"] "risk_verdict": "PASS"|"FLAG"|"BLOCK" } BLOCK on: not_found, revoked, name mismatch, borrowed credentials. This check is unique to dental/medical professional loans.
OCR-parse an uploaded document, classify its type, extract fields, and detect tampering. Supports: PAN, Aadhaar, ITR, Bank Statement, GST Certificate, BDS/MDS Degree, Machinery Invoice, Lease Agreement, Project Report, Udyam Certificate. Args: - file_reference: File path or reference ID from the document upload (e.g. "uploads/pan_card.pdf") - expected_type: (optional) Expected document type to validate against Returns: { "document_id": string, // Unique ID for this parsed doc (use in downstream tools) "document_type": string, // Classified type "extracted_fields": object, // All extracted key-value pairs "confidence_score": number, // 0-100, below 70 needs manual review "tamper_detected": boolean, "tamper_signals": string[], // e.g. ["FONT_INCONSISTENCY", "METADATA_MISMATCH"] "ocr_quality": "high"|"medium"|"low", "parsed_at": string } Use when: Starting verification of any uploaded document. Watch for: tamper_detected=true or confidence_score < 70 — route to manual review.
Output schemas are documented in prose descriptions but not formalized as returnSchema in tool definitions. LLMs cannot programmatically parse expected output structure. Zod should define output types and include them in tool metadata.
Some parameters require structured references (file_reference, registration_number) but descriptions do not clarify whether human-readable names/formats are accepted. E.g., doc_parse_document requires 'file_reference', can agents pass 'my_pan_card.pdf' or only an opaque upload ID?
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 59 | 2025-06-18+ | v2 |
| 2026-03-09 | F | 49 | - | v1 |
Check if all mandatory documents for a specific loan type have been uploaded. Returns a checklist with missing/present status for each required document. Loan types: "clinic_setup" | "equipment" | "working_capital" | "expansion" Returns: { "complete": boolean, "loan_type": string, "checklist": [{ "document": string, "status": "present"|"missing"|"expired", "notes": string }], "missing_documents": string[], "can_proceed": boolean } Use when: Before starting verification pipeline to ensure no documents are missing.
Query the bank's fraud intelligence registry for a given entity. Checks for known bad actors, identity layering patterns, reused invoices, and signals submitted by other agents in previous cases. This is a CROSS-CUTTING tool — called by agents in Stages 2, 3, 4, and 7. Args: - entity_type: "pan"|"gstin"|"aadhaar"|"phone"|"account"|"invoice" - entity_value: The value to check (e.g. PAN number, GSTIN, phone) - case_id: (optional) Current case ID for audit trail Returns: { "entity_id": string, "risk_score": number, // 0-100; above 60 = block "fraud_signals": [{ "signal_type": string, "severity": "low"|"medium"|"high"|"critical", "description": string, "reported_at": string }], "identity_layering_risk": boolean, "known_bad_actor": boolean, "risk_verdict": "PASS"|"FLAG"|"BLOCK" } Critical: BLOCK on known_bad_actor=true or risk_score > 60. Escalate immediately.
Submit a new fraud signal discovered during loan processing to the central registry. This enables network learning — each case improves detection for future cases. Called by any agent when they discover an anomaly: tampered docs, vendor mismatch, income-bank discrepancy, identity layering, etc. Args: - entity_type: Type of entity this signal applies to - entity_value: Entity value (PAN, GSTIN, etc.) - signal_type: Signal category (e.g. "TAMPERED_DOCUMENT", "IDENTITY_LAYERING", "FAKE_INVOICE") - severity: "low"|"medium"|"high"|"critical" - description: Human-readable description of what was found - case_id: The case where this was discovered Returns: { "signal_id": string, "accepted": boolean, "message": string }
Retrieve month-by-month GST filing history for a GSTIN. Used to detect cash flow patterns, seasonality, and diversion signals in WC monitoring (Stage 7). Args: - gstin: 15-character GSTIN - months: Number of months of history to retrieve (default: 12, max: 36) Returns: { "gstin": string, "filing_history": [{ "period": "MMYYYY", "filed": boolean, "taxable_turnover": number, "tax_paid": number }], "trend": "growing"|"stable"|"declining"|"erratic", "average_monthly_turnover": number, "missed_filings": string[], "diversion_signals": string[] } Use in Stage 7 working capital monitoring to verify monthly business activity.
Verify a GSTIN against the GST portal, check filing compliance, detect shell entities. This is the primary GST check used in Stage 2 (business verification) and reused in Stage 3 (vendor checks). Args: - gstin: 15-character GSTIN (e.g. "29ABCDE1234F1Z5") - entity_name: Declared entity name to match against GST records Returns: { "gstin": string, "legal_name": string, "status": "active"|"cancelled"|"suspended"|"provisional", "filing_compliance_score": number, // 0-100 "months_since_last_filing": number, "annual_turnover_band": string, "shell_entity_risk_score": number, // 0-100; above 40 = high risk "shell_entity_signals": string[], "risk_verdict": "PASS"|"FLAG"|"BLOCK", "risk_reasons": string[], "verified_at": string } Shell entity signals include: new registration, no turnover, address issues, filing gaps. This resource is shared with Stage 3 vendor tools — no re-verification needed.
Validate a PAN number against NSDL, verify name match, check for duplicates within bank, and screen against watchlists (PMLA, court orders, OFAC). Args: - pan: 10-character PAN number (e.g. "ABCDE1234F") - applicant_name: Full name as given in the application - check_dedup: Whether to check if this PAN is used by another customer in the bank Returns: { "pan": string, "valid_format": boolean, "name_on_pan": string, "name_match_score": number, // 0-100; below 75 = flag "pan_type": "individual"|"company"|"trust"|"unknown", "dedup_status": "clean"|"duplicate_within_bank"|"watchlist_hit", "watchlist_flags": string[], "risk_verdict": "PASS"|"FLAG"|"BLOCK", "risk_reasons": string[], "validated_at": string } Risk verdicts: PASS = proceed, FLAG = need explanation, BLOCK = stop application. Watchlist hits → always BLOCK and escalate to fraud team.
Verify Aadhaar identity via UIDAI. Checks name consistency, address signals, and optionally face match for video KYC flows. Args: - aadhaar_last4: Last 4 digits of Aadhaar (we never store full Aadhaar) - name_on_application: Name as given in the application - address_state: State declared in the application - face_image_reference: (optional) Reference to face photo for video KYC face match Returns: { "name_match": boolean, "name_match_score": number, "address_consistency": boolean, "address_risk_signals": string[], "face_match_score": number|null, "verification_status": "verified"|"mismatch"|"not_found"|"error", "risk_verdict": "PASS"|"FLAG"|"BLOCK", "risk_reasons": string[] } Note: Aadhaar is never stored in full. Only last 4 digits used for reference.
Error handling descriptions lack recovery guidance. Tool descriptions explain what to watch for (e.g., 'tamper_detected=true or confidence_score < 70') but do not prescribe explicit recovery steps for LLM automation. Should state: 'Route to manual_review_queue' or 'Call fraud_submit_signal with signal_type=TAMPERED_DOCUMENT'.
gst_get_filing_history lacks default behavior clarity. It accepts 'months' with default=12 but the description does not state whether months=0 is invalid or whether the tool handles partial month data gracefully. Max=36 is specified but min is not.
kyc_verify_aadhaar stores only last 4 digits per security requirements, but no explicit guidance for LLMs on how to source/validate aadhaar_last4 from uploaded Aadhaar documents. Should reference: 'Extract aadhaar_last4 from the parsed Aadhaar document (use doc_parse_document first)'.