59 tools

Business Workflow Diagrams

Interactive flow diagrams showing how the MCP tools chain together for each business process. Click any card to expand the diagram. Tool names shown in teal are the MCP tools used at each step.

API Reference

Complete reference for all 67 MCP tools. Each tool is callable via JSON-RPC using the tools/call method.

System Architecture

How the TazWorks MCP Server fits within the PCS backend microservices ecosystem.

MCP CLIENTS Claude Desktop / Web Playground / Custom Apps stdio / streamable-http TazWorks MCP Server Port 8004 | FastMCP + Starlette | 67 AI-Callable Tools JWT Auth | Response Caching | Structured Logging Direct API (REST) HTTP Proxy TazWorks Cloud API api-sandbox.instascreen.net Orders | Applicants | Results | Searches Disclosures | Webhooks | Client Users | Fees background-service Port 8005 | High-level Workflows Candidates | Background Orders Adverse Actions | Results Parsing PostgreSQL Background Data & Compliance API Gateway :8000 BFF + Routing Auth Service :8001 JWT + RBAC + MFA Org Service :8002 Multi-tenant Orgs Apache Kafka (KRaft :9092) Event Bus: pcs.tazworks.* topics Redis :6379 Cache | Sessions | Token Blacklist
MCP Server (this service)
Direct TazWorks API calls
PCS proxy calls
Database
Message broker
Cache

Transport Modes

  • streamable-http (default) -- Web clients connect via HTTP to port 8004
  • stdio -- Claude Desktop communicates over stdin/stdout
  • Protocol version: 2025-03-26 (MCP v1)

Technology Stack

  • Python 3.11+ with FastMCP framework
  • httpx for async HTTP calls
  • JWT authentication to TazWorks API
  • In-memory response caching (TTL-based)
  • structlog for structured logging

Tool Sources

  • 47 tools call TazWorks Cloud API directly
  • 12 tools proxy to background-service (PCS internal)
  • 2 tools report server health and cache stats
  • 6 tools for compliance and consent verification
Total: 67 tools (was 59, +8 new)

Security

  • TazWorks API: JWT bearer token (auto-refreshed)
  • Sensitive data: SSN masked in logs
  • All requests authenticated via client credentials
  • Sandbox and production API support

Detailed API Flows & Test Scenarios

Comprehensive technical flows with timing, database interactions, and production test coverage. All 202 tests documented with real-world scenarios.

📊 Coverage Statistics (Session 2026-02-07)

API COVERAGE
46% → 68%
119/175 endpoints
MCP TOOLS
59 → 67
+8 new tools
TOTAL TESTS
130 → 202
+72 new tests
PYDANTIC MODELS
15 → 49
+34 schemas

🔄 Complete Background Check Workflow (7 Phases)

