@crscreditapi/finstack-mcp-server
v0.11.0-f993467
Published
MCP server for Finstack
Readme
finstack-mcp-server
MCP server exposing CRS B2B (Finstack) customer data over the Model Context Protocol. Backed by the mware-portal chatbase API.
Tools
| Name | Purpose |
|---|---|
| finstack_search_customer | Fuzzy-match a customer by name and return candidate CIDs. Use when only a name is known. |
| finstack_get_customer_summary | Non-PII summary for one customer: portal account status and account type, onboarding progress, products, sales opportunities (type + stage), API credentials, inspection status, recent billing. |
| finstack_get_customer_revenue | Revenue for one customer over a date range, bucketed by day / week / month / quarter / year. |
| finstack_get_customer_invoices | Paginated list of finalized invoices for one customer with full line-item breakdown. |
| finstack_get_customer_pricing_config | Full configured pricing state for one customer: products, pricing addendums, and environment-user productPricing. Use to cross-check invoiced rates against contracted pricing. |
| finstack_get_pricing_addendum_text | Extracted text from a pricing addendum PDF (with or without disclaimer). Server-side parses the PDF and returns plain text. |
| finstack_get_customer_users | Portal users and no-portal-access contacts for one customer, with names, emails, phones, roles (labelled as on the portal Users tab), owner flag, invitation status and lock/MFA state. The only tool that returns people for an account. |
| finstack_get_customer_cohort | Bulk, paginated list of all customers with portal status, account type, and sales opportunities (type + stage). For cohort/tracker refreshes instead of per-customer summary calls. Optional status / stage filters. |
| finstack_get_product_customers | Which customers hold a product, by billing product code (e.g. TUC1002). Paged over customers; each row carries its subscription status and add-ons. |
| finstack_get_add_on_customers | Which customers have an add-on (by add-on code, e.g. CRS1002) attached to at least one product, and on which products. Paged. |
| finstack_get_customer_products | The products one customer holds with subscription status, platform, activation date and attached add-ons. No prices. |
| finstack_get_customer_add_ons | The add-ons one customer has, each with the products it is attached to. |
| finstack_get_leadiq_analytics | System-wide LeadsIQ analytics for a trailing window: totals vs previous period, the complete list of customers that pulled (revenue desc), entitled/active/invited split, and enrolled-but-never-pulled accounts. Revenue is split into the two products under the LeadsIQ umbrella (leadsiq_revenue export vs data_append_revenue). |
| finstack_get_leadiq_customer | One customer's LeadsIQ detail: enrollment state, window/YTD/lifetime stats, match rate and append hit rates, most commonly used pull filters, recent pulls. |
| finstack_get_cop_ai_analytics | Credit Order Pro AI summary & chat usage for a trailing window: totals, per-customer activity (reports, summaries, opens, questions, ratings, Bedrock cost) and who currently has the feature enabled. |
| finstack_get_product_catalog | The CRS product catalog: code, status, vendor, names, description, base cost / default price, inquiry type, FCRA, platforms, add-ons and permissible purposes. Optional exact code / status / vendor filters plus free-text query. |
| finstack_get_vendors | Look up who to contact at an external vendor/partner (credit bureaus and data vendors like Equifax, TransUnion, Experian, CIC). OR-matches query across company, name, role, notes, location, and specialty tags; optional connection degree filter. |
| finstack_invalidate_cache | Clear MWARE's cached credit report for one customer (by request id / MISMO file number or applicant name) so the next pull is fresh. Support AI action for Salesforce invalidate_cache tickets; idempotent per case number, portal-enforced scope, caps and kill switch. Returns an outcome, never throws on 4xx/5xx. |
Install
npm install -g @crscreditapi/finstack-mcp-serverAfter install, the finstack-mcp-server binary is on your PATH.
Configuration
The server reads configuration from environment variables (also loaded from a local .env file via dotenv).
| Variable | Required | Default | Description |
|---|---|---|---|
| FINSTACK_PROD_BASE_URL | yes | — | Base URL of the mware-portal API (production). |
| FINSTACK_CHATBASE_SECRET | yes | — | Shared secret sent as X-Chatbase-Secret on every request. |
| FINSTACK_DEV_BASE_URL | no | falls back to prod | Base URL for the dev environment. Used when a tool call passes environment: "dev". |
| FINSTACK_TIMEOUT_MS | no | 30000 | Per-request timeout in milliseconds. |
| MCP_TRANSPORT | no | stdio | Transport mode: stdio (for Claude Code and other CLI clients) or http (for n8n and remote clients). |
| MCP_PORT | no | 3002 | Port for the HTTP transport. Ignored when MCP_TRANSPORT=stdio. |
A starter file is included as .env.example.
Usage
Stdio (Claude Code, Claude Desktop, other CLI clients)
Add an entry to your MCP config (.mcp.json for Claude Code, claude_desktop_config.json for Claude Desktop):
{
"mcpServers": {
"finstack": {
"command": "finstack-mcp-server",
"env": {
"MCP_TRANSPORT": "stdio",
"FINSTACK_PROD_BASE_URL": "https://portal.example.com",
"FINSTACK_CHATBASE_SECRET": "<your-secret>"
}
}
}
}The client launches the process; tool calls travel over stdio. No port to open.
HTTP (n8n, remote MCP clients)
Run it as a long-lived service:
MCP_TRANSPORT=http \
MCP_PORT=3002 \
FINSTACK_PROD_BASE_URL=https://portal.example.com \
FINSTACK_CHATBASE_SECRET=<your-secret> \
finstack-mcp-serverEndpoints:
POST /andPOST /mcp— MCP requests (streamable HTTP transport)GET /health— health check, returns{"status":"ok","uptime":<seconds>}
Point your client at http://<host>:3002/mcp.
Docker
FROM node:20-alpine
RUN npm install -g @crscreditapi/finstack-mcp-server
ENV MCP_TRANSPORT=http MCP_PORT=3002
EXPOSE 3002
CMD ["finstack-mcp-server"]Pass the FINSTACK_* variables at runtime (e.g. via --env-file or an orchestrator's secret store).
Tool call reference
finstack_search_customer
{ "q": "rentvine", "threshold": 0.8 }q (required, min 2 chars) is matched case-insensitively. threshold (optional, 0.0–1.0, default 0.9) controls fuzziness — lower it if nothing comes back.
finstack_get_customer_summary
{ "customer_code": "CID18068" }finstack_get_customer_revenue
{
"customer_code": "CID18068",
"type": "month",
"start_date": "2025-05-08",
"end_date": "2026-05-08"
}Range caps depend on type: day ≤ 92 days, week ≤ 2 years, month/quarter ≤ 10 years, year ≤ 50 years.
finstack_get_customer_invoices
{ "customer_code": "CID18068", "page": 1, "per_page": 50 }Identify the customer with either customer_code or user_id. page defaults to 1, per_page defaults to 50 and is silently capped at 100. Returns {customer_code, page, per_page, total_count, total_pages, invoices: [...]}, where each invoice carries its full items[] line-item breakdown.
finstack_get_customer_pricing_config
{ "customer_code": "CID18068" }Returns {products, pricing_addendums, environment_users}. pricing_addendums[] entries carry id, name, status, quote_id, timestamps, has_pdf, has_pdf_without_disclaimer, and pdf_url / pdf_without_disclaimer_url. The PDF URLs require the chatbase secret to hit directly — use finstack_get_pricing_addendum_text to read the contents instead.
finstack_get_customer_users
{ "customer_code": "CID18068" }Identify the customer with either customer_code or user_id. Returns {customer, users_count, users: [...], contacts_count, contacts: [...]}. Each users[] row is a portal login: id, name, email, phone, title, roles (customer-facing role names), role_labels (as shown on the portal Users tab — Admin (owner), Admin, Developer, Agent, Billing, Main billing contact, Generic), is_owner, status (active / invited / not_invited), locked, mfa_enabled, sign_in_count, and sign-in / invitation timestamps; the owner comes first, then alphabetical. contacts[] are the "Contacts (No portal access)" rows: id, name, email, phone, title, roles. This payload carries PII by design and is backed by the MCP-only customer_users chatbase endpoint (mware-portal); credentials and tokens are never included.
finstack_get_customer_cohort
{ "page": 1, "per_page": 500, "status": "active", "stage": "closed_won" }All parameters optional. page defaults to 1; per_page defaults to 500, capped at 1000. status filters by portal account status (active, inactive, blacklisted, locked, obsolete); stage keeps only customers with at least one sales opportunity in that stage (closed_won / closed_lost / churned). Returns {page, per_page, total_count, total_pages, customers: [...]} where each customer carries customer_code, name, status, account_type, and sales_opportunities[]. Read total_pages and fetch the remaining pages to cover the whole cohort.
finstack_get_pricing_addendum_text
{ "id": 1234, "variant": "with_disclaimer" }variant is optional and defaults to "with_disclaimer". Returns {addendum_id, variant, page_count, text}. The server fetches the PDF over the chatbase API and extracts text with pdf-parse; complex table layouts may run columns together but remain readable for LLM reasoning.
finstack_get_product_customers
{ "code": "TUC1002", "status": "activated", "page": 1, "per_page": 500 }code (required) is an exact billing product code. status (optional) is one subscription status or a comma list / array of them — not_categorized, activated, in_review, disabled, terminating, deactivated, quoted, archived; omit it and every status comes back, each row labelled. page defaults to 1; per_page defaults to 500, capped at 1000. Returns {product: {code, name, private_name, status}, page, per_page, total_count, total_pages, customers: [...]} — total_count counts customers, not subscriptions, and each customer carries products[], its subscriptions to that product (one per platform, possibly more than one). Each product row has code, name, private_name, vendor, category, status, enabled, platform, format, activated_at, part_of_merge, part_of_bundle and add_ons[{code, name}]. Unknown code → 404, unknown status → 400. Backed by the MCP-only customers_by_product chatbase endpoint.
finstack_get_add_on_customers
{ "code": "CRS1002", "status": "activated" }Same parameters and paging as finstack_get_product_customers, keyed by add-on code. Returns {add_on: {code, name, private_name, status, category, category_label}, page, per_page, total_count, total_pages, customers: [...]}; each customer's products[] lists only the products carrying this add-on. add_on.status is active, inactive or null (null means active). status filters on the subscription status of the product the add-on is attached to.
finstack_get_customer_products
{ "customer_code": "CID18068", "status": "activated,in_review" }Identify the customer with either customer_code or user_id. Returns {customer: {customer_code, name, status}, count, products: [...]} ordered by product code, with the product rows described above. No prices — use finstack_get_customer_pricing_config for those.
finstack_get_customer_add_ons
{ "customer_code": "CID18068" }Identify the customer with either customer_code or user_id. Returns {customer, count, add_ons: [...]} where count is the number of distinct add-ons and each add-on carries products[], the product rows it is attached to (without their own add_ons list). status filters on the status of the product the add-on is attached to.
finstack_get_leadiq_analytics
{ "days": 30 }days is optional (default 7, clamped server-side to 1–366). Returns {period, totals, prev_period_totals, customers, customers_truncated, entitlement, never_pulled}. customers[] is the complete list of accounts with ≥ 1 pull in the window, highest revenue first (customers_truncated is only true if the 50-account safety cap trimmed it). Definitions match the portal's admin LeadsIQ customer dashboard: a pull is one top-level LeadsIQ job, records count the export leg only, and revenue is the job's cost. totals, prev_period_totals and every customers[] row also split that revenue into the two products under the LeadsIQ umbrella — leadsiq_revenue (LeadsIQ export) and data_append_revenue (Data Append) — with revenue always equal to their sum.
finstack_get_leadiq_customer
{ "customer_code": "CID18068", "days": 30 }Identify the customer with either customer_code or user_id; days is optional (default 30) and only scopes the period block. Returns {customer, entitlement, contacts, period, year_to_date, lifetime, top_filters, recent_pulls}. top_filters[] aggregates each pull's submitted form filters (dashboard formatting) with per-filter usage share and most common values.
finstack_get_cop_ai_analytics
{ "days": 30 }days is optional (default 7, clamped server-side to 1–92; the window ends yesterday). Returns {period, totals, customers, enabled_customers}. customers[] lists every account with activity in the window, most reports first: reports are successful credit reports on products carrying the AI add-on, summaries the AI summaries generated (precomputed of them right after the order), opened how many a user actually looked at, questions chat messages answered with up/down ratings, and cost the Bedrock spend in USD. enabled_customers[] is who has the feature on right now (id, name, product codes, enabled_at), regardless of activity. Counts only; report and chat content is never exposed.
finstack_get_product_catalog
{ "vendor": "exp", "status": "active", "query": "credit profile" }All arguments are optional. code (one code or a comma list, e.g. "EXP1001,TUC2000"), status (active / terminated) and vendor (exp, tuc, eqf, cic, lnr, pps, mcl, kcb, cic_tn, service_link, fico, crs, ubq, at_data, accurate_append, socure, hansa, tod) are exact-match filters applied by the portal; query is a case-insensitive AND-match over code, names, description, labels, add-ons and permissible purposes, applied in the MCP server. Returns {filters, count, products}, ordered by code. Each product carries status / termination_date, type / category / vendor (each with a _label), public_name, private_name, description, plan_includes, base_cost and default_price (decimal strings, default = base × 2), inquiry (hard / soft / not_applicable), fcra, on_path, platforms (mcl, crs, b2c, liq, bureau_direct), parent_codes, product_codes, warning_notice, add_ons[] (code, status, category, name, bureau_service_code, base_cost, rolled_up_in_parent) and permissible_purposes[]. Backed by the MCP product_catalog chatbase endpoint (mware-portal); subscriber codes and internal notes are not exposed.
All tools accept an optional environment: "prod" | "dev" (default "prod").
Development
git clone https://github.com/StitchCredit/finstack-mcp-server.git
cd finstack-mcp-server
npm install
cp .env.example .env # fill in FINSTACK_PROD_BASE_URL and FINSTACK_CHATBASE_SECRET
npm run build
npm startFor stdio mode while iterating, set MCP_TRANSPORT=stdio in .env and wire the local dist/index.js into your MCP client's config.
License
Private — internal use within CRS Credit API.
finstack_invalidate_cache
{ "case_number": "00085021", "customer_code": "CID51534", "reference": "104863973" }case_number and customer_code are required, plus reference (MWARE request id or MISMO credit file number) or applicant_name (first and last). Optional environment (production default, or sandbox), dry_run (report what would be cleared), portal_environment (prod default, dev).
Calls POST /api/v1/chatbase/invalidate_cache on the portal and returns {outcome, http_status, message, matched_by, reports, dry_run, cleared, handoff, guidance}. cleared is true only for invalidated / nothing_cached on a live call: that is the only case a reply may say the next pull is fresh. handoff is true for every other outcome (not_found 404, too_many_matches / could_not_verify 409, rate_limited 429, disabled / unavailable 503, invalid 422). unavailable is retried once. The portal keeps the safety rules: the report must belong to the customer, at most 3 matches are cleared, the same case number replays the first success, 10 clears per customer per hour, and the Flipper flag support_ai_invalidate_cache is the kill switch (dry runs still answer when it is off).
