@gizmodata/hardcharger-mcp 0.0.0 → 2.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 +129 -0
- package/LICENSE +201 -0
- package/NOTICE +8 -0
- package/README.md +490 -3
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +75 -0
- package/dist/cli.js.map +1 -0
- package/dist/connection.d.ts +260 -0
- package/dist/connection.js +797 -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/oauth-facade.d.ts +50 -0
- package/dist/oauth-facade.js +223 -0
- package/dist/oauth-facade.js.map +1 -0
- package/dist/oauth.d.ts +94 -0
- package/dist/oauth.js +228 -0
- package/dist/oauth.js.map +1 -0
- package/dist/params.d.ts +61 -0
- package/dist/params.js +200 -0
- package/dist/params.js.map +1 -0
- package/dist/registry.d.ts +45 -0
- package/dist/registry.js +91 -0
- package/dist/registry.js.map +1 -0
- package/dist/server.d.ts +38 -0
- package/dist/server.js +753 -0
- package/dist/server.js.map +1 -0
- package/dist/sessions.d.ts +52 -0
- package/dist/sessions.js +113 -0
- package/dist/sessions.js.map +1 -0
- package/dist/sql-guard.d.ts +62 -0
- package/dist/sql-guard.js +460 -0
- package/dist/sql-guard.js.map +1 -0
- package/dist/sso.d.ts +29 -0
- package/dist/sso.js +145 -0
- package/dist/sso.js.map +1 -0
- package/dist/transports.d.ts +29 -0
- package/dist/transports.js +308 -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 +65 -9
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { type BrowserSignInTarget, type Connection, type ConnectOptions } from "@gizmodata/hardcharger";
|
|
2
|
+
import { Table } from "apache-arrow";
|
|
3
|
+
import type { OAuthConfig } from "./oauth.js";
|
|
4
|
+
import type { BoundParams } from "./params.js";
|
|
5
|
+
/** How a connection signs in. */
|
|
6
|
+
export type AuthMethod = "password" | "token" | "mtls" | "sso" | "none";
|
|
7
|
+
/** Settings for one Hardcharger server. */
|
|
8
|
+
export interface ConnectionConfig {
|
|
9
|
+
/** Unique, case-insensitive name used in tool arguments (e.g. "default", "prod"). */
|
|
10
|
+
name: string;
|
|
11
|
+
/** `hardcharger://host[:port][/prefix][?tls=false]` (TLS unless `?tls=false`, port 31337 by default). */
|
|
12
|
+
uri: string;
|
|
13
|
+
/** Host and TLS of `uri`, as the client reads it. */
|
|
14
|
+
host: string;
|
|
15
|
+
port: number;
|
|
16
|
+
tls: boolean;
|
|
17
|
+
/** Password sign-in. */
|
|
18
|
+
username?: string;
|
|
19
|
+
password?: string;
|
|
20
|
+
/** A signed sign-in token (an identity provider's ID token, or one minted for Hardcharger): the token_exchange grant. */
|
|
21
|
+
token?: string;
|
|
22
|
+
/** Client certificate and key (PEM file paths) for mutual TLS. Alone, the certificate is the credential. */
|
|
23
|
+
mtlsCertFile?: string;
|
|
24
|
+
mtlsKeyFile?: string;
|
|
25
|
+
/** CA bundle (PEM file path) that verifies the server's certificate, for a private CA. */
|
|
26
|
+
tlsRootsFile?: string;
|
|
27
|
+
tlsSkipVerify: boolean;
|
|
28
|
+
/** Catalog to use at session start (optional). */
|
|
29
|
+
defaultCatalog?: string;
|
|
30
|
+
/** Schema to use at session start (optional). */
|
|
31
|
+
defaultSchema?: string;
|
|
32
|
+
/** Per-statement timeout applied to this connection's statements (0 = none). */
|
|
33
|
+
queryTimeoutSeconds: number;
|
|
34
|
+
}
|
|
35
|
+
/** Whole-server settings plus every configured connection (the first is the initial default). */
|
|
36
|
+
export interface McpConfig {
|
|
37
|
+
connections: ConnectionConfig[];
|
|
38
|
+
allowWrites: boolean;
|
|
39
|
+
maxRows: number;
|
|
40
|
+
maxCellChars: number;
|
|
41
|
+
queryTimeoutSeconds: number;
|
|
42
|
+
/** Bearer token required on every Streamable HTTP request (http transport only). */
|
|
43
|
+
mcpBearerToken?: string;
|
|
44
|
+
/** OAuth resource-server settings for the HTTP transport (set when HARDCHARGER_MCP_OAUTH_ISSUER is configured). */
|
|
45
|
+
mcpOAuth?: OAuthConfig;
|
|
46
|
+
/** HTTP transport with OAuth: seconds a per-user session may sit idle before its connections are closed. */
|
|
47
|
+
mcpSessionIdleSeconds: number;
|
|
48
|
+
/** HTTP transport with OAuth: cap on concurrent per-user sessions (least recently used is closed first). */
|
|
49
|
+
mcpMaxSessions: number;
|
|
50
|
+
/** Enables the optional `login_sso` tool (the server's OAuth browser sign-in). */
|
|
51
|
+
enableSso: boolean;
|
|
52
|
+
}
|
|
53
|
+
export declare const DEFAULTS: {
|
|
54
|
+
readonly maxRows: 500;
|
|
55
|
+
readonly maxCellChars: 200;
|
|
56
|
+
readonly queryTimeoutSeconds: 60;
|
|
57
|
+
readonly connectionName: "default";
|
|
58
|
+
readonly sessionIdleSeconds: 1800;
|
|
59
|
+
readonly maxSessions: 200;
|
|
60
|
+
};
|
|
61
|
+
/** Extra connection slots the Claude Desktop manifest exposes (`HARDCHARGER_2_*`, `HARDCHARGER_3_*`). */
|
|
62
|
+
export declare const MANIFEST_SLOTS: readonly ["2", "3"];
|
|
63
|
+
export declare class ConfigError extends Error {
|
|
64
|
+
constructor(message: string);
|
|
65
|
+
}
|
|
66
|
+
/** True when an env value should be treated as absent. */
|
|
67
|
+
export declare function isUnset(raw: string | undefined): boolean;
|
|
68
|
+
export declare function parseBoolean(name: string, raw: string | undefined, fallback: boolean): boolean;
|
|
69
|
+
export declare function parseInteger(name: string, raw: string | undefined, fallback: number, { min, max }: {
|
|
70
|
+
min: number;
|
|
71
|
+
max?: number;
|
|
72
|
+
}): number;
|
|
73
|
+
/** Env-variable key fragment for a connection key: `prod-eu` -> `PROD_EU`. */
|
|
74
|
+
export declare function envKey(key: string): string;
|
|
75
|
+
/** Reads and validates a `hardcharger://` URI the way the client will (throws ConfigError). */
|
|
76
|
+
export declare function parseHardchargerUri(name: string, raw: string): {
|
|
77
|
+
uri: string;
|
|
78
|
+
host: string;
|
|
79
|
+
port: number;
|
|
80
|
+
tls: boolean;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Builds the effective configuration from environment variables.
|
|
84
|
+
*
|
|
85
|
+
* Connections:
|
|
86
|
+
* - primary: `HARDCHARGER_URI` etc. (name `HARDCHARGER_CONNECTION_NAME`, default "default");
|
|
87
|
+
* - manifest slots: `HARDCHARGER_2_URI` / `HARDCHARGER_3_URI` etc. (names `HARDCHARGER_2_NAME`,
|
|
88
|
+
* default "server2"/"server3");
|
|
89
|
+
* - any names listed in `HARDCHARGER_CONNECTIONS` (comma separated), read from
|
|
90
|
+
* `HARDCHARGER_<NAME>_URI` etc. with the name upper-cased and non-alphanumerics
|
|
91
|
+
* replaced by `_`.
|
|
92
|
+
* Slots without a URI are ignored. At least one connection is required.
|
|
93
|
+
*/
|
|
94
|
+
export declare function parseConfig(env?: NodeJS.ProcessEnv): McpConfig;
|
|
95
|
+
/** Default claim precedence used to name an authenticated caller. */
|
|
96
|
+
export declare const DEFAULT_USER_CLAIMS: readonly ["email", "preferred_username", "upn", "name", "sub"];
|
|
97
|
+
/**
|
|
98
|
+
* Reads the OAuth resource-server settings for the HTTP transport. Returns
|
|
99
|
+
* undefined unless HARDCHARGER_MCP_OAUTH_ISSUER is set. Plain http URLs are
|
|
100
|
+
* accepted for the issuer and public URL only when
|
|
101
|
+
* HARDCHARGER_MCP_OAUTH_ALLOW_INSECURE=true (local testing).
|
|
102
|
+
*/
|
|
103
|
+
export declare function parseOAuth(env: NodeJS.ProcessEnv): OAuthConfig | undefined;
|
|
104
|
+
/** The sign-in a connection's settings call for (before any login_sso). */
|
|
105
|
+
export declare function authMethod(config: Pick<ConnectionConfig, "username" | "token" | "mtlsCertFile">): AuthMethod;
|
|
106
|
+
/** Replaces every configured secret in `text` with `***`. */
|
|
107
|
+
export declare function redactSecrets(text: string, secrets: Array<string | undefined>): string;
|
|
108
|
+
export declare class QueryTimeoutError extends Error {
|
|
109
|
+
constructor(seconds: number);
|
|
110
|
+
}
|
|
111
|
+
/** A capped result: up to `maxRows + 1` rows so callers can detect truncation. */
|
|
112
|
+
export interface CappedResult {
|
|
113
|
+
table: Table;
|
|
114
|
+
/** True when more rows existed beyond `maxRows` (the extra row is not in `table`). */
|
|
115
|
+
truncated: boolean;
|
|
116
|
+
}
|
|
117
|
+
/** The error's Hardcharger (Chargewire) code, if it is one of the client's errors. */
|
|
118
|
+
export declare function errorCode(err: unknown): string | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Does this error mean the connection (or the server's session behind it) is gone in a
|
|
121
|
+
* way that a fresh connection with the same credentials cures? The client itself already
|
|
122
|
+
* replaces a session the server lost (`session_not_found`, an expired token) and replays
|
|
123
|
+
* the session's options; this covers what it can't: a session an administrator ended
|
|
124
|
+
* (`session_ended` with reason `killed`, e.g. `KILL SESSION`, an expired token, or a reason
|
|
125
|
+
* this server doesn't know), a closed connection, a transport failure, and a lost session
|
|
126
|
+
* the client could not replace. A refused credential is never retried, and neither is a
|
|
127
|
+
* session ended because the sign-in was withdrawn (`token_revoked`, `credentials_changed`,
|
|
128
|
+
* `principal_dropped`).
|
|
129
|
+
*/
|
|
130
|
+
export declare function isConnectionLost(err: unknown): boolean;
|
|
131
|
+
export interface SessionOverrides {
|
|
132
|
+
/**
|
|
133
|
+
* Replaces the configured credentials with the Hardcharger access token a browser sign-in
|
|
134
|
+
* (login_sso) handed out; kept in memory only and used as is, never renewed.
|
|
135
|
+
*/
|
|
136
|
+
accessToken?: string;
|
|
137
|
+
}
|
|
138
|
+
/** The session's catalog and schema, kept by the client and replayed on a replacement session. */
|
|
139
|
+
export interface SearchPath {
|
|
140
|
+
catalog?: string;
|
|
141
|
+
schema?: string;
|
|
142
|
+
}
|
|
143
|
+
export interface RunOptions {
|
|
144
|
+
/** Overrides the configured timeout for this operation (seconds; 0 = none). */
|
|
145
|
+
timeoutSeconds?: number;
|
|
146
|
+
}
|
|
147
|
+
/** What `run` hands each operation: the connection and the statement options to use. */
|
|
148
|
+
export interface RunContext {
|
|
149
|
+
signal: AbortSignal | undefined;
|
|
150
|
+
/** The server-side timeout (§6.9) for statements, when one applies. */
|
|
151
|
+
statementTimeoutMs: number | undefined;
|
|
152
|
+
}
|
|
153
|
+
/** Setting names read from hardcharger_settings() and reported by server_info. */
|
|
154
|
+
export declare const SERVER_SETTINGS_OF_INTEREST: readonly ["hardcharger.version", "hardcharger.read_only", "hardcharger.max_sessions", "hardcharger.session_idle_timeout", "hardcharger.query_timeout", "hardcharger.memory_limit", "hardcharger.max_concurrent_statements", "hardcharger.instance_id", "hardcharger.cluster_id"];
|
|
155
|
+
export interface ConnectionHooks {
|
|
156
|
+
/** Test hook: opens the client connection (defaults to `connect` from @gizmodata/hardcharger). */
|
|
157
|
+
connect?: (options: ConnectOptions) => Promise<Connection>;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* One Hardcharger connection per configured server, opened lazily and serialized so a
|
|
161
|
+
* single statement is in flight at a time. Timeouts are enforced by the server
|
|
162
|
+
* (`statementTimeoutMs`, Chargewire §6.9) with a client-side abort as backstop that cancels
|
|
163
|
+
* the statement on the server; only if that fails to settle the call is the connection
|
|
164
|
+
* dropped and reopened. The client replaces a session the server lost and replays its
|
|
165
|
+
* catalog and schema; a connection that is gone altogether (a killed session, a closed
|
|
166
|
+
* connection, a transport failure) is reopened once and the operation retried.
|
|
167
|
+
*/
|
|
168
|
+
export declare class HardchargerConnection {
|
|
169
|
+
readonly config: ConnectionConfig;
|
|
170
|
+
private readonly log;
|
|
171
|
+
private client;
|
|
172
|
+
private connecting;
|
|
173
|
+
private queue;
|
|
174
|
+
private overrides;
|
|
175
|
+
private warnings;
|
|
176
|
+
private searchPath;
|
|
177
|
+
/** Wall-clock at which the current client was opened (for server_info). */
|
|
178
|
+
connectedAt: Date | null;
|
|
179
|
+
/** Sessions the server lost and the client replaced, over every client this connection opened. */
|
|
180
|
+
private replacedBefore;
|
|
181
|
+
/** Times a lost connection was reopened by this layer (a killed session, a transport failure). */
|
|
182
|
+
reconnects: number;
|
|
183
|
+
/** The server's startup settings from hardcharger_settings(); null until read or when unavailable. */
|
|
184
|
+
private serverSettings;
|
|
185
|
+
private readonly openClient;
|
|
186
|
+
constructor(config: ConnectionConfig, log?: (message: string) => void, hooks?: ConnectionHooks);
|
|
187
|
+
/** The search path (catalog, schema) applied to every session. */
|
|
188
|
+
currentSearchPath(): SearchPath;
|
|
189
|
+
/**
|
|
190
|
+
* Switches the session's default catalog and/or schema (Chargewire session options, which
|
|
191
|
+
* the client replays on a replacement session). Throws when the server refuses it.
|
|
192
|
+
*/
|
|
193
|
+
useSchema(path: SearchPath): Promise<SearchPath>;
|
|
194
|
+
/**
|
|
195
|
+
* Re-reads the session's catalog and schema (after a `USE`, which the server applies but
|
|
196
|
+
* the client does not replay) and sets both as session options, so a replacement session
|
|
197
|
+
* gets the same search path.
|
|
198
|
+
*/
|
|
199
|
+
syncSearchPath(): Promise<SearchPath>;
|
|
200
|
+
private pinSearchPath;
|
|
201
|
+
/** Secrets to redact from any message that might reach a client. */
|
|
202
|
+
secrets(): Array<string | undefined>;
|
|
203
|
+
redact(text: string): string;
|
|
204
|
+
/** Effective auth method, taking login_sso into account. */
|
|
205
|
+
effectiveAuth(): {
|
|
206
|
+
method: AuthMethod;
|
|
207
|
+
user?: string;
|
|
208
|
+
};
|
|
209
|
+
/** Session-setup warnings (e.g. a default catalog the server does not have). */
|
|
210
|
+
sessionWarnings(): string[];
|
|
211
|
+
/** Sessions the server lost and the client replaced (over this connection's lifetime). */
|
|
212
|
+
sessionReplacements(): number;
|
|
213
|
+
/** The server's idle timeout for this connection's session, as the session document announced it. */
|
|
214
|
+
sessionIdleTimeoutSeconds(): Promise<number | null>;
|
|
215
|
+
/** The server's discovery document (name, version, capabilities, grants), once connected. */
|
|
216
|
+
discovery(): Connection["server"] | null;
|
|
217
|
+
/** Swaps in new credentials (login_sso) and drops the current connection. */
|
|
218
|
+
useCredentials(overrides: SessionOverrides): Promise<void>;
|
|
219
|
+
/** Where a browser sign-in (login_sso) runs: the connection's own URI, with its TLS settings. */
|
|
220
|
+
signInTarget(): BrowserSignInTarget;
|
|
221
|
+
/** The TLS settings (roots, client certificate, skip verify) for this connection, if any. */
|
|
222
|
+
private tlsOptions;
|
|
223
|
+
/** The client's connect options for this connection's settings. */
|
|
224
|
+
clientOptions(): ConnectOptions;
|
|
225
|
+
/** Opens a fresh client and applies the session settings. */
|
|
226
|
+
private open;
|
|
227
|
+
/**
|
|
228
|
+
* The search path, as Chargewire session options. A catalog or schema the server does not
|
|
229
|
+
* have is reported (with the catalogs it does have) instead of failing the connection;
|
|
230
|
+
* the server's default then applies.
|
|
231
|
+
*/
|
|
232
|
+
private applySessionSettings;
|
|
233
|
+
/** Reads the server's startup settings once per connection; never fails the connection. */
|
|
234
|
+
private probeServerSettings;
|
|
235
|
+
/** The server's reported startup settings (name -> value); empty when unknown. */
|
|
236
|
+
serverSettingsSnapshot(): Record<string, string>;
|
|
237
|
+
/** Returns the shared client, opening it on first use. */
|
|
238
|
+
get(): Promise<Connection>;
|
|
239
|
+
/** Closes the current client (ending its session on the server). */
|
|
240
|
+
reset(): Promise<void>;
|
|
241
|
+
close(): Promise<void>;
|
|
242
|
+
/**
|
|
243
|
+
* Runs `fn` against the shared client with: serialization, one retry after the
|
|
244
|
+
* connection was lost (see isConnectionLost), and a deadline: the server's statement
|
|
245
|
+
* timeout, a client-side abort a few seconds later that cancels the statement on the
|
|
246
|
+
* server, and as a last resort dropping the connection.
|
|
247
|
+
*/
|
|
248
|
+
run<T>(fn: (client: Connection, ctx: RunContext) => Promise<T>, options?: RunOptions): Promise<T>;
|
|
249
|
+
private withDeadline;
|
|
250
|
+
/** Convenience: execute a query returning an Arrow table. */
|
|
251
|
+
query(sql: string, params?: BoundParams, options?: RunOptions): Promise<Table>;
|
|
252
|
+
/**
|
|
253
|
+
* Executes a query and reads at most `maxRows + 1` rows from one result stream, then
|
|
254
|
+
* closes the stream, which stops the statement on the server: no further batches are
|
|
255
|
+
* transferred or computed.
|
|
256
|
+
*/
|
|
257
|
+
queryCapped(sql: string, params: BoundParams | undefined, maxRows: number, options?: RunOptions): Promise<CappedResult>;
|
|
258
|
+
/** Convenience: execute a statement returning the affected-row count (-1 when the engine does not count). */
|
|
259
|
+
update(sql: string, params?: BoundParams, options?: RunOptions): Promise<number>;
|
|
260
|
+
}
|