@crscreditapi/finstack-mcp-server 0.10.0-80b4ec3 → 0.10.0-b823b70

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/.env.example CHANGED
@@ -15,4 +15,9 @@ FINSTACK_CHATBASE_SECRET=
15
15
  # Support Autopsy observability: insert one row per tool call into the shared tool_calls table
16
16
  # (n8n Postgres). Leave unset to emit a JSON log line instead. TOOL_LOG=off disables both.
17
17
  TOOL_CALLS_DATABASE_URL=
18
+ # Preferred over the URL (no percent-encoding needed):
19
+ # TOOL_CALLS_PGHOST=
20
+ # TOOL_CALLS_PGUSER=n8n
21
+ # TOOL_CALLS_PGPASSWORD=
22
+ # TOOL_CALLS_PGDATABASE=n8n
18
23
  # SSL is on by default (no sslmode needed in the URL). TOOL_CALLS_PGSSL=off for a local DB.
package/dist/toolLog.d.ts CHANGED
@@ -30,4 +30,5 @@ export declare function toRecord(e: ToolLogEntry): {
30
30
  truncated: boolean;
31
31
  upstream_status: number | null;
32
32
  };
33
+ /** Never throws: a logging problem must never fail a tool call. */
33
34
  export declare function logToolCall(e: ToolLogEntry): void;
package/dist/toolLog.js CHANGED
@@ -18,21 +18,46 @@ const ENABLED = (process.env.TOOL_LOG || 'on').toLowerCase() !== 'off';
18
18
  // TOOL_CALLS_PGSSL=off disables it for a local database.
19
19
  const DB_URL = (process.env.TOOL_CALLS_DATABASE_URL || '').replace(/[?&]sslmode=[^&]+/, '').replace(/\?$/, '');
20
20
  const DB_SSL = (process.env.TOOL_CALLS_PGSSL || 'on').toLowerCase() === 'off' ? false : { rejectUnauthorized: false };
21
+ // Either a URL (password must be percent-encoded) or discrete variables, which need no
22
+ // encoding and are therefore preferred: TOOL_CALLS_PGHOST, TOOL_CALLS_PGUSER,
23
+ // TOOL_CALLS_PGPASSWORD, TOOL_CALLS_PGDATABASE (default n8n), TOOL_CALLS_PGPORT (default 5432).
24
+ function poolConfig() {
25
+ const base = { max: 2, idleTimeoutMillis: 30_000, connectionTimeoutMillis: 3_000, ssl: DB_SSL };
26
+ const host = process.env.TOOL_CALLS_PGHOST;
27
+ if (host) {
28
+ return {
29
+ ...base,
30
+ host,
31
+ port: Number(process.env.TOOL_CALLS_PGPORT || 5432),
32
+ user: process.env.TOOL_CALLS_PGUSER || 'n8n',
33
+ password: process.env.TOOL_CALLS_PGPASSWORD || '',
34
+ database: process.env.TOOL_CALLS_PGDATABASE || 'n8n',
35
+ };
36
+ }
37
+ if (DB_URL)
38
+ return { ...base, connectionString: DB_URL };
39
+ return null;
40
+ }
21
41
  const STREAM = (process.env.MCP_TRANSPORT || 'stdio') === 'http' ? process.stdout : process.stderr;
22
42
  let pool = null;
23
43
  let lastDbErrorAt = 0;
44
+ let poolBroken = false;
24
45
  function getPool() {
25
- if (!DB_URL)
46
+ if (poolBroken)
26
47
  return null;
27
48
  if (!pool) {
28
- pool = new pg.Pool({
29
- connectionString: DB_URL,
30
- max: 2,
31
- idleTimeoutMillis: 30_000,
32
- connectionTimeoutMillis: 3_000,
33
- ssl: DB_SSL,
34
- });
35
- pool.on('error', (err) => warnDb(err));
49
+ const cfg = poolConfig();
50
+ if (!cfg)
51
+ return null;
52
+ try {
53
+ pool = new pg.Pool(cfg);
54
+ pool.on('error', (err) => warnDb(err));
55
+ }
56
+ catch (err) {
57
+ poolBroken = true; // bad config (e.g. unencoded password in the URL): fall back to log lines
58
+ warnDb(err);
59
+ return null;
60
+ }
36
61
  }
37
62
  return pool;
38
63
  }
@@ -79,18 +104,31 @@ const INSERT = `INSERT INTO tool_calls
79
104
  (trace_id, channel, agent, server, tool, args_hash, args_summary, started_at,
80
105
  duration_ms, ok, error_class, error_message, result_bytes, truncated, upstream_status)
81
106
  VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)`;
107
+ /** Never throws: a logging problem must never fail a tool call. */
82
108
  export function logToolCall(e) {
83
- if (!ENABLED)
84
- return;
85
- const r = toRecord(e);
86
- const p = getPool();
87
- if (!p) {
88
- STREAM.write(JSON.stringify({ ts: new Date().toISOString(), kind: 'tool_call', ...r }) + '\n');
89
- return;
109
+ try {
110
+ if (!ENABLED)
111
+ return;
112
+ const r = toRecord(e);
113
+ const p = getPool();
114
+ if (!p) {
115
+ STREAM.write(JSON.stringify({ ts: new Date().toISOString(), kind: 'tool_call', ...r }) + '\n');
116
+ return;
117
+ }
118
+ try {
119
+ p.query(INSERT, [
120
+ r.trace_id, r.channel, r.agent, r.server, r.tool, r.args_hash, JSON.stringify(r.args_summary),
121
+ r.started_at, r.duration_ms, r.ok, r.error_class, r.error_message, r.result_bytes,
122
+ r.truncated, r.upstream_status,
123
+ ]).catch(warnDb);
124
+ }
125
+ catch (err) {
126
+ // pg can throw synchronously on an unparseable connection string
127
+ poolBroken = true;
128
+ warnDb(err);
129
+ }
130
+ }
131
+ catch (err) {
132
+ warnDb(err);
90
133
  }
91
- p.query(INSERT, [
92
- r.trace_id, r.channel, r.agent, r.server, r.tool, r.args_hash, JSON.stringify(r.args_summary),
93
- r.started_at, r.duration_ms, r.ok, r.error_class, r.error_message, r.result_bytes,
94
- r.truncated, r.upstream_status,
95
- ]).catch(warnDb);
96
134
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crscreditapi/finstack-mcp-server",
3
- "version": "0.10.0-80b4ec3",
3
+ "version": "0.10.0-b823b70",
4
4
  "description": "MCP server for Finstack",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",