@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.
@@ -0,0 +1,45 @@
1
+ import { HardchargerConnection, type ConnectionConfig, type McpConfig } from "./connection.js";
2
+ export declare class UnknownConnectionError extends Error {
3
+ constructor(name: string, available: string[]);
4
+ }
5
+ export interface ConnectionSummary {
6
+ name: string;
7
+ /** The connection's hardcharger:// URI (never carries credentials). */
8
+ uri: string;
9
+ host: string;
10
+ port: number;
11
+ tls: boolean;
12
+ auth: string;
13
+ default_catalog: string | null;
14
+ default_schema: string | null;
15
+ current: boolean;
16
+ connected: boolean;
17
+ }
18
+ /**
19
+ * Holds one lazily opened HardchargerConnection per configured server. Names are
20
+ * matched case-insensitively. The first configured connection is the
21
+ * initial default; `use()` switches it for the rest of the process.
22
+ */
23
+ export declare class ConnectionRegistry {
24
+ readonly config: McpConfig;
25
+ private readonly byName;
26
+ private readonly order;
27
+ private currentName;
28
+ constructor(config: McpConfig, log?: (message: string) => void);
29
+ /** Names in configuration order. */
30
+ names(): string[];
31
+ /** Name of the current default connection. */
32
+ current(): string;
33
+ has(name: string): boolean;
34
+ /** Resolves a connection by name (case-insensitive); undefined/blank means the current default. */
35
+ get(name?: string): HardchargerConnection;
36
+ /** Makes `name` the default for subsequent calls; returns its canonical name. */
37
+ use(name: string): string;
38
+ all(): HardchargerConnection[];
39
+ configFor(name?: string): ConnectionConfig;
40
+ /** Every secret from every connection plus the HTTP bearer token. */
41
+ secrets(): Array<string | undefined>;
42
+ redact(text: string): string;
43
+ summaries(): ConnectionSummary[];
44
+ close(): Promise<void>;
45
+ }
@@ -0,0 +1,91 @@
1
+ // Registry of named Hardcharger connections with a switchable default.
2
+ import { HardchargerConnection, redactSecrets } from "./connection.js";
3
+ export class UnknownConnectionError extends Error {
4
+ constructor(name, available) {
5
+ super(`Unknown connection "${name}". Available connections: ${available.join(", ")}.`);
6
+ this.name = "UnknownConnectionError";
7
+ }
8
+ }
9
+ /**
10
+ * Holds one lazily opened HardchargerConnection per configured server. Names are
11
+ * matched case-insensitively. The first configured connection is the
12
+ * initial default; `use()` switches it for the rest of the process.
13
+ */
14
+ export class ConnectionRegistry {
15
+ config;
16
+ byName = new Map();
17
+ order = [];
18
+ currentName;
19
+ constructor(config, log = (m) => console.error(m)) {
20
+ this.config = config;
21
+ if (config.connections.length === 0)
22
+ throw new Error("At least one connection is required.");
23
+ for (const c of config.connections) {
24
+ const conn = new HardchargerConnection(c, (m) => log(config.connections.length > 1 ? `${m} [${c.name}]` : m));
25
+ this.byName.set(c.name.toLowerCase(), conn);
26
+ this.order.push(c.name);
27
+ }
28
+ this.currentName = config.connections[0].name;
29
+ }
30
+ /** Names in configuration order. */
31
+ names() {
32
+ return [...this.order];
33
+ }
34
+ /** Name of the current default connection. */
35
+ current() {
36
+ return this.currentName;
37
+ }
38
+ has(name) {
39
+ return this.byName.has(name.trim().toLowerCase());
40
+ }
41
+ /** Resolves a connection by name (case-insensitive); undefined/blank means the current default. */
42
+ get(name) {
43
+ const key = (name ?? "").trim();
44
+ if (key === "")
45
+ return this.byName.get(this.currentName.toLowerCase());
46
+ const conn = this.byName.get(key.toLowerCase());
47
+ if (!conn)
48
+ throw new UnknownConnectionError(key, this.order);
49
+ return conn;
50
+ }
51
+ /** Makes `name` the default for subsequent calls; returns its canonical name. */
52
+ use(name) {
53
+ const conn = this.get(name);
54
+ this.currentName = conn.config.name;
55
+ return this.currentName;
56
+ }
57
+ all() {
58
+ return this.order.map((n) => this.byName.get(n.toLowerCase()));
59
+ }
60
+ configFor(name) {
61
+ return this.get(name).config;
62
+ }
63
+ /** Every secret from every connection plus the HTTP bearer token. */
64
+ secrets() {
65
+ return [...this.all().flatMap((c) => c.secrets()), this.config.mcpBearerToken];
66
+ }
67
+ redact(text) {
68
+ return redactSecrets(text, this.secrets());
69
+ }
70
+ summaries() {
71
+ return this.all().map((c) => {
72
+ const auth = c.effectiveAuth();
73
+ return {
74
+ name: c.config.name,
75
+ uri: c.config.uri,
76
+ host: c.config.host,
77
+ port: c.config.port,
78
+ tls: c.config.tls,
79
+ auth: auth.method === "password" ? `password (${auth.user ?? ""})` : auth.method,
80
+ default_catalog: c.currentSearchPath().catalog ?? null,
81
+ default_schema: c.currentSearchPath().schema ?? null,
82
+ current: c.config.name === this.currentName,
83
+ connected: c.connectedAt !== null,
84
+ };
85
+ });
86
+ }
87
+ async close() {
88
+ await Promise.all(this.all().map((c) => c.close().catch(() => undefined)));
89
+ }
90
+ }
91
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type McpConfig } from "./connection.js";
3
+ import type { AuthenticatedUser } from "./oauth.js";
4
+ import type { SessionInfo } from "./sessions.js";
5
+ import { ConnectionRegistry } from "./registry.js";
6
+ export interface ServerContext {
7
+ registry: ConnectionRegistry;
8
+ config: McpConfig;
9
+ transport: "stdio" | "http";
10
+ /** Caller verified by the HTTP transport's OAuth layer (absent on stdio or with a static bearer token). */
11
+ user?: AuthenticatedUser;
12
+ /** The caller's per-user session (HTTP transport with OAuth). */
13
+ session?: SessionInfo;
14
+ /** Called once a tool result has told the caller their previous session expired. */
15
+ acknowledgeSessionReset?: () => void;
16
+ }
17
+ /**
18
+ * Converts a thrown error into a redacted, user-facing message. The client's errors
19
+ * answered by the server end with their code, SQLSTATE, HTTP status and request id, e.g.
20
+ * "Catalog Error: Table with name nope does not exist! ... (sql_error, SQLSTATE 42P01,
21
+ * HTTP 400, request r_...)", which is what a bug report needs, so they pass through.
22
+ */
23
+ export declare function describeError(err: unknown, redact: (text: string) => string): string;
24
+ /**
25
+ * Per-backend temporary schemas of an attached Postgres database
26
+ * (`pg_temp_N` / `pg_toast_temp_N`). They hold nothing a client can use,
27
+ * one pair exists per Postgres backend, and there can be hundreds, so
28
+ * list_schemas never enumerates them.
29
+ */
30
+ export declare function isTransientSchema(name: string): boolean;
31
+ /**
32
+ * Schemas DuckDB and the Postgres-compatibility layer create in every
33
+ * catalog. Attached Postgres databases also expose one `pg_temp_N` /
34
+ * `pg_toast_temp_N` pair per backend, which can run into the hundreds.
35
+ */
36
+ export declare function isSystemSchema(name: string): boolean;
37
+ /** Builds the McpServer with every tool/resource registered against `ctx`. */
38
+ export declare function createServer(ctx: ServerContext): McpServer;