@crscreditapi/mware-mcp-server
v0.8.0-73aec7e
Published
MCP server for mware
Readme
mware-mcp-server
MCP server exposing CRS mware (B2B middleware) over the Model Context Protocol. Logs in with admin credentials, caches the JWT, and proxies calls to the mware Spring API. Most tools are read-only; the mware_pxe_offersiq_* create/update/assign tools write.
Tools
| Name | Purpose |
|---|---|
| mware_find_customer | Case-insensitive name substring → matching customers (UUID id, externalId/CID, name). |
| mware_get_user_config | All config entries for one user (rate limits, products, billing codes, pricing). |
| mware_request_logs | Most recent 40 request logs (sorted by createdAt DESC). Optional filters: request_id, applicant, customer_code, customer_name. |
| mware_get_retention | Raw request/response payloads for one request log id (upstream + client request/response + headers). |
| mware_get_billing | Aggregated billing for a date range: grand totals, per-customer rollups (sorted by net amount), per-product rollups. Optional product filter narrows entries to one product family before rollup, so by_customer becomes "which customers used product X". |
| mware_pxe_offersiq_list_attributes | The OffersIQ attribute catalog: every valid rule-condition key with label, category, data type, and allowed operators. Call before authoring — keys are environment-specific. |
| mware_pxe_offersiq_list_rulesets | List OffersIQ rulesets (always PXE productId 3 — other PXE products like LeadIQ are out of scope), optionally filtered by owner customer and/or name substring, with human-readable summaries of the active rules. |
| mware_pxe_offersiq_get_ruleset | One ruleset: metadata, active definition (raw + human-readable), optional full version history. Rejects non-OffersIQ rulesets. |
| mware_pxe_offersiq_create_ruleset | Create a ruleset (locally validated definition tree), optionally owned by a customer; always under the OffersIQ product (id 3). |
| mware_pxe_offersiq_update_ruleset | Update name/description/definition; a new definition creates a new version and (by default) activates it. |
| mware_pxe_offersiq_assign_ruleset | Enable/disable/remove a ruleset on a customer's product config (decisioningConfig) — this is what makes it live for /offersiq/evaluate. |
| mware_pxe_offersiq_metrics | OffersIQ usage for a required date range: totals, per-day and per-customer breakdowns of requests, live pulls vs cached re-evaluations, failures, billable counts. Hit/no-hit and approval rates are not available (not exposed by the backend). |
| mware_get_error_codes | The CRS error-code catalog (code, message, description) with optional substring filter — for interpreting CRSxxx codes in API error responses. |
All tools require ROLE_ADMIN on the upstream mware API. All accept an optional environment: "prod" \| "dev" (default "prod").
Install
npm install -g @crscreditapi/mware-mcp-serverAfter install, the mware-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 |
|---|---|---|---|
| MWARE_PROD_BASE_URL | yes | — | Base URL of the mware API (production). Must include the /api context path. |
| MWARE_PROD_USERNAME | yes | — | Admin username for POST /users/login. |
| MWARE_PROD_PASSWORD | yes | — | Admin password for POST /users/login. |
| MWARE_DEV_BASE_URL | no | falls back to prod | Dev base URL. Used when a tool call passes environment: "dev". |
| MWARE_DEV_USERNAME | no | falls back to prod | Dev admin username. |
| MWARE_DEV_PASSWORD | no | falls back to prod | Dev admin password. |
| MWARE_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 / remote clients). |
| MCP_PORT | no | 3003 | Port for the HTTP transport. Ignored when MCP_TRANSPORT=stdio. |
A starter file is included as .env.example.
Auth
On startup the client lazily POSTs to /users/login with the configured username/password, caches the returned JWT (using the upstream expires value, or a 55-minute TTL if absent), and sends Authorization: Bearer <token> on every request. On a 401 the cached token is cleared and one retry is attempted.
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": {
"mware": {
"command": "mware-mcp-server",
"env": {
"MCP_TRANSPORT": "stdio",
"MWARE_PROD_BASE_URL": "https://mware.example.com/api",
"MWARE_PROD_USERNAME": "<admin-email>",
"MWARE_PROD_PASSWORD": "<admin-password>"
}
}
}
}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=3003 \
MWARE_PROD_BASE_URL=https://mware.example.com/api \
MWARE_PROD_USERNAME=<admin-email> \
MWARE_PROD_PASSWORD=<admin-password> \
mware-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>:3003/mcp.
Docker
FROM node:20-alpine
RUN npm install -g @crscreditapi/mware-mcp-server
ENV MCP_TRANSPORT=http MCP_PORT=3003
EXPOSE 3003
CMD ["mware-mcp-server"]Pass the MWARE_* variables at runtime (e.g. via --env-file or an orchestrator's secret store).
Tool call reference
mware_find_customer
{ "query": "unlock", "limit": 20 }query is matched case-insensitively as a substring of name. limit (optional, 1–100, default 20) caps the result count. Returns { query, count, matches: [{ id, externalId, name }] }.
The upstream
/customersendpoint has no name search, so this tool fetches a customer page (size 500) and filters client-side.
mware_get_user_config
{ "user_id": "e98794ff-d151-4205-bdbe-b654c558474d" }Returns { user_id, count, configs: [...] } where each config has configName, queryString, dailyMaxRequests, monthlyMaxRequests, billingCode, product, isEnabled, isDefault, productPricing, and friends.
mware_request_logs
{ "customer_code": "CID11117" }All filters are optional; combine them to narrow down. The upstream endpoint sorts by createdAt DESC, so you always get the most recent page (size 40):
request_id— exact UUID matchapplicant— substring on the applicant namecustomer_code— CID (clientNumber). Resolved to user UUIDs via/users/all(cached per environment for the process lifetime) and queried through the fast indexeduserIdfilter; a CID shared by several API users fans out into parallel queries whose results are merged newest-first. Falls back to the slowcompositesubstring search only when the code matches no users (the response carries anotewhen that happens).customer_name— customer name, routed throughcomposite(ignored ifcustomer_codeis set). Composite substring search scans the full log table and can time out — prefercustomer_code.
mware_get_retention
{ "request_log_id": "fa2eb0b3-cc3a-4ecf-a336-ccf7bfff3bc8" }Returns the stored payloads for that request: rawRequest, rawResponse, rawClientRequest, rawClientResponse, rawRequestHeaders, rawResponseHeaders, plus userId and type. Responses can be large (100 KB+ for credit reports).
mware_get_billing
{
"start_day": "2026-05-01T00:00:00Z",
"end_day": "2026-05-08T23:59:59Z"
}Both dates are ISO-8601 instants. Returns:
{
"window": { "start": "...", "end": "..." },
"product_filter": null, // or { "query", "matched_rows" } when product filter is set
"totals": { "rows", "customers", "requests", "total_amount", "refund_amount", "net_amount" },
"by_customer": [{ "client_name", "client_num", "requests", "total_amount", "refund_amount", "net_amount" }, "..."],
"by_product": [{ "product", "requests", "total_amount", "refund_amount", "net_amount" }, "..."]
}by_customer and by_product are sorted descending by net_amount. Backed by GET /api/billing/total (the newer pricing engine — computes amounts from per-config pricing/tiers).
Pass an optional product to filter entries before rollup (case-insensitive substring on the product field):
{
"start_day": "2026-04-01T00:00:00Z",
"end_day": "2026-04-30T23:59:59Z",
"product": "Bridger Insight"
}by_customer then lists only customers who used that product family in the window, and by_product shows the exact product strings that matched the substring (helpful for disambiguating product names).
OffersIQ ruleset tools
Rulesets are trees of group nodes (AND/OR) and condition nodes (attribute + operator + value) encoded as a flat node list with parent indices; the node schema and operator list are embedded in the mware_pxe_offersiq_create_ruleset / mware_pxe_offersiq_update_ruleset tool descriptions. Attribute keys come from the product's live attribute catalog (mware_pxe_offersiq_list_attributes) — they are environment-specific (e.g. fico_v8, not creditScore) and each attribute restricts which operators it allows. Definitions are validated before hitting the API: structure locally, then attribute keys and operators against the catalog, with "did you mean" suggestions on unknown keys.
{
"name": "Prescreen — Standard",
"customer_id": "e98794ff-d151-4205-bdbe-b654c558474d",
"definition": {
"nodes": [
{ "type": "group", "operator": "AND", "parent": null, "negated": false },
{ "type": "condition", "attribute": "creditScore", "operator": "GREATER_THAN_OR_EQUALS", "value": 620, "parent": 0, "negated": false },
{ "type": "condition", "attribute": "publicRecordBankruptcyCount", "operator": "EQUALS", "value": 0, "parent": 0, "negated": false }
]
}
}Creating a ruleset does not make it live: wire it to a customer config with mware_pxe_offersiq_assign_ruleset ({ customer_id, config_id, ruleset_id, action: "enable" | "disable" | "remove" }, config_id from mware_get_user_config). The assign response echoes the config's resulting decisioning-ruleset list plus a per-config assignment overview for that ruleset.
mware_pxe_offersiq_list_rulesets filters by owner client-side (the upstream list endpoint has no userId param), paging up to 20×100 rulesets; truncated: true in the response means the cap was hit.
Development
git clone https://github.com/StitchCredit/mware-mcp-server.git
cd mware-mcp-server
npm install
cp .env.example .env # fill in MWARE_PROD_BASE_URL, MWARE_PROD_USERNAME, MWARE_PROD_PASSWORD
npm run build
npm test # node:test suite (validation logic)
npm startFor stdio mode while iterating, set MCP_TRANSPORT=stdio in .env and point your MCP client's config at the local dist/index.js:
{
"mcpServers": {
"mware": {
"command": "node",
"args": ["/absolute/path/to/mware-mcp-server/dist/index.js"]
}
}
}License
Private — internal use within CRS Credit API.