┌─────────────────────────────────────────────────────────────────────────────┐
│  Frontend → API Gateway → Background-Service → Kafka → TazWorks → Database  │
│                                                                             │
│  PHASE 1: Candidate Creation (< 200ms)                                     │
│    POST /candidates → INSERT candidates (status=NEW) → 201 Created         │
│                                                                             │
│  PHASE 2: Order Submission (< 500ms, async)                                │
│    POST /orders → INSERT orders (status=QUEUED) → Publish Kafka event      │
│    → 202 Accepted {order_id, status: "queued", progress_pct: 0}           │
│                                                                             │
│  PHASE 3: TazWorks Submission (2-5s, background consumer)                  │
│    Consumer polls Kafka → handle_order_requested()                         │
│    → Check if applicant exists in TazWorks                                  │
│    → [IF NOT] POST /v1/clients/{guid}/applicants                           │
│    → POST /v1/clients/{guid}/orders {applicantGuid, productCode}           │
│    → UPDATE orders (status=SUBMITTED, tazworks_order_guid)                 │
│    → Publish "pcs.background.order.submitted"                              │
│                                                                             │
│  PHASE 4: TazWorks Processing (10s - 72 hours, external)                   │
│    TazWorks runs searches: County Criminal, Employment, Education, Driving │
│    Each search transitions: PENDING → IN_PROGRESS → COMPLETE               │
│                                                                             │
│  PHASE 5: Webhook Notification (< 100ms)                                   │
│    TazWorks → POST /webhooks/tazworks                                       │
│    → Validate HMAC signature                                               │
│    → Publish "pcs.background.webhook.received"                             │
│    → 200 OK                                                                 │
│                                                                             │
│  PHASE 6: Result Processing (5-30s, background consumer)                   │
│    Consumer polls webhook topic → handle_webhook_received()                │
│    → Find order by tazworks_order_guid                                     │
│    → GET /v1/clients/{guid}/orders/{orderGuid} (order status)             │
│    → GET /v1/clients/{guid}/orders/{orderGuid}/searches (all searches)    │
│    → FOR EACH COMPLETE SEARCH:                                             │
│      → GET /v1/results/{searchGuid} (raw results)                          │
│      → ResultParser.parse_XXX_results() (criminal/civil/employment/etc)    │
│      → INSERT search_results (raw_data + parsed fields)                    │
│      → UPDATE searches (status=COMPLETE, result="clear"/"records_found")   │
│      → Publish "pcs.background.search.completed"                           │
│    → Calculate progress_pct = (completed_count / total) * 100              │
│    → UPDATE orders (progress_pct)                                          │
│    → [IF ALL COMPLETE] UPDATE orders (status=COMPLETE, progress_pct=100)   │
│    → [IF ALL COMPLETE] Publish "pcs.background.order.completed"            │
│                                                                             │
│  PHASE 7: Client Retrieves Results (< 200ms cached, < 500ms DB)            │
│    GET /orders/{id} → SELECT order + searches → 200 OK                     │
│    GET /searches/{id}/results → Check Redis → [HIT] Return cached          │
│                               → [MISS] SELECT search_results → Cache 1h    │
│                                                                             │
│  Status Transitions:                                                        │
│    Order: QUEUED → SUBMITTED → IN_PROGRESS → PARTIAL_RESULTS → COMPLETE    │
│    Search: NEW → IN_PROGRESS → COMPLETE                                    │
└─────────────────────────────────────────────────────────────────────────────┘

⚖️ FCRA Adverse Action Workflow (7-Day Process)

┌─────────────────────────────────────────────────────────────────────────────┐
│  FCRA ADVERSE ACTION - Complete Lifecycle with Validation & Time Tracking  │
│                                                                             │
│  DAY 0: Create & Send Pre-Adverse Notice                                   │
│    POST /adverse-actions                                                    │
│      {order_id, reason: "Criminal record...", delivery_method, send_to}    │
│    → Validate order has findings (flagged=true)                            │
│    → INSERT adverse_actions (status=DRAFT, type=PRE_ADVERSE)               │
│    → 201 Created {action_id, status: "draft"}                              │
│                                                                             │
│    POST /adverse-actions/{id}/send                                          │
│    → Validate status=DRAFT                                                  │
│    → Calculate can_finalize_at = now() + 7 days                            │
│    → UPDATE adverse_actions (status=SENT, sent_at, can_finalize_at)        │
│    → Send email/mail via delivery service                                   │
│    → 200 OK {status: "sent", can_finalize_at}                              │
│                                                                             │
│  DAY 0-7: Waiting Period (FCRA Required)                                   │
│    Candidate receives pre-adverse letter explaining:                        │
│      - Which records triggered adverse action                               │
│      - Right to dispute inaccuracies                                        │
│      - 7-day period to respond                                              │
│      - Copy of consumer rights summary                                      │
│                                                                             │
│  DAY 3 (Optional): Candidate Disputes                                       │
│    POST /adverse-actions/{id}/dispute                                       │
│      {dispute_notes: "The criminal record is not mine..."}                 │
│    → Validate status in [SENT, WAITING]                                    │
│    → UPDATE adverse_actions (status=DISPUTED, dispute_received_at,         │
│                                dispute_notes, disputed=true)                │
│    → Trigger reinvestigation workflow                                       │
│    → 200 OK {status: "disputed", dispute_received_at}                      │
│                                                                             │
│  DAY 7+: Finalize Adverse Action                                           │
│    POST /adverse-actions/{id}/finalize                                      │
│      {final_decision: "NOT_HIRED", decision_notes: "..."}                  │
│    → Validate status in [SENT, WAITING, DISPUTED]                          │
│    → Validate datetime.now(UTC) >= can_finalize_at                         │
│    → [FAIL] 400 Bad Request "Cannot finalize before {date}"                │
│    → [PASS] UPDATE adverse_actions (status=FINALIZED, finalized_at,        │
│                                      final_decision, dispute_resolved_at)   │
│    → Send final adverse action letter                                       │
│    → 200 OK {status: "finalized", finalized_at}                            │
│                                                                             │
│  State Machine:                                                             │
│    DRAFT → SENT → [DISPUTED] → FINALIZED                                   │
│            ↓                                                                │
│          WAITING (after 7 days)                                            │
│                                                                             │
│  Validation Rules:                                                          │
│    ✅ Cannot send unless status=DRAFT                                       │
│    ✅ Cannot dispute unless status in [SENT, WAITING]                       │
│    ✅ Cannot finalize unless status in [SENT, WAITING, DISPUTED]            │
│    ✅ Cannot finalize before 7-day waiting period elapses                   │
│    ✅ Timezone normalization (SQLite naive → PostgreSQL aware)              │
└─────────────────────────────────────────────────────────────────────────────┘

