@crscreditapi/finstack-mcp-server 0.7.0-92ce169 → 0.9.0-6062c00

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,6 +16,8 @@ MCP server exposing CRS B2B (Finstack) customer data over the [Model Context Pro
16
16
  | `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. |
17
17
  | `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. |
18
18
  | `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. |
19
+ | `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. |
20
+ | `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`. |
19
21
  | `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. |
20
22
 
21
23
  ## Install
@@ -180,6 +182,21 @@ All parameters optional. `page` defaults to `1`; `per_page` defaults to `500`, c
180
182
 
181
183
  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.
182
184
 
185
+ ### `finstack_get_cop_ai_analytics`
186
+
187
+ ```json
188
+ { "days": 30 }
189
+ ```
190
+
191
+ `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.
192
+ ### `finstack_get_product_catalog`
193
+
194
+ ```json
195
+ { "vendor": "exp", "status": "active", "query": "credit profile" }
196
+ ```
197
+
198
+ 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.
199
+
183
200
  All tools accept an optional `environment: "prod" | "dev"` (default `"prod"`).
184
201
 
185
202
  ## Development
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Credit Order Pro AI summary & chat usage against the mware-portal API.
3
+ *
4
+ * Same numbers the #cop-ai-usage Slack digest posts: per customer, the
5
+ * successful credit reports on products that carry the AI add-on, the
6
+ * summaries generated (precomputed vs on click), how many were opened,
7
+ * chat questions with thumbs up/down, and the Bedrock cost in USD. Counts
8
+ * only — the portal never exposes report or chat content here.
9
+ */
10
+ import type { ApiClient } from './client.js';
11
+ export interface CopAiCustomerRow {
12
+ customer: string;
13
+ reports: number;
14
+ summaries: number;
15
+ precomputed: number;
16
+ opened: number;
17
+ questions: number;
18
+ up: number;
19
+ down: number;
20
+ /** Bedrock cost in USD (Haiku 4.5 list price). */
21
+ cost: number;
22
+ }
23
+ export interface CopAiTotals {
24
+ reports: number;
25
+ summaries: number;
26
+ precomputed: number;
27
+ opened: number;
28
+ /** Opened summaries as a percentage of generated summaries. */
29
+ opened_pct: number;
30
+ questions: number;
31
+ up: number;
32
+ down: number;
33
+ cost: number;
34
+ /** Customers with at least one enabled report in the window. */
35
+ customers: number;
36
+ }
37
+ export interface CopAiEnabledCustomer {
38
+ id: number;
39
+ name: string;
40
+ /** Billing product codes carrying the add-on, e.g. ["EXP1101", "TUC1101"]. */
41
+ products: string[];
42
+ enabled_at: string | null;
43
+ }
44
+ export interface CopAiAnalyticsDigest {
45
+ period: {
46
+ start_date: string;
47
+ end_date: string;
48
+ days: number;
49
+ };
50
+ totals: CopAiTotals;
51
+ /** Every customer with activity in the window, most reports first. */
52
+ customers: CopAiCustomerRow[];
53
+ /** Who has the feature switched on right now, regardless of activity. */
54
+ enabled_customers: CopAiEnabledCustomer[];
55
+ }
56
+ export declare function getCopAiAnalytics(client: ApiClient, days?: number): Promise<CopAiAnalyticsDigest>;
@@ -0,0 +1,15 @@
1
+ export async function getCopAiAnalytics(client, days) {
2
+ const secret = process.env.FINSTACK_CHATBASE_SECRET;
3
+ if (!secret) {
4
+ throw new Error('FINSTACK_CHATBASE_SECRET must be set');
5
+ }
6
+ const params = new URLSearchParams();
7
+ if (days !== undefined) {
8
+ params.set('days', String(days));
9
+ }
10
+ const response = await client.get(`/api/v1/chatbase/cop_ai_analytics?${params}`, { 'X-Chatbase-Secret': secret });
11
+ if (response.status !== 'success' || !response.data) {
12
+ throw new Error(response.message || 'Failed to fetch Credit Order Pro AI analytics');
13
+ }
14
+ return response.data;
15
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Product catalog calls.
3
+ *
4
+ * Backed by the mware-portal chatbase API:
5
+ * GET /api/v1/chatbase/product_catalog returns the full catalog snapshot (no
6
+ * pagination, ordered by code), authenticated with the shared
7
+ * X-Chatbase-Secret. `code`, `status` and `vendor` are exact-match filters
8
+ * applied server-side; the free-text `query` is matched here in-process.
9
+ */
10
+ import type { ApiClient } from './client.js';
11
+ export declare const PRODUCT_VENDORS: readonly ["exp", "tuc", "eqf", "cic", "lnr", "pps", "mcl", "kcb", "cic_tn", "service_link", "fico", "crs", "ubq", "at_data", "accurate_append", "socure", "hansa", "tod"];
12
+ export type ProductVendor = (typeof PRODUCT_VENDORS)[number];
13
+ export type ProductStatus = 'active' | 'terminated';
14
+ export interface ProductAddOn {
15
+ id: number;
16
+ code: string;
17
+ /** null = active */
18
+ status: 'active' | 'inactive' | null;
19
+ category: string | null;
20
+ category_label: string | null;
21
+ name: string | null;
22
+ private_name: string | null;
23
+ description: string | null;
24
+ bureau_service_code: string | null;
25
+ /** Decimal string */
26
+ base_cost: string | null;
27
+ rolled_up_in_parent: boolean;
28
+ }
29
+ export interface ProductPermissiblePurpose {
30
+ id: number;
31
+ code: string;
32
+ name: string;
33
+ onboarding_path: string | null;
34
+ }
35
+ export interface Product {
36
+ id: number;
37
+ code: string;
38
+ status: ProductStatus;
39
+ termination_date: string | null;
40
+ type: string | null;
41
+ type_label: string | null;
42
+ category: string | null;
43
+ category_label: string | null;
44
+ vendor: string | null;
45
+ vendor_label: string | null;
46
+ public_name: string | null;
47
+ private_name: string | null;
48
+ description: string | null;
49
+ plan_includes: string | null;
50
+ /** Decimal string */
51
+ base_cost: string | null;
52
+ /** Decimal string, base_cost x 2 */
53
+ default_price: string | null;
54
+ inquiry: 'hard' | 'soft' | 'not_applicable' | null;
55
+ inquiry_label: string | null;
56
+ fcra: boolean | null;
57
+ on_path: string | null;
58
+ platforms: Record<string, boolean>;
59
+ parent_codes: string | null;
60
+ product_codes: string | null;
61
+ warning_notice: string | null;
62
+ add_ons: ProductAddOn[];
63
+ permissible_purposes: ProductPermissiblePurpose[];
64
+ created_at: string | null;
65
+ updated_at: string | null;
66
+ }
67
+ export interface ProductCatalogResult {
68
+ filters: {
69
+ code: string | null;
70
+ status: ProductStatus | null;
71
+ vendor: ProductVendor | null;
72
+ query: string | null;
73
+ };
74
+ count: number;
75
+ products: Product[];
76
+ }
77
+ export declare function getProductCatalog(client: ApiClient, args: {
78
+ code?: string;
79
+ status?: ProductStatus;
80
+ vendor?: ProductVendor;
81
+ query?: string;
82
+ }): Promise<ProductCatalogResult>;
@@ -0,0 +1,81 @@
1
+ export const PRODUCT_VENDORS = [
2
+ 'exp',
3
+ 'tuc',
4
+ 'eqf',
5
+ 'cic',
6
+ 'lnr',
7
+ 'pps',
8
+ 'mcl',
9
+ 'kcb',
10
+ 'cic_tn',
11
+ 'service_link',
12
+ 'fico',
13
+ 'crs',
14
+ 'ubq',
15
+ 'at_data',
16
+ 'accurate_append',
17
+ 'socure',
18
+ 'hansa',
19
+ 'tod',
20
+ ];
21
+ function productHaystack(p) {
22
+ return [
23
+ p.code,
24
+ p.public_name,
25
+ p.private_name,
26
+ p.description,
27
+ p.type_label,
28
+ p.category_label,
29
+ p.vendor_label,
30
+ p.product_codes,
31
+ p.parent_codes,
32
+ ...p.add_ons.flatMap((a) => [a.code, a.name, a.private_name, a.bureau_service_code]),
33
+ ...p.permissible_purposes.flatMap((pp) => [pp.code, pp.name]),
34
+ ]
35
+ .filter(Boolean)
36
+ .join(' ')
37
+ .toLowerCase();
38
+ }
39
+ export async function getProductCatalog(client, args) {
40
+ const secret = process.env.FINSTACK_CHATBASE_SECRET;
41
+ if (!secret) {
42
+ throw new Error('FINSTACK_CHATBASE_SECRET must be set');
43
+ }
44
+ const code = args.code
45
+ ?.split(',')
46
+ .map((c) => c.trim().toUpperCase())
47
+ .filter(Boolean)
48
+ .join(',');
49
+ const params = new URLSearchParams();
50
+ if (code)
51
+ params.set('code', code);
52
+ if (args.status)
53
+ params.set('status', args.status);
54
+ if (args.vendor)
55
+ params.set('vendor', args.vendor);
56
+ const qs = params.toString();
57
+ const response = await client.get(`/api/v1/chatbase/product_catalog${qs ? `?${qs}` : ''}`, { 'X-Chatbase-Secret': secret });
58
+ if (response.status !== 'success' || !response.data) {
59
+ throw new Error(response.message || 'Failed to fetch product catalog');
60
+ }
61
+ let products = response.data.products;
62
+ // Every term must match (AND), so "experian soft" narrows rather than widens.
63
+ const q = args.query?.trim().toLowerCase();
64
+ if (q) {
65
+ const terms = q.split(/\s+/).filter(Boolean);
66
+ products = products.filter((p) => {
67
+ const haystack = productHaystack(p);
68
+ return terms.every((t) => haystack.includes(t));
69
+ });
70
+ }
71
+ return {
72
+ filters: {
73
+ code: code || null,
74
+ status: args.status ?? null,
75
+ vendor: args.vendor ?? null,
76
+ query: args.query ?? null,
77
+ },
78
+ count: products.length,
79
+ products,
80
+ };
81
+ }
@@ -0,0 +1,6 @@
1
+ interface GetCopAiAnalyticsArgs {
2
+ days?: number;
3
+ environment?: string;
4
+ }
5
+ export declare function handleGetCopAiAnalytics(args: GetCopAiAnalyticsArgs): Promise<unknown>;
6
+ export {};
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Credit Order Pro AI tool handlers
3
+ */
4
+ import { getClient } from '../api/client.js';
5
+ import { getCopAiAnalytics } from '../api/copai.api.js';
6
+ export async function handleGetCopAiAnalytics(args) {
7
+ const client = getClient(args.environment ?? 'prod');
8
+ return getCopAiAnalytics(client, args.days);
9
+ }
@@ -1,5 +1,7 @@
1
+ import { handleGetCopAiAnalytics } from './copai.handler.js';
1
2
  import { handleGetCustomerCohort, handleGetCustomerInvoices, handleGetCustomerPricingConfig, handleGetCustomerRevenue, handleGetCustomerSummary, handleGetCustomerUsers, handleGetPricingAddendumText, handleSearchCustomer, } from './customer.handler.js';
2
3
  import { handleGetLeadiqAnalytics, handleGetLeadiqCustomer, } from './leadiq.handler.js';
4
+ import { handleGetProductCatalog } from './product.handler.js';
3
5
  import { handleGetVendors } from './vendor.handler.js';
4
6
  const wrap = (fn) => {
5
7
  return async (args) => fn(args);
@@ -15,5 +17,7 @@ export const handlers = {
15
17
  finstack_get_customer_users: wrap(handleGetCustomerUsers),
16
18
  finstack_get_leadiq_analytics: wrap(handleGetLeadiqAnalytics),
17
19
  finstack_get_leadiq_customer: wrap(handleGetLeadiqCustomer),
20
+ finstack_get_cop_ai_analytics: wrap(handleGetCopAiAnalytics),
21
+ finstack_get_product_catalog: wrap(handleGetProductCatalog),
18
22
  finstack_get_vendors: wrap(handleGetVendors),
19
23
  };
@@ -0,0 +1,10 @@
1
+ import { type ProductStatus, type ProductVendor } from '../api/product.api.js';
2
+ interface GetProductCatalogArgs {
3
+ code?: string;
4
+ status?: ProductStatus;
5
+ vendor?: ProductVendor;
6
+ query?: string;
7
+ environment?: string;
8
+ }
9
+ export declare function handleGetProductCatalog(args: GetProductCatalogArgs): Promise<unknown>;
10
+ export {};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Product catalog handlers
3
+ */
4
+ import { getClient } from '../api/client.js';
5
+ import { getProductCatalog, } from '../api/product.api.js';
6
+ export async function handleGetProductCatalog(args) {
7
+ const client = getClient(args.environment ?? 'prod');
8
+ return getProductCatalog(client, {
9
+ code: args.code,
10
+ status: args.status,
11
+ vendor: args.vendor,
12
+ query: args.query,
13
+ });
14
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Credit Order Pro AI summary & chat tool definitions
3
+ */
4
+ import type { ToolDefinition } from '../types/tool.types.js';
5
+ export declare const copAiTools: ToolDefinition[];
@@ -0,0 +1,22 @@
1
+ export const copAiTools = [
2
+ {
3
+ name: 'finstack_get_cop_ai_analytics',
4
+ description: 'Usage of the Credit Order Pro AI summary & chat (early-access feature on the customer portal) for a trailing window. Returns totals (reports on AI-enabled products, summaries generated and how many were precomputed, opened count and opened_pct, chat questions, thumbs up/down, Bedrock cost in USD, active customers), customers[] — every account with activity in the window, most reports first, with the same fields — and enabled_customers[] — who currently has the add-on switched on, with their product codes and when it was enabled. Use for questions like "how is the AI summary beta going" (totals + customers[]), "who has enabled AI summary" (enabled_customers[]), "is anyone using the chat" (questions), or "what does the AI feature cost us per week" (totals.cost). Counts only; report and chat content is never exposed.',
5
+ inputSchema: {
6
+ type: 'object',
7
+ properties: {
8
+ days: {
9
+ type: 'number',
10
+ description: 'Trailing window in days ending yesterday, 1-92 (default 7; values outside the range are clamped server-side). Use 30 for "last month".',
11
+ minimum: 1,
12
+ maximum: 92,
13
+ },
14
+ environment: {
15
+ type: 'string',
16
+ description: 'Target environment: "prod" (default) or "dev"',
17
+ enum: ['dev', 'prod'],
18
+ },
19
+ },
20
+ },
21
+ },
22
+ ];
@@ -1,8 +1,12 @@
1
+ import { copAiTools } from './copai.tools.js';
1
2
  import { customerTools } from './customer.tools.js';
2
3
  import { leadiqTools } from './leadiq.tools.js';
4
+ import { productTools } from './product.tools.js';
3
5
  import { vendorTools } from './vendor.tools.js';
4
6
  export const tools = [
5
7
  ...customerTools,
8
+ ...copAiTools,
6
9
  ...leadiqTools,
10
+ ...productTools,
7
11
  ...vendorTools,
8
12
  ];
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from '../types/tool.types.js';
2
+ export declare const productTools: ToolDefinition[];
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Product catalog tool definitions
3
+ */
4
+ import { PRODUCT_VENDORS } from '../api/product.api.js';
5
+ export const productTools = [
6
+ {
7
+ name: 'finstack_get_product_catalog',
8
+ description: "The CRS product catalog — every product CRS sells (not a specific customer's configuration; for what one customer has, use finstack_get_customer_pricing_config). Use when asked what a product code (e.g. EXP1001, TUC2000) is, what products exist for a bureau/vendor, whether a product is hard or soft pull / FCRA, its base cost or default list price, which platforms it is on (mcl, crs, b2c, liq, bureau_direct), its add-ons (score models etc. with bureau service codes and base costs), its permissible purposes, or whether it is active or terminated. Each product includes: code, status (active/terminated) and termination_date, type, category, vendor, public_name and private_name, description, plan_includes, base_cost and default_price (decimal strings; default_price = base_cost x 2), inquiry (hard/soft/not_applicable), fcra, on_path, platforms, parent_codes, product_codes, warning_notice, add_ons[], permissible_purposes[]. Filters: `code` (exact, one or comma-separated), `status`, `vendor` are applied server-side; `query` is a free-text AND-match across code, names, description, labels, add-on names/codes and permissible purposes. With no filters the whole catalog is returned (can be large — prefer a filter). Does not include subscriber codes or internal notes. Backed by the mware-portal chatbase product_catalog endpoint.",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ code: {
13
+ type: 'string',
14
+ description: 'Exact product code, or a comma-separated list — e.g. "EXP1001" or "EXP1001,TUC2000".',
15
+ },
16
+ status: {
17
+ type: 'string',
18
+ enum: ['active', 'terminated'],
19
+ description: 'Only products with this status. Omit for both.',
20
+ },
21
+ vendor: {
22
+ type: 'string',
23
+ enum: [...PRODUCT_VENDORS],
24
+ description: 'Only products from this vendor. exp=Experian, tuc=TransUnion, eqf=Equifax, lnr=LexisNexis, fico=FICO, crs=CRS; others as named.',
25
+ },
26
+ query: {
27
+ type: 'string',
28
+ description: "Free-text keywords, all of which must match (case-insensitive) across code, public/private name, description, type/category/vendor labels, add-on names/codes and permissible purposes. e.g. 'credit profile', 'FICO 9', 'tenant'.",
29
+ },
30
+ environment: {
31
+ type: 'string',
32
+ description: 'Target environment: "prod" (default) or "dev"',
33
+ enum: ['dev', 'prod'],
34
+ },
35
+ },
36
+ },
37
+ },
38
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crscreditapi/finstack-mcp-server",
3
- "version": "0.7.0-92ce169",
3
+ "version": "0.9.0-6062c00",
4
4
  "description": "MCP server for Finstack",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",