@gizmodata/gizmosql-mcp 0.1.0
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/CHANGELOG.md +39 -0
- package/LICENSE +201 -0
- package/README.md +295 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +107 -0
- package/dist/cli.js.map +1 -0
- package/dist/connection.d.ts +120 -0
- package/dist/connection.js +349 -0
- package/dist/connection.js.map +1 -0
- package/dist/format.d.ts +56 -0
- package/dist/format.js +240 -0
- package/dist/format.js.map +1 -0
- package/dist/params.d.ts +59 -0
- package/dist/params.js +160 -0
- package/dist/params.js.map +1 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +446 -0
- package/dist/server.js.map +1 -0
- package/dist/sql-guard.d.ts +57 -0
- package/dist/sql-guard.js +429 -0
- package/dist/sql-guard.js.map +1 -0
- package/dist/sso.d.ts +22 -0
- package/dist/sso.js +143 -0
- package/dist/sso.js.map +1 -0
- package/dist/transports.d.ts +18 -0
- package/dist/transports.js +119 -0
- package/dist/transports.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { FlightSQLClient, type SqlParameters } from "@gizmodata/gizmosql-client";
|
|
2
|
+
import { Table } from "apache-arrow";
|
|
3
|
+
export type AuthMethod = "password" | "token" | "none";
|
|
4
|
+
export interface McpConfig {
|
|
5
|
+
host: string;
|
|
6
|
+
port: number;
|
|
7
|
+
username?: string;
|
|
8
|
+
password?: string;
|
|
9
|
+
token?: string;
|
|
10
|
+
plaintext: boolean;
|
|
11
|
+
tlsSkipVerify: boolean;
|
|
12
|
+
oauthPort: number;
|
|
13
|
+
allowWrites: boolean;
|
|
14
|
+
maxRows: number;
|
|
15
|
+
maxCellChars: number;
|
|
16
|
+
queryTimeoutSeconds: number;
|
|
17
|
+
/** Bearer token required on every Streamable HTTP request (http transport only). */
|
|
18
|
+
mcpBearerToken?: string;
|
|
19
|
+
/** Enables the optional `login_sso` tool (OAuth/SSO browser flow). */
|
|
20
|
+
enableSso: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare const DEFAULTS: {
|
|
23
|
+
readonly port: 31337;
|
|
24
|
+
readonly oauthPort: 31339;
|
|
25
|
+
readonly maxRows: 500;
|
|
26
|
+
readonly maxCellChars: 200;
|
|
27
|
+
readonly queryTimeoutSeconds: 60;
|
|
28
|
+
};
|
|
29
|
+
export declare class ConfigError extends Error {
|
|
30
|
+
constructor(message: string);
|
|
31
|
+
}
|
|
32
|
+
export declare function parseBoolean(name: string, raw: string | undefined, fallback: boolean): boolean;
|
|
33
|
+
export declare function parseInteger(name: string, raw: string | undefined, fallback: number, { min, max }: {
|
|
34
|
+
min: number;
|
|
35
|
+
max?: number;
|
|
36
|
+
}): number;
|
|
37
|
+
/** Builds the effective configuration from environment variables. */
|
|
38
|
+
export declare function parseConfig(env?: NodeJS.ProcessEnv): McpConfig;
|
|
39
|
+
export declare function authMethod(config: Pick<McpConfig, "username" | "password" | "token">): AuthMethod;
|
|
40
|
+
/** Connection URI with the password/token never included. */
|
|
41
|
+
export declare function redactedUri(config: McpConfig, overrideUser?: string): string;
|
|
42
|
+
/** Replaces every configured secret in `text` with `***`. */
|
|
43
|
+
export declare function redactSecrets(text: string, secrets: Array<string | undefined>): string;
|
|
44
|
+
export declare class QueryTimeoutError extends Error {
|
|
45
|
+
constructor(seconds: number);
|
|
46
|
+
}
|
|
47
|
+
/** A capped result: up to `maxRows + 1` rows so callers can detect truncation. */
|
|
48
|
+
export interface CappedResult {
|
|
49
|
+
table: Table;
|
|
50
|
+
/** True when more rows existed beyond `maxRows` (the extra row is not in `table`). */
|
|
51
|
+
truncated: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** Heuristic: does this error indicate the underlying connection is unusable? */
|
|
54
|
+
export declare function isConnectionError(err: unknown): boolean;
|
|
55
|
+
export interface SessionOverrides {
|
|
56
|
+
/** Replaces the configured credentials (used by the SSO flow; kept in memory only). */
|
|
57
|
+
username?: string;
|
|
58
|
+
password?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface RunOptions {
|
|
61
|
+
/** Overrides the configured timeout for this operation (seconds; 0 = none). */
|
|
62
|
+
timeoutSeconds?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* One FlightSQLClient per process, opened lazily, serialized so a single
|
|
66
|
+
* statement is in flight at a time, reconnected once on connection loss.
|
|
67
|
+
* Timeouts are enforced server-side (`SET gizmosql.query_timeout`) with a
|
|
68
|
+
* client-side deadline as backstop that cancels the statement through the
|
|
69
|
+
* client's AbortSignal support; only if that fails to settle the call is
|
|
70
|
+
* the connection dropped and reopened.
|
|
71
|
+
*/
|
|
72
|
+
export declare class GizmoConnection {
|
|
73
|
+
readonly config: McpConfig;
|
|
74
|
+
private readonly log;
|
|
75
|
+
private client;
|
|
76
|
+
private connecting;
|
|
77
|
+
private queue;
|
|
78
|
+
private overrides;
|
|
79
|
+
private warnings;
|
|
80
|
+
/** Wall-clock at which the current client was opened (for server_info). */
|
|
81
|
+
connectedAt: Date | null;
|
|
82
|
+
constructor(config: McpConfig, log?: (message: string) => void);
|
|
83
|
+
/** Secrets to redact from any message that might reach a client. */
|
|
84
|
+
secrets(): Array<string | undefined>;
|
|
85
|
+
redact(text: string): string;
|
|
86
|
+
/** Effective auth method, taking SSO overrides into account. */
|
|
87
|
+
effectiveAuth(): {
|
|
88
|
+
method: AuthMethod;
|
|
89
|
+
user?: string;
|
|
90
|
+
};
|
|
91
|
+
/** Session-setup warnings (e.g. server too old for SET gizmosql.query_timeout). */
|
|
92
|
+
sessionWarnings(): string[];
|
|
93
|
+
/** Swaps in new credentials (SSO) and drops the current connection. */
|
|
94
|
+
useCredentials(overrides: SessionOverrides): Promise<void>;
|
|
95
|
+
private clientConfig;
|
|
96
|
+
/** Opens a fresh client and applies session settings. */
|
|
97
|
+
private open;
|
|
98
|
+
/** Returns the shared client, opening it on first use. */
|
|
99
|
+
get(): Promise<FlightSQLClient>;
|
|
100
|
+
/** Closes the current client (cancelling any in-flight statement server-side). */
|
|
101
|
+
reset(): Promise<void>;
|
|
102
|
+
close(): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Runs `fn` against the shared client with: serialization, one retry
|
|
105
|
+
* after a connection-level failure, and a client-side deadline that
|
|
106
|
+
* aborts the statement via `signal` (falling back to dropping the
|
|
107
|
+
* connection if the abort does not settle the call).
|
|
108
|
+
*/
|
|
109
|
+
run<T>(fn: (client: FlightSQLClient, signal: AbortSignal | undefined) => Promise<T>, options?: RunOptions): Promise<T>;
|
|
110
|
+
private withDeadline;
|
|
111
|
+
/** Convenience: execute a query returning an Arrow table. */
|
|
112
|
+
query(sql: string, params?: SqlParameters, options?: RunOptions): Promise<Table>;
|
|
113
|
+
/**
|
|
114
|
+
* Executes a query and reads at most `maxRows + 1` rows from the result
|
|
115
|
+
* stream, then releases the stream so no further batches are transferred.
|
|
116
|
+
*/
|
|
117
|
+
queryCapped(sql: string, params: SqlParameters | undefined, maxRows: number, options?: RunOptions): Promise<CappedResult>;
|
|
118
|
+
/** Convenience: execute a statement returning the affected-row count. */
|
|
119
|
+
update(sql: string, params?: SqlParameters, options?: RunOptions): Promise<number>;
|
|
120
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
// Configuration parsing, credential redaction, and the single lazily
|
|
2
|
+
// opened FlightSQLClient shared by the whole server process.
|
|
3
|
+
import { FlightSQLClient, QueryCancelledError } from "@gizmodata/gizmosql-client";
|
|
4
|
+
import { Table } from "apache-arrow";
|
|
5
|
+
export const DEFAULTS = {
|
|
6
|
+
port: 31337,
|
|
7
|
+
oauthPort: 31339,
|
|
8
|
+
maxRows: 500,
|
|
9
|
+
maxCellChars: 200,
|
|
10
|
+
queryTimeoutSeconds: 60,
|
|
11
|
+
};
|
|
12
|
+
export class ConfigError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "ConfigError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const TRUE_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
19
|
+
const FALSE_VALUES = new Set(["0", "false", "no", "off", ""]);
|
|
20
|
+
export function parseBoolean(name, raw, fallback) {
|
|
21
|
+
if (raw === undefined)
|
|
22
|
+
return fallback;
|
|
23
|
+
const v = raw.trim().toLowerCase();
|
|
24
|
+
if (TRUE_VALUES.has(v))
|
|
25
|
+
return true;
|
|
26
|
+
if (FALSE_VALUES.has(v))
|
|
27
|
+
return false;
|
|
28
|
+
throw new ConfigError(`${name} must be true/false (got "${raw}").`);
|
|
29
|
+
}
|
|
30
|
+
export function parseInteger(name, raw, fallback, { min, max }) {
|
|
31
|
+
if (raw === undefined || raw.trim() === "")
|
|
32
|
+
return fallback;
|
|
33
|
+
const n = Number(raw.trim());
|
|
34
|
+
if (!Number.isInteger(n) || n < min || (max !== undefined && n > max)) {
|
|
35
|
+
const range = max === undefined ? `>= ${min}` : `between ${min} and ${max}`;
|
|
36
|
+
throw new ConfigError(`${name} must be an integer ${range} (got "${raw}").`);
|
|
37
|
+
}
|
|
38
|
+
return n;
|
|
39
|
+
}
|
|
40
|
+
function nonEmpty(raw) {
|
|
41
|
+
if (raw === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
const v = raw.trim();
|
|
44
|
+
return v === "" ? undefined : v;
|
|
45
|
+
}
|
|
46
|
+
/** Builds the effective configuration from environment variables. */
|
|
47
|
+
export function parseConfig(env = process.env) {
|
|
48
|
+
const host = nonEmpty(env.GIZMOSQL_HOST);
|
|
49
|
+
if (!host) {
|
|
50
|
+
throw new ConfigError("GIZMOSQL_HOST is required (hostname or IP of the GizmoSQL server).");
|
|
51
|
+
}
|
|
52
|
+
const username = nonEmpty(env.GIZMOSQL_USERNAME);
|
|
53
|
+
const password = env.GIZMOSQL_PASSWORD !== undefined ? env.GIZMOSQL_PASSWORD : undefined;
|
|
54
|
+
const token = nonEmpty(env.GIZMOSQL_TOKEN);
|
|
55
|
+
const enableSso = parseBoolean("GIZMOSQL_ENABLE_SSO", env.GIZMOSQL_ENABLE_SSO, false);
|
|
56
|
+
const hasPassword = username !== undefined || (password !== undefined && password !== "");
|
|
57
|
+
const hasToken = token !== undefined;
|
|
58
|
+
if (hasPassword && hasToken) {
|
|
59
|
+
throw new ConfigError("Set either GIZMOSQL_USERNAME/GIZMOSQL_PASSWORD or GIZMOSQL_TOKEN, not both.");
|
|
60
|
+
}
|
|
61
|
+
if (hasPassword && (username === undefined || password === undefined)) {
|
|
62
|
+
throw new ConfigError("GIZMOSQL_USERNAME and GIZMOSQL_PASSWORD must be set together.");
|
|
63
|
+
}
|
|
64
|
+
if (!hasPassword && !hasToken && !enableSso) {
|
|
65
|
+
throw new ConfigError("No credentials configured: set GIZMOSQL_USERNAME + GIZMOSQL_PASSWORD, or GIZMOSQL_TOKEN " +
|
|
66
|
+
"(or GIZMOSQL_ENABLE_SSO=true to sign in with the login_sso tool).");
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
host,
|
|
70
|
+
port: parseInteger("GIZMOSQL_PORT", env.GIZMOSQL_PORT, DEFAULTS.port, { min: 1, max: 65535 }),
|
|
71
|
+
username: hasPassword ? username : undefined,
|
|
72
|
+
password: hasPassword ? password : undefined,
|
|
73
|
+
token: hasToken ? token : undefined,
|
|
74
|
+
plaintext: parseBoolean("GIZMOSQL_PLAINTEXT", env.GIZMOSQL_PLAINTEXT, false),
|
|
75
|
+
tlsSkipVerify: parseBoolean("GIZMOSQL_TLS_SKIP_VERIFY", env.GIZMOSQL_TLS_SKIP_VERIFY, false),
|
|
76
|
+
oauthPort: parseInteger("GIZMOSQL_OAUTH_PORT", env.GIZMOSQL_OAUTH_PORT, DEFAULTS.oauthPort, {
|
|
77
|
+
min: 1,
|
|
78
|
+
max: 65535,
|
|
79
|
+
}),
|
|
80
|
+
allowWrites: parseBoolean("GIZMOSQL_ALLOW_WRITES", env.GIZMOSQL_ALLOW_WRITES, false),
|
|
81
|
+
maxRows: parseInteger("GIZMOSQL_MAX_ROWS", env.GIZMOSQL_MAX_ROWS, DEFAULTS.maxRows, {
|
|
82
|
+
min: 1,
|
|
83
|
+
max: 100000,
|
|
84
|
+
}),
|
|
85
|
+
maxCellChars: parseInteger("GIZMOSQL_MAX_CELL_CHARS", env.GIZMOSQL_MAX_CELL_CHARS, DEFAULTS.maxCellChars, { min: 1, max: 100000 }),
|
|
86
|
+
queryTimeoutSeconds: parseInteger("GIZMOSQL_QUERY_TIMEOUT_SECONDS", env.GIZMOSQL_QUERY_TIMEOUT_SECONDS, DEFAULTS.queryTimeoutSeconds, { min: 0, max: 86400 }),
|
|
87
|
+
mcpBearerToken: nonEmpty(env.GIZMOSQL_MCP_BEARER_TOKEN),
|
|
88
|
+
enableSso,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function authMethod(config) {
|
|
92
|
+
if (config.token)
|
|
93
|
+
return "token";
|
|
94
|
+
if (config.username !== undefined)
|
|
95
|
+
return "password";
|
|
96
|
+
return "none";
|
|
97
|
+
}
|
|
98
|
+
/** Connection URI with the password/token never included. */
|
|
99
|
+
export function redactedUri(config, overrideUser) {
|
|
100
|
+
const user = overrideUser ?? (authMethod(config) === "token" ? "token" : config.username);
|
|
101
|
+
const cred = user ? `${encodeURIComponent(user)}:***@` : "";
|
|
102
|
+
const transport = config.plaintext ? "?transport=tcp" : "";
|
|
103
|
+
return `gizmosql://${cred}${config.host}:${config.port}${transport}`;
|
|
104
|
+
}
|
|
105
|
+
/** Replaces every configured secret in `text` with `***`. */
|
|
106
|
+
export function redactSecrets(text, secrets) {
|
|
107
|
+
let out = text;
|
|
108
|
+
for (const s of secrets) {
|
|
109
|
+
if (!s || s.length === 0)
|
|
110
|
+
continue;
|
|
111
|
+
out = out.split(s).join("***");
|
|
112
|
+
const encoded = encodeURIComponent(s);
|
|
113
|
+
if (encoded !== s)
|
|
114
|
+
out = out.split(encoded).join("***");
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
export class QueryTimeoutError extends Error {
|
|
119
|
+
constructor(seconds) {
|
|
120
|
+
super(`Query exceeded the ${seconds}s timeout (GIZMOSQL_QUERY_TIMEOUT_SECONDS) and was cancelled.`);
|
|
121
|
+
this.name = "QueryTimeoutError";
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Grace added to the server-side timeout before the client-side abort fires. */
|
|
125
|
+
const CLIENT_DEADLINE_GRACE_MS = 5000;
|
|
126
|
+
/** If an abort does not settle the call (e.g. a DoPut update), drop the connection after this. */
|
|
127
|
+
const HARD_RESET_GRACE_MS = 15000;
|
|
128
|
+
const CONNECTION_LOST = /unavailable|connection (?:refused|reset|closed|lost)|transport is closing|broken pipe|\bEOF\b|not connected|failed to connect|socket hang up|ECONNRESET|ECONNREFUSED|EPIPE|canceled|deadline exceeded|no connection/i;
|
|
129
|
+
/** Heuristic: does this error indicate the underlying connection is unusable? */
|
|
130
|
+
export function isConnectionError(err) {
|
|
131
|
+
const name = err?.name ?? "";
|
|
132
|
+
if (name === "ConnectionError" || name === "AuthenticationError")
|
|
133
|
+
return name === "ConnectionError";
|
|
134
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
135
|
+
return CONNECTION_LOST.test(message);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* One FlightSQLClient per process, opened lazily, serialized so a single
|
|
139
|
+
* statement is in flight at a time, reconnected once on connection loss.
|
|
140
|
+
* Timeouts are enforced server-side (`SET gizmosql.query_timeout`) with a
|
|
141
|
+
* client-side deadline as backstop that cancels the statement through the
|
|
142
|
+
* client's AbortSignal support; only if that fails to settle the call is
|
|
143
|
+
* the connection dropped and reopened.
|
|
144
|
+
*/
|
|
145
|
+
export class GizmoConnection {
|
|
146
|
+
config;
|
|
147
|
+
log;
|
|
148
|
+
client = null;
|
|
149
|
+
connecting = null;
|
|
150
|
+
queue = Promise.resolve();
|
|
151
|
+
overrides = {};
|
|
152
|
+
warnings = [];
|
|
153
|
+
/** Wall-clock at which the current client was opened (for server_info). */
|
|
154
|
+
connectedAt = null;
|
|
155
|
+
constructor(config, log = (m) => console.error(m)) {
|
|
156
|
+
this.config = config;
|
|
157
|
+
this.log = log;
|
|
158
|
+
}
|
|
159
|
+
/** Secrets to redact from any message that might reach a client. */
|
|
160
|
+
secrets() {
|
|
161
|
+
return [this.config.password, this.config.token, this.overrides.password, this.config.mcpBearerToken];
|
|
162
|
+
}
|
|
163
|
+
redact(text) {
|
|
164
|
+
return redactSecrets(text, this.secrets());
|
|
165
|
+
}
|
|
166
|
+
/** Effective auth method, taking SSO overrides into account. */
|
|
167
|
+
effectiveAuth() {
|
|
168
|
+
if (this.overrides.username !== undefined) {
|
|
169
|
+
return { method: "password", user: this.overrides.username };
|
|
170
|
+
}
|
|
171
|
+
const method = authMethod(this.config);
|
|
172
|
+
return { method, user: method === "password" ? this.config.username : undefined };
|
|
173
|
+
}
|
|
174
|
+
/** Session-setup warnings (e.g. server too old for SET gizmosql.query_timeout). */
|
|
175
|
+
sessionWarnings() {
|
|
176
|
+
return [...this.warnings];
|
|
177
|
+
}
|
|
178
|
+
/** Swaps in new credentials (SSO) and drops the current connection. */
|
|
179
|
+
async useCredentials(overrides) {
|
|
180
|
+
this.overrides = overrides;
|
|
181
|
+
await this.reset();
|
|
182
|
+
}
|
|
183
|
+
clientConfig() {
|
|
184
|
+
const base = {
|
|
185
|
+
host: this.config.host,
|
|
186
|
+
port: this.config.port,
|
|
187
|
+
plaintext: this.config.plaintext,
|
|
188
|
+
tlsSkipVerify: this.config.tlsSkipVerify,
|
|
189
|
+
oauthPort: this.config.oauthPort,
|
|
190
|
+
};
|
|
191
|
+
if (this.overrides.username !== undefined) {
|
|
192
|
+
return { ...base, username: this.overrides.username, password: this.overrides.password ?? "" };
|
|
193
|
+
}
|
|
194
|
+
if (this.config.token)
|
|
195
|
+
return { ...base, token: this.config.token };
|
|
196
|
+
if (this.config.username !== undefined) {
|
|
197
|
+
return { ...base, username: this.config.username, password: this.config.password ?? "" };
|
|
198
|
+
}
|
|
199
|
+
return base;
|
|
200
|
+
}
|
|
201
|
+
/** Opens a fresh client and applies session settings. */
|
|
202
|
+
async open() {
|
|
203
|
+
const client = new FlightSQLClient(this.clientConfig());
|
|
204
|
+
await client.connect();
|
|
205
|
+
this.warnings = [];
|
|
206
|
+
if (this.config.queryTimeoutSeconds > 0) {
|
|
207
|
+
try {
|
|
208
|
+
await client.executeUpdate(`SET gizmosql.query_timeout = ${this.config.queryTimeoutSeconds}`);
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
const msg = this.redact(err instanceof Error ? err.message : String(err));
|
|
212
|
+
this.warnings.push(`Server-side query timeout could not be set (server may predate SET gizmosql.query_timeout); ` +
|
|
213
|
+
`falling back to the client-side deadline only. ${msg}`);
|
|
214
|
+
this.log(`[gizmosql-mcp] warning: ${this.warnings[this.warnings.length - 1]}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
this.connectedAt = new Date();
|
|
218
|
+
return client;
|
|
219
|
+
}
|
|
220
|
+
/** Returns the shared client, opening it on first use. */
|
|
221
|
+
async get() {
|
|
222
|
+
if (this.client)
|
|
223
|
+
return this.client;
|
|
224
|
+
if (!this.connecting) {
|
|
225
|
+
this.connecting = this.open()
|
|
226
|
+
.then((c) => {
|
|
227
|
+
this.client = c;
|
|
228
|
+
return c;
|
|
229
|
+
})
|
|
230
|
+
.finally(() => {
|
|
231
|
+
this.connecting = null;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return this.connecting;
|
|
235
|
+
}
|
|
236
|
+
/** Closes the current client (cancelling any in-flight statement server-side). */
|
|
237
|
+
async reset() {
|
|
238
|
+
const client = this.client;
|
|
239
|
+
this.client = null;
|
|
240
|
+
this.connectedAt = null;
|
|
241
|
+
if (client) {
|
|
242
|
+
try {
|
|
243
|
+
await client.close();
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// already gone
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async close() {
|
|
251
|
+
await this.reset();
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Runs `fn` against the shared client with: serialization, one retry
|
|
255
|
+
* after a connection-level failure, and a client-side deadline that
|
|
256
|
+
* aborts the statement via `signal` (falling back to dropping the
|
|
257
|
+
* connection if the abort does not settle the call).
|
|
258
|
+
*/
|
|
259
|
+
async run(fn, options = {}) {
|
|
260
|
+
const task = async () => {
|
|
261
|
+
let attempt = 0;
|
|
262
|
+
for (;;) {
|
|
263
|
+
attempt++;
|
|
264
|
+
const client = await this.get();
|
|
265
|
+
try {
|
|
266
|
+
return await this.withDeadline((signal) => fn(client, signal), options.timeoutSeconds);
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
if (err instanceof QueryTimeoutError) {
|
|
270
|
+
throw err;
|
|
271
|
+
}
|
|
272
|
+
if (attempt < 2 && isConnectionError(err)) {
|
|
273
|
+
this.log(`[gizmosql-mcp] connection error, reconnecting: ${this.redact(err instanceof Error ? err.message : String(err))}`);
|
|
274
|
+
await this.reset();
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
throw err;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
const result = this.queue.then(task, task);
|
|
282
|
+
this.queue = result.catch(() => undefined);
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
async withDeadline(fn, timeoutSeconds) {
|
|
286
|
+
const seconds = timeoutSeconds ?? this.config.queryTimeoutSeconds;
|
|
287
|
+
if (!seconds || seconds <= 0)
|
|
288
|
+
return fn(undefined);
|
|
289
|
+
// The server enforces `gizmosql.query_timeout` at `seconds`; the
|
|
290
|
+
// client-side abort is a backstop a few seconds later.
|
|
291
|
+
const controller = new AbortController();
|
|
292
|
+
const timeoutError = new QueryTimeoutError(seconds);
|
|
293
|
+
let abortTimer;
|
|
294
|
+
let resetTimer;
|
|
295
|
+
const hardReset = new Promise((_, reject) => {
|
|
296
|
+
abortTimer = setTimeout(() => {
|
|
297
|
+
controller.abort(timeoutError);
|
|
298
|
+
// If the abort cannot interrupt the call (e.g. a DoPut update),
|
|
299
|
+
// drop the connection so the server sees the client go away.
|
|
300
|
+
resetTimer = setTimeout(() => {
|
|
301
|
+
void this.reset().finally(() => reject(timeoutError));
|
|
302
|
+
}, HARD_RESET_GRACE_MS);
|
|
303
|
+
}, seconds * 1000 + CLIENT_DEADLINE_GRACE_MS);
|
|
304
|
+
});
|
|
305
|
+
try {
|
|
306
|
+
return await Promise.race([fn(controller.signal), hardReset]);
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
if (controller.signal.aborted && (err instanceof QueryCancelledError || err === timeoutError)) {
|
|
310
|
+
throw timeoutError;
|
|
311
|
+
}
|
|
312
|
+
throw err;
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
if (abortTimer)
|
|
316
|
+
clearTimeout(abortTimer);
|
|
317
|
+
if (resetTimer)
|
|
318
|
+
clearTimeout(resetTimer);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/** Convenience: execute a query returning an Arrow table. */
|
|
322
|
+
query(sql, params, options) {
|
|
323
|
+
return this.run((c, signal) => c.execute(sql, params, { signal }), options);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Executes a query and reads at most `maxRows + 1` rows from the result
|
|
327
|
+
* stream, then releases the stream so no further batches are transferred.
|
|
328
|
+
*/
|
|
329
|
+
queryCapped(sql, params, maxRows, options) {
|
|
330
|
+
return this.run(async (c, signal) => {
|
|
331
|
+
const stream = await c.executeStream(sql, params, { signal });
|
|
332
|
+
const batches = [];
|
|
333
|
+
let rows = 0;
|
|
334
|
+
for await (const batch of stream) {
|
|
335
|
+
batches.push(batch);
|
|
336
|
+
rows += batch.numRows;
|
|
337
|
+
if (rows > maxRows)
|
|
338
|
+
break; // releases the stream
|
|
339
|
+
}
|
|
340
|
+
const table = new Table(stream.schema, batches);
|
|
341
|
+
return { table: rows > maxRows ? table.slice(0, maxRows) : table, truncated: rows > maxRows };
|
|
342
|
+
}, options);
|
|
343
|
+
}
|
|
344
|
+
/** Convenience: execute a statement returning the affected-row count. */
|
|
345
|
+
update(sql, params, options) {
|
|
346
|
+
return this.run((c, signal) => c.executeUpdate(sql, params, { signal }), options);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
|
package/dist/format.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DataType, type Field, type Table } from "apache-arrow";
|
|
2
|
+
export interface FormatOptions {
|
|
3
|
+
/** Maximum number of rows to render. */
|
|
4
|
+
maxRows: number;
|
|
5
|
+
/** Maximum characters per cell before truncation with `…`. */
|
|
6
|
+
maxCellChars: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ColumnInfo {
|
|
9
|
+
name: string;
|
|
10
|
+
/** Arrow type rendered as a string, e.g. `Int64`, `Utf8`, `Decimal[10e+2]`. */
|
|
11
|
+
type: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FormattedResult {
|
|
14
|
+
columns: ColumnInfo[];
|
|
15
|
+
/** JSON-safe row values (bigint -> number/string, dates -> ISO, binary -> base64). */
|
|
16
|
+
rows: unknown[][];
|
|
17
|
+
/** Rows actually rendered (<= maxRows). */
|
|
18
|
+
rowCount: number;
|
|
19
|
+
/** True when the source table held more rows than `rowCount`. */
|
|
20
|
+
truncated: boolean;
|
|
21
|
+
/** Markdown table of the rendered rows. */
|
|
22
|
+
markdown: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Truncates `text` to `maxChars` Unicode code points (never splitting a
|
|
26
|
+
* surrogate pair), appending `…` when anything was removed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function truncateText(text: string, maxChars: number): string;
|
|
29
|
+
/** Escapes a cell for use inside a Markdown table row. */
|
|
30
|
+
export declare function escapeMarkdownCell(text: string): string;
|
|
31
|
+
/** Renders a Markdown table. Cells must already be escaped/truncated strings. */
|
|
32
|
+
export declare function toMarkdownTable(headers: string[], rows: string[][]): string;
|
|
33
|
+
/** Formats an unscaled decimal (as a decimal-digit string) with `scale` digits. */
|
|
34
|
+
export declare function formatDecimal(unscaled: string, scale: number): string;
|
|
35
|
+
/**
|
|
36
|
+
* Converts one Arrow cell to a JSON-safe value using the column type for
|
|
37
|
+
* temporal / decimal / binary rendering.
|
|
38
|
+
*/
|
|
39
|
+
export declare function cellToJson(value: unknown, type: DataType): unknown;
|
|
40
|
+
/** Renders a JSON-safe cell value as display text (no truncation). */
|
|
41
|
+
export declare function cellToText(json: unknown): string;
|
|
42
|
+
/** Human-readable Arrow type name for a field. */
|
|
43
|
+
export declare function fieldTypeName(field: Field): string;
|
|
44
|
+
/**
|
|
45
|
+
* Renders up to `maxRows` rows of an Arrow table as Markdown and JSON.
|
|
46
|
+
* Reads column vectors row-by-row and stops at the cap — it never
|
|
47
|
+
* materializes the whole table into JS objects.
|
|
48
|
+
*/
|
|
49
|
+
export declare function formatTable(table: Table, options: FormatOptions): FormattedResult;
|
|
50
|
+
/** Footer line appended to query results. */
|
|
51
|
+
export declare function resultFooter(input: {
|
|
52
|
+
rowCount: number;
|
|
53
|
+
truncated: boolean;
|
|
54
|
+
maxRows: number;
|
|
55
|
+
elapsedMs: number;
|
|
56
|
+
}): string;
|