@crscreditapi/finstack-mcp-server 0.5.0-23af60a → 0.6.0-06bd3a8

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
@@ -12,6 +12,7 @@ MCP server exposing CRS B2B (Finstack) customer data over the [Model Context Pro
12
12
  | `finstack_get_customer_invoices` | Paginated list of finalized invoices for one customer with full line-item breakdown. |
13
13
  | `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. |
14
14
  | `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. |
15
+ | `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. |
15
16
  | `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. |
16
17
  | `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. |
17
18
  | `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. |
@@ -138,6 +139,14 @@ Identify the customer with either `customer_code` or `user_id`. `page` defaults
138
139
 
139
140
  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.
140
141
 
142
+ ### `finstack_get_customer_cohort`
143
+
144
+ ```json
145
+ { "page": 1, "per_page": 500, "status": "active", "stage": "closed_won" }
146
+ ```
147
+
148
+ 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.
149
+
141
150
  ### `finstack_get_pricing_addendum_text`
142
151
 
143
152
  ```json
@@ -161,3 +161,29 @@ export declare function getPricingAddendumText(client: ApiClient, args: {
161
161
  id: number;
162
162
  variant: PricingAddendumVariant;
163
163
  }): Promise<PricingAddendumText>;
164
+ export interface CohortCustomer {
165
+ customer_code: string | null;
166
+ name: string;
167
+ status: string | null;
168
+ account_type: 'account' | 'channel_partner' | null;
169
+ sales_opportunities: Array<{
170
+ opportunity_code: string | null;
171
+ opportunity_type: 'full' | 'upsell' | 'expand' | 'land';
172
+ stage: 'closed_won' | 'closed_lost' | 'churned';
173
+ booking_value_mrr: number | null;
174
+ close_date: string | null;
175
+ }>;
176
+ }
177
+ export interface CustomerCohortPage {
178
+ page: number;
179
+ per_page: number;
180
+ total_count: number;
181
+ total_pages: number;
182
+ customers: CohortCustomer[];
183
+ }
184
+ export declare function getCustomerCohort(client: ApiClient, args: {
185
+ page?: number;
186
+ perPage?: number;
187
+ status?: string;
188
+ stage?: string;
189
+ }): Promise<CustomerCohortPage>;
@@ -106,3 +106,23 @@ export async function getPricingAddendumText(client, args) {
106
106
  await parser.destroy();
107
107
  }
108
108
  }
109
+ export async function getCustomerCohort(client, args) {
110
+ const secret = process.env.FINSTACK_CHATBASE_SECRET;
111
+ if (!secret) {
112
+ throw new Error('FINSTACK_CHATBASE_SECRET must be set');
113
+ }
114
+ const params = new URLSearchParams();
115
+ if (args.page !== undefined)
116
+ params.set('page', String(args.page));
117
+ if (args.perPage !== undefined)
118
+ params.set('per_page', String(args.perPage));
119
+ if (args.status)
120
+ params.set('status', args.status);
121
+ if (args.stage)
122
+ params.set('stage', args.stage);
123
+ const response = await client.get(`/api/v1/chatbase/customer_cohort?${params}`, { 'X-Chatbase-Secret': secret });
124
+ if (response.status !== 'success' || !response.data) {
125
+ throw new Error(response.message || 'Failed to fetch customer cohort');
126
+ }
127
+ return response.data;
128
+ }
@@ -31,6 +31,14 @@ interface GetCustomerPricingConfigArgs {
31
31
  environment?: string;
32
32
  }
33
33
  export declare function handleGetCustomerPricingConfig(args: GetCustomerPricingConfigArgs): Promise<unknown>;
34
+ interface GetCustomerCohortArgs {
35
+ page?: number;
36
+ per_page?: number;
37
+ status?: string;
38
+ stage?: string;
39
+ environment?: string;
40
+ }
41
+ export declare function handleGetCustomerCohort(args: GetCustomerCohortArgs): Promise<unknown>;
34
42
  interface GetPricingAddendumTextArgs {
35
43
  id: number;
36
44
  variant?: PricingAddendumVariant;
@@ -2,7 +2,7 @@
2
2
  * Customer tool handlers
3
3
  */
4
4
  import { getClient } from '../api/client.js';
5
- import { getCustomerInvoices, getCustomerPricingConfig, getCustomerRevenue, getCustomerSummary, getPricingAddendumText, searchCustomers, } from '../api/customer.api.js';
5
+ import { getCustomerCohort, getCustomerInvoices, getCustomerPricingConfig, getCustomerRevenue, getCustomerSummary, getPricingAddendumText, searchCustomers, } from '../api/customer.api.js';
6
6
  export async function handleGetCustomerSummary(args) {
7
7
  const client = getClient(args.environment ?? 'prod');
8
8
  return getCustomerSummary(client, args.customer_code);
@@ -33,6 +33,15 @@ export async function handleGetCustomerPricingConfig(args) {
33
33
  const client = getClient(args.environment ?? 'prod');
34
34
  return getCustomerPricingConfig(client, args.customer_code);
35
35
  }
36
+ export async function handleGetCustomerCohort(args) {
37
+ const client = getClient(args.environment ?? 'prod');
38
+ return getCustomerCohort(client, {
39
+ page: args.page,
40
+ perPage: args.per_page,
41
+ status: args.status,
42
+ stage: args.stage,
43
+ });
44
+ }
36
45
  export async function handleGetPricingAddendumText(args) {
37
46
  const client = getClient(args.environment ?? 'prod');
38
47
  return getPricingAddendumText(client, {
@@ -1,4 +1,4 @@
1
- import { handleGetCustomerInvoices, handleGetCustomerPricingConfig, handleGetCustomerRevenue, handleGetCustomerSummary, handleGetPricingAddendumText, handleSearchCustomer, } from './customer.handler.js';
1
+ import { handleGetCustomerCohort, handleGetCustomerInvoices, handleGetCustomerPricingConfig, handleGetCustomerRevenue, handleGetCustomerSummary, handleGetPricingAddendumText, handleSearchCustomer, } from './customer.handler.js';
2
2
  import { handleGetLeadiqAnalytics, handleGetLeadiqCustomer, } from './leadiq.handler.js';
3
3
  import { handleGetVendors } from './vendor.handler.js';
4
4
  const wrap = (fn) => {
@@ -11,6 +11,7 @@ export const handlers = {
11
11
  finstack_get_customer_invoices: wrap(handleGetCustomerInvoices),
12
12
  finstack_get_customer_pricing_config: wrap(handleGetCustomerPricingConfig),
13
13
  finstack_get_pricing_addendum_text: wrap(handleGetPricingAddendumText),
14
+ finstack_get_customer_cohort: wrap(handleGetCustomerCohort),
14
15
  finstack_get_leadiq_analytics: wrap(handleGetLeadiqAnalytics),
15
16
  finstack_get_leadiq_customer: wrap(handleGetLeadiqCustomer),
16
17
  finstack_get_vendors: wrap(handleGetVendors),
@@ -152,4 +152,38 @@ export const customerTools = [
152
152
  required: ['customer_code', 'type', 'start_date', 'end_date'],
153
153
  },
154
154
  },
155
+ {
156
+ name: 'finstack_get_customer_cohort',
157
+ description: 'Bulk, paginated list of ALL B2B customers with their tracker fields: portal account status (active/inactive/blacklisted/locked/obsolete/new_account), account_type (account/channel_partner), and sales_opportunities[] (opportunity_code, opportunity_type full/upsell/expand/land, stage closed_won/closed_lost/churned, booking_value_mrr, close_date). Use this for cohort/tracker/dashboard refreshes or any question spanning many customers — NEVER call finstack_get_customer_summary once per customer for that. Default 500 customers per page (max 1000); read total_pages from the response and fetch the remaining pages. Optional server-side filters: status and stage.',
158
+ inputSchema: {
159
+ type: 'object',
160
+ properties: {
161
+ page: {
162
+ type: 'number',
163
+ description: 'Page number, 1-indexed. Default 1.',
164
+ minimum: 1,
165
+ },
166
+ per_page: {
167
+ type: 'number',
168
+ description: 'Customers per page. Default 500, capped at 1000.',
169
+ minimum: 1,
170
+ maximum: 1000,
171
+ },
172
+ status: {
173
+ type: 'string',
174
+ description: 'Only customers with this portal status, e.g. "active", "inactive", "blacklisted", "locked", "obsolete". Omit for all.',
175
+ },
176
+ stage: {
177
+ type: 'string',
178
+ enum: ['closed_won', 'closed_lost', 'churned'],
179
+ description: 'Only customers having at least one sales opportunity in this stage. Omit for all.',
180
+ },
181
+ environment: {
182
+ type: 'string',
183
+ description: 'Target environment: "prod" (default) or "dev"',
184
+ enum: ['dev', 'prod'],
185
+ },
186
+ },
187
+ },
188
+ },
155
189
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crscreditapi/finstack-mcp-server",
3
- "version": "0.5.0-23af60a",
3
+ "version": "0.6.0-06bd3a8",
4
4
  "description": "MCP server for Finstack",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",