📎 Order Attachments Flow (FCRA Critical)

┌─────────────────────────────────────────────────────────────────────────────┐
│  ORDER ATTACHMENTS - FCRA Authorization Forms & Supporting Documents       │
│                                                                             │
│  Step 1: Get QuickApp Signed Disclosure                                    │
│    GET /v1/clients/{guid}/orders/{orderGuid}/attach/quickapp               │
│      ?type=APPLICANT_AUTHORIZATION                                          │
│    → Returns base64-encoded signed disclosure form                          │
│    → Includes applicant e-signature and timestamp                           │
│    → Response: {base64_content, created_at, order_guid}                    │
│                                                                             │
│  Step 2: Upload Authorization Form (Multipart)                             │
│    POST /v1/clients/{guid}/orders/{orderGuid}/attach                       │
│      {                                                                      │
│        name: "FCRA Authorization Form",                                     │
│        originalFileName: "authorization.pdf",                               │
│        encodedContent: "base64...",                                         │
│        isAuthorizationForm: true,                                           │
│        isCraOnly: false  // False = visible to client                       │
│      }                                                                      │
│    → TazWorks stores attachment                                             │
│    → Returns {attachment_guid, upload_timestamp}                            │
│                                                                             │
│  Step 3: Upload Supporting Documents (Base64)                              │
│    POST /v1/clients/{guid}/orders/{orderGuid}/attach                       │
│      {                                                                      │
│        name: "Driver License Copy",                                         │
│        encodedContent: "data:image/jpeg;base64,...",                        │
│        type: "SUPPORTING_DOCUMENT"                                          │
│      }                                                                      │
│                                                                             │
│  Step 4: List All Attachments                                              │
│    GET /v1/clients/{guid}/orders/{orderGuid}/attachments                   │
│    → Returns [{attachment_guid, name, file_size, uploaded_at}, ...]        │
│                                                                             │
│  Step 5: Delete Attachment (CRA API Only)                                  │
│    DELETE /v1/clients/{guid}/orders/{orderGuid}/attach/{attachmentGuid}    │
│    → Requires CRA API permissions                                           │
│    → 403 Forbidden if insufficient permissions                              │
│    → 204 No Content on success                                              │
│                                                                             │
│  Attachment Types:                                                          │
│    - APPLICANT_AUTHORIZATION (FCRA disclosure)                              │
│    - AUTHORIZATION_FORMS (consent forms)                                    │
│    - E_SIGNATURE (digital signatures)                                       │
│    - SUPPORTING_DOCUMENT (ID copies, etc.)                                  │
│    - CUSTOM_DOCUMENT (client-defined)                                       │
│                                                                             │
│  MCP Tools:                                                                 │
│    • get_order_disclosure_forms (client, order, type)                      │
│    • upload_authorization_form (client, order, filename, content, cra_only)│
│    • upload_base64_document (client, order, name, base64, is_auth)         │
│    • list_order_attachments (client, order)                                │
│    • delete_order_attachment (client, order, attachment) [CRA only]        │
└─────────────────────────────────────────────────────────────────────────────┘

