@hydradb/mcp 1.3.0 → 1.4.1
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 +30 -0
- package/README.md +33 -2
- package/dist/adapters.d.ts +3 -3
- package/dist/adapters.js.map +1 -1
- package/dist/config.d.ts +21 -2
- package/dist/config.js +18 -4
- package/dist/config.js.map +1 -1
- package/dist/descriptions.d.ts +34 -0
- package/dist/descriptions.js +74 -1
- package/dist/descriptions.js.map +1 -1
- package/dist/http-config.d.ts +6 -1
- package/dist/http-config.js +9 -6
- package/dist/http-config.js.map +1 -1
- package/dist/hydra/client.d.ts +194 -5
- package/dist/hydra/client.js +136 -9
- package/dist/hydra/client.js.map +1 -1
- package/dist/hydra/graph.d.ts +1 -5
- package/dist/hydra/graph.js +5 -92
- package/dist/hydra/graph.js.map +1 -1
- package/dist/hydra/index.d.ts +3 -1
- package/dist/hydra/index.js +1 -0
- package/dist/hydra/index.js.map +1 -1
- package/dist/hydra/transport.d.ts +37 -0
- package/dist/hydra/transport.js +114 -0
- package/dist/hydra/transport.js.map +1 -0
- package/dist/server.js +241 -1
- package/dist/server.js.map +1 -1
- package/dist/tool-names.d.ts +4 -1
- package/dist/tool-names.js +10 -0
- package/dist/tool-names.js.map +1 -1
- package/package.json +2 -2
package/dist/hydra/graph.js
CHANGED
|
@@ -18,10 +18,8 @@
|
|
|
18
18
|
* That reasoning is unaffected here — there is no generated name to be
|
|
19
19
|
* insulated from yet.
|
|
20
20
|
*/
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
/** The SDK's own default, restated so this file does not depend on importing it. */
|
|
24
|
-
const DEFAULT_BASE_URL = "https://api.hydradb.com";
|
|
21
|
+
import { HydraWrapperError } from "./errors.js";
|
|
22
|
+
import { newRawTransport, sendRaw } from "./transport.js";
|
|
25
23
|
/**
|
|
26
24
|
* Status codes worth retrying.
|
|
27
25
|
*
|
|
@@ -29,9 +27,6 @@ const DEFAULT_BASE_URL = "https://api.hydradb.com";
|
|
|
29
27
|
* rejected construct, a Cypher error and a bad collection name all fail
|
|
30
28
|
* identically on retry, so retrying them only delays the message.
|
|
31
29
|
*/
|
|
32
|
-
function isRetryable(status) {
|
|
33
|
-
return status === 429 || (status >= 500 && status <= 599);
|
|
34
|
-
}
|
|
35
30
|
/**
|
|
36
31
|
* A 2xx whose body is not the shape this endpoint promises.
|
|
37
32
|
*
|
|
@@ -57,12 +52,7 @@ function unexpectedShape(path, expected, got) {
|
|
|
57
52
|
}
|
|
58
53
|
export class GraphResource {
|
|
59
54
|
constructor(config) {
|
|
60
|
-
this.
|
|
61
|
-
// Trailing slashes would produce `//byog/query`, which some proxies treat
|
|
62
|
-
// as a different path.
|
|
63
|
-
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
64
|
-
this.timeoutMs = (config.timeoutSeconds ?? 30) * 1000;
|
|
65
|
-
this.maxRetries = config.maxRetries ?? 2;
|
|
55
|
+
this.transport = newRawTransport(config, { timeoutSeconds: 30, maxRetries: 2 });
|
|
66
56
|
}
|
|
67
57
|
/**
|
|
68
58
|
* Run Cypher against one collection (`POST /byog/query`).
|
|
@@ -133,85 +123,8 @@ export class GraphResource {
|
|
|
133
123
|
return this.send("/byog/databases", "DELETE", { database }, opts);
|
|
134
124
|
}
|
|
135
125
|
// --- Transport ---
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
139
|
-
try {
|
|
140
|
-
return await this.attempt(path, method, body, opts);
|
|
141
|
-
}
|
|
142
|
-
catch (err) {
|
|
143
|
-
lastError = err;
|
|
144
|
-
const status = err instanceof HydraWrapperError ? err.status : undefined;
|
|
145
|
-
// A caller who cancelled is not waiting for a retry.
|
|
146
|
-
if (opts?.signal?.aborted)
|
|
147
|
-
throw err;
|
|
148
|
-
if (attempt === this.maxRetries)
|
|
149
|
-
break;
|
|
150
|
-
if (status != null && !isRetryable(status))
|
|
151
|
-
break;
|
|
152
|
-
// Exponential backoff. Bounded so a 429 on the last attempt does not
|
|
153
|
-
// hold the MCP host's tool timeout open for its own sake.
|
|
154
|
-
const delay = Math.min(250 * 2 ** attempt, 2000);
|
|
155
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
throw lastError;
|
|
159
|
-
}
|
|
160
|
-
async attempt(path, method, body, opts) {
|
|
161
|
-
// The host's cancellation and our own deadline both have to be able to
|
|
162
|
-
// abort the request, and `AbortSignal.any` is not available on every Node
|
|
163
|
-
// 18 this package supports — so they are combined by hand.
|
|
164
|
-
const controller = new AbortController();
|
|
165
|
-
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
166
|
-
const onAbort = () => controller.abort();
|
|
167
|
-
opts?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
168
|
-
try {
|
|
169
|
-
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
170
|
-
method,
|
|
171
|
-
headers: {
|
|
172
|
-
Authorization: `Bearer ${this.config.token}`,
|
|
173
|
-
"Content-Type": "application/json",
|
|
174
|
-
// CONTRACT §2 rule 6. The SDK sends this on every call; a
|
|
175
|
-
// hand-rolled path that omitted it would silently get v1
|
|
176
|
-
// behaviour from the same endpoints.
|
|
177
|
-
"API-Version": "2",
|
|
178
|
-
},
|
|
179
|
-
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
180
|
-
signal: controller.signal,
|
|
181
|
-
});
|
|
182
|
-
const text = await response.text();
|
|
183
|
-
let parsed;
|
|
184
|
-
try {
|
|
185
|
-
parsed = text === "" ? null : JSON.parse(text);
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
parsed = text;
|
|
189
|
-
}
|
|
190
|
-
if (!response.ok) {
|
|
191
|
-
// Hand the parsed envelope to the shared formatter so a BYOG
|
|
192
|
-
// failure reads exactly like an SDK one, error code and request id
|
|
193
|
-
// and all.
|
|
194
|
-
throw responseError(path, response.status, parsed);
|
|
195
|
-
}
|
|
196
|
-
return unwrap(parsed);
|
|
197
|
-
}
|
|
198
|
-
catch (err) {
|
|
199
|
-
if (err instanceof HydraWrapperError)
|
|
200
|
-
throw err;
|
|
201
|
-
// Distinguish our own deadline from the caller's cancellation: they
|
|
202
|
-
// need different actions, and "aborted" alone says neither.
|
|
203
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
204
|
-
if (opts?.signal?.aborted) {
|
|
205
|
-
throw new HydraWrapperError(`Hydra DB ${path} → ERR: request cancelled by the caller`, path, { cause: err });
|
|
206
|
-
}
|
|
207
|
-
throw new HydraWrapperError(`Hydra DB ${path} → ERR: request timed out after ${this.timeoutMs / 1000}s`, path, { cause: err });
|
|
208
|
-
}
|
|
209
|
-
throw translateError(path, err);
|
|
210
|
-
}
|
|
211
|
-
finally {
|
|
212
|
-
clearTimeout(timer);
|
|
213
|
-
opts?.signal?.removeEventListener("abort", onAbort);
|
|
214
|
-
}
|
|
126
|
+
send(path, method, body, opts) {
|
|
127
|
+
return sendRaw(this.transport, path, method, body, opts);
|
|
215
128
|
}
|
|
216
129
|
}
|
|
217
130
|
//# sourceMappingURL=graph.js.map
|
package/dist/hydra/graph.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/hydra/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/hydra/graph.ts"],"names":[],"mappings":"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"}
|
package/dist/hydra/index.d.ts
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* other client repos (per CONTRACT.md).
|
|
7
7
|
*/
|
|
8
8
|
export { HydraDB, ContextResource, DatabasesResource, DEFAULT_TIMEOUT_SECONDS, DEFAULT_MAX_RETRIES, } from "./client.js";
|
|
9
|
-
export type { HydraConfig, ContextKind, RequestOptions, QueryKind, ConversationTurn, QueryParams, IngestParams, ListParams, InspectParams, IngestionStatusParams, RelationsParams, DeleteParams, CreateDatabaseParams, } from "./client.js";
|
|
9
|
+
export type { HydraConfig, ContextKind, RequestOptions, QueryKind, ConversationTurn, QueryParams, IngestParams, ListParams, InspectParams, IngestionStatusParams, RelationsParams, SubgraphParams, SubgraphMember, SubgraphResult, DeleteParams, CreateDatabaseParams, DeleteCollectionParams, } from "./client.js";
|
|
10
10
|
export { GraphResource } from "./graph.js";
|
|
11
11
|
export type { GraphConfig, GraphQueryParams, GraphScopeParams, GraphRow, } from "./graph.js";
|
|
12
12
|
export { HydraWrapperError, responseError, translateError } from "./errors.js";
|
|
13
13
|
export { assertCollectionAllowed, assertDatabaseAllowed, DatabaseNotAllowedError, ScopeNotAllowedError, } from "./client.js";
|
|
14
14
|
export { unwrap } from "./envelope.js";
|
|
15
|
+
export { DEFAULT_BASE_URL, newRawTransport, sendRaw } from "./transport.js";
|
|
16
|
+
export type { RawTransport } from "./transport.js";
|
package/dist/hydra/index.js
CHANGED
|
@@ -10,4 +10,5 @@ export { GraphResource } from "./graph.js";
|
|
|
10
10
|
export { HydraWrapperError, responseError, translateError } from "./errors.js";
|
|
11
11
|
export { assertCollectionAllowed, assertDatabaseAllowed, DatabaseNotAllowedError, ScopeNotAllowedError, } from "./client.js";
|
|
12
12
|
export { unwrap } from "./envelope.js";
|
|
13
|
+
export { DEFAULT_BASE_URL, newRawTransport, sendRaw } from "./transport.js";
|
|
13
14
|
//# sourceMappingURL=index.js.map
|
package/dist/hydra/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hydra/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,OAAO,EACP,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,GACnB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hydra/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,OAAO,EACP,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,GACnB,MAAM,aAAa,CAAC;AAoBrB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAO3C,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EACN,uBAAuB,EACvB,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hand-rolled HTTP path for endpoints the SDK does not expose.
|
|
3
|
+
*
|
|
4
|
+
* CONTRACT §2 rule 7: a call that bypasses the SDK is still the wrapper — same
|
|
5
|
+
* `API-Version: 2` header, same envelope-by-shape unwrap, same translated error
|
|
6
|
+
* type — so a caller cannot tell which methods went through the SDK. This used
|
|
7
|
+
* to live inside GraphResource, where BYOG was the only such surface. The
|
|
8
|
+
* connected-subgraph read (PRO-1848) is the second, and a second copy of the
|
|
9
|
+
* retry/abort/translate logic is exactly what the rule exists to prevent, so
|
|
10
|
+
* it moved here and both resources call it.
|
|
11
|
+
*
|
|
12
|
+
* `fetchFn` is injectable for tests only; production never sets it.
|
|
13
|
+
*/
|
|
14
|
+
/** The SDK's own default, restated so this file does not depend on importing it. */
|
|
15
|
+
export declare const DEFAULT_BASE_URL = "https://api.hydradb.com";
|
|
16
|
+
export interface RawTransport {
|
|
17
|
+
token: string;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
timeoutMs: number;
|
|
20
|
+
maxRetries: number;
|
|
21
|
+
fetchFn?: typeof fetch;
|
|
22
|
+
}
|
|
23
|
+
export interface RawRequestOptions {
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}
|
|
26
|
+
export declare function newRawTransport(config: {
|
|
27
|
+
token: string;
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
timeoutSeconds?: number;
|
|
30
|
+
maxRetries?: number;
|
|
31
|
+
fetchFn?: typeof fetch;
|
|
32
|
+
}, defaults: {
|
|
33
|
+
timeoutSeconds: number;
|
|
34
|
+
maxRetries: number;
|
|
35
|
+
}): RawTransport;
|
|
36
|
+
/** Send with bounded retries on 429/5xx; the caller's abort ends retrying. */
|
|
37
|
+
export declare function sendRaw<T>(t: RawTransport, path: string, method: "GET" | "POST" | "DELETE", body: unknown, opts?: RawRequestOptions): Promise<T>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hand-rolled HTTP path for endpoints the SDK does not expose.
|
|
3
|
+
*
|
|
4
|
+
* CONTRACT §2 rule 7: a call that bypasses the SDK is still the wrapper — same
|
|
5
|
+
* `API-Version: 2` header, same envelope-by-shape unwrap, same translated error
|
|
6
|
+
* type — so a caller cannot tell which methods went through the SDK. This used
|
|
7
|
+
* to live inside GraphResource, where BYOG was the only such surface. The
|
|
8
|
+
* connected-subgraph read (PRO-1848) is the second, and a second copy of the
|
|
9
|
+
* retry/abort/translate logic is exactly what the rule exists to prevent, so
|
|
10
|
+
* it moved here and both resources call it.
|
|
11
|
+
*
|
|
12
|
+
* `fetchFn` is injectable for tests only; production never sets it.
|
|
13
|
+
*/
|
|
14
|
+
import { unwrap } from "./envelope.js";
|
|
15
|
+
import { HydraWrapperError, responseError, translateError } from "./errors.js";
|
|
16
|
+
/** The SDK's own default, restated so this file does not depend on importing it. */
|
|
17
|
+
export const DEFAULT_BASE_URL = "https://api.hydradb.com";
|
|
18
|
+
export function newRawTransport(config, defaults) {
|
|
19
|
+
return {
|
|
20
|
+
token: config.token,
|
|
21
|
+
// Trailing slashes would produce `//byog/query`, which some proxies treat
|
|
22
|
+
// as a different path.
|
|
23
|
+
baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""),
|
|
24
|
+
timeoutMs: (config.timeoutSeconds ?? defaults.timeoutSeconds) * 1000,
|
|
25
|
+
maxRetries: config.maxRetries ?? defaults.maxRetries,
|
|
26
|
+
...(config.fetchFn ? { fetchFn: config.fetchFn } : {}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function isRetryable(status) {
|
|
30
|
+
return status === 429 || (status >= 500 && status <= 599);
|
|
31
|
+
}
|
|
32
|
+
/** Send with bounded retries on 429/5xx; the caller's abort ends retrying. */
|
|
33
|
+
export async function sendRaw(t, path, method, body, opts) {
|
|
34
|
+
let lastError;
|
|
35
|
+
for (let attempt = 0; attempt <= t.maxRetries; attempt++) {
|
|
36
|
+
try {
|
|
37
|
+
return await attemptRaw(t, path, method, body, opts);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
lastError = err;
|
|
41
|
+
const status = err instanceof HydraWrapperError ? err.status : undefined;
|
|
42
|
+
// A caller who cancelled is not waiting for a retry.
|
|
43
|
+
if (opts?.signal?.aborted)
|
|
44
|
+
throw err;
|
|
45
|
+
if (attempt === t.maxRetries)
|
|
46
|
+
break;
|
|
47
|
+
if (status != null && !isRetryable(status))
|
|
48
|
+
break;
|
|
49
|
+
// Exponential backoff. Bounded so a 429 on the last attempt does not
|
|
50
|
+
// hold the MCP host's tool timeout open for its own sake.
|
|
51
|
+
const delay = Math.min(250 * 2 ** attempt, 2000);
|
|
52
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
throw lastError;
|
|
56
|
+
}
|
|
57
|
+
async function attemptRaw(t, path, method, body, opts) {
|
|
58
|
+
// The host's cancellation and our own deadline both have to be able to
|
|
59
|
+
// abort the request, and `AbortSignal.any` is not available on every Node
|
|
60
|
+
// 18 this package supports — so they are combined by hand.
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
const timer = setTimeout(() => controller.abort(), t.timeoutMs);
|
|
63
|
+
const onAbort = () => controller.abort();
|
|
64
|
+
opts?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
65
|
+
const doFetch = t.fetchFn ?? fetch;
|
|
66
|
+
try {
|
|
67
|
+
const response = await doFetch(`${t.baseUrl}${path}`, {
|
|
68
|
+
method,
|
|
69
|
+
headers: {
|
|
70
|
+
Authorization: `Bearer ${t.token}`,
|
|
71
|
+
"Content-Type": "application/json",
|
|
72
|
+
// CONTRACT §2 rule 6. The SDK sends this on every call; a
|
|
73
|
+
// hand-rolled path that omitted it would silently get v1
|
|
74
|
+
// behaviour from the same endpoints.
|
|
75
|
+
"API-Version": "2",
|
|
76
|
+
},
|
|
77
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
78
|
+
signal: controller.signal,
|
|
79
|
+
});
|
|
80
|
+
const text = await response.text();
|
|
81
|
+
let parsed;
|
|
82
|
+
try {
|
|
83
|
+
parsed = text === "" ? null : JSON.parse(text);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
parsed = text;
|
|
87
|
+
}
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
// Hand the parsed envelope to the shared formatter so a raw-path
|
|
90
|
+
// failure reads exactly like an SDK one, error code and request id
|
|
91
|
+
// and all.
|
|
92
|
+
throw responseError(path, response.status, parsed);
|
|
93
|
+
}
|
|
94
|
+
return unwrap(parsed);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
if (err instanceof HydraWrapperError)
|
|
98
|
+
throw err;
|
|
99
|
+
// Distinguish our own deadline from the caller's cancellation: they
|
|
100
|
+
// need different actions, and "aborted" alone says neither.
|
|
101
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
102
|
+
if (opts?.signal?.aborted) {
|
|
103
|
+
throw new HydraWrapperError(`Hydra DB ${path} → ERR: request cancelled by the caller`, path, { cause: err });
|
|
104
|
+
}
|
|
105
|
+
throw new HydraWrapperError(`Hydra DB ${path} → ERR: request timed out after ${t.timeoutMs / 1000}s`, path, { cause: err });
|
|
106
|
+
}
|
|
107
|
+
throw translateError(path, err);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
opts?.signal?.removeEventListener("abort", onAbort);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/hydra/transport.ts"],"names":[],"mappings":"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"}
|