🔧 Advanced Order Operations

┌─────────────────────────────────────────────────────────────────────────────┐
│  ADVANCED ORDER OPERATIONS - Modify Orders Post-Creation                   │
│                                                                             │
│  1. Add Searches to Existing Order                                         │
│    POST /v1/clients/{guid}/orders/{orderGuid}/searches                     │
│      [                                                                      │
│        {                                                                    │
│          type: "STATE_CRIMINAL_COURT",                                      │
│          jurisdiction: {state: "CA", county: "Los Angeles"},                │
│          required: true,                                                    │
│          priority: 1                                                        │
│        },                                                                   │
│        {                                                                    │
│          type: "PROFESSIONAL_LICENSE",                                      │
│          values: {licenseType: "RN", state: "CA"}                          │
│        }                                                                    │
│      ]                                                                      │
│    → TazWorks adds searches to order                                        │
│    → Triggers additional screening workflows                                │
│    → Returns {order_guid, searches_added: 2, total_searches: 7}            │
│                                                                             │
│  2. Add Notes to Order                                                     │
│    PUT /v1/clients/{guid}/orders/{orderGuid}/notes                         │
│      {                                                                      │
│        client_notes: "Candidate explained gap in employment",              │
│        report_notes: "Internal: check with previous employer"  // CRA only │
│      }                                                                      │
│    → client_notes visible to all parties                                    │
│    → report_notes visible to CRA only (restricted)                          │
│    → Useful for documenting adjudication decisions                          │
│                                                                             │
│  3. Get Results PDF Download Link                                          │
│    GET /v1/clients/{guid}/orders/{orderGuid}/resultsAsPdf                  │
│    → Returns {pdf_url: "https://...", expires_at: "2026-02-08T..."}        │
│    → Direct download link (no re-fetch of result data)                     │
│    → Link expires after 1 hour                                              │
│                                                                             │
│  4. Set Hiring Decision                                                    │
│    POST /v1/clients/{guid}/orders/{orderGuid}/decision                     │
│      {decision_guid: "uuid-of-decision-template"}                          │
│    → Records adjudication outcome (hired/not_hired/pending)                 │
│    → Tracks who made decision and when                                      │
│    → Can trigger automated workflows (adverse action, notifications)        │
│                                                                             │
│  5. Get Candidate Order History                                            │
│    GET /v1/clients/{guid}/applicants/{applicantGuid}/orders                │
│    → Returns all historical orders for candidate                            │
│    → Useful for annual re-screening                                         │
│    → [{order_guid, status, product, completed_at}, ...]                    │
│                                                                             │
│  MCP Tools:                                                                 │
│    • add_background_searches (client, order, search_types[])               │
│    • add_report_notes (client, order, client_notes, report_notes)          │
│    • get_results_pdf_link (client, order)                                  │
│    • set_hiring_decision (client, order, decision_guid)                    │
│    • get_candidate_order_history (client, applicant)                       │
└─────────────────────────────────────────────────────────────────────────────┘

⚙️ Client Preferences Configuration

┌─────────────────────────────────────────────────────────────────────────────┐
│  CLIENT PREFERENCES - Configuration & Drug Testing Provider Settings       │
│                                                                             │
│  General Preferences (PII Masking & SLA)                                   │
│    GET /v1/clients/{guid}/preferences/general                              │
│    → {mask_ssn: true, mask_year_of_birth: true, mask_drivers_license: true,│
│        service_level_agreement_hours: 24, enable_auto_archive: false}      │
│                                                                             │
│    PUT /v1/clients/{guid}/preferences/general                              │
│      {mask_ssn: false, service_level_agreement_hours: 48}                  │
│    → Cache invalidated (preferences:{client}:general)                       │
│    → 200 OK {updated preferences}                                           │
│                                                                             │
│  Order Preferences (Email Notifications)                                   │
│    GET /v1/clients/{guid}/preferences/order                                │
│    → {send_completed_email_timing: "UPON_COMPLETION_OF_REPORT",            │
│        notify_if_flags_are_present: true,                                   │
│        notify_when_flags_are_present_email: "alerts@company.com",          │
│        allow_client_to_add_searches: false}                                │
│                                                                             │
│  Drug Testing Provider Settings (I3Screen, Quest, ClearMD, EScreen)        │
│    GET /v1/clients/{guid}/drug-providers/i3screen                          │
│    → {organization_id: "...", location_code: "...",                        │
│        manual_permitted: true, sso_permitted: true,                        │
│        applicant_invite_permitted: false,                                   │
│        send_status_to_user_guids: ["user-guid-1"],                         │
│        copy_status_to_pending_notes: true}                                 │
│                                                                             │
│    PUT /v1/clients/{guid}/drug-providers/quest                             │
│      {preferred_network: true, preferred_fee: 45.00,                       │
│        include_patient_service_centers: true,                              │
│        send_copy_of_donor_passport: true,                                  │
│        copy_of_donor_passport_send_email: "hr@company.com"}                │
│    → Cached for 600 seconds (preferences rarely change)                     │
│    → Cache key: preferences:{client}:quest                                  │
│                                                                             │
│  Report Decision Tool                                                      │
│    GET /v1/clients/{guid}/preferences/report-decision                      │
│    → {enable_report_decision_tool: true,                                   │
│        report_decision_tool_style: "GRAPHICAL",  // or "TEXTUAL"           │
│        email_all_decisions_to_requestor: true,                             │
│        require_decision_before_release: false}                             │
│                                                                             │
│  Caching Strategy:                                                          │
│    - TTL: 600 seconds (10 minutes)                                         │
│    - Key pattern: preferences:{client_guid}:{category}                     │
│    - Invalidation: On PUT operations                                        │
│    - Cache miss: Fetch from TazWorks API                                    │
│                                                                             │
│  MCP Tools (7):                                                             │
│    • get_client_general_preferences (client)                               │
│    • update_ssn_masking (client, mask_ssn, mask_yob, mask_dl)              │
│    • get_order_notification_settings (client)                              │
│    • update_order_notifications (client, settings{})                        │
│    • get_drug_provider_settings (client, provider)                         │
│    • configure_drug_testing_provider (client, provider, settings{})        │
│    • get_report_decision_workflow (client)                                 │
└─────────────────────────────────────────────────────────────────────────────┘

🧪 E2E Test Scenarios (6 Production Tests)

Test 1: Bulk Multi-Candidate Screening

Scenario: Order 3 different packages for 10 candidates across 5 states
- Create 10 candidates (varied locations: CA, NY, TX, FL, IL)
- Submit 30 orders (10 candidates × 3 packages)
  • Package A: County Criminal + Employment Verification
  • Package B: State Criminal + Education Verification
  • Package C: Federal Criminal + Professional License
- Simulate concurrent webhook arrivals for all 30 orders
- Track progress for all orders simultaneously
- Verify multi-tenant isolation (3 orgs, same names)

Expected Results:
  ✅ All 30 orders transition: QUEUED → SUBMITTED → IN_PROGRESS → COMPLETE
  ✅ No cross-contamination between orgs
  ✅ Correct search type matching (90 total searches)
  ✅ Progress calculations accurate (0% → 100%)
  ✅ All Kafka events published (order.requested, order.submitted, search.completed, order.completed)

File: background-service/tests/e2e/test_bulk_multi_candidate_screening.py
Status: Requires full integration environment (TazWorks API + Kafka)
    

Test 2: Concurrent Webhook Processing

Scenario: 50 webhooks arriving simultaneously, testing race conditions
- Create 1 order with 5 searches
- Simulate 50 concurrent webhooks using asyncio.gather():
  • 10 webhooks for search 1 (COMPLETE)
  • 10 webhooks for search 2 (COMPLETE)
  • 10 webhooks for search 3 (COMPLETE)
  • 10 webhooks for search 4 (IN_PROGRESS)
  • 10 webhooks for search 5 (IN_PROGRESS)
- Test database locking and transaction isolation
- Verify no duplicate SearchResult records created
- Test idempotency (same webhook received multiple times)

Expected Results:
  ✅ Only 1 SearchResult per search (no duplicates)
  ✅ Final order status correctly reflects all searches
  ✅ Progress percentage accurate despite race conditions
  ✅ No database deadlocks or conflicts
  ✅ Idempotent processing (repeated webhooks don't cause errors)

Race Conditions Tested:
  - Same order, multiple searches completing simultaneously
  - Out-of-order webhook arrival (COMPLETE before IN_PROGRESS)
  - Duplicate webhooks for same search
  - Concurrent progress_pct calculations

File: background-service/tests/e2e/test_concurrent_webhook_processing.py
Status: Tests database transaction handling and concurrent processing
    

Test 3: FCRA Full Workflow (Time-Mocked)

Scenario: Complete adverse action cycle with 7-day waiting period
- Create order with findings (flagged=true)
- Create pre-adverse action
- Send pre-adverse letter (starts 7-day clock)
- [Time mocked] Advance 3 days
- Candidate disputes findings
- [Time mocked] Advance 5 more days (total 8 days)
- Finalize with decision (NOT_HIRED)
- Verify all state transitions and timestamps

Expected Results:
  ✅ Status transitions: DRAFT → SENT → DISPUTED → FINALIZED
  ✅ can_finalize_at calculated correctly (sent_at + 7 days)
  ✅ Finalize rejected if called before 7 days (400 Bad Request)
  ✅ Finalize succeeds after waiting period
  ✅ All timestamps recorded correctly (sent_at, dispute_received_at, finalized_at)
  ✅ Timezone handling works (SQLite naive → PostgreSQL aware)

State Machine Tested:
  DRAFT ──send()──> SENT ──wait 7d──> WAITING ──dispute()──> DISPUTED ──finalize()──> FINALIZED
         ✅              ✅              ✅              ✅                ✅

FCRA Compliance:
  ✅ 7-day waiting period enforced
  ✅ Dispute mechanism functional
  ✅ Final decision recorded with notes

File: background-service/tests/e2e/test_fcra_adverse_action_full_workflow.py
Status: Uses freezegun for time mocking, tests FCRA compliance
    

Test 4: Malformed Payload Handling

Scenario: Various webhook payload errors to test graceful degradation
- Missing required fields (order_guid, search_guid, status)
- Invalid UUIDs (malformed, wrong format)
- Wrong enum values (status="INVALID_STATUS")
- Null values where not expected
- Mismatched search types (TazWorks returns type not in our database)

Test Cases:
  1. Webhook with missing order_guid → Early return, log warning, no crash
  2. Webhook with invalid UUID → Validation error, 422 response
  3. Status not in enum → Default to "UNKNOWN", log warning
  4. Null search results → Skip result parsing, mark search complete without data
  5. Search type mismatch → Log debug message, continue processing other searches

Expected Results:
  ✅ No service crashes or exceptions propagated to client
  ✅ All errors logged with context (order_id, search_guid, error details)
  ✅ Partial processing continues (don't fail entire batch for one error)
  ✅ Database state remains consistent (no half-updated records)
  ✅ Kafka events published for successful parts

Error Handling Patterns Tested:
  - Try/except with specific error logging
  - Graceful degradation (skip invalid, continue processing)
  - Validation at API boundary (Pydantic schemas)
  - Database rollback on transaction failures

File: background-service/tests/e2e/test_malformed_payload_handling.py
Status: Tests production-grade error resilience
    

Test 5: Partial Results with Failures

Scenario: Single order with 7 searches, mixed outcomes
- Search 1 (County Criminal) → COMPLETE, clear ✅
- Search 2 (State Criminal) → COMPLETE, clear ✅
- Search 3 (Employment) → COMPLETE, verified ✅
- Search 4 (Federal Criminal) → COMPLETE, records_found, flagged=true 🚩
- Search 5 (Education) → COMPLETE, unable_to_verify ⚠️
- Search 6 (Driving) → FAILED, network error ❌
- Search 7 (License) → TIMEOUT, slow search ⏱️

Expected Results:
  ✅ Order reaches PARTIAL_RESULTS state (not COMPLETE)
  ✅ Progress: 71% (5 complete / 7 total)
  ✅ Flagged searches marked correctly
  ✅ Failed searches logged, don't block other searches
  ✅ Timeout handling (mark as PENDING, retry later)
  ✅ Client receives partial results via API

Progress Calculation Edge Cases:
  - 0 searches complete: 0%
  - 1 of 7 complete: 14%
  - 5 of 7 complete: 71%
  - 7 of 7 complete: 100%
  - Division by zero guard (no searches)

File: background-service/tests/e2e/test_partial_results_with_failures.py
Status: Tests real-world failure scenarios and partial result handling
    

Test 6: Result Parser - All Types

Scenario: Comprehensive result parsing for all search types
- Criminal Results (7 types):
  • County Criminal, State Criminal, Federal Criminal
  • International Criminal, National Criminal Database
  • Sex Offender Registry, National Criminal Database Alias

- Civil Results (4 types):
  • County Civil, Federal Civil
  • Liens & Judgments, Bankruptcy Filings

- Employment Verification:
  • Verified with dates, position, reason for leaving
  • Unable to verify (company closed, no records)

- Education Verification:
  • Degree verified (BS, MS, PhD)
  • Attendance verified but no degree
  • Unable to verify (school closed)

- Professional License:
  • Active license (RN, MD, CPA, etc.)
  • Expired license
  • License not found

- Driving Records (2 types):
  • Instant Driving Record (MVR)
  • Commercial Driver's License (CDL)

Parser Logic Tested:
  ✅ records vs record fallback (API inconsistency)
  ✅ Nested field extraction (court.name, defendant.address.city)
  ✅ Date parsing (ISO 8601 format)
  ✅ Status mapping ("VERIFIED" → verified=true)
  ✅ Result categorization (clear, records_found, verified, unable_to_verify)
  ✅ Flagging logic (criminal/civil with records → flagged=true)

File: background-service/tests/e2e/test_result_parser_all_types.py
Status: Tests all 6 result parser functions with realistic payloads
    

📝 Implementation Details

TazWorksClient Methods Added (+25)

Attachments (4): get_quickapp_attachment, add_multipart_attachment, add_encoded_attachment, delete_attachment
Advanced Orders (5): add_searches_to_order, get_order_results_pdf, add_order_notes, set_report_decision, get_applicant_orders
Preferences (13): get_general_preferences, update_general_preferences, get_order_preferences, update_order_preferences, get_i3screen_settings, update_i3screen_settings, get_quest_settings, update_quest_settings, get_clearmd_settings, update_clearmd_settings, get_escreen_settings, update_escreen_settings, get_report_tool_preferences
Plus: update_report_tool_preferences, get_pre_search_preferences, update_pre_search_preferences

Pydantic Schemas Created (34 models)

attachments.py: OrderAttachment, QuickAppAttachment, AttachmentMetadata, AttachmentDownload, AttachmentType (enum)
order_enhancements.py: SearchJurisdiction, AddSearchToOrder, OrderNotes, ReportDecision, CustomSearchConfiguration, OrderModification
co_applicants.py: CoApplicantInfo, CoApplicantGroup, CoApplicantGroupResponse, CoApplicantGroupSummary, CoApplicantNotification
preferences.py: GeneralPreferences, OrderPreferences, PreSearchPreferences, ReportDecisionToolPreferences, DrugProviderBaseSettings, I3ScreenSettings, QuestSettings, ClearMDSettings, EScreenSettings (479 lines)
applicant_portal.py: ApplicantPortalSettings, PortalEmailTemplate, PortalMessage, PortalDocumentRequirement, PortalStatusCard
quickapp.py: QuickAppDisclosureSet, QuickAppFormSet, QuickAppEmailSet, QuickAppLegacySettings, QuickAppAdvancedSettings, QuickAppInvitation

Test Suite Breakdown (202 total)

Service Test Type Count Status
background-service Unit Tests 19 ✅ All Pass
background-service Integration Tests 36 ✅ All Pass
background-service E2E Tests 17 ⚠️ Need Infrastructure
tazworks-mcp Tool Tests 86 ✅ All Pass
tazworks-mcp Client Tests 9 ✅ All Pass
tazworks-mcp New Tool Tests 35 ✅ All Pass (attachments, preferences, advanced orders)
TOTAL 202 185 Pass, 17 Require Infrastructure

🎯 API Endpoint Coverage

Complete breakdown of all 175 TazWorks API endpoints and implementation status.

Category Documented Implemented Coverage Status
Orders (Core) 13 13 100% ✅ Complete
Order Attachments 4 4 100% ✅ Complete (P1)
Advanced Orders 5 5 100% ✅ Complete
Applicants 16 16 100% ✅ Complete
Searches 5 5 100% ✅ Complete
Webhooks 5 5 100% ✅ Complete
Client Preferences 20 13 65% ✅ Core Complete (P2)
Disclosure Settings 6 4 67% ⚠️ Missing jurisdiction tags
Client Users 9 5 56% ⚠️ Missing delete, link, add permissions
Client Products 14 3 21% ❌ Missing CRUD operations
Co-Applicants 2 0 0% ❌ Schemas ready, no client methods
QuickApp Config 9 0 0% ❌ Schemas ready, no client methods
Applicant Portal 4 0 0% ❌ Schemas ready, no client methods
Billing & Fees 11 0 0% ❌ Not implemented
Client Management 5 2 40% ⚠️ Read-only, no CRUD
General/Utility 3 0 0% ❌ ISO countries, usage stats
TOTAL 175 119 68% +22% this session

📚 Documentation Created

  • docs/api/COVERAGE.md (18KB)
    All 175 TazWorks API endpoints documented with implementation status, priorities (P1-P4), and missing endpoint tracking
  • docs/api/FLOWS.md (169KB)
    Comprehensive ASCII flow diagrams for all 9 major workflows: background check, FCRA adverse action, order status transitions, result parsing, MCP tool chains, package listing, webhook processing, candidate lifecycle, error handling
  • docs/api/CLAUDE_MD_ADDITIONS.md (39KB)
    Updates for CLAUDE.md with new tool categories, architecture diagrams, and schema documentation
  • tazworks-mcp/app/schemas/SCHEMA_COVERAGE.md
    Complete schema inventory with usage examples, design patterns, and API endpoint mappings. 34 models, 8 enums, 250+ fields, 40+ endpoints

📖 Further Reading

For complete technical details, see:

  • docs/api/FLOWS.md - All workflow diagrams with timing, caching, error paths
  • docs/api/COVERAGE.md - Complete API endpoint inventory and implementation roadmap
  • CLAUDE.md - Project context, architecture overview, development guidelines
  • background-service/tests/e2e/README.md - E2E test setup and infrastructure requirements
  • tazworks-mcp/app/schemas/SCHEMA_COVERAGE.md - Pydantic model usage and examples