@pairsystems/goodmem-mcp 0.1.17 → 0.1.19
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/README.md +51 -3
- package/dist/index.js +1243 -238
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -3105,6 +3105,9 @@ var require_utils = __commonJS({
|
|
|
3105
3105
|
"use strict";
|
|
3106
3106
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3107
3107
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3108
|
+
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3109
|
+
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3110
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
|
|
3108
3111
|
function stringArrayToHexStripped(input) {
|
|
3109
3112
|
let acc = "";
|
|
3110
3113
|
let code = 0;
|
|
@@ -3297,27 +3300,77 @@ var require_utils = __commonJS({
|
|
|
3297
3300
|
}
|
|
3298
3301
|
return output.join("");
|
|
3299
3302
|
}
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3303
|
+
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
3304
|
+
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
3305
|
+
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
3306
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
3307
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
3308
|
+
re.lastIndex = 0;
|
|
3309
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
3310
|
+
}
|
|
3311
|
+
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
3312
|
+
if (input.indexOf("%") === -1) {
|
|
3313
|
+
return input;
|
|
3310
3314
|
}
|
|
3311
|
-
|
|
3312
|
-
|
|
3315
|
+
let output = "";
|
|
3316
|
+
for (let i = 0; i < input.length; i++) {
|
|
3317
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3318
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3319
|
+
if (isHexPair(hex)) {
|
|
3320
|
+
const normalizedHex = hex.toUpperCase();
|
|
3321
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3322
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
3323
|
+
output += decoded;
|
|
3324
|
+
} else {
|
|
3325
|
+
output += "%" + normalizedHex;
|
|
3326
|
+
}
|
|
3327
|
+
i += 2;
|
|
3328
|
+
continue;
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
output += input[i];
|
|
3313
3332
|
}
|
|
3314
|
-
|
|
3315
|
-
|
|
3333
|
+
return output;
|
|
3334
|
+
}
|
|
3335
|
+
function normalizePathEncoding(input) {
|
|
3336
|
+
let output = "";
|
|
3337
|
+
for (let i = 0; i < input.length; i++) {
|
|
3338
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3339
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3340
|
+
if (isHexPair(hex)) {
|
|
3341
|
+
const normalizedHex = hex.toUpperCase();
|
|
3342
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3343
|
+
if (decoded !== "." && isUnreserved(decoded)) {
|
|
3344
|
+
output += decoded;
|
|
3345
|
+
} else {
|
|
3346
|
+
output += "%" + normalizedHex;
|
|
3347
|
+
}
|
|
3348
|
+
i += 2;
|
|
3349
|
+
continue;
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
if (isPathCharacter(input[i])) {
|
|
3353
|
+
output += input[i];
|
|
3354
|
+
} else {
|
|
3355
|
+
output += escape(input[i]);
|
|
3356
|
+
}
|
|
3316
3357
|
}
|
|
3317
|
-
|
|
3318
|
-
|
|
3358
|
+
return output;
|
|
3359
|
+
}
|
|
3360
|
+
function escapePreservingEscapes(input) {
|
|
3361
|
+
let output = "";
|
|
3362
|
+
for (let i = 0; i < input.length; i++) {
|
|
3363
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3364
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3365
|
+
if (isHexPair(hex)) {
|
|
3366
|
+
output += "%" + hex.toUpperCase();
|
|
3367
|
+
i += 2;
|
|
3368
|
+
continue;
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
output += escape(input[i]);
|
|
3319
3372
|
}
|
|
3320
|
-
return
|
|
3373
|
+
return output;
|
|
3321
3374
|
}
|
|
3322
3375
|
function recomposeAuthority(component) {
|
|
3323
3376
|
const uriTokens = [];
|
|
@@ -3332,7 +3385,7 @@ var require_utils = __commonJS({
|
|
|
3332
3385
|
if (ipV6res.isIPV6 === true) {
|
|
3333
3386
|
host = `[${ipV6res.escapedHost}]`;
|
|
3334
3387
|
} else {
|
|
3335
|
-
host =
|
|
3388
|
+
host = reescapeHostDelimiters(host, false);
|
|
3336
3389
|
}
|
|
3337
3390
|
}
|
|
3338
3391
|
uriTokens.push(host);
|
|
@@ -3346,7 +3399,10 @@ var require_utils = __commonJS({
|
|
|
3346
3399
|
module.exports = {
|
|
3347
3400
|
nonSimpleDomain,
|
|
3348
3401
|
recomposeAuthority,
|
|
3349
|
-
|
|
3402
|
+
reescapeHostDelimiters,
|
|
3403
|
+
normalizePercentEncoding,
|
|
3404
|
+
normalizePathEncoding,
|
|
3405
|
+
escapePreservingEscapes,
|
|
3350
3406
|
removeDotSegments,
|
|
3351
3407
|
isIPv4,
|
|
3352
3408
|
isUUID,
|
|
@@ -3570,12 +3626,12 @@ var require_schemes = __commonJS({
|
|
|
3570
3626
|
var require_fast_uri = __commonJS({
|
|
3571
3627
|
"node_modules/fast-uri/index.js"(exports, module) {
|
|
3572
3628
|
"use strict";
|
|
3573
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
3629
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3574
3630
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3575
3631
|
function normalize(uri, options) {
|
|
3576
3632
|
if (typeof uri === "string") {
|
|
3577
3633
|
uri = /** @type {T} */
|
|
3578
|
-
|
|
3634
|
+
normalizeString(uri, options);
|
|
3579
3635
|
} else if (typeof uri === "object") {
|
|
3580
3636
|
uri = /** @type {T} */
|
|
3581
3637
|
parse3(serialize(uri, options), options);
|
|
@@ -3584,7 +3640,12 @@ var require_fast_uri = __commonJS({
|
|
|
3584
3640
|
}
|
|
3585
3641
|
function resolve(baseURI, relativeURI, options) {
|
|
3586
3642
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3587
|
-
const
|
|
3643
|
+
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
|
|
3644
|
+
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
|
|
3645
|
+
if (baseMalformed || relativeMalformed) {
|
|
3646
|
+
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3647
|
+
}
|
|
3648
|
+
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3588
3649
|
schemelessOptions.skipEscape = true;
|
|
3589
3650
|
return serialize(resolved, schemelessOptions);
|
|
3590
3651
|
}
|
|
@@ -3642,19 +3703,9 @@ var require_fast_uri = __commonJS({
|
|
|
3642
3703
|
return target;
|
|
3643
3704
|
}
|
|
3644
3705
|
function equal(uriA, uriB, options) {
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
} else if (typeof uriA === "object") {
|
|
3649
|
-
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
3650
|
-
}
|
|
3651
|
-
if (typeof uriB === "string") {
|
|
3652
|
-
uriB = unescape(uriB);
|
|
3653
|
-
uriB = serialize(normalizeComponentEncoding(parse3(uriB, options), true), { ...options, skipEscape: true });
|
|
3654
|
-
} else if (typeof uriB === "object") {
|
|
3655
|
-
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
3656
|
-
}
|
|
3657
|
-
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
3706
|
+
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3707
|
+
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3708
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
|
|
3658
3709
|
}
|
|
3659
3710
|
function serialize(cmpts, opts) {
|
|
3660
3711
|
const component = {
|
|
@@ -3679,12 +3730,12 @@ var require_fast_uri = __commonJS({
|
|
|
3679
3730
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
3680
3731
|
if (component.path !== void 0) {
|
|
3681
3732
|
if (!options.skipEscape) {
|
|
3682
|
-
component.path =
|
|
3733
|
+
component.path = escapePreservingEscapes(component.path);
|
|
3683
3734
|
if (component.scheme !== void 0) {
|
|
3684
3735
|
component.path = component.path.split("%3A").join(":");
|
|
3685
3736
|
}
|
|
3686
3737
|
} else {
|
|
3687
|
-
component.path =
|
|
3738
|
+
component.path = normalizePercentEncoding(component.path);
|
|
3688
3739
|
}
|
|
3689
3740
|
}
|
|
3690
3741
|
if (options.reference !== "suffix" && component.scheme) {
|
|
@@ -3719,7 +3770,18 @@ var require_fast_uri = __commonJS({
|
|
|
3719
3770
|
return uriTokens.join("");
|
|
3720
3771
|
}
|
|
3721
3772
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3722
|
-
|
|
3773
|
+
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
3774
|
+
var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
|
|
3775
|
+
function getParseError(parsed, matches) {
|
|
3776
|
+
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3777
|
+
return 'URI path must start with "/" when authority is present.';
|
|
3778
|
+
}
|
|
3779
|
+
if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
|
|
3780
|
+
return "URI port is malformed.";
|
|
3781
|
+
}
|
|
3782
|
+
return void 0;
|
|
3783
|
+
}
|
|
3784
|
+
function parseWithStatus(uri, opts) {
|
|
3723
3785
|
const options = Object.assign({}, opts);
|
|
3724
3786
|
const parsed = {
|
|
3725
3787
|
scheme: void 0,
|
|
@@ -3730,6 +3792,7 @@ var require_fast_uri = __commonJS({
|
|
|
3730
3792
|
query: void 0,
|
|
3731
3793
|
fragment: void 0
|
|
3732
3794
|
};
|
|
3795
|
+
let malformedAuthorityOrPort = false;
|
|
3733
3796
|
let isIP = false;
|
|
3734
3797
|
if (options.reference === "suffix") {
|
|
3735
3798
|
if (options.scheme) {
|
|
@@ -3738,6 +3801,25 @@ var require_fast_uri = __commonJS({
|
|
|
3738
3801
|
uri = "//" + uri;
|
|
3739
3802
|
}
|
|
3740
3803
|
}
|
|
3804
|
+
const authorityMatch = uri.match(AUTHORITY_PREFIX);
|
|
3805
|
+
if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
|
|
3806
|
+
parsed.error = "URI authority must not contain a literal backslash.";
|
|
3807
|
+
malformedAuthorityOrPort = true;
|
|
3808
|
+
}
|
|
3809
|
+
const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
|
|
3810
|
+
if (introducerMatch !== null) {
|
|
3811
|
+
const region = introducerMatch[1];
|
|
3812
|
+
const normalizedRegion = region.replace(/[\t\n\r]/g, "");
|
|
3813
|
+
if (normalizedRegion.length >= 2) {
|
|
3814
|
+
if (normalizedRegion.slice(0, 2) !== "//") {
|
|
3815
|
+
parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
|
|
3816
|
+
malformedAuthorityOrPort = true;
|
|
3817
|
+
} else if (region.length !== normalizedRegion.length) {
|
|
3818
|
+
parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
|
|
3819
|
+
malformedAuthorityOrPort = true;
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3741
3823
|
const matches = uri.match(URI_PARSE);
|
|
3742
3824
|
if (matches) {
|
|
3743
3825
|
parsed.scheme = matches[1];
|
|
@@ -3750,6 +3832,11 @@ var require_fast_uri = __commonJS({
|
|
|
3750
3832
|
if (isNaN(parsed.port)) {
|
|
3751
3833
|
parsed.port = matches[5];
|
|
3752
3834
|
}
|
|
3835
|
+
const parseError = getParseError(parsed, matches);
|
|
3836
|
+
if (parseError !== void 0) {
|
|
3837
|
+
parsed.error = parsed.error || parseError;
|
|
3838
|
+
malformedAuthorityOrPort = true;
|
|
3839
|
+
}
|
|
3753
3840
|
if (parsed.host) {
|
|
3754
3841
|
const ipv4result = isIPv4(parsed.host);
|
|
3755
3842
|
if (ipv4result === false) {
|
|
@@ -3776,7 +3863,7 @@ var require_fast_uri = __commonJS({
|
|
|
3776
3863
|
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
|
|
3777
3864
|
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
3778
3865
|
try {
|
|
3779
|
-
parsed.host = URL
|
|
3866
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3780
3867
|
} catch (e) {
|
|
3781
3868
|
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3782
3869
|
}
|
|
@@ -3788,14 +3875,18 @@ var require_fast_uri = __commonJS({
|
|
|
3788
3875
|
parsed.scheme = unescape(parsed.scheme);
|
|
3789
3876
|
}
|
|
3790
3877
|
if (parsed.host !== void 0) {
|
|
3791
|
-
parsed.host = unescape(parsed.host);
|
|
3878
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
3792
3879
|
}
|
|
3793
3880
|
}
|
|
3794
3881
|
if (parsed.path) {
|
|
3795
|
-
parsed.path =
|
|
3882
|
+
parsed.path = normalizePathEncoding(parsed.path);
|
|
3796
3883
|
}
|
|
3797
3884
|
if (parsed.fragment) {
|
|
3798
|
-
|
|
3885
|
+
try {
|
|
3886
|
+
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3887
|
+
} catch {
|
|
3888
|
+
parsed.error = parsed.error || "URI malformed";
|
|
3889
|
+
}
|
|
3799
3890
|
}
|
|
3800
3891
|
}
|
|
3801
3892
|
if (schemeHandler && schemeHandler.parse) {
|
|
@@ -3804,7 +3895,29 @@ var require_fast_uri = __commonJS({
|
|
|
3804
3895
|
} else {
|
|
3805
3896
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3806
3897
|
}
|
|
3807
|
-
return parsed;
|
|
3898
|
+
return { parsed, malformedAuthorityOrPort };
|
|
3899
|
+
}
|
|
3900
|
+
function parse3(uri, opts) {
|
|
3901
|
+
return parseWithStatus(uri, opts).parsed;
|
|
3902
|
+
}
|
|
3903
|
+
function normalizeString(uri, opts) {
|
|
3904
|
+
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3905
|
+
}
|
|
3906
|
+
function normalizeStringWithStatus(uri, opts) {
|
|
3907
|
+
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
3908
|
+
return {
|
|
3909
|
+
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3910
|
+
malformedAuthorityOrPort
|
|
3911
|
+
};
|
|
3912
|
+
}
|
|
3913
|
+
function normalizeComparableURI(uri, opts) {
|
|
3914
|
+
if (typeof uri === "string") {
|
|
3915
|
+
const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
|
|
3916
|
+
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
3917
|
+
}
|
|
3918
|
+
if (typeof uri === "object") {
|
|
3919
|
+
return serialize(uri, opts);
|
|
3920
|
+
}
|
|
3808
3921
|
}
|
|
3809
3922
|
var fastUri = {
|
|
3810
3923
|
SCHEMES,
|
|
@@ -20988,7 +21101,21 @@ var StdioServerTransport = class {
|
|
|
20988
21101
|
// dist/index.js
|
|
20989
21102
|
var goodmemBaseUrl = process.env.GOODMEM_BASE_URL || "";
|
|
20990
21103
|
var goodmemApiKey = process.env.GOODMEM_API_KEY || "";
|
|
20991
|
-
var
|
|
21104
|
+
var DEFAULT_STREAM_MAX_LINE_BYTES = 8 * 1024 * 1024;
|
|
21105
|
+
function _parseStreamMaxLineBytes(raw) {
|
|
21106
|
+
if (!raw)
|
|
21107
|
+
return 0;
|
|
21108
|
+
const n = Number(raw);
|
|
21109
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : 0;
|
|
21110
|
+
}
|
|
21111
|
+
var goodmemStreamMaxLineBytes = _parseStreamMaxLineBytes(process.env.GOODMEM_STREAM_MAX_LINE_BYTES);
|
|
21112
|
+
function _concatBytes(a, b) {
|
|
21113
|
+
const out = new Uint8Array(a.length + b.length);
|
|
21114
|
+
out.set(a, 0);
|
|
21115
|
+
out.set(b, a.length);
|
|
21116
|
+
return out;
|
|
21117
|
+
}
|
|
21118
|
+
var BASED_ON_GOODMEM_COMMIT = "232e437dbe75cefc1f075649027ce7275d357380";
|
|
20992
21119
|
function isConfigured() {
|
|
20993
21120
|
return goodmemBaseUrl !== "";
|
|
20994
21121
|
}
|
|
@@ -21104,18 +21231,61 @@ async function callApiNdjson(method, path, body, query, timeoutSec) {
|
|
|
21104
21231
|
...body ? { body: JSON.stringify(body) } : {}
|
|
21105
21232
|
});
|
|
21106
21233
|
if (!resp.ok) {
|
|
21107
|
-
const
|
|
21108
|
-
throw new Error(`GoodMem API error ${resp.status}: ${_trimBody(
|
|
21234
|
+
const text = await resp.text();
|
|
21235
|
+
throw new Error(`GoodMem API error ${resp.status}: ${_trimBody(text)}`);
|
|
21109
21236
|
}
|
|
21110
|
-
const
|
|
21111
|
-
const
|
|
21112
|
-
|
|
21237
|
+
const maxLineBytes = goodmemStreamMaxLineBytes > 0 ? goodmemStreamMaxLineBytes : DEFAULT_STREAM_MAX_LINE_BYTES;
|
|
21238
|
+
const results = [];
|
|
21239
|
+
if (resp.body === null) {
|
|
21240
|
+
return results;
|
|
21241
|
+
}
|
|
21242
|
+
const _overCap = () => new Error(`stream event exceeded the ${maxLineBytes}-byte per-event line cap; raise it via the goodmem_configure stream_max_line_bytes option (or the GOODMEM_STREAM_MAX_LINE_BYTES env var), or avoid inlining large bodies by leaving fetch_memory_content unset and fetching content via the memory content tool`);
|
|
21243
|
+
const reader = resp.body.getReader();
|
|
21244
|
+
const decoder = new TextDecoder("utf-8");
|
|
21245
|
+
let pending = new Uint8Array(0);
|
|
21246
|
+
let lineNo = 0;
|
|
21247
|
+
const _emit = (bytes) => {
|
|
21248
|
+
const line = decoder.decode(bytes).trim();
|
|
21249
|
+
if (!line)
|
|
21250
|
+
return;
|
|
21251
|
+
lineNo++;
|
|
21113
21252
|
try {
|
|
21114
|
-
|
|
21253
|
+
results.push(JSON.parse(line));
|
|
21115
21254
|
} catch (e) {
|
|
21116
|
-
throw new Error(`NDJSON parse error on line ${
|
|
21255
|
+
throw new Error(`NDJSON parse error on line ${lineNo}: ${e instanceof Error ? e.message : String(e)}`);
|
|
21117
21256
|
}
|
|
21118
|
-
}
|
|
21257
|
+
};
|
|
21258
|
+
try {
|
|
21259
|
+
for (; ; ) {
|
|
21260
|
+
const { done, value } = await reader.read();
|
|
21261
|
+
if (done)
|
|
21262
|
+
break;
|
|
21263
|
+
if (value === void 0 || value.length === 0)
|
|
21264
|
+
continue;
|
|
21265
|
+
pending = pending.length === 0 ? value : _concatBytes(pending, value);
|
|
21266
|
+
let nl;
|
|
21267
|
+
while ((nl = pending.indexOf(10)) !== -1) {
|
|
21268
|
+
const lineBytes = pending.subarray(0, nl);
|
|
21269
|
+
if (lineBytes.length > maxLineBytes)
|
|
21270
|
+
throw _overCap();
|
|
21271
|
+
_emit(lineBytes);
|
|
21272
|
+
pending = pending.subarray(nl + 1);
|
|
21273
|
+
}
|
|
21274
|
+
if (pending.length > maxLineBytes)
|
|
21275
|
+
throw _overCap();
|
|
21276
|
+
}
|
|
21277
|
+
if (pending.length > 0) {
|
|
21278
|
+
if (pending.length > maxLineBytes)
|
|
21279
|
+
throw _overCap();
|
|
21280
|
+
_emit(pending);
|
|
21281
|
+
}
|
|
21282
|
+
} finally {
|
|
21283
|
+
try {
|
|
21284
|
+
reader.releaseLock();
|
|
21285
|
+
} catch {
|
|
21286
|
+
}
|
|
21287
|
+
}
|
|
21288
|
+
return results;
|
|
21119
21289
|
}
|
|
21120
21290
|
var MODEL_REGISTRY = {
|
|
21121
21291
|
"embedders": {
|
|
@@ -21220,15 +21390,74 @@ var MODEL_REGISTRY = {
|
|
|
21220
21390
|
],
|
|
21221
21391
|
"maxSequenceLength": 512
|
|
21222
21392
|
},
|
|
21223
|
-
"jina-embeddings-
|
|
21393
|
+
"jina-embeddings-v5-text-small": {
|
|
21224
21394
|
"providerType": "JINA",
|
|
21225
21395
|
"dimensions": {
|
|
21226
21396
|
"default": 1024,
|
|
21227
|
-
"
|
|
21228
|
-
|
|
21229
|
-
|
|
21230
|
-
|
|
21231
|
-
|
|
21397
|
+
"range": [
|
|
21398
|
+
1,
|
|
21399
|
+
1024
|
|
21400
|
+
]
|
|
21401
|
+
},
|
|
21402
|
+
"supportedModalities": [
|
|
21403
|
+
"TEXT"
|
|
21404
|
+
],
|
|
21405
|
+
"maxSequenceLength": 32768
|
|
21406
|
+
},
|
|
21407
|
+
"jina-embeddings-v5-text-nano": {
|
|
21408
|
+
"providerType": "JINA",
|
|
21409
|
+
"dimensions": {
|
|
21410
|
+
"default": 768,
|
|
21411
|
+
"range": [
|
|
21412
|
+
1,
|
|
21413
|
+
768
|
|
21414
|
+
]
|
|
21415
|
+
},
|
|
21416
|
+
"supportedModalities": [
|
|
21417
|
+
"TEXT"
|
|
21418
|
+
],
|
|
21419
|
+
"maxSequenceLength": 8192
|
|
21420
|
+
},
|
|
21421
|
+
"jina-embeddings-v5-omni-small": {
|
|
21422
|
+
"providerType": "JINA",
|
|
21423
|
+
"dimensions": {
|
|
21424
|
+
"default": 1024,
|
|
21425
|
+
"range": [
|
|
21426
|
+
1,
|
|
21427
|
+
1024
|
|
21428
|
+
]
|
|
21429
|
+
},
|
|
21430
|
+
"supportedModalities": [
|
|
21431
|
+
"TEXT",
|
|
21432
|
+
"IMAGE",
|
|
21433
|
+
"AUDIO",
|
|
21434
|
+
"VIDEO"
|
|
21435
|
+
],
|
|
21436
|
+
"maxSequenceLength": 32768
|
|
21437
|
+
},
|
|
21438
|
+
"jina-embeddings-v5-omni-nano": {
|
|
21439
|
+
"providerType": "JINA",
|
|
21440
|
+
"dimensions": {
|
|
21441
|
+
"default": 768,
|
|
21442
|
+
"range": [
|
|
21443
|
+
1,
|
|
21444
|
+
768
|
|
21445
|
+
]
|
|
21446
|
+
},
|
|
21447
|
+
"supportedModalities": [
|
|
21448
|
+
"TEXT",
|
|
21449
|
+
"IMAGE",
|
|
21450
|
+
"AUDIO",
|
|
21451
|
+
"VIDEO"
|
|
21452
|
+
],
|
|
21453
|
+
"maxSequenceLength": 8192
|
|
21454
|
+
},
|
|
21455
|
+
"jina-embeddings-v4": {
|
|
21456
|
+
"providerType": "JINA",
|
|
21457
|
+
"dimensions": {
|
|
21458
|
+
"default": 1536,
|
|
21459
|
+
"range": [
|
|
21460
|
+
1,
|
|
21232
21461
|
2048
|
|
21233
21462
|
]
|
|
21234
21463
|
},
|
|
@@ -21238,17 +21467,40 @@ var MODEL_REGISTRY = {
|
|
|
21238
21467
|
],
|
|
21239
21468
|
"maxSequenceLength": 32768
|
|
21240
21469
|
},
|
|
21470
|
+
"jina-code-embeddings-1.5b": {
|
|
21471
|
+
"providerType": "JINA",
|
|
21472
|
+
"dimensions": {
|
|
21473
|
+
"default": 1536,
|
|
21474
|
+
"range": [
|
|
21475
|
+
1,
|
|
21476
|
+
1536
|
|
21477
|
+
]
|
|
21478
|
+
},
|
|
21479
|
+
"supportedModalities": [
|
|
21480
|
+
"TEXT"
|
|
21481
|
+
],
|
|
21482
|
+
"maxSequenceLength": 32768
|
|
21483
|
+
},
|
|
21484
|
+
"jina-code-embeddings-0.5b": {
|
|
21485
|
+
"providerType": "JINA",
|
|
21486
|
+
"dimensions": {
|
|
21487
|
+
"default": 896,
|
|
21488
|
+
"range": [
|
|
21489
|
+
1,
|
|
21490
|
+
896
|
|
21491
|
+
]
|
|
21492
|
+
},
|
|
21493
|
+
"supportedModalities": [
|
|
21494
|
+
"TEXT"
|
|
21495
|
+
],
|
|
21496
|
+
"maxSequenceLength": 32768
|
|
21497
|
+
},
|
|
21241
21498
|
"jina-embeddings-v3": {
|
|
21242
21499
|
"providerType": "JINA",
|
|
21243
21500
|
"dimensions": {
|
|
21244
21501
|
"default": 1024,
|
|
21245
|
-
"
|
|
21246
|
-
|
|
21247
|
-
64,
|
|
21248
|
-
128,
|
|
21249
|
-
256,
|
|
21250
|
-
512,
|
|
21251
|
-
768,
|
|
21502
|
+
"range": [
|
|
21503
|
+
1,
|
|
21252
21504
|
1024
|
|
21253
21505
|
]
|
|
21254
21506
|
},
|
|
@@ -21340,12 +21592,8 @@ var MODEL_REGISTRY = {
|
|
|
21340
21592
|
"providerType": "JINA",
|
|
21341
21593
|
"dimensions": {
|
|
21342
21594
|
"default": 1024,
|
|
21343
|
-
"
|
|
21344
|
-
|
|
21345
|
-
128,
|
|
21346
|
-
256,
|
|
21347
|
-
512,
|
|
21348
|
-
768,
|
|
21595
|
+
"range": [
|
|
21596
|
+
1,
|
|
21349
21597
|
1024
|
|
21350
21598
|
]
|
|
21351
21599
|
},
|
|
@@ -21403,6 +21651,22 @@ var MODEL_REGISTRY = {
|
|
|
21403
21651
|
],
|
|
21404
21652
|
"maxSequenceLength": 32e3
|
|
21405
21653
|
},
|
|
21654
|
+
"voyage-code-4": {
|
|
21655
|
+
"providerType": "VOYAGE",
|
|
21656
|
+
"dimensions": {
|
|
21657
|
+
"default": 1024,
|
|
21658
|
+
"allowed": [
|
|
21659
|
+
256,
|
|
21660
|
+
512,
|
|
21661
|
+
1024,
|
|
21662
|
+
2048
|
|
21663
|
+
]
|
|
21664
|
+
},
|
|
21665
|
+
"supportedModalities": [
|
|
21666
|
+
"TEXT"
|
|
21667
|
+
],
|
|
21668
|
+
"maxSequenceLength": 32e3
|
|
21669
|
+
},
|
|
21406
21670
|
"voyage-code-3": {
|
|
21407
21671
|
"providerType": "VOYAGE",
|
|
21408
21672
|
"dimensions": {
|
|
@@ -21544,40 +21808,142 @@ var MODEL_REGISTRY = {
|
|
|
21544
21808
|
"TEXT"
|
|
21545
21809
|
],
|
|
21546
21810
|
"maxSequenceLength": 32e3
|
|
21547
|
-
}
|
|
21548
|
-
|
|
21549
|
-
|
|
21550
|
-
|
|
21551
|
-
|
|
21811
|
+
},
|
|
21812
|
+
"text-embedding-v4": {
|
|
21813
|
+
"providerType": "DASHSCOPE",
|
|
21814
|
+
"dimensions": {
|
|
21815
|
+
"default": 1024,
|
|
21816
|
+
"allowed": [
|
|
21817
|
+
64,
|
|
21818
|
+
128,
|
|
21819
|
+
256,
|
|
21820
|
+
512,
|
|
21821
|
+
768,
|
|
21822
|
+
1024,
|
|
21823
|
+
1536,
|
|
21824
|
+
2048
|
|
21825
|
+
]
|
|
21826
|
+
},
|
|
21552
21827
|
"supportedModalities": [
|
|
21553
|
-
"TEXT"
|
|
21554
|
-
"IMAGE"
|
|
21828
|
+
"TEXT"
|
|
21555
21829
|
],
|
|
21556
|
-
"
|
|
21830
|
+
"maxSequenceLength": 8192
|
|
21557
21831
|
},
|
|
21558
|
-
"
|
|
21559
|
-
"providerType": "
|
|
21832
|
+
"text-embedding-v3": {
|
|
21833
|
+
"providerType": "DASHSCOPE",
|
|
21834
|
+
"dimensions": {
|
|
21835
|
+
"default": 1024,
|
|
21836
|
+
"allowed": [
|
|
21837
|
+
512,
|
|
21838
|
+
768,
|
|
21839
|
+
1024
|
|
21840
|
+
]
|
|
21841
|
+
},
|
|
21560
21842
|
"supportedModalities": [
|
|
21561
|
-
"TEXT"
|
|
21562
|
-
"IMAGE"
|
|
21843
|
+
"TEXT"
|
|
21563
21844
|
],
|
|
21564
|
-
"
|
|
21845
|
+
"maxSequenceLength": 8192
|
|
21565
21846
|
},
|
|
21566
|
-
"
|
|
21567
|
-
"providerType": "
|
|
21847
|
+
"tongyi-embedding-vision-plus": {
|
|
21848
|
+
"providerType": "DASHSCOPE",
|
|
21849
|
+
"dimensions": {
|
|
21850
|
+
"default": 1152,
|
|
21851
|
+
"allowed": [
|
|
21852
|
+
64,
|
|
21853
|
+
128,
|
|
21854
|
+
256,
|
|
21855
|
+
512,
|
|
21856
|
+
1024,
|
|
21857
|
+
1152
|
|
21858
|
+
]
|
|
21859
|
+
},
|
|
21568
21860
|
"supportedModalities": [
|
|
21569
|
-
"TEXT"
|
|
21570
|
-
"IMAGE"
|
|
21861
|
+
"TEXT"
|
|
21571
21862
|
],
|
|
21572
|
-
"
|
|
21863
|
+
"maxSequenceLength": 1024
|
|
21573
21864
|
},
|
|
21574
|
-
"
|
|
21575
|
-
"providerType": "
|
|
21865
|
+
"tongyi-embedding-vision-flash": {
|
|
21866
|
+
"providerType": "DASHSCOPE",
|
|
21867
|
+
"dimensions": {
|
|
21868
|
+
"default": 768,
|
|
21869
|
+
"allowed": [
|
|
21870
|
+
64,
|
|
21871
|
+
128,
|
|
21872
|
+
256,
|
|
21873
|
+
512,
|
|
21874
|
+
768
|
|
21875
|
+
]
|
|
21876
|
+
},
|
|
21576
21877
|
"supportedModalities": [
|
|
21577
|
-
"TEXT"
|
|
21578
|
-
"IMAGE"
|
|
21878
|
+
"TEXT"
|
|
21579
21879
|
],
|
|
21580
|
-
"
|
|
21880
|
+
"maxSequenceLength": 1024
|
|
21881
|
+
},
|
|
21882
|
+
"qwen3-vl-embedding": {
|
|
21883
|
+
"providerType": "DASHSCOPE",
|
|
21884
|
+
"dimensions": {
|
|
21885
|
+
"default": 1536,
|
|
21886
|
+
"allowed": [
|
|
21887
|
+
256,
|
|
21888
|
+
512,
|
|
21889
|
+
768,
|
|
21890
|
+
1024,
|
|
21891
|
+
1536,
|
|
21892
|
+
2048,
|
|
21893
|
+
2560
|
|
21894
|
+
]
|
|
21895
|
+
},
|
|
21896
|
+
"supportedModalities": [
|
|
21897
|
+
"TEXT"
|
|
21898
|
+
],
|
|
21899
|
+
"maxSequenceLength": 32e3
|
|
21900
|
+
},
|
|
21901
|
+
"multimodal-embedding-v1": {
|
|
21902
|
+
"providerType": "DASHSCOPE",
|
|
21903
|
+
"dimensions": {
|
|
21904
|
+
"default": 1024,
|
|
21905
|
+
"allowed": [
|
|
21906
|
+
1024
|
|
21907
|
+
]
|
|
21908
|
+
},
|
|
21909
|
+
"supportedModalities": [
|
|
21910
|
+
"TEXT"
|
|
21911
|
+
],
|
|
21912
|
+
"maxSequenceLength": 512
|
|
21913
|
+
}
|
|
21914
|
+
},
|
|
21915
|
+
"llms": {
|
|
21916
|
+
"gpt-5.2": {
|
|
21917
|
+
"providerType": "OPENAI",
|
|
21918
|
+
"supportedModalities": [
|
|
21919
|
+
"TEXT",
|
|
21920
|
+
"IMAGE"
|
|
21921
|
+
],
|
|
21922
|
+
"maxContextLength": 4e5
|
|
21923
|
+
},
|
|
21924
|
+
"gpt-5.2-pro": {
|
|
21925
|
+
"providerType": "OPENAI",
|
|
21926
|
+
"supportedModalities": [
|
|
21927
|
+
"TEXT",
|
|
21928
|
+
"IMAGE"
|
|
21929
|
+
],
|
|
21930
|
+
"maxContextLength": 4e5
|
|
21931
|
+
},
|
|
21932
|
+
"gpt-5.1": {
|
|
21933
|
+
"providerType": "OPENAI",
|
|
21934
|
+
"supportedModalities": [
|
|
21935
|
+
"TEXT",
|
|
21936
|
+
"IMAGE"
|
|
21937
|
+
],
|
|
21938
|
+
"maxContextLength": 4e5
|
|
21939
|
+
},
|
|
21940
|
+
"gpt-5": {
|
|
21941
|
+
"providerType": "OPENAI",
|
|
21942
|
+
"supportedModalities": [
|
|
21943
|
+
"TEXT",
|
|
21944
|
+
"IMAGE"
|
|
21945
|
+
],
|
|
21946
|
+
"maxContextLength": 4e5
|
|
21581
21947
|
},
|
|
21582
21948
|
"gpt-5-mini": {
|
|
21583
21949
|
"providerType": "OPENAI",
|
|
@@ -21696,6 +22062,97 @@ var MODEL_REGISTRY = {
|
|
|
21696
22062
|
"TEXT"
|
|
21697
22063
|
],
|
|
21698
22064
|
"maxContextLength": 128e3
|
|
22065
|
+
},
|
|
22066
|
+
"qwen-max": {
|
|
22067
|
+
"providerType": "DASHSCOPE",
|
|
22068
|
+
"supportedModalities": [
|
|
22069
|
+
"TEXT"
|
|
22070
|
+
],
|
|
22071
|
+
"maxContextLength": 32768
|
|
22072
|
+
},
|
|
22073
|
+
"qwen-plus": {
|
|
22074
|
+
"providerType": "DASHSCOPE",
|
|
22075
|
+
"supportedModalities": [
|
|
22076
|
+
"TEXT"
|
|
22077
|
+
],
|
|
22078
|
+
"maxContextLength": 1e6
|
|
22079
|
+
},
|
|
22080
|
+
"qwen-turbo": {
|
|
22081
|
+
"providerType": "DASHSCOPE",
|
|
22082
|
+
"supportedModalities": [
|
|
22083
|
+
"TEXT"
|
|
22084
|
+
],
|
|
22085
|
+
"maxContextLength": 131072
|
|
22086
|
+
},
|
|
22087
|
+
"qwen-long": {
|
|
22088
|
+
"providerType": "DASHSCOPE",
|
|
22089
|
+
"supportedModalities": [
|
|
22090
|
+
"TEXT"
|
|
22091
|
+
],
|
|
22092
|
+
"maxContextLength": 1e7
|
|
22093
|
+
},
|
|
22094
|
+
"qwen3-max": {
|
|
22095
|
+
"providerType": "DASHSCOPE",
|
|
22096
|
+
"supportedModalities": [
|
|
22097
|
+
"TEXT"
|
|
22098
|
+
],
|
|
22099
|
+
"maxContextLength": 262144
|
|
22100
|
+
},
|
|
22101
|
+
"qwen3-coder-plus": {
|
|
22102
|
+
"providerType": "DASHSCOPE",
|
|
22103
|
+
"supportedModalities": [
|
|
22104
|
+
"TEXT"
|
|
22105
|
+
],
|
|
22106
|
+
"maxContextLength": 1e6
|
|
22107
|
+
},
|
|
22108
|
+
"qwen3.7-max": {
|
|
22109
|
+
"providerType": "DASHSCOPE",
|
|
22110
|
+
"supportedModalities": [
|
|
22111
|
+
"TEXT"
|
|
22112
|
+
],
|
|
22113
|
+
"maxContextLength": 1e6
|
|
22114
|
+
},
|
|
22115
|
+
"qwen3.7-plus": {
|
|
22116
|
+
"providerType": "DASHSCOPE",
|
|
22117
|
+
"supportedModalities": [
|
|
22118
|
+
"TEXT"
|
|
22119
|
+
],
|
|
22120
|
+
"maxContextLength": 1e6
|
|
22121
|
+
},
|
|
22122
|
+
"qwen3.8-max": {
|
|
22123
|
+
"providerType": "DASHSCOPE",
|
|
22124
|
+
"supportedModalities": [
|
|
22125
|
+
"TEXT"
|
|
22126
|
+
],
|
|
22127
|
+
"maxContextLength": 1e6
|
|
22128
|
+
},
|
|
22129
|
+
"qwen3.6-flash": {
|
|
22130
|
+
"providerType": "DASHSCOPE",
|
|
22131
|
+
"supportedModalities": [
|
|
22132
|
+
"TEXT"
|
|
22133
|
+
],
|
|
22134
|
+
"maxContextLength": 1e6
|
|
22135
|
+
},
|
|
22136
|
+
"qwen-vl-max": {
|
|
22137
|
+
"providerType": "DASHSCOPE",
|
|
22138
|
+
"supportedModalities": [
|
|
22139
|
+
"TEXT"
|
|
22140
|
+
],
|
|
22141
|
+
"maxContextLength": 131072
|
|
22142
|
+
},
|
|
22143
|
+
"qwen-vl-plus": {
|
|
22144
|
+
"providerType": "DASHSCOPE",
|
|
22145
|
+
"supportedModalities": [
|
|
22146
|
+
"TEXT"
|
|
22147
|
+
],
|
|
22148
|
+
"maxContextLength": 131072
|
|
22149
|
+
},
|
|
22150
|
+
"deepseek-v4-pro": {
|
|
22151
|
+
"providerType": "DASHSCOPE",
|
|
22152
|
+
"supportedModalities": [
|
|
22153
|
+
"TEXT"
|
|
22154
|
+
],
|
|
22155
|
+
"maxContextLength": 1e6
|
|
21699
22156
|
}
|
|
21700
22157
|
},
|
|
21701
22158
|
"rerankers": {
|
|
@@ -21794,6 +22251,24 @@ var MODEL_REGISTRY = {
|
|
|
21794
22251
|
"supportedModalities": [
|
|
21795
22252
|
"TEXT"
|
|
21796
22253
|
]
|
|
22254
|
+
},
|
|
22255
|
+
"qwen3-vl-rerank": {
|
|
22256
|
+
"providerType": "DASHSCOPE",
|
|
22257
|
+
"supportedModalities": [
|
|
22258
|
+
"TEXT"
|
|
22259
|
+
]
|
|
22260
|
+
},
|
|
22261
|
+
"gte-rerank-v2": {
|
|
22262
|
+
"providerType": "DASHSCOPE",
|
|
22263
|
+
"supportedModalities": [
|
|
22264
|
+
"TEXT"
|
|
22265
|
+
]
|
|
22266
|
+
},
|
|
22267
|
+
"qwen3-rerank": {
|
|
22268
|
+
"providerType": "DASHSCOPE",
|
|
22269
|
+
"supportedModalities": [
|
|
22270
|
+
"TEXT"
|
|
22271
|
+
]
|
|
21797
22272
|
}
|
|
21798
22273
|
}
|
|
21799
22274
|
};
|
|
@@ -21801,7 +22276,8 @@ var PROVIDER_ENDPOINTS = {
|
|
|
21801
22276
|
"OPENAI": "https://api.openai.com/v1",
|
|
21802
22277
|
"COHERE": "https://api.cohere.com",
|
|
21803
22278
|
"VOYAGE": "https://api.voyageai.com/v1",
|
|
21804
|
-
"JINA": "https://api.jina.ai"
|
|
22279
|
+
"JINA": "https://api.jina.ai",
|
|
22280
|
+
"DASHSCOPE": "https://dashscope.aliyuncs.com"
|
|
21805
22281
|
};
|
|
21806
22282
|
var PROVIDER_CREDENTIAL_REQUIREMENTS = {
|
|
21807
22283
|
"OPENAI": [
|
|
@@ -21818,6 +22294,12 @@ var PROVIDER_CREDENTIAL_REQUIREMENTS = {
|
|
|
21818
22294
|
],
|
|
21819
22295
|
"JINA": [
|
|
21820
22296
|
"api.jina.ai"
|
|
22297
|
+
],
|
|
22298
|
+
"DASHSCOPE": [
|
|
22299
|
+
"dashscope.aliyuncs.com",
|
|
22300
|
+
"dashscope-intl.aliyuncs.com",
|
|
22301
|
+
"dashscope-us.aliyuncs.com",
|
|
22302
|
+
"cn-hongkong.dashscope.aliyuncs.com"
|
|
21821
22303
|
]
|
|
21822
22304
|
};
|
|
21823
22305
|
function checkCredentialRequired(args) {
|
|
@@ -21876,12 +22358,13 @@ function autoInferFromRegistry(registryType, args) {
|
|
|
21876
22358
|
}
|
|
21877
22359
|
var server = new McpServer({
|
|
21878
22360
|
name: "goodmem",
|
|
21879
|
-
version: "0.1.
|
|
22361
|
+
version: "0.1.19"
|
|
21880
22362
|
});
|
|
21881
22363
|
server.tool("goodmem_configure", "Configure GoodMem server connection. Call this before using other GoodMem tools if GOODMEM_BASE_URL and GOODMEM_API_KEY environment variables are not set. Session credentials override environment variables. For bootstrap workflows that need to call /v1/system/info or /v1/system/init before keys exist, api_key may be omitted; most other tools will return AuthenticationException until a real key is provided.", {
|
|
21882
22364
|
base_url: external_exports.string().describe("GoodMem server URL (e.g., https://your-server.example.com)"),
|
|
21883
|
-
api_key: external_exports.string().describe("GoodMem API key (starts with gm_). Omit for bootstrap-only sessions that call /v1/system/info or /v1/system/init.").optional()
|
|
21884
|
-
|
|
22365
|
+
api_key: external_exports.string().describe("GoodMem API key (starts with gm_). Omit for bootstrap-only sessions that call /v1/system/info or /v1/system/init.").optional(),
|
|
22366
|
+
stream_max_line_bytes: external_exports.number().int().positive().describe("Maximum size in bytes of a single NDJSON stream event (memories.retrieve, ping.stream). Events larger than this are rejected instead of buffering without bound. Defaults to 8388608 (8 MiB).").optional()
|
|
22367
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }, async (args) => {
|
|
21885
22368
|
if (!/^https?:\/\//i.test(args.base_url)) {
|
|
21886
22369
|
return { isError: true, content: [{ type: "text", text: `base_url must include a scheme (e.g., http://${args.base_url} or https://${args.base_url}).` }] };
|
|
21887
22370
|
}
|
|
@@ -21904,6 +22387,9 @@ server.tool("goodmem_configure", "Configure GoodMem server connection. Call this
|
|
|
21904
22387
|
const info = await resp.json().catch(() => ({}));
|
|
21905
22388
|
goodmemBaseUrl = args.base_url;
|
|
21906
22389
|
goodmemApiKey = args.api_key ?? "";
|
|
22390
|
+
if (args.stream_max_line_bytes !== void 0) {
|
|
22391
|
+
goodmemStreamMaxLineBytes = args.stream_max_line_bytes;
|
|
22392
|
+
}
|
|
21907
22393
|
const keyNote = goodmemApiKey === "" ? " (bootstrap-only session \u2014 no api_key set)" : "";
|
|
21908
22394
|
return { content: [{ type: "text", text: `Connected to GoodMem at ${goodmemBaseUrl}. Server version: ${info.version ?? "unknown"}.${keyNote}` }] };
|
|
21909
22395
|
} catch (err) {
|
|
@@ -21918,7 +22404,7 @@ server.tool("goodmem_configure", "Configure GoodMem server connection. Call this
|
|
|
21918
22404
|
server.tool("goodmem_lookup_model", "Look up a model in the registry to see its provider, endpoint, dimensions, and other auto-inferred fields. Use this to check what models are available before creating an embedder, LLM, or reranker.", {
|
|
21919
22405
|
model_identifier: external_exports.string().describe("Model name to look up (e.g., text-embedding-3-large, gpt-4o, rerank-2)"),
|
|
21920
22406
|
type: external_exports.enum(["embedder", "llm", "reranker"]).describe("Model type to search").optional()
|
|
21921
|
-
}, async (args) => {
|
|
22407
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
21922
22408
|
const searches = args.type ? [[args.type + "s", args.type]] : [["embedders", "embedder"], ["llms", "llm"], ["rerankers", "reranker"]];
|
|
21923
22409
|
for (const [registryKey, label] of searches) {
|
|
21924
22410
|
const registry2 = MODEL_REGISTRY[registryKey] ?? {};
|
|
@@ -21956,19 +22442,166 @@ server.tool("goodmem_lookup_model", "Look up a model in the registry to see its
|
|
|
21956
22442
|
return { content: [{ type: "text", text: `Model "${args.model_identifier}" not found in ${scope}. Available models:
|
|
21957
22443
|
${allModels.join("\n")}` }] };
|
|
21958
22444
|
});
|
|
21959
|
-
server.tool("goodmem_client_info", "Return the MCP client package version and the goodmem server commit it was built against. No server connection required.", {}, async () => {
|
|
22445
|
+
server.tool("goodmem_client_info", "Return the MCP client package version and the goodmem server commit it was built against. No server connection required.", {}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async () => {
|
|
21960
22446
|
return { content: [{ type: "text", text: JSON.stringify({
|
|
21961
|
-
mcp_version: "0.1.
|
|
22447
|
+
mcp_version: "0.1.19",
|
|
21962
22448
|
based_on_goodmem_commit: BASED_ON_GOODMEM_COMMIT
|
|
21963
22449
|
}, null, 2) }] };
|
|
21964
22450
|
});
|
|
21965
22451
|
function registerTools() {
|
|
22452
|
+
server.tool("goodmem_access_policy_check", "Check effective authorization\n\nEvaluates 1 to 50 concrete operation-and-target checks under the authenticated caller's live authority and any API-key ceiling. Results are positional and advisory: missing targets and denied operations both return allowed=false, and every later resource request performs fresh authorization. Top-level creates target INSTANCE; CREATE_MEMORY and LIST_MEMORY target their parent SPACE; reads, mutations, proxy operations, and access-policy administration target concrete resources. LIST_API_KEY and LIST_RETRIEVE_MEMORY_LOG_POLICY are rejected because their current candidate-based list rules have no instance-wide preflight.", {
|
|
22453
|
+
checks: external_exports.array(external_exports.object({
|
|
22454
|
+
operation: external_exports.enum(["CREATE_USER", "READ_USER", "UPDATE_USER", "DELETE_USER", "LIST_USER", "MANAGE_USER_ENROLLMENT", "CREATE_SERVICE_IDENTITY", "READ_SERVICE_IDENTITY", "UPDATE_SERVICE_IDENTITY", "DELETE_SERVICE_IDENTITY", "LIST_SERVICE_IDENTITY", "CREATE_SPACE", "READ_SPACE", "UPDATE_SPACE", "DELETE_SPACE", "LIST_SPACE", "CREATE_API_KEY", "READ_API_KEY", "UPDATE_API_KEY", "DELETE_API_KEY", "LIST_API_KEY", "CREATE_EMBEDDER", "READ_EMBEDDER", "UPDATE_EMBEDDER", "DELETE_EMBEDDER", "LIST_EMBEDDER", "PING_EMBEDDER", "EXECUTE_EMBEDDER", "READ_EMBEDDER_CREDENTIALS", "CREATE_RERANKER", "READ_RERANKER", "UPDATE_RERANKER", "DELETE_RERANKER", "LIST_RERANKER", "PING_RERANKER", "EXECUTE_RERANKER", "READ_RERANKER_CREDENTIALS", "CREATE_LLM", "READ_LLM", "UPDATE_LLM", "DELETE_LLM", "LIST_LLM", "PING_LLM", "EXECUTE_LLM", "READ_LLM_CREDENTIALS", "PROXY_INFERENCE_TARGET", "OCR_DOCUMENT", "CREATE_MEMORY", "READ_MEMORY", "DELETE_MEMORY", "LIST_MEMORY", "CREATE_EXTENSION", "READ_EXTENSION", "UPDATE_EXTENSION", "DELETE_EXTENSION", "LIST_EXTENSION", "DOWNLOAD_EXTENSION", "READ_INSTANCE", "TRANSFER_INSTANCE_OWNERSHIP", "TRANSFER_RESOURCE_OWNERSHIP", "RELOAD_LICENSE", "DRAIN_SERVER", "PURGE_BACKGROUND_JOBS", "CREATE_RETRIEVE_MEMORY_LOG_POLICY", "READ_RETRIEVE_MEMORY_LOG_POLICY", "LIST_RETRIEVE_MEMORY_LOG_POLICY", "DELETE_RETRIEVE_MEMORY_LOG_POLICY", "MANAGE_ACCESS"]).describe("Operation the caller proposes to perform."),
|
|
22455
|
+
target: external_exports.object({
|
|
22456
|
+
kind: external_exports.enum(["INSTANCE", "USER", "SERVICE_IDENTITY", "SPACE", "API_KEY", "EMBEDDER", "RERANKER", "LLM", "MEMORY", "EXTENSION", "RETRIEVE_MEMORY_LOG_POLICY"]).describe("Concrete target kind."),
|
|
22457
|
+
resourceId: external_exports.string().describe("Concrete resource UUID; omitted for the singleton INSTANCE target.").optional()
|
|
22458
|
+
}).passthrough().describe("Target required by the operation: INSTANCE for top-level creates, parent SPACE for CREATE_MEMORY or LIST_MEMORY, otherwise the concrete resource.")
|
|
22459
|
+
}).passthrough()).describe("Concrete checks evaluated in request order.")
|
|
22460
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22461
|
+
const body = {};
|
|
22462
|
+
if (args.checks !== void 0)
|
|
22463
|
+
body["checks"] = args.checks;
|
|
22464
|
+
const result = await callApi("POST", `/v1/access-policy:check`, body);
|
|
22465
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22466
|
+
});
|
|
22467
|
+
server.tool("goodmem_access_policy_grants_create", "Create an authorization grant\n\nCreates one direct grant after resolving its typed policy target and requiring MANAGE_ACCESS. Direct grants cannot confer credential-read or ownership-transfer authority. ALL_AUTHENTICATED grants require an assigned-resource selector. MANAGE_ACCESS and MANAGE_USER_ENROLLMENT require a concrete principal and ANY or EXACT; MANAGE_USER_ENROLLMENT with EXACT must target USER.", {
|
|
22468
|
+
grant_id: external_exports.string().describe("Optional caller-provided grant UUID.").optional(),
|
|
22469
|
+
audience: external_exports.object({
|
|
22470
|
+
principalId: external_exports.string().describe("Active HUMAN or SERVICE principal UUID.").optional(),
|
|
22471
|
+
allAuthenticated: external_exports.literal(true).describe("Set to true to address every authenticated principal.").optional()
|
|
22472
|
+
}).passthrough().describe("Audience receiving the grant."),
|
|
22473
|
+
rule: external_exports.object({
|
|
22474
|
+
operation: external_exports.enum(["CREATE_USER", "READ_USER", "UPDATE_USER", "DELETE_USER", "LIST_USER", "MANAGE_USER_ENROLLMENT", "CREATE_SERVICE_IDENTITY", "READ_SERVICE_IDENTITY", "UPDATE_SERVICE_IDENTITY", "DELETE_SERVICE_IDENTITY", "LIST_SERVICE_IDENTITY", "CREATE_SPACE", "READ_SPACE", "UPDATE_SPACE", "DELETE_SPACE", "LIST_SPACE", "CREATE_API_KEY", "READ_API_KEY", "UPDATE_API_KEY", "DELETE_API_KEY", "LIST_API_KEY", "CREATE_EMBEDDER", "READ_EMBEDDER", "UPDATE_EMBEDDER", "DELETE_EMBEDDER", "LIST_EMBEDDER", "PING_EMBEDDER", "EXECUTE_EMBEDDER", "READ_EMBEDDER_CREDENTIALS", "CREATE_RERANKER", "READ_RERANKER", "UPDATE_RERANKER", "DELETE_RERANKER", "LIST_RERANKER", "PING_RERANKER", "EXECUTE_RERANKER", "READ_RERANKER_CREDENTIALS", "CREATE_LLM", "READ_LLM", "UPDATE_LLM", "DELETE_LLM", "LIST_LLM", "PING_LLM", "EXECUTE_LLM", "READ_LLM_CREDENTIALS", "PROXY_INFERENCE_TARGET", "OCR_DOCUMENT", "CREATE_MEMORY", "READ_MEMORY", "DELETE_MEMORY", "LIST_MEMORY", "CREATE_EXTENSION", "READ_EXTENSION", "UPDATE_EXTENSION", "DELETE_EXTENSION", "LIST_EXTENSION", "DOWNLOAD_EXTENSION", "READ_INSTANCE", "TRANSFER_INSTANCE_OWNERSHIP", "TRANSFER_RESOURCE_OWNERSHIP", "RELOAD_LICENSE", "DRAIN_SERVER", "PURGE_BACKGROUND_JOBS", "CREATE_RETRIEVE_MEMORY_LOG_POLICY", "READ_RETRIEVE_MEMORY_LOG_POLICY", "LIST_RETRIEVE_MEMORY_LOG_POLICY", "DELETE_RETRIEVE_MEMORY_LOG_POLICY", "MANAGE_ACCESS"]).describe("Protected operation."),
|
|
22475
|
+
selector: external_exports.enum(["ANY", "OWN", "EXACT", "DIRECT_MEMBERS_OF"]).describe("Resource-selection semantics."),
|
|
22476
|
+
assignedResource: external_exports.object({
|
|
22477
|
+
kind: external_exports.enum(["INSTANCE", "USER", "SERVICE_IDENTITY", "SPACE", "API_KEY", "EMBEDDER", "RERANKER", "LLM", "MEMORY", "EXTENSION", "RETRIEVE_MEMORY_LOG_POLICY"]).describe("Concrete target kind."),
|
|
22478
|
+
resourceId: external_exports.string().describe("Concrete resource UUID; omitted for the singleton INSTANCE target.").optional()
|
|
22479
|
+
}).passthrough().describe("Required exactly for EXACT and DIRECT_MEMBERS_OF selectors.").optional()
|
|
22480
|
+
}).passthrough().describe("Authorization descriptor to grant.")
|
|
22481
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22482
|
+
const body = {};
|
|
22483
|
+
if (args.grant_id !== void 0)
|
|
22484
|
+
body["grantId"] = args.grant_id;
|
|
22485
|
+
if (args.audience !== void 0)
|
|
22486
|
+
body["audience"] = args.audience;
|
|
22487
|
+
if (args.rule !== void 0)
|
|
22488
|
+
body["rule"] = args.rule;
|
|
22489
|
+
const result = await callApi("POST", `/v1/access-policy/grants`, body);
|
|
22490
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22491
|
+
});
|
|
22492
|
+
server.tool("goodmem_access_policy_grants_delete", "Revoke an authorization grant\n\nSoft-revokes one grant and returns its durable historical row. Repeating the request is idempotent while the caller retains MANAGE_ACCESS on the target.", {
|
|
22493
|
+
id: external_exports.string().describe("Grant UUID")
|
|
22494
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22495
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
22496
|
+
throw new Error("'id' must be a non-empty string");
|
|
22497
|
+
}
|
|
22498
|
+
await callApi("DELETE", `/v1/access-policy/grants/${encodeURIComponent(String(args.id))}`, void 0);
|
|
22499
|
+
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
22500
|
+
});
|
|
22501
|
+
server.tool("goodmem_access_policy_grants_get", "Get an authorization grant\n\nReads one live grant, or one revoked historical grant when include_revoked is true, after requiring MANAGE_ACCESS on its policy target.", {
|
|
22502
|
+
id: external_exports.string().describe("Grant UUID"),
|
|
22503
|
+
include_revoked: external_exports.boolean().describe("Include a revoked historical row").optional()
|
|
22504
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22505
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
22506
|
+
throw new Error("'id' must be a non-empty string");
|
|
22507
|
+
}
|
|
22508
|
+
const query = {};
|
|
22509
|
+
if (args.include_revoked !== void 0)
|
|
22510
|
+
query["includeRevoked"] = String(args.include_revoked);
|
|
22511
|
+
const result = await callApi("GET", `/v1/access-policy/grants/${encodeURIComponent(String(args.id))}`, void 0, query);
|
|
22512
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22513
|
+
});
|
|
22514
|
+
server.tool("goodmem_access_policy_grants_list", "List authorization grants\n\nLists grants attached to one resource. MANAGE_ACCESS is required on that resource; continuation tokens are bound to the caller and filters.", {
|
|
22515
|
+
resource_kind: external_exports.enum(["INSTANCE", "USER", "SERVICE_IDENTITY", "SPACE", "API_KEY", "EMBEDDER", "RERANKER", "LLM", "MEMORY", "EXTENSION", "RETRIEVE_MEMORY_LOG_POLICY"]).describe("Required target resource kind"),
|
|
22516
|
+
resource_id: external_exports.string().describe("Required target UUID except when resource_kind is INSTANCE").optional(),
|
|
22517
|
+
include_revoked: external_exports.boolean().describe("Include revoked history").optional(),
|
|
22518
|
+
max_results: external_exports.number().int().describe("Page size; 0 or omission uses the default of 50, maximum 1,000").optional(),
|
|
22519
|
+
next_token: external_exports.string().describe("Opaque continuation token").optional()
|
|
22520
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22521
|
+
const query = {};
|
|
22522
|
+
if (args.resource_kind !== void 0)
|
|
22523
|
+
query["resourceKind"] = String(args.resource_kind);
|
|
22524
|
+
if (args.resource_id !== void 0)
|
|
22525
|
+
query["resourceId"] = String(args.resource_id);
|
|
22526
|
+
if (args.include_revoked !== void 0)
|
|
22527
|
+
query["includeRevoked"] = String(args.include_revoked);
|
|
22528
|
+
if (args.max_results !== void 0)
|
|
22529
|
+
query["maxResults"] = String(args.max_results);
|
|
22530
|
+
if (args.next_token !== void 0)
|
|
22531
|
+
query["nextToken"] = String(args.next_token);
|
|
22532
|
+
const result = await callApi("GET", `/v1/access-policy/grants`, void 0, query);
|
|
22533
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22534
|
+
});
|
|
22535
|
+
server.tool("goodmem_access_policy_role_assignments_create", "Assign a scoped role\n\nAssigns one code-defined role to an active principal at INSTANCE or SPACE scope after requiring MANAGE_ACCESS. ROOT is maintained only by ownership workflows.", {
|
|
22536
|
+
role_assignment_id: external_exports.string().describe("Optional caller-provided role-assignment UUID.").optional(),
|
|
22537
|
+
principal_id: external_exports.string().describe("Active principal receiving the role."),
|
|
22538
|
+
role: external_exports.enum(["ADMIN", "USER", "SPACE_VIEWER", "SPACE_CONTRIBUTOR", "SPACE_CONTENT_MANAGER", "SPACE_ADMIN"]).describe("Code-defined non-ROOT role to assign."),
|
|
22539
|
+
assigned_resource: external_exports.object({
|
|
22540
|
+
kind: external_exports.enum(["INSTANCE", "SPACE"]).describe("Role-assignment target kind."),
|
|
22541
|
+
resourceId: external_exports.string().describe("Memory-space UUID; omitted for the singleton INSTANCE target.").optional()
|
|
22542
|
+
}).passthrough().describe("INSTANCE or SPACE boundary receiving the assignment.")
|
|
22543
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22544
|
+
const body = {};
|
|
22545
|
+
if (args.role_assignment_id !== void 0)
|
|
22546
|
+
body["roleAssignmentId"] = args.role_assignment_id;
|
|
22547
|
+
if (args.principal_id !== void 0)
|
|
22548
|
+
body["principalId"] = args.principal_id;
|
|
22549
|
+
if (args.role !== void 0)
|
|
22550
|
+
body["role"] = args.role;
|
|
22551
|
+
if (args.assigned_resource !== void 0)
|
|
22552
|
+
body["assignedResource"] = args.assigned_resource;
|
|
22553
|
+
const result = await callApi("POST", `/v1/access-policy/role-assignments`, body);
|
|
22554
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22555
|
+
});
|
|
22556
|
+
server.tool("goodmem_access_policy_role_assignments_delete", "Revoke a scoped role assignment\n\nSoft-revokes one non-ROOT assignment and returns its durable historical row. Repeating the request is idempotent while the caller retains MANAGE_ACCESS.", {
|
|
22557
|
+
id: external_exports.string().describe("Role-assignment UUID")
|
|
22558
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22559
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
22560
|
+
throw new Error("'id' must be a non-empty string");
|
|
22561
|
+
}
|
|
22562
|
+
await callApi("DELETE", `/v1/access-policy/role-assignments/${encodeURIComponent(String(args.id))}`, void 0);
|
|
22563
|
+
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
22564
|
+
});
|
|
22565
|
+
server.tool("goodmem_access_policy_role_assignments_get", "Get a scoped role assignment\n\nReads one live assignment, or one revoked historical assignment when include_revoked is true, after requiring MANAGE_ACCESS on its policy target.", {
|
|
22566
|
+
id: external_exports.string().describe("Role-assignment UUID"),
|
|
22567
|
+
include_revoked: external_exports.boolean().describe("Include a revoked historical row").optional()
|
|
22568
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22569
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
22570
|
+
throw new Error("'id' must be a non-empty string");
|
|
22571
|
+
}
|
|
22572
|
+
const query = {};
|
|
22573
|
+
if (args.include_revoked !== void 0)
|
|
22574
|
+
query["includeRevoked"] = String(args.include_revoked);
|
|
22575
|
+
const result = await callApi("GET", `/v1/access-policy/role-assignments/${encodeURIComponent(String(args.id))}`, void 0, query);
|
|
22576
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22577
|
+
});
|
|
22578
|
+
server.tool("goodmem_access_policy_role_assignments_list", "List scoped role assignments\n\nLists assignments attached to one required INSTANCE or SPACE boundary after requiring MANAGE_ACCESS. Continuation tokens are bound to the caller and filters.", {
|
|
22579
|
+
resource_kind: external_exports.enum(["INSTANCE", "SPACE"]).describe("Required INSTANCE or SPACE kind"),
|
|
22580
|
+
resource_id: external_exports.string().describe("Required space UUID; omitted for INSTANCE").optional(),
|
|
22581
|
+
include_revoked: external_exports.boolean().describe("Include revoked history").optional(),
|
|
22582
|
+
max_results: external_exports.number().int().describe("Page size; 0 or omission uses the default of 50, maximum 1,000").optional(),
|
|
22583
|
+
next_token: external_exports.string().describe("Opaque continuation token").optional()
|
|
22584
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22585
|
+
const query = {};
|
|
22586
|
+
if (args.resource_kind !== void 0)
|
|
22587
|
+
query["resourceKind"] = String(args.resource_kind);
|
|
22588
|
+
if (args.resource_id !== void 0)
|
|
22589
|
+
query["resourceId"] = String(args.resource_id);
|
|
22590
|
+
if (args.include_revoked !== void 0)
|
|
22591
|
+
query["includeRevoked"] = String(args.include_revoked);
|
|
22592
|
+
if (args.max_results !== void 0)
|
|
22593
|
+
query["maxResults"] = String(args.max_results);
|
|
22594
|
+
if (args.next_token !== void 0)
|
|
22595
|
+
query["nextToken"] = String(args.next_token);
|
|
22596
|
+
const result = await callApi("GET", `/v1/access-policy/role-assignments`, void 0, query);
|
|
22597
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22598
|
+
});
|
|
21966
22599
|
server.tool("goodmem_admin_background_jobs_purge", "Purge completed background jobs\n\nDeletes terminal background jobs older than a retention cutoff.", {
|
|
21967
22600
|
older_than: external_exports.string().describe("ISO-8601 timestamp cutoff; only terminal jobs older than this instant are eligible."),
|
|
21968
22601
|
statuses: external_exports.array(external_exports.enum(["BACKGROUND_JOB_SUCCEEDED", "BACKGROUND_JOB_FAILED", "BACKGROUND_JOB_CANCELED"])).describe("Optional terminal background job statuses to target for purging. If omitted, all terminal statuses are eligible. Canonical values are BACKGROUND_JOB_SUCCEEDED, BACKGROUND_JOB_FAILED, and BACKGROUND_JOB_CANCELED. Short aliases SUCCEEDED, FAILED, and CANCELED are also accepted for compatibility.").optional(),
|
|
21969
22602
|
dry_run: external_exports.boolean().describe("If true, report purge counts without deleting any rows.").optional(),
|
|
21970
22603
|
limit: external_exports.number().int().describe("Maximum number of jobs to purge in this request. Must be >= 0; 0 means no limit.").optional()
|
|
21971
|
-
}, async (args) => {
|
|
22604
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
21972
22605
|
const body = {};
|
|
21973
22606
|
if (args.older_than !== void 0)
|
|
21974
22607
|
body["olderThan"] = args.older_than;
|
|
@@ -21985,7 +22618,7 @@ function registerTools() {
|
|
|
21985
22618
|
timeout_sec: external_exports.number().int().describe("Maximum seconds to wait for the server to quiesce before returning.").optional(),
|
|
21986
22619
|
reason: external_exports.string().describe("Human-readable reason for initiating drain mode.").optional(),
|
|
21987
22620
|
wait_for_quiesce: external_exports.boolean().describe("If true, wait for in-flight requests to complete and the server to reach QUIESCED before responding.").optional()
|
|
21988
|
-
}, async (args) => {
|
|
22621
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
21989
22622
|
const body = {};
|
|
21990
22623
|
if (args.timeout_sec !== void 0)
|
|
21991
22624
|
body["timeoutSec"] = args.timeout_sec;
|
|
@@ -21996,7 +22629,7 @@ function registerTools() {
|
|
|
21996
22629
|
const result = await callApi("POST", `/v1/admin:drain`, body, void 0, ((args.timeout_sec ?? 900) + 30) * 1e3);
|
|
21997
22630
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
21998
22631
|
});
|
|
21999
|
-
server.tool("goodmem_admin_license_reload", "Reload the active license from disk\n\nTriggers the server to reload its license file from the configured directory and returns metadata about the currently active license.", {}, async (args) => {
|
|
22632
|
+
server.tool("goodmem_admin_license_reload", "Reload the active license from disk\n\nTriggers the server to reload its license file from the configured directory and returns metadata about the currently active license.", {}, { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22000
22633
|
const result = await callApi("POST", `/v1/admin/license:reload`, void 0);
|
|
22001
22634
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22002
22635
|
});
|
|
@@ -22017,7 +22650,7 @@ function registerTools() {
|
|
|
22017
22650
|
active_from: external_exports.number().int().describe("Inclusive activation time in milliseconds since epoch.").optional(),
|
|
22018
22651
|
active_until: external_exports.number().int().describe("Exclusive deactivation time in milliseconds since epoch.").optional(),
|
|
22019
22652
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Operator labels for listing and administration.").optional()
|
|
22020
|
-
}, async (args) => {
|
|
22653
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22021
22654
|
const body = {};
|
|
22022
22655
|
if (args.policy_id !== void 0)
|
|
22023
22656
|
body["policyId"] = args.policy_id;
|
|
@@ -22039,7 +22672,7 @@ function registerTools() {
|
|
|
22039
22672
|
server.tool("goodmem_admin_retrieve_memory_log_policies_delete", "Delete a RetrieveMemory log policy\n\nIdempotently tombstones an immutable RetrieveMemory log policy.", {
|
|
22040
22673
|
id: external_exports.string().describe("The UUID of the policy to delete"),
|
|
22041
22674
|
reason: external_exports.string().describe("Optional tombstone reason.").optional()
|
|
22042
|
-
}, async (args) => {
|
|
22675
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22043
22676
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22044
22677
|
throw new Error("'id' must be a non-empty string");
|
|
22045
22678
|
}
|
|
@@ -22052,7 +22685,7 @@ function registerTools() {
|
|
|
22052
22685
|
server.tool("goodmem_admin_retrieve_memory_log_policies_get", "Get a RetrieveMemory log policy\n\nRetrieves a live RetrieveMemory log policy by UUID, or a tombstoned policy when include_deleted is true.", {
|
|
22053
22686
|
id: external_exports.string().describe("The UUID of the policy to retrieve"),
|
|
22054
22687
|
include_deleted: external_exports.boolean().describe("Whether to include tombstoned policies. Also accepts include_deleted.").optional()
|
|
22055
|
-
}, async (args) => {
|
|
22688
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22056
22689
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22057
22690
|
throw new Error("'id' must be a non-empty string");
|
|
22058
22691
|
}
|
|
@@ -22071,7 +22704,7 @@ function registerTools() {
|
|
|
22071
22704
|
sort_by: external_exports.enum(["created_at", "updated_at", "display_name"]).describe("Sort field: created_at, updated_at, or display_name. Also accepts sort_by.").optional(),
|
|
22072
22705
|
sort_order: external_exports.enum(["ASCENDING", "DESCENDING", "SORT_ORDER_UNSPECIFIED"]).describe("Sort order. Also accepts sort_order.").optional(),
|
|
22073
22706
|
label: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by label. Each key-value pair is sent as label[key]=value query parameter.").optional()
|
|
22074
|
-
}, async (args) => {
|
|
22707
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22075
22708
|
const query = {};
|
|
22076
22709
|
if (args.include_deleted !== void 0)
|
|
22077
22710
|
query["includeDeleted"] = String(args.include_deleted);
|
|
@@ -22094,11 +22727,31 @@ function registerTools() {
|
|
|
22094
22727
|
const result = await callApi("GET", `/v1/admin/retrieve-memory-log-policies`, void 0, query);
|
|
22095
22728
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22096
22729
|
});
|
|
22097
|
-
server.tool("
|
|
22098
|
-
|
|
22099
|
-
|
|
22100
|
-
|
|
22101
|
-
|
|
22730
|
+
server.tool("goodmem_admin_transfer_instance_ownership", "Transfer GoodMem instance ownership\n\nTransfers the singleton GoodMem instance to another active human principal. Only the current instance owner may invoke this operation; ADMIN, MANAGE_ACCESS, and ordinary grants are insufficient. Ownership and the synthetic ROOT assignment move atomically. All ordinary roles, including ADMIN, remain unchanged. No credential is created or returned. After an unknown outcome, read the current owner before retrying.", {
|
|
22731
|
+
new_owner_id: external_exports.string().describe("Existing principal UUID that will become the new owner.")
|
|
22732
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22733
|
+
const body = {};
|
|
22734
|
+
if (args.new_owner_id !== void 0)
|
|
22735
|
+
body["newOwnerId"] = args.new_owner_id;
|
|
22736
|
+
const result = await callApi("POST", `/v1/admin:transferInstanceOwnership`, body);
|
|
22737
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22738
|
+
});
|
|
22739
|
+
server.tool("goodmem_apikeys_create", "Create a new API key\n\nIssues a new API key and returns its raw value exactly once. Omitted subject and authority_mode create a self-issued human key that inherits the subject's live authority. A SCOPED key requires a nonempty immutable ceiling, and every ceiling rule must be conservatively covered by both the subject's live authority and the issuing credential's effective authority. A scoped issuer can create only scoped children. SERVICE subjects require SCOPED mode and MANAGE_ACCESS on the service identity. AUTHORIZATION: Requires CREATE_API_KEY on the proposed credential; subject and ceiling checks are repeated by the final insertion statement.", {
|
|
22740
|
+
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Key-value pairs of metadata associated with the API key. Used for organization and filtering. At most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional(),
|
|
22741
|
+
expires_at: external_exports.number().int().describe("Exclusive expiration timestamp in milliseconds since epoch. It must be later than valid_from, which defaults to issuance time; if omitted, the key does not expire.").optional(),
|
|
22742
|
+
api_key_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional(),
|
|
22743
|
+
subject_principal_id: external_exports.string().describe("Principal authenticated by this key. Omit to use the authenticated principal.").optional(),
|
|
22744
|
+
authority_mode: external_exports.enum(["INHERIT_SUBJECT", "SCOPED"]).describe("Authority mode. Omit to create a self-issued human key that inherits live authority. A scoped issuing credential may create only SCOPED children.").optional(),
|
|
22745
|
+
ceiling: external_exports.array(external_exports.object({
|
|
22746
|
+
operation: external_exports.enum(["CREATE_USER", "READ_USER", "UPDATE_USER", "DELETE_USER", "LIST_USER", "MANAGE_USER_ENROLLMENT", "CREATE_SERVICE_IDENTITY", "READ_SERVICE_IDENTITY", "UPDATE_SERVICE_IDENTITY", "DELETE_SERVICE_IDENTITY", "LIST_SERVICE_IDENTITY", "CREATE_SPACE", "READ_SPACE", "UPDATE_SPACE", "DELETE_SPACE", "LIST_SPACE", "CREATE_API_KEY", "READ_API_KEY", "UPDATE_API_KEY", "DELETE_API_KEY", "LIST_API_KEY", "CREATE_EMBEDDER", "READ_EMBEDDER", "UPDATE_EMBEDDER", "DELETE_EMBEDDER", "LIST_EMBEDDER", "PING_EMBEDDER", "EXECUTE_EMBEDDER", "READ_EMBEDDER_CREDENTIALS", "CREATE_RERANKER", "READ_RERANKER", "UPDATE_RERANKER", "DELETE_RERANKER", "LIST_RERANKER", "PING_RERANKER", "EXECUTE_RERANKER", "READ_RERANKER_CREDENTIALS", "CREATE_LLM", "READ_LLM", "UPDATE_LLM", "DELETE_LLM", "LIST_LLM", "PING_LLM", "EXECUTE_LLM", "READ_LLM_CREDENTIALS", "PROXY_INFERENCE_TARGET", "OCR_DOCUMENT", "CREATE_MEMORY", "READ_MEMORY", "DELETE_MEMORY", "LIST_MEMORY", "CREATE_EXTENSION", "READ_EXTENSION", "UPDATE_EXTENSION", "DELETE_EXTENSION", "LIST_EXTENSION", "DOWNLOAD_EXTENSION", "READ_INSTANCE", "TRANSFER_INSTANCE_OWNERSHIP", "TRANSFER_RESOURCE_OWNERSHIP", "RELOAD_LICENSE", "DRAIN_SERVER", "PURGE_BACKGROUND_JOBS", "CREATE_RETRIEVE_MEMORY_LOG_POLICY", "READ_RETRIEVE_MEMORY_LOG_POLICY", "LIST_RETRIEVE_MEMORY_LOG_POLICY", "DELETE_RETRIEVE_MEMORY_LOG_POLICY", "MANAGE_ACCESS"]).describe("Protected operation."),
|
|
22747
|
+
selector: external_exports.enum(["ANY", "OWN", "EXACT", "DIRECT_MEMBERS_OF"]).describe("Resource-selection semantics."),
|
|
22748
|
+
assignedResource: external_exports.object({
|
|
22749
|
+
kind: external_exports.enum(["INSTANCE", "USER", "SERVICE_IDENTITY", "SPACE", "API_KEY", "EMBEDDER", "RERANKER", "LLM", "MEMORY", "EXTENSION", "RETRIEVE_MEMORY_LOG_POLICY"]).describe("Concrete target kind."),
|
|
22750
|
+
resourceId: external_exports.string().describe("Concrete resource UUID; omitted for the singleton INSTANCE target.").optional()
|
|
22751
|
+
}).passthrough().describe("Required exactly for EXACT and DIRECT_MEMBERS_OF selectors.").optional()
|
|
22752
|
+
}).passthrough()).describe("Immutable authorization ceiling. Required and nonempty for SCOPED; omitted for INHERIT_SUBJECT, with at most 1,000 rules. Every rule must be covered by both the subject's live authority and the issuing credential's effective authority.").optional(),
|
|
22753
|
+
valid_from: external_exports.number().int().describe("Inclusive activation time in epoch milliseconds. Omit to activate at issuance time.").optional()
|
|
22754
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22102
22755
|
const body = {};
|
|
22103
22756
|
if (args.labels !== void 0)
|
|
22104
22757
|
body["labels"] = args.labels;
|
|
@@ -22106,28 +22759,65 @@ function registerTools() {
|
|
|
22106
22759
|
body["expiresAt"] = args.expires_at;
|
|
22107
22760
|
if (args.api_key_id !== void 0)
|
|
22108
22761
|
body["apiKeyId"] = args.api_key_id;
|
|
22762
|
+
if (args.subject_principal_id !== void 0)
|
|
22763
|
+
body["subjectPrincipalId"] = args.subject_principal_id;
|
|
22764
|
+
if (args.authority_mode !== void 0)
|
|
22765
|
+
body["authorityMode"] = args.authority_mode;
|
|
22766
|
+
if (args.ceiling !== void 0)
|
|
22767
|
+
body["ceiling"] = args.ceiling;
|
|
22768
|
+
if (args.valid_from !== void 0)
|
|
22769
|
+
body["validFrom"] = args.valid_from;
|
|
22109
22770
|
const result = await callApi("POST", `/v1/apikeys`, body);
|
|
22110
22771
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22111
22772
|
});
|
|
22112
|
-
server.tool("goodmem_apikeys_delete", 'Delete an API key\n\nPermanently
|
|
22773
|
+
server.tool("goodmem_apikeys_delete", 'Delete an API key\n\nPermanently revokes an API key and immediately rejects it for future authentication. The durable credential and audit history remain stored. This operation requires DELETE_API_KEY and records the revocation time and actor; it cannot be undone. The `goodmem_apikeys_update` tool with `status: "INACTIVE"` performs the same permanent revocation; revoked keys cannot be reactivated.', {
|
|
22113
22774
|
id: external_exports.string().describe("The UUID of the API key to delete")
|
|
22114
|
-
}, async (args) => {
|
|
22775
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22115
22776
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22116
22777
|
throw new Error("'id' must be a non-empty string");
|
|
22117
22778
|
}
|
|
22118
22779
|
await callApi("DELETE", `/v1/apikeys/${encodeURIComponent(String(args.id))}`, void 0);
|
|
22119
22780
|
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
22120
22781
|
});
|
|
22121
|
-
server.tool("
|
|
22122
|
-
|
|
22782
|
+
server.tool("goodmem_apikeys_get", "Get an API key\n\nReturns complete non-secret metadata for one existing credential after requiring effective READ_API_KEY authority. The immutable ceiling is always complete and ceilingOmitted is false. Raw key material and hashes are never returned.", {
|
|
22783
|
+
id: external_exports.string().describe("API-key UUID")
|
|
22784
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22785
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
22786
|
+
throw new Error("'id' must be a non-empty string");
|
|
22787
|
+
}
|
|
22788
|
+
const result = await callApi("GET", `/v1/apikeys/${encodeURIComponent(String(args.id))}`, void 0);
|
|
22789
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22790
|
+
});
|
|
22791
|
+
server.tool("goodmem_apikeys_list", "List API keys\n\nRetrieves one UUID-ordered page of API keys discoverable under the authenticated principal's effective API-key policy. Subject, owner, and lifecycle filters are applied after authorization. FULL includes complete immutable ceilings; BASIC omits them, sets ceilingOmitted=true, and permits larger pages. Raw key values and key hashes are never returned.", {
|
|
22792
|
+
subject_principal_id: external_exports.string().describe("Filter by exact subject-principal UUID").optional(),
|
|
22793
|
+
owner_principal_id: external_exports.string().describe("Filter by exact administrative-owner UUID").optional(),
|
|
22794
|
+
lifecycle_state: external_exports.enum(["NOT_YET_VALID", "USABLE", "EXPIRED", "REVOKED"]).describe("Filter by precise lifecycle state").optional(),
|
|
22795
|
+
view: external_exports.enum(["FULL", "BASIC"]).describe("Metadata projection; omission defaults to FULL").optional(),
|
|
22796
|
+
max_results: external_exports.number().int().describe("Page size; FULL defaults to 10 and permits at most 20, while BASIC defaults to 50 and permits at most 1,000").optional(),
|
|
22797
|
+
next_token: external_exports.string().describe("Opaque continuation token returned by the preceding page").optional()
|
|
22798
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22799
|
+
const query = {};
|
|
22800
|
+
if (args.subject_principal_id !== void 0)
|
|
22801
|
+
query["subjectPrincipalId"] = String(args.subject_principal_id);
|
|
22802
|
+
if (args.owner_principal_id !== void 0)
|
|
22803
|
+
query["ownerPrincipalId"] = String(args.owner_principal_id);
|
|
22804
|
+
if (args.lifecycle_state !== void 0)
|
|
22805
|
+
query["lifecycleState"] = String(args.lifecycle_state);
|
|
22806
|
+
if (args.view !== void 0)
|
|
22807
|
+
query["view"] = String(args.view);
|
|
22808
|
+
if (args.max_results !== void 0)
|
|
22809
|
+
query["maxResults"] = String(args.max_results);
|
|
22810
|
+
if (args.next_token !== void 0)
|
|
22811
|
+
query["nextToken"] = String(args.next_token);
|
|
22812
|
+
const result = await callApi("GET", `/v1/apikeys`, void 0, query);
|
|
22123
22813
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22124
22814
|
});
|
|
22125
|
-
server.tool("goodmem_apikeys_update", "Update an API key\n\nUpdates an existing API key
|
|
22815
|
+
server.tool("goodmem_apikeys_update", "Update an API key\n\nUpdates an existing API key's labels or lifecycle status. Key ID, subject, ownership, key material, validity window, and creation audit fields remain immutable. Label changes require UPDATE_API_KEY; setting status=INACTIVE permanently revokes the key and requires DELETE_API_KEY; a request doing both requires both operations. Revoked keys cannot be reactivated. Side effects include updating administrative audit fields and, for revocation, recording the revocation time and actor.", {
|
|
22126
22816
|
id: external_exports.string().describe("The UUID of the API key to update"),
|
|
22127
|
-
status: external_exports.enum(["ACTIVE", "INACTIVE"]).describe("New status for the API key.
|
|
22128
|
-
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with this set. Mutually exclusive with merge_labels.").optional(),
|
|
22129
|
-
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones. Mutually exclusive with replace_labels.").optional()
|
|
22130
|
-
}, async (args) => {
|
|
22817
|
+
status: external_exports.enum(["ACTIVE", "INACTIVE"]).describe("New status for the API key. INACTIVE is permanent; revoked keys cannot be reactivated.").optional(),
|
|
22818
|
+
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with this set. Mutually exclusive with merge_labels. The stored map may contain at most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional(),
|
|
22819
|
+
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones. Mutually exclusive with replace_labels. The final stored map may contain at most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional()
|
|
22820
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22131
22821
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22132
22822
|
throw new Error("'id' must be a non-empty string");
|
|
22133
22823
|
}
|
|
@@ -22145,12 +22835,12 @@ function registerTools() {
|
|
|
22145
22835
|
const result = await callApi("PUT", `/v1/apikeys/${encodeURIComponent(String(args.id))}`, body);
|
|
22146
22836
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22147
22837
|
});
|
|
22148
|
-
server.tool("goodmem_embedders_create", "Create a new embedder\n\nCreates
|
|
22838
|
+
server.tool("goodmem_embedders_create", "Create a new embedder\n\nCreates an embedder configuration for use with memory spaces. If owner_id is omitted, the authenticated principal becomes the owner; CREATE_EMBEDDER is evaluated against that proposed embedder and owner. Returns 409 when an equivalent embedder configuration already exists for the owner. See the [embedder provider guide](https://github.com/PAIR-Systems-Inc/goodmem/blob/main/docs/guides/embedder-providers.md) for provider-specific configuration.", {
|
|
22149
22839
|
display_name: external_exports.string().describe("User-facing name of the embedder"),
|
|
22150
22840
|
description: external_exports.string().describe("Description of the embedder").optional(),
|
|
22151
|
-
provider_type: external_exports.enum(["OPENAI", "VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA"]).describe("Type of embedding provider (auto-inferred from model_identifier if omitted)").optional(),
|
|
22152
|
-
endpoint_url: external_exports.string().describe("
|
|
22153
|
-
api_path: external_exports.string().describe("
|
|
22841
|
+
provider_type: external_exports.enum(["OPENAI", "VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA", "DASHSCOPE", "GEMINI"]).describe("Type of embedding provider (auto-inferred from model_identifier if omitted)").optional(),
|
|
22842
|
+
endpoint_url: external_exports.string().describe("Base HTTP(S) endpoint for provider requests. Gemini endpoint URLs must not contain query parameters. (auto-inferred from model_identifier if omitted)").optional(),
|
|
22843
|
+
api_path: external_exports.string().describe("Provider-relative request path. Omit or send blank to use the provider default. For Gemini, this is an API version: /v1beta for Developer and /v1 for Google Cloud.").optional(),
|
|
22154
22844
|
model_identifier: external_exports.string().describe("Model identifier"),
|
|
22155
22845
|
dimensionality: external_exports.number().int().describe("Output vector dimensions (auto-inferred from model_identifier if omitted)").optional(),
|
|
22156
22846
|
distribution_type: external_exports.enum(["DENSE", "SPARSE"]).describe("Type of embedding distribution (DENSE or SPARSE) (auto-inferred from model_identifier if omitted)").optional(),
|
|
@@ -22176,9 +22866,15 @@ function registerTools() {
|
|
|
22176
22866
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
|
|
22177
22867
|
version: external_exports.string().describe("Version information").optional(),
|
|
22178
22868
|
monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
|
|
22179
|
-
owner_id: external_exports.string().describe("Optional owner
|
|
22180
|
-
embedder_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional()
|
|
22181
|
-
|
|
22869
|
+
owner_id: external_exports.string().describe("Optional owner principal UUID. If omitted, defaults to the authenticated principal. CREATE_EMBEDDER is evaluated against the proposed embedder and owner.").optional(),
|
|
22870
|
+
embedder_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional(),
|
|
22871
|
+
dashscope_api_dialect: external_exports.enum(["EMBEDDING_NATIVE_TEXT", "EMBEDDING_NATIVE_CONTENTS", "OPENAI_COMPATIBLE"]).describe("DashScope request and response API dialect. Valid only for the DASHSCOPE provider. Omit to infer the dialect from api_path, the model catalog, or the native text default.").optional(),
|
|
22872
|
+
gemini_endpoint_config: external_exports.object({
|
|
22873
|
+
backend: external_exports.enum(["UNSPECIFIED", "DEVELOPER", "GOOGLE_CLOUD"]).describe("Google API surface. UNSPECIFIED is invalid when this configuration is supplied on a write."),
|
|
22874
|
+
projectId: external_exports.string().describe("Google Cloud resource project. Required for GOOGLE_CLOUD and unused for DEVELOPER; this is distinct from the ADC quota project.").optional(),
|
|
22875
|
+
location: external_exports.string().describe("Google Cloud location. Valid only for GOOGLE_CLOUD; omission defaults to global.").optional()
|
|
22876
|
+
}).passthrough().describe("Gemini backend routing. Valid only for the GEMINI provider. Omit to use the Developer API; when present, backend is required and the gRPC service validates the backend-specific projectId and location contract.").optional()
|
|
22877
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22182
22878
|
const inferred = autoInferFromRegistry("embedders", args);
|
|
22183
22879
|
checkCredentialRequired(inferred);
|
|
22184
22880
|
const body = {};
|
|
@@ -22214,32 +22910,40 @@ function registerTools() {
|
|
|
22214
22910
|
body["ownerId"] = inferred.owner_id;
|
|
22215
22911
|
if (inferred.embedder_id !== void 0)
|
|
22216
22912
|
body["embedderId"] = inferred.embedder_id;
|
|
22913
|
+
if (inferred.dashscope_api_dialect !== void 0)
|
|
22914
|
+
body["dashscopeApiDialect"] = inferred.dashscope_api_dialect;
|
|
22915
|
+
if (inferred.gemini_endpoint_config !== void 0)
|
|
22916
|
+
body["geminiEndpointConfig"] = inferred.gemini_endpoint_config;
|
|
22217
22917
|
const result = await callApi("POST", `/v1/embedders`, body);
|
|
22218
22918
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22219
22919
|
});
|
|
22220
|
-
server.tool("goodmem_embedders_delete", "Delete an embedder\n\nPermanently deletes an embedder configuration. This operation cannot be undone and removes the embedder record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete embeddings previously created with this embedder - existing embeddings remain accessible. CONFLICT: Returns HTTP 409 Conflict if the embedder is still referenced by a space. Requires
|
|
22920
|
+
server.tool("goodmem_embedders_delete", "Delete an embedder\n\nPermanently deletes an embedder configuration. This operation cannot be undone and removes the embedder record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete embeddings previously created with this embedder - existing embeddings remain accessible. CONFLICT: Returns HTTP 409 Conflict if the embedder is still referenced by a space. Requires DELETE_EMBEDDER on the requested embedder.", {
|
|
22221
22921
|
id: external_exports.string().describe("The unique identifier of the embedder to delete")
|
|
22222
|
-
}, async (args) => {
|
|
22922
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22223
22923
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22224
22924
|
throw new Error("'id' must be a non-empty string");
|
|
22225
22925
|
}
|
|
22226
22926
|
await callApi("DELETE", `/v1/embedders/${encodeURIComponent(String(args.id))}`, void 0);
|
|
22227
22927
|
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
22228
22928
|
});
|
|
22229
|
-
server.tool("goodmem_embedders_get", "Get an embedder by ID\n\nRetrieves the details of a specific embedder configuration by its unique identifier. Requires
|
|
22230
|
-
id: external_exports.string().describe("The unique identifier of the embedder to retrieve")
|
|
22231
|
-
|
|
22929
|
+
server.tool("goodmem_embedders_get", "Get an embedder by ID\n\nRetrieves the details of a specific embedder configuration by its unique identifier. Requires READ_EMBEDDER on the requested embedder. The service distinguishes a missing embedder from an existing embedder the caller cannot read. This is a read-only operation with no side effects.", {
|
|
22930
|
+
id: external_exports.string().describe("The unique identifier of the embedder to retrieve"),
|
|
22931
|
+
include_credentials: external_exports.boolean().describe("Whether to return stored credentials. Also accepts include_credentials. Requires READ_EMBEDDER_CREDENTIALS in addition to READ_EMBEDDER.").optional()
|
|
22932
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22232
22933
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22233
22934
|
throw new Error("'id' must be a non-empty string");
|
|
22234
22935
|
}
|
|
22235
|
-
const
|
|
22936
|
+
const query = {};
|
|
22937
|
+
if (args.include_credentials !== void 0)
|
|
22938
|
+
query["includeCredentials"] = String(args.include_credentials);
|
|
22939
|
+
const result = await callApi("GET", `/v1/embedders/${encodeURIComponent(String(args.id))}`, void 0, query);
|
|
22236
22940
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22237
22941
|
});
|
|
22238
|
-
server.tool("goodmem_embedders_list", "List embedders\n\nRetrieves a list of embedder configurations accessible to the caller, with optional filtering. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production).
|
|
22239
|
-
owner_id: external_exports.string().describe("Filter
|
|
22240
|
-
provider_type: external_exports.enum(["OPENAI", "VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA"]).describe("Filter embedders by provider type. Allowed values match the ProviderType schema.").optional(),
|
|
22942
|
+
server.tool("goodmem_embedders_list", "List embedders\n\nRetrieves a list of embedder configurations accessible to the caller, with optional filtering. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production). AUTHORIZATION: Requires LIST_EMBEDDER on the GoodMem instance. Each returned embedder must also be visible through READ_EMBEDDER; unauthorized embedders are filtered in PostgreSQL. The owner_id parameter filters that already-authorized result set and does not grant additional visibility. This is a read-only operation with no side effects.", {
|
|
22943
|
+
owner_id: external_exports.string().describe("Filter the already-authorized result set by owner principal UUID. Omitting this parameter does not bypass per-embedder READ_EMBEDDER filtering.").optional(),
|
|
22944
|
+
provider_type: external_exports.enum(["OPENAI", "VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA", "DASHSCOPE", "GEMINI"]).describe("Filter embedders by provider type. Allowed values match the ProviderType schema.").optional(),
|
|
22241
22945
|
label: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by label. Each key-value pair is sent as label[key]=value query parameter.").optional()
|
|
22242
|
-
}, async (args) => {
|
|
22946
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22243
22947
|
const query = {};
|
|
22244
22948
|
if (args.owner_id !== void 0)
|
|
22245
22949
|
query["ownerId"] = String(args.owner_id);
|
|
@@ -22252,12 +22956,12 @@ function registerTools() {
|
|
|
22252
22956
|
const result = await callApi("GET", `/v1/embedders`, void 0, query);
|
|
22253
22957
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22254
22958
|
});
|
|
22255
|
-
server.tool("goodmem_embedders_update", "Update an embedder\n\nUpdates
|
|
22959
|
+
server.tool("goodmem_embedders_update", "Update an embedder\n\nUpdates explicitly supplied embedder fields; at least one mutable field is required. Field omission and reset semantics are defined by the request schema, and providerType cannot be changed. Returns 409 if the resulting configuration duplicates another embedder for the owner, and 412 when model-defining fields are changed while the embedder is in use. Requires UPDATE_EMBEDDER on the requested embedder. See the [embedder provider guide](https://github.com/PAIR-Systems-Inc/goodmem/blob/main/docs/guides/embedder-providers.md) for provider-specific configuration.", {
|
|
22256
22960
|
id: external_exports.string().describe("The unique identifier of the embedder to update"),
|
|
22257
22961
|
display_name: external_exports.string().describe("User-facing name of the embedder").optional(),
|
|
22258
22962
|
description: external_exports.string().describe("Description of the embedder").optional(),
|
|
22259
|
-
endpoint_url: external_exports.string().describe("
|
|
22260
|
-
api_path: external_exports.string().describe("
|
|
22963
|
+
endpoint_url: external_exports.string().describe("Replacement base HTTP(S) endpoint. Omit to preserve the stored value. Gemini endpoint URLs must not contain query parameters.").optional(),
|
|
22964
|
+
api_path: external_exports.string().describe("Replacement provider-relative request path. Omit to preserve the stored value, except that changing the Gemini backend without api_path selects that backend's default; send blank to restore the provider default. For Gemini, this is an API version: /v1beta for Developer and /v1 for Google Cloud.").optional(),
|
|
22261
22965
|
model_identifier: external_exports.string().describe("Model identifier").optional(),
|
|
22262
22966
|
dimensionality: external_exports.number().int().describe("Output vector dimensions").optional(),
|
|
22263
22967
|
distribution_type: external_exports.enum(["DENSE", "SPARSE"]).describe("Type of embedding distribution (DENSE or SPARSE)").optional(),
|
|
@@ -22278,12 +22982,18 @@ function registerTools() {
|
|
|
22278
22982
|
quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
|
|
22279
22983
|
}).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
|
|
22280
22984
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
|
|
22281
|
-
}).passthrough().describe("
|
|
22985
|
+
}).passthrough().describe("Replace stored credentials. Omit this field to preserve the current credentials; a present empty payload is invalid and never clears them.").optional(),
|
|
22282
22986
|
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with these (mutually exclusive with merge_labels)").optional(),
|
|
22283
22987
|
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones (mutually exclusive with replace_labels)").optional(),
|
|
22284
22988
|
version: external_exports.string().describe("Version information").optional(),
|
|
22285
|
-
monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
|
|
22286
|
-
|
|
22989
|
+
monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
|
|
22990
|
+
dashscope_api_dialect: external_exports.enum(["EMBEDDING_NATIVE_TEXT", "EMBEDDING_NATIVE_CONTENTS", "OPENAI_COMPATIBLE"]).describe("Update the DashScope request and response API dialect. Valid only for the DASHSCOPE provider. Omit to preserve the stored dialect. Changing api_path to a recognized canonical DashScope dialect infers its matching dialect; a custom path preserves an existing dialect, while a legacy null dialect is inferred.").optional(),
|
|
22991
|
+
gemini_endpoint_config: external_exports.object({
|
|
22992
|
+
backend: external_exports.enum(["UNSPECIFIED", "DEVELOPER", "GOOGLE_CLOUD"]).describe("Google API surface. UNSPECIFIED is invalid when this configuration is supplied on a write."),
|
|
22993
|
+
projectId: external_exports.string().describe("Google Cloud resource project. Required for GOOGLE_CLOUD and unused for DEVELOPER; this is distinct from the ADC quota project.").optional(),
|
|
22994
|
+
location: external_exports.string().describe("Google Cloud location. Valid only for GOOGLE_CLOUD; omission defaults to global.").optional()
|
|
22995
|
+
}).passthrough().describe("When present, atomically replaces the complete Gemini backend routing configuration. Valid only for a GEMINI embedder. Omit to preserve the stored configuration; the gRPC service validates the backend-specific projectId and location contract.").optional()
|
|
22996
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22287
22997
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22288
22998
|
throw new Error("'id' must be a non-empty string");
|
|
22289
22999
|
}
|
|
@@ -22318,13 +23028,21 @@ function registerTools() {
|
|
|
22318
23028
|
body["version"] = args.version;
|
|
22319
23029
|
if (args.monitoring_endpoint !== void 0)
|
|
22320
23030
|
body["monitoringEndpoint"] = args.monitoring_endpoint;
|
|
23031
|
+
if (args.dashscope_api_dialect !== void 0)
|
|
23032
|
+
body["dashscopeApiDialect"] = args.dashscope_api_dialect;
|
|
23033
|
+
if (args.gemini_endpoint_config !== void 0)
|
|
23034
|
+
body["geminiEndpointConfig"] = args.gemini_endpoint_config;
|
|
22321
23035
|
const result = await callApi("PUT", `/v1/embedders/${encodeURIComponent(String(args.id))}`, body);
|
|
22322
23036
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22323
23037
|
});
|
|
22324
|
-
server.tool("
|
|
23038
|
+
server.tool("goodmem_instance_get", "Get the GoodMem instance\n\nReturns singleton instance identity, ownership, and audit metadata after requiring effective READ_INSTANCE authority. The built-in ADMIN role supplies this authority; instance ownership alone does not. A scoped API key must also retain READ_INSTANCE in its immutable ceiling. This operation does not expose credentials or mutate instance state.", {}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23039
|
+
const result = await callApi("GET", `/v1/instance`, void 0);
|
|
23040
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23041
|
+
});
|
|
23042
|
+
server.tool("goodmem_llms_create", "Create a new LLM\n\nCreates a new LLM configuration for text generation services. LLMs represent connections to different language model API services (like OpenAI, vLLM, etc.) and include all the necessary configuration to use them for text generation. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another LLM exists with the same effective provider connection and model configuration for this owner after endpoint canonicalization and provider-default resolution. Equivalent credentials participate in the comparison. The api_path field defaults to '/chat/completions' if omitted. OWNER DEFAULTS: Owner defaults to the authenticated principal unless owner_id is provided; CREATE_LLM is evaluated against the proposed LLM and owner.", {
|
|
22325
23043
|
display_name: external_exports.string().describe("User-facing name of the LLM"),
|
|
22326
23044
|
description: external_exports.string().describe("Description of the LLM").optional(),
|
|
22327
|
-
provider_type: external_exports.enum(["OPENAI", "LITELLM_PROXY", "OPEN_ROUTER", "VLLM", "OLLAMA", "LLAMA_CPP", "CUSTOM_OPENAI_COMPATIBLE"]).describe("Type of LLM provider (auto-inferred from model_identifier if omitted)").optional(),
|
|
23045
|
+
provider_type: external_exports.enum(["OPENAI", "LITELLM_PROXY", "OPEN_ROUTER", "DASHSCOPE", "VLLM", "OLLAMA", "LLAMA_CPP", "CUSTOM_OPENAI_COMPATIBLE"]).describe("Type of LLM provider (auto-inferred from model_identifier if omitted)").optional(),
|
|
22328
23046
|
endpoint_url: external_exports.string().describe("API endpoint base URL (OpenAI-compatible base, typically ends with /v1) (auto-inferred from model_identifier if omitted)").optional(),
|
|
22329
23047
|
api_path: external_exports.string().describe("API path for chat/completions request (defaults to /chat/completions if not provided)").optional(),
|
|
22330
23048
|
model_identifier: external_exports.string().describe("Model identifier"),
|
|
@@ -22368,9 +23086,10 @@ function registerTools() {
|
|
|
22368
23086
|
}).passthrough().describe("Default sampling parameters for generation requests").optional(),
|
|
22369
23087
|
max_context_length: external_exports.number().int().describe("Maximum context window size in tokens").optional(),
|
|
22370
23088
|
client_config: external_exports.record(external_exports.string(), external_exports.any()).describe("Provider-specific client configuration as flexible JSON structure").optional(),
|
|
22371
|
-
owner_id: external_exports.string().describe("Optional owner
|
|
22372
|
-
llm_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional()
|
|
22373
|
-
|
|
23089
|
+
owner_id: external_exports.string().describe("Optional owner principal UUID. If omitted, defaults to the authenticated principal. CREATE_LLM is evaluated against the proposed LLM and owner.").optional(),
|
|
23090
|
+
llm_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional(),
|
|
23091
|
+
dashscope_api_dialect: external_exports.enum(["LLM_NATIVE_TEXT", "LLM_NATIVE_MULTIMODAL", "OPENAI_COMPATIBLE"]).describe("DashScope request and response API dialect. Valid only for the DASHSCOPE provider. When omitted, a recognized api_path determines the dialect; otherwise OPENAI_COMPATIBLE is used.").optional()
|
|
23092
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22374
23093
|
const inferred = autoInferFromRegistry("llms", args);
|
|
22375
23094
|
checkCredentialRequired(inferred);
|
|
22376
23095
|
const body = {};
|
|
@@ -22408,32 +23127,38 @@ function registerTools() {
|
|
|
22408
23127
|
body["ownerId"] = inferred.owner_id;
|
|
22409
23128
|
if (inferred.llm_id !== void 0)
|
|
22410
23129
|
body["llmId"] = inferred.llm_id;
|
|
23130
|
+
if (inferred.dashscope_api_dialect !== void 0)
|
|
23131
|
+
body["dashscopeApiDialect"] = inferred.dashscope_api_dialect;
|
|
22411
23132
|
const result = await callApi("POST", `/v1/llms`, body);
|
|
22412
23133
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22413
23134
|
});
|
|
22414
|
-
server.tool("goodmem_llms_delete", "Delete an LLM\n\nPermanently deletes an LLM configuration. This operation cannot be undone and removes the LLM record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete any previously generated content using this LLM - existing generations remain accessible. Requires
|
|
23135
|
+
server.tool("goodmem_llms_delete", "Delete an LLM\n\nPermanently deletes an LLM configuration. This operation cannot be undone and removes the LLM record and securely deletes stored credentials. IMPORTANT: This does NOT invalidate or delete any previously generated content using this LLM - existing generations remain accessible. Requires DELETE_LLM on the requested LLM.", {
|
|
22415
23136
|
id: external_exports.string().describe("The unique identifier of the LLM to delete")
|
|
22416
|
-
}, async (args) => {
|
|
23137
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22417
23138
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22418
23139
|
throw new Error("'id' must be a non-empty string");
|
|
22419
23140
|
}
|
|
22420
23141
|
await callApi("DELETE", `/v1/llms/${encodeURIComponent(String(args.id))}`, void 0);
|
|
22421
23142
|
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
22422
23143
|
});
|
|
22423
|
-
server.tool("goodmem_llms_get", "Get an LLM by ID\n\nRetrieves the details of a specific LLM configuration by its unique identifier. Requires
|
|
22424
|
-
id: external_exports.string().describe("The unique identifier of the LLM to retrieve")
|
|
22425
|
-
|
|
23144
|
+
server.tool("goodmem_llms_get", "Get an LLM by ID\n\nRetrieves the details of a specific LLM configuration by its unique identifier. Requires READ_LLM on the requested LLM. The service distinguishes a missing LLM from an existing LLM the caller cannot read. This is a read-only operation with no side effects.", {
|
|
23145
|
+
id: external_exports.string().describe("The unique identifier of the LLM to retrieve"),
|
|
23146
|
+
include_credentials: external_exports.boolean().describe("Whether to return stored credentials. Also accepts include_credentials. Requires READ_LLM_CREDENTIALS in addition to READ_LLM.").optional()
|
|
23147
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22426
23148
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22427
23149
|
throw new Error("'id' must be a non-empty string");
|
|
22428
23150
|
}
|
|
22429
|
-
const
|
|
23151
|
+
const query = {};
|
|
23152
|
+
if (args.include_credentials !== void 0)
|
|
23153
|
+
query["includeCredentials"] = String(args.include_credentials);
|
|
23154
|
+
const result = await callApi("GET", `/v1/llms/${encodeURIComponent(String(args.id))}`, void 0, query);
|
|
22430
23155
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22431
23156
|
});
|
|
22432
|
-
server.tool("goodmem_llms_list", "List LLMs\n\nRetrieves a list of LLM configurations accessible to the caller, with optional filtering. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production).
|
|
22433
|
-
owner_id: external_exports.string().describe("Filter
|
|
22434
|
-
provider_type: external_exports.enum(["OPENAI", "LITELLM_PROXY", "OPEN_ROUTER", "VLLM", "OLLAMA", "LLAMA_CPP", "CUSTOM_OPENAI_COMPATIBLE"]).describe("Filter LLMs by provider type. Allowed values match the LLMProviderType schema.").optional(),
|
|
23157
|
+
server.tool("goodmem_llms_list", "List LLMs\n\nRetrieves a list of LLM configurations accessible to the caller, with optional filtering. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production). AUTHORIZATION: Requires LIST_LLM on the GoodMem instance. Each returned LLM must also be visible through READ_LLM; unauthorized LLMs are filtered in PostgreSQL. The owner_id parameter filters that already-authorized result set and does not grant additional visibility. This is a read-only operation with no side effects.", {
|
|
23158
|
+
owner_id: external_exports.string().describe("Filter the already-authorized result set by owner principal UUID. Omitting this parameter does not bypass per-LLM READ_LLM filtering.").optional(),
|
|
23159
|
+
provider_type: external_exports.enum(["OPENAI", "LITELLM_PROXY", "OPEN_ROUTER", "DASHSCOPE", "VLLM", "OLLAMA", "LLAMA_CPP", "CUSTOM_OPENAI_COMPATIBLE"]).describe("Filter LLMs by provider type. Allowed values match the LLMProviderType schema.").optional(),
|
|
22435
23160
|
label: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by label. Each key-value pair is sent as label[key]=value query parameter.").optional()
|
|
22436
|
-
}, async (args) => {
|
|
23161
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22437
23162
|
const query = {};
|
|
22438
23163
|
if (args.owner_id !== void 0)
|
|
22439
23164
|
query["ownerId"] = String(args.owner_id);
|
|
@@ -22446,7 +23171,7 @@ function registerTools() {
|
|
|
22446
23171
|
const result = await callApi("GET", `/v1/llms`, void 0, query);
|
|
22447
23172
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22448
23173
|
});
|
|
22449
|
-
server.tool("goodmem_llms_update", "Update an LLM\n\nUpdates an existing LLM configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. SUPPORTED_MODALITIES UPDATE: If the array contains >=1 elements, it replaces the stored set; if empty or omitted, no change occurs and it does not count as an update by itself. IMPORTANT: providerType is IMMUTABLE after creation and cannot be changed. Requires
|
|
23174
|
+
server.tool("goodmem_llms_update", "Update an LLM\n\nUpdates an existing LLM configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. SUPPORTED_MODALITIES UPDATE: If the array contains >=1 elements, it replaces the stored set; if empty or omitted, no change occurs and it does not count as an update by itself. IMPORTANT: providerType is IMMUTABLE after creation and cannot be changed. Requires UPDATE_LLM on the requested LLM.", {
|
|
22450
23175
|
id: external_exports.string().describe("The unique identifier of the LLM to update"),
|
|
22451
23176
|
display_name: external_exports.string().describe("Update display name").optional(),
|
|
22452
23177
|
description: external_exports.string().describe("Update description").optional(),
|
|
@@ -22470,7 +23195,7 @@ function registerTools() {
|
|
|
22470
23195
|
quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
|
|
22471
23196
|
}).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
|
|
22472
23197
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
|
|
22473
|
-
}).passthrough().describe("
|
|
23198
|
+
}).passthrough().describe("Replace stored credentials. Omit this field to preserve the current credentials; a present empty payload is invalid and never clears them.").optional(),
|
|
22474
23199
|
version: external_exports.string().describe("Update version information").optional(),
|
|
22475
23200
|
monitoring_endpoint: external_exports.string().describe("Update monitoring endpoint URL").optional(),
|
|
22476
23201
|
capabilities: external_exports.object({
|
|
@@ -22493,8 +23218,9 @@ function registerTools() {
|
|
|
22493
23218
|
max_context_length: external_exports.number().int().describe("Update maximum context window size in tokens").optional(),
|
|
22494
23219
|
client_config: external_exports.record(external_exports.string(), external_exports.any()).describe("Update provider-specific client configuration (replaces entire config; no merging)").optional(),
|
|
22495
23220
|
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with this set. Empty map clears all labels. Cannot be used with merge_labels.").optional(),
|
|
22496
|
-
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge with existing labels: upserts with overwrite. Labels not mentioned are preserved. Cannot be used with replace_labels.").optional()
|
|
22497
|
-
|
|
23221
|
+
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge with existing labels: upserts with overwrite. Labels not mentioned are preserved. Cannot be used with replace_labels.").optional(),
|
|
23222
|
+
dashscope_api_dialect: external_exports.enum(["LLM_NATIVE_TEXT", "LLM_NATIVE_MULTIMODAL", "OPENAI_COMPATIBLE"]).describe("Update the DashScope request and response API dialect. Valid only for the DASHSCOPE provider. Omit to preserve the stored dialect. Changing api_path to a recognized canonical DashScope dialect infers its matching dialect; a custom path preserves an existing dialect, while a legacy null dialect is inferred.").optional()
|
|
23223
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22498
23224
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22499
23225
|
throw new Error("'id' must be a non-empty string");
|
|
22500
23226
|
}
|
|
@@ -22533,6 +23259,8 @@ function registerTools() {
|
|
|
22533
23259
|
body["replaceLabels"] = args.replace_labels;
|
|
22534
23260
|
if (args.merge_labels !== void 0)
|
|
22535
23261
|
body["mergeLabels"] = args.merge_labels;
|
|
23262
|
+
if (args.dashscope_api_dialect !== void 0)
|
|
23263
|
+
body["dashscopeApiDialect"] = args.dashscope_api_dialect;
|
|
22536
23264
|
const result = await callApi("PUT", `/v1/llms/${encodeURIComponent(String(args.id))}`, body);
|
|
22537
23265
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22538
23266
|
});
|
|
@@ -22544,7 +23272,7 @@ function registerTools() {
|
|
|
22544
23272
|
originalContentB64: external_exports.string().describe("Original content as base64-encoded binary data (use either this or originalContent)").optional(),
|
|
22545
23273
|
originalContentRef: external_exports.string().describe("Reference to external content location").optional(),
|
|
22546
23274
|
contentType: external_exports.string().describe("MIME type of the content").optional(),
|
|
22547
|
-
metadata: external_exports.record(external_exports.string(), external_exports.any()).describe("Additional metadata for the memory").optional(),
|
|
23275
|
+
metadata: external_exports.record(external_exports.string(), external_exports.any()).describe("Additional metadata for the memory. A top-level textual title is an optional document-title hint for embedding providers that support one; blank or non-string titles are ignored. Later metadata edits do not automatically re-embed existing chunks.").optional(),
|
|
22548
23276
|
chunkingConfig: external_exports.object({
|
|
22549
23277
|
none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
|
|
22550
23278
|
recursive: external_exports.object({
|
|
@@ -22564,7 +23292,7 @@ function registerTools() {
|
|
|
22564
23292
|
}).passthrough().describe("Chunking strategy for this memory (if not provided, uses space default)").optional(),
|
|
22565
23293
|
extractPageImages: external_exports.boolean().describe("Optional hint to extract page images for eligible document types (for example, PDFs)").optional()
|
|
22566
23294
|
}).passthrough()).describe("Array of memory creation requests.")
|
|
22567
|
-
}, async (args) => {
|
|
23295
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22568
23296
|
for (const [_i, _item] of (Array.isArray(args.requests) ? args.requests : []).entries()) {
|
|
22569
23297
|
const _itemSet = [_item?.["originalContent"] !== void 0 && _item?.["originalContent"] !== null, _item?.["originalContentB64"] !== void 0 && _item?.["originalContentB64"] !== null].filter(Boolean).length;
|
|
22570
23298
|
if (_itemSet !== 1) {
|
|
@@ -22588,7 +23316,7 @@ function registerTools() {
|
|
|
22588
23316
|
const result = await callApi("POST", `/v1/memories:batchCreate`, body);
|
|
22589
23317
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22590
23318
|
});
|
|
22591
|
-
server.tool("goodmem_memories_batch_delete", "Delete memories in batch\n\nDeletes memories using selector entries. Each selector can target either a specific memory ID or a filtered subset scoped to a specific space.", {
|
|
23319
|
+
server.tool("goodmem_memories_batch_delete", "Delete memories in batch\n\nDeletes memories using selector entries. Each selector can target either a specific memory ID or a filtered subset scoped to a specific space. Each selected memory requires DELETE_MEMORY; authority may be granted through DIRECT_MEMBERS_OF its containing space.", {
|
|
22592
23320
|
requests: external_exports.array(external_exports.object({
|
|
22593
23321
|
memoryId: external_exports.string().describe("Deletes one specific memory by UUID").optional(),
|
|
22594
23322
|
filterSelector: external_exports.object({
|
|
@@ -22597,18 +23325,18 @@ function registerTools() {
|
|
|
22597
23325
|
filter: external_exports.string().describe("Optional metadata filter expression").optional()
|
|
22598
23326
|
}).passthrough().describe("Deletes a filtered set of memories within a specific space").optional()
|
|
22599
23327
|
}).passthrough()).describe("Array of delete selectors")
|
|
22600
|
-
}, async (args) => {
|
|
23328
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22601
23329
|
const body = {};
|
|
22602
23330
|
if (args.requests !== void 0)
|
|
22603
23331
|
body["requests"] = args.requests;
|
|
22604
23332
|
const result = await callApi("POST", `/v1/memories:batchDelete`, body);
|
|
22605
23333
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22606
23334
|
});
|
|
22607
|
-
server.tool("goodmem_memories_batch_get", "Get multiple memories by ID\n\nRetrieves multiple memories in a single operation, with individual success/failure results.", {
|
|
23335
|
+
server.tool("goodmem_memories_batch_get", "Get multiple memories by ID\n\nRetrieves multiple memories in a single operation, with individual success/failure results. Each item requires READ_MEMORY on the requested memory; authority may be granted through DIRECT_MEMBERS_OF its containing space.", {
|
|
22608
23336
|
memory_ids: external_exports.array(external_exports.string()).describe("Array of memory IDs to retrieve"),
|
|
22609
23337
|
include_content: external_exports.boolean().describe("Whether to include the original content in the response").optional(),
|
|
22610
23338
|
include_processing_history: external_exports.boolean().describe("Whether to include background job processing history for each memory").optional()
|
|
22611
|
-
}, async (args) => {
|
|
23339
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22612
23340
|
const body = {};
|
|
22613
23341
|
if (args.memory_ids !== void 0)
|
|
22614
23342
|
body["memoryIds"] = args.memory_ids;
|
|
@@ -22619,10 +23347,10 @@ function registerTools() {
|
|
|
22619
23347
|
const result = await callApi("POST", `/v1/memories:batchGet`, body);
|
|
22620
23348
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22621
23349
|
});
|
|
22622
|
-
server.tool("goodmem_memories_content", "Download memory content\n\nReturns the original binary payload for a memory. The response uses the memory's stored content type when available. Returns 404 when the memory does not have inline content; clients can check originalContentRef from the metadata endpoint to locate external content.", {
|
|
23350
|
+
server.tool("goodmem_memories_content", "Download memory content\n\nReturns the original binary payload for a memory. The response uses the memory's stored content type when available. Returns 404 when the memory does not have inline content; clients can check originalContentRef from the metadata endpoint to locate external content. Requires READ_MEMORY on the requested memory; authority may be granted through DIRECT_MEMBERS_OF its containing space.", {
|
|
22623
23351
|
id: external_exports.string().describe("The UUID of the memory to download"),
|
|
22624
23352
|
max_inline_bytes: external_exports.number().int().positive().describe("Maximum bytes to deliver inline as a content block. Defaults to 8388608. Hard server ceiling: 67108864. If the payload exceeds this cap the tool errors with the actual size \u2014 retry with a larger value (up to the ceiling) to receive it.").optional()
|
|
22625
|
-
}, async (args) => {
|
|
23353
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22626
23354
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22627
23355
|
throw new Error("'id' must be a non-empty string");
|
|
22628
23356
|
}
|
|
@@ -22649,7 +23377,7 @@ function registerTools() {
|
|
|
22649
23377
|
original_content_b64: external_exports.string().describe("Original content as base64-encoded binary data (use either this or original_content)").optional(),
|
|
22650
23378
|
original_content_ref: external_exports.string().describe("Reference to external content location").optional(),
|
|
22651
23379
|
content_type: external_exports.string().describe("MIME type of the content (defaults to text/plain when original_content is provided)").optional(),
|
|
22652
|
-
metadata: external_exports.record(external_exports.string(), external_exports.any()).describe("Additional metadata for the memory").optional(),
|
|
23380
|
+
metadata: external_exports.record(external_exports.string(), external_exports.any()).describe("Additional metadata for the memory. A top-level textual title is an optional document-title hint for embedding providers that support one; blank or non-string titles are ignored. Later metadata edits do not automatically re-embed existing chunks.").optional(),
|
|
22653
23381
|
chunking_config: external_exports.object({
|
|
22654
23382
|
none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
|
|
22655
23383
|
recursive: external_exports.object({
|
|
@@ -22668,7 +23396,7 @@ function registerTools() {
|
|
|
22668
23396
|
}).passthrough().describe("Sentence-based chunking strategy with language detection").optional()
|
|
22669
23397
|
}).passthrough().describe("Chunking strategy for this memory (if not provided, uses space default)").optional(),
|
|
22670
23398
|
extract_page_images: external_exports.boolean().describe("Optional hint to extract page images for eligible document types (for example, PDFs)").optional()
|
|
22671
|
-
}, async (args) => {
|
|
23399
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22672
23400
|
const _set = [args.original_content !== void 0 && args.original_content !== null, args.original_content_b64 !== void 0 && args.original_content_b64 !== null].filter(Boolean).length;
|
|
22673
23401
|
if (_set !== 1) {
|
|
22674
23402
|
throw new Error("exactly one of original_content or original_content_b64 must be set");
|
|
@@ -22701,20 +23429,20 @@ function registerTools() {
|
|
|
22701
23429
|
const result = await callApi("POST", `/v1/memories`, body);
|
|
22702
23430
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22703
23431
|
});
|
|
22704
|
-
server.tool("goodmem_memories_delete", "Delete a memory\n\nPermanently deletes a memory and its associated chunks. This operation cannot be undone and immediately removes the memory record from the database. IDEMPOTENCY: This operation is safe to retry - may return NOT_FOUND if the memory was already deleted or never existed. Requires
|
|
23432
|
+
server.tool("goodmem_memories_delete", "Delete a memory\n\nPermanently deletes a memory and its associated chunks. This operation cannot be undone and immediately removes the memory record from the database. IDEMPOTENCY: This operation is safe to retry - may return NOT_FOUND if the memory was already deleted or never existed. AUTHORIZATION: Requires DELETE_MEMORY on the requested memory; authority may be granted through DIRECT_MEMBERS_OF its containing space. Side effects include permanent removal of the memory record and all associated chunk data.", {
|
|
22705
23433
|
id: external_exports.string().describe("The UUID of the memory to delete")
|
|
22706
|
-
}, async (args) => {
|
|
23434
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
22707
23435
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22708
23436
|
throw new Error("'id' must be a non-empty string");
|
|
22709
23437
|
}
|
|
22710
23438
|
await callApi("DELETE", `/v1/memories/${encodeURIComponent(String(args.id))}`, void 0);
|
|
22711
23439
|
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
22712
23440
|
});
|
|
22713
|
-
server.tool("goodmem_memories_get", "Get a memory by ID\n\nRetrieves a single memory by its ID.
|
|
23441
|
+
server.tool("goodmem_memories_get", "Get a memory by ID\n\nRetrieves a single memory by its ID. AUTHORIZATION: Requires READ_MEMORY on the requested memory; authority may be granted directly or through DIRECT_MEMBERS_OF its containing space. This is a read-only operation with no side effects and is safe to retry. Returns NOT_FOUND if the memory or its parent space does not exist.", {
|
|
22714
23442
|
id: external_exports.string().describe("The UUID of the memory to retrieve"),
|
|
22715
23443
|
include_content: external_exports.boolean().describe("Whether to include the original content in the response (defaults to false).").optional(),
|
|
22716
23444
|
include_processing_history: external_exports.boolean().describe("Whether to include background job processing history in the response (defaults to false).").optional()
|
|
22717
|
-
}, async (args) => {
|
|
23445
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22718
23446
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22719
23447
|
throw new Error("'id' must be a non-empty string");
|
|
22720
23448
|
}
|
|
@@ -22736,7 +23464,7 @@ function registerTools() {
|
|
|
22736
23464
|
next_token: external_exports.string().describe("Opaque pagination token for the next page. URL-safe Base64 without padding; do not parse or construct it.").optional(),
|
|
22737
23465
|
sort_by: external_exports.enum(["created_at", "updated_at", "content_type", "processing_status"]).describe("Field to sort by (e.g., 'created_at').").optional(),
|
|
22738
23466
|
sort_order: external_exports.enum(["ASCENDING", "DESCENDING", "SORT_ORDER_UNSPECIFIED"]).describe("Sort direction (ASCENDING or DESCENDING).").optional()
|
|
22739
|
-
}, async (args) => {
|
|
23467
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22740
23468
|
if (typeof args.space_id !== "string" || args.space_id === "") {
|
|
22741
23469
|
throw new Error("'space_id' must be a non-empty string");
|
|
22742
23470
|
}
|
|
@@ -22760,7 +23488,7 @@ function registerTools() {
|
|
|
22760
23488
|
const result = await callApi("GET", `/v1/spaces/${encodeURIComponent(String(args.space_id))}/memories`, void 0, query);
|
|
22761
23489
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22762
23490
|
});
|
|
22763
|
-
server.tool("goodmem_memories_pages", "List memory page images\n\nLists extracted page-image metadata for a memory with optional filters and pagination.", {
|
|
23491
|
+
server.tool("goodmem_memories_pages", "List memory page images\n\nLists extracted page-image metadata for a memory with optional filters and pagination. Requires READ_MEMORY on the containing memory; authority may be granted through DIRECT_MEMBERS_OF its containing space.", {
|
|
22764
23492
|
id: external_exports.string().describe("Memory UUID"),
|
|
22765
23493
|
start_page_index: external_exports.number().int().describe("Optional lower bound for returned page indices, inclusive.").optional(),
|
|
22766
23494
|
end_page_index: external_exports.number().int().describe("Optional upper bound for returned page indices, inclusive.").optional(),
|
|
@@ -22768,7 +23496,7 @@ function registerTools() {
|
|
|
22768
23496
|
content_type: external_exports.string().describe("Optional rendition filter for page-image MIME type, such as image/png.").optional(),
|
|
22769
23497
|
max_results: external_exports.number().int().describe("Maximum number of results per page.").optional(),
|
|
22770
23498
|
next_token: external_exports.string().describe("Opaque pagination token for the next page. Do not parse or construct it.").optional()
|
|
22771
|
-
}, async (args) => {
|
|
23499
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22772
23500
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22773
23501
|
throw new Error("'id' must be a non-empty string");
|
|
22774
23502
|
}
|
|
@@ -22788,13 +23516,13 @@ function registerTools() {
|
|
|
22788
23516
|
const result = await callApi("GET", `/v1/memories/${encodeURIComponent(String(args.id))}/pages`, void 0, query);
|
|
22789
23517
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22790
23518
|
});
|
|
22791
|
-
server.tool("goodmem_memories_pages_image", "Download memory page image content\n\nDownloads inline bytes for one page image. The page index is required. The optional dpi and content type query parameters act as rendition filters; if omitted, the server returns the unique rendition for that page or rejects ambiguous matches.", {
|
|
23519
|
+
server.tool("goodmem_memories_pages_image", "Download memory page image content\n\nDownloads inline bytes for one page image. The page index is required. The optional dpi and content type query parameters act as rendition filters; if omitted, the server returns the unique rendition for that page or rejects ambiguous matches. Requires READ_MEMORY on the containing memory; authority may be granted through DIRECT_MEMBERS_OF its containing space.", {
|
|
22792
23520
|
id: external_exports.string().describe("Memory UUID"),
|
|
22793
23521
|
page_index: external_exports.number().int().describe("0-based page index"),
|
|
22794
23522
|
dpi: external_exports.number().int().describe("Optional rendition filter. If omitted, the unique page-image rendition for the page is returned; if multiple renditions exist, specify dpi and/or content_type.").optional(),
|
|
22795
23523
|
content_type: external_exports.string().describe("Optional rendition filter. MIME type of the desired page image, such as image/png.").optional(),
|
|
22796
23524
|
max_inline_bytes: external_exports.number().int().positive().describe("Maximum bytes to deliver inline as a content block. Defaults to 8388608. Hard server ceiling: 67108864. If the payload exceeds this cap the tool errors with the actual size \u2014 retry with a larger value (up to the ceiling) to receive it.").optional()
|
|
22797
|
-
}, async (args) => {
|
|
23525
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
22798
23526
|
if (typeof args.id !== "string" || args.id === "") {
|
|
22799
23527
|
throw new Error("'id' must be a non-empty string");
|
|
22800
23528
|
}
|
|
@@ -22855,12 +23583,8 @@ function registerTools() {
|
|
|
22855
23583
|
name: external_exports.string().describe("Fully qualified factory class name of the post-processor to apply."),
|
|
22856
23584
|
config: external_exports.record(external_exports.string(), external_exports.any()).describe("Configuration parameters for the post-processor. Fields depend on the selected processor; see the linked documentation for the built-in ChatPostProcessor schema.").optional()
|
|
22857
23585
|
}).passthrough().describe("Optional post-processor configuration to transform retrieval results.").optional(),
|
|
22858
|
-
logging: external_exports.object({
|
|
22859
|
-
enabled: external_exports.boolean().describe("Opts this request in to durable server-side request logging. False or omitted does not opt out of admin policy logging.").optional(),
|
|
22860
|
-
callerAttributes: external_exports.record(external_exports.string(), external_exports.any()).describe("Optional flat scalar attributes attached if this request is persisted by caller opt-in or admin policy logging. Supported value types are string, integer, floating-point, and boolean. At most 32 entries are accepted.").optional()
|
|
22861
|
-
}).passthrough().describe("Optional durable request logging block for POST retrieve requests. Set logging.enabled=true to opt in, or supply flat scalar logging.callerAttributes to attach if caller opt-in or an admin policy logs the request.").optional(),
|
|
22862
23586
|
timeout_sec: external_exports.number().int().describe("Maximum seconds to wait for the streaming response (default: 200).").optional()
|
|
22863
|
-
}, async (args) => {
|
|
23587
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22864
23588
|
const body = {};
|
|
22865
23589
|
if (args.message !== void 0)
|
|
22866
23590
|
body["message"] = args.message;
|
|
@@ -22880,8 +23604,6 @@ function registerTools() {
|
|
|
22880
23604
|
body["hnsw"] = args.hnsw;
|
|
22881
23605
|
if (args.post_processor !== void 0)
|
|
22882
23606
|
body["postProcessor"] = args.post_processor;
|
|
22883
|
-
if (args.logging !== void 0)
|
|
22884
|
-
body["logging"] = args.logging;
|
|
22885
23607
|
const result = await callApiNdjson("POST", `/v1/memories:retrieve`, body, void 0, args.timeout_sec);
|
|
22886
23608
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22887
23609
|
});
|
|
@@ -22892,7 +23614,7 @@ function registerTools() {
|
|
|
22892
23614
|
include_markdown: external_exports.boolean().describe("Include markdown rendering in the response").optional(),
|
|
22893
23615
|
start_page: external_exports.number().int().describe("0-based inclusive start page").optional(),
|
|
22894
23616
|
end_page: external_exports.number().int().describe("0-based inclusive end page").optional()
|
|
22895
|
-
}, async (args) => {
|
|
23617
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22896
23618
|
const body = {};
|
|
22897
23619
|
if (args.content !== void 0)
|
|
22898
23620
|
body["content"] = args.content;
|
|
@@ -22909,14 +23631,14 @@ function registerTools() {
|
|
|
22909
23631
|
const result = await callApi("POST", `/v1/ocr:document`, body);
|
|
22910
23632
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22911
23633
|
});
|
|
22912
|
-
server.tool("goodmem_ping_once", "Run a single ping probe\n\nRuns a single ping probe and returns the probe result.", {
|
|
23634
|
+
server.tool("goodmem_ping_once", "Run a single ping probe\n\nRuns a single ping probe and returns the probe result. Requires both the target-specific PING operation and its corresponding EXECUTE operation: PING_EMBEDDER plus EXECUTE_EMBEDDER, PING_RERANKER plus EXECUTE_RERANKER, or PING_LLM plus EXECUTE_LLM.", {
|
|
22913
23635
|
target_id: external_exports.string().describe("Target resource ID (UUID)"),
|
|
22914
23636
|
target_type_hint: external_exports.enum(["TARGET_TYPE_UNSPECIFIED", "EMBEDDER", "RERANKER", "LLM"]).describe("Optional hint for the target resource type").optional(),
|
|
22915
23637
|
payload_type: external_exports.enum(["PAYLOAD_TYPE_UNSPECIFIED", "TEXT", "JSON", "BINARY"]).describe("Desired payload type (defaults to provider-specific value)").optional(),
|
|
22916
23638
|
payload: external_exports.string().describe("Explicit UTF-8 payload to send with the probe (mutually exclusive with payload_size_bytes)").optional(),
|
|
22917
23639
|
payload_size_bytes: external_exports.number().int().describe("Synthetic payload size in bytes (mutually exclusive with payload)").optional(),
|
|
22918
23640
|
timeout_ms: external_exports.number().int().describe("Per-probe timeout in milliseconds (0 uses server default)").optional()
|
|
22919
|
-
}, async (args) => {
|
|
23641
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22920
23642
|
const _set = [args.payload !== void 0 && args.payload !== null, args.payload_size_bytes !== void 0 && args.payload_size_bytes !== null].filter(Boolean).length;
|
|
22921
23643
|
if (_set > 1) {
|
|
22922
23644
|
throw new Error("at most one of payload or payload_size_bytes may be set");
|
|
@@ -22937,7 +23659,7 @@ function registerTools() {
|
|
|
22937
23659
|
const result = await callApi("POST", `/v1/ping:once`, body, void 0, (args.timeout_ms ?? 5e3) + 3e4);
|
|
22938
23660
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22939
23661
|
});
|
|
22940
|
-
server.tool("goodmem_ping_stream", "Stream ping probe results\n\nOpens a streaming ping session and returns per-probe results plus a terminal summary.", {
|
|
23662
|
+
server.tool("goodmem_ping_stream", "Stream ping probe results\n\nOpens a streaming ping session and returns per-probe results plus a terminal summary. Requires both the target-specific PING operation and its corresponding EXECUTE operation: PING_EMBEDDER plus EXECUTE_EMBEDDER, PING_RERANKER plus EXECUTE_RERANKER, or PING_LLM plus EXECUTE_LLM.", {
|
|
22941
23663
|
target_id: external_exports.string().describe("Target resource ID (UUID)"),
|
|
22942
23664
|
target_type_hint: external_exports.enum(["TARGET_TYPE_UNSPECIFIED", "EMBEDDER", "RERANKER", "LLM"]).describe("Optional hint for the target resource type").optional(),
|
|
22943
23665
|
count: external_exports.number().int().describe("Number of probes to run (0 uses server default)").optional(),
|
|
@@ -22950,7 +23672,7 @@ function registerTools() {
|
|
|
22950
23672
|
jitter: external_exports.boolean().describe("Add jitter to probe scheduling").optional(),
|
|
22951
23673
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Optional labels to attach to the ping session").optional(),
|
|
22952
23674
|
timeout_sec: external_exports.number().int().describe("Maximum seconds to wait for the streaming response (default: 200).").optional()
|
|
22953
|
-
}, async (args) => {
|
|
23675
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
22954
23676
|
const _set = [args.payload !== void 0 && args.payload !== null, args.payload_size_bytes !== void 0 && args.payload_size_bytes !== null].filter(Boolean).length;
|
|
22955
23677
|
if (_set > 1) {
|
|
22956
23678
|
throw new Error("at most one of payload or payload_size_bytes may be set");
|
|
@@ -22981,10 +23703,10 @@ function registerTools() {
|
|
|
22981
23703
|
const result = await callApiNdjson("POST", `/v1/ping:stream`, body, void 0, args.timeout_sec ?? Math.ceil(((args.count || 100) * (args.interval_ms || 1e3) + (args.timeout_ms || 5e3) + 6e4) / 1e3));
|
|
22982
23704
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22983
23705
|
});
|
|
22984
|
-
server.tool("goodmem_rerankers_create", "Create a new reranker\n\nCreates a new reranker configuration for ranking search results. Rerankers represent connections to different reranking API services (like TEI, OpenAI, etc.) and include all the necessary configuration to use them for result ranking. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another reranker exists with
|
|
23706
|
+
server.tool("goodmem_rerankers_create", "Create a new reranker\n\nCreates a new reranker configuration for ranking search results. Rerankers represent connections to different reranking API services (like TEI, OpenAI, etc.) and include all the necessary configuration to use them for result ranking. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another reranker exists with the same effective provider connection and model configuration for this owner after endpoint canonicalization and provider-default resolution. Equivalent credentials participate in the comparison. DEFAULTS: api_path defaults to '/v2/rerank' for Cohere and '/rerank' for other providers if omitted; supported_modalities defaults to [TEXT] if omitted. OWNER DEFAULTS: Owner defaults to the authenticated principal unless owner_id is provided; CREATE_RERANKER is evaluated against the proposed reranker and owner. This operation is NOT idempotent - each request creates a new reranker record.", {
|
|
22985
23707
|
display_name: external_exports.string().describe("User-facing name of the reranker"),
|
|
22986
23708
|
description: external_exports.string().describe("Description of the reranker").optional(),
|
|
22987
|
-
provider_type: external_exports.enum(["
|
|
23709
|
+
provider_type: external_exports.enum(["VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA", "DASHSCOPE"]).describe("Type of reranking provider (auto-inferred from model_identifier if omitted)").optional(),
|
|
22988
23710
|
endpoint_url: external_exports.string().describe("API endpoint URL (auto-inferred from model_identifier if omitted)").optional(),
|
|
22989
23711
|
api_path: external_exports.string().describe("API path for reranking request (defaults: Cohere /v2/rerank, Jina /v1/rerank, others /rerank)").optional(),
|
|
22990
23712
|
model_identifier: external_exports.string().describe("Model identifier"),
|
|
@@ -23009,9 +23731,10 @@ function registerTools() {
|
|
|
23009
23731
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
|
|
23010
23732
|
version: external_exports.string().describe("Version information").optional(),
|
|
23011
23733
|
monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
|
|
23012
|
-
owner_id: external_exports.string().describe("Optional owner
|
|
23013
|
-
reranker_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional()
|
|
23014
|
-
|
|
23734
|
+
owner_id: external_exports.string().describe("Optional owner principal UUID. If omitted, defaults to the authenticated principal. CREATE_RERANKER is evaluated against the proposed reranker and owner.").optional(),
|
|
23735
|
+
reranker_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional(),
|
|
23736
|
+
dashscope_api_dialect: external_exports.enum(["RERANK_NATIVE_NESTED", "RERANK_COMPATIBLE_FLAT"]).describe("DashScope request and response API dialect. Valid only for the DASHSCOPE provider. Omit to infer the dialect from api_path, the model catalog, or the native reranking default.").optional()
|
|
23737
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
23015
23738
|
const inferred = autoInferFromRegistry("rerankers", args);
|
|
23016
23739
|
checkCredentialRequired(inferred);
|
|
23017
23740
|
const body = {};
|
|
@@ -23041,32 +23764,38 @@ function registerTools() {
|
|
|
23041
23764
|
body["ownerId"] = inferred.owner_id;
|
|
23042
23765
|
if (inferred.reranker_id !== void 0)
|
|
23043
23766
|
body["rerankerId"] = inferred.reranker_id;
|
|
23767
|
+
if (inferred.dashscope_api_dialect !== void 0)
|
|
23768
|
+
body["dashscopeApiDialect"] = inferred.dashscope_api_dialect;
|
|
23044
23769
|
const result = await callApi("POST", `/v1/rerankers`, body);
|
|
23045
23770
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23046
23771
|
});
|
|
23047
|
-
server.tool("goodmem_rerankers_delete", "Delete a reranker\n\nPermanently deletes a reranker configuration. This operation cannot be undone and immediately removes the reranker record from the database. SIDE EFFECTS: Invalidates any cached references to this reranker; does not affect historical usage data or audit logs. Requires
|
|
23772
|
+
server.tool("goodmem_rerankers_delete", "Delete a reranker\n\nPermanently deletes a reranker configuration. This operation cannot be undone and immediately removes the reranker record from the database. SIDE EFFECTS: Invalidates any cached references to this reranker; does not affect historical usage data or audit logs. Requires DELETE_RERANKER on the requested reranker. This operation is safe to retry - may return NOT_FOUND if already deleted.", {
|
|
23048
23773
|
id: external_exports.string().describe("The unique identifier of the reranker to delete")
|
|
23049
|
-
}, async (args) => {
|
|
23774
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
23050
23775
|
if (typeof args.id !== "string" || args.id === "") {
|
|
23051
23776
|
throw new Error("'id' must be a non-empty string");
|
|
23052
23777
|
}
|
|
23053
23778
|
await callApi("DELETE", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, void 0);
|
|
23054
23779
|
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
23055
23780
|
});
|
|
23056
|
-
server.tool("goodmem_rerankers_get", "Get a reranker by ID\n\nRetrieves the details of a specific reranker configuration by its unique identifier.
|
|
23057
|
-
id: external_exports.string().describe("The unique identifier of the reranker to retrieve")
|
|
23058
|
-
|
|
23781
|
+
server.tool("goodmem_rerankers_get", "Get a reranker by ID\n\nRetrieves the details of a specific reranker configuration by its unique identifier. Stored credentials are omitted unless include_credentials is true and the caller also has READ_RERANKER_CREDENTIALS. Requires READ_RERANKER on the requested reranker. The service distinguishes a missing reranker from an existing reranker the caller cannot read. This is a read-only operation with no side effects and is safe to retry.", {
|
|
23782
|
+
id: external_exports.string().describe("The unique identifier of the reranker to retrieve"),
|
|
23783
|
+
include_credentials: external_exports.boolean().describe("Whether to return stored credentials. Also accepts include_credentials. Requires READ_RERANKER_CREDENTIALS in addition to READ_RERANKER.").optional()
|
|
23784
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23059
23785
|
if (typeof args.id !== "string" || args.id === "") {
|
|
23060
23786
|
throw new Error("'id' must be a non-empty string");
|
|
23061
23787
|
}
|
|
23062
|
-
const
|
|
23788
|
+
const query = {};
|
|
23789
|
+
if (args.include_credentials !== void 0)
|
|
23790
|
+
query["includeCredentials"] = String(args.include_credentials);
|
|
23791
|
+
const result = await callApi("GET", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, void 0, query);
|
|
23063
23792
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23064
23793
|
});
|
|
23065
|
-
server.tool("goodmem_rerankers_list", "List rerankers\n\nRetrieves a list of reranker configurations accessible to the caller, with optional filtering. IMPORTANT: Pagination is NOT supported - all matching results are returned. Results are ordered by created_at descending.
|
|
23066
|
-
owner_id: external_exports.string().describe("Filter
|
|
23067
|
-
provider_type: external_exports.enum(["OPENAI", "VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA"]).describe("Filter rerankers by provider type. Allowed values match the ProviderType schema.").optional(),
|
|
23794
|
+
server.tool("goodmem_rerankers_list", "List rerankers\n\nRetrieves a list of reranker configurations accessible to the caller, with optional filtering. IMPORTANT: Pagination is NOT supported - all matching results are returned. Results are ordered by created_at descending. Stored credentials are never included in list responses. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production). AUTHORIZATION: Requires LIST_RERANKER on the GoodMem instance. Each returned reranker must also be visible through READ_RERANKER; unauthorized rerankers are filtered in PostgreSQL. The owner_id parameter filters that already-authorized result set and does not grant additional visibility.", {
|
|
23795
|
+
owner_id: external_exports.string().describe("Filter the already-authorized result set by owner principal UUID. Omitting this parameter does not bypass per-reranker READ_RERANKER filtering.").optional(),
|
|
23796
|
+
provider_type: external_exports.enum(["OPENAI", "VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA", "DASHSCOPE", "GEMINI"]).describe("Filter rerankers by provider type. Allowed values match the ProviderType schema.").optional(),
|
|
23068
23797
|
label: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by label. Each key-value pair is sent as label[key]=value query parameter.").optional()
|
|
23069
|
-
}, async (args) => {
|
|
23798
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23070
23799
|
const query = {};
|
|
23071
23800
|
if (args.owner_id !== void 0)
|
|
23072
23801
|
query["ownerId"] = String(args.owner_id);
|
|
@@ -23079,7 +23808,7 @@ function registerTools() {
|
|
|
23079
23808
|
const result = await callApi("GET", `/v1/rerankers`, void 0, query);
|
|
23080
23809
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23081
23810
|
});
|
|
23082
|
-
server.tool("goodmem_rerankers_update", "Update a reranker\n\nUpdates an existing reranker configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. IMMUTABLE FIELDS: providerType and ownerId cannot be changed after creation. SUPPORTED_MODALITIES UPDATE: If the array contains >=1 elements, it replaces the stored set; if empty or omitted, no change occurs and it does not count as an update by itself. Returns ALREADY_EXISTS if update would create
|
|
23811
|
+
server.tool("goodmem_rerankers_update", "Update a reranker\n\nUpdates an existing reranker configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. IMMUTABLE FIELDS: providerType and ownerId cannot be changed after creation. SUPPORTED_MODALITIES UPDATE: If the array contains >=1 elements, it replaces the stored set; if empty or omitted, no change occurs and it does not count as an update by itself. Returns ALREADY_EXISTS if update would create an equivalent reranker configuration for this owner after endpoint canonicalization and provider-default resolution (HTTP 409 Conflict / ALREADY_EXISTS). Requires UPDATE_RERANKER on the requested reranker. This operation is idempotent.", {
|
|
23083
23812
|
id: external_exports.string().describe("The unique identifier of the reranker to update"),
|
|
23084
23813
|
display_name: external_exports.string().describe("User-facing name of the reranker").optional(),
|
|
23085
23814
|
description: external_exports.string().describe("Description of the reranker").optional(),
|
|
@@ -23103,12 +23832,13 @@ function registerTools() {
|
|
|
23103
23832
|
quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
|
|
23104
23833
|
}).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
|
|
23105
23834
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
|
|
23106
|
-
}).passthrough().describe("
|
|
23835
|
+
}).passthrough().describe("Replace stored credentials. Omit this field to preserve the current credentials; a present empty payload is invalid and never clears them.").optional(),
|
|
23107
23836
|
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with these (mutually exclusive with merge_labels)").optional(),
|
|
23108
23837
|
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones (mutually exclusive with replace_labels)").optional(),
|
|
23109
23838
|
version: external_exports.string().describe("Version information").optional(),
|
|
23110
|
-
monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
|
|
23111
|
-
|
|
23839
|
+
monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
|
|
23840
|
+
dashscope_api_dialect: external_exports.enum(["RERANK_NATIVE_NESTED", "RERANK_COMPATIBLE_FLAT"]).describe("Update the DashScope request and response API dialect. Valid only for the DASHSCOPE provider. Omit to preserve the stored dialect. Changing api_path to a recognized canonical DashScope dialect infers its matching dialect; a custom path preserves an existing dialect, while a legacy null dialect is inferred.").optional()
|
|
23841
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
23112
23842
|
if (typeof args.id !== "string" || args.id === "") {
|
|
23113
23843
|
throw new Error("'id' must be a non-empty string");
|
|
23114
23844
|
}
|
|
@@ -23139,18 +23869,117 @@ function registerTools() {
|
|
|
23139
23869
|
body["version"] = args.version;
|
|
23140
23870
|
if (args.monitoring_endpoint !== void 0)
|
|
23141
23871
|
body["monitoringEndpoint"] = args.monitoring_endpoint;
|
|
23872
|
+
if (args.dashscope_api_dialect !== void 0)
|
|
23873
|
+
body["dashscopeApiDialect"] = args.dashscope_api_dialect;
|
|
23142
23874
|
const result = await callApi("PUT", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, body);
|
|
23143
23875
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23144
23876
|
});
|
|
23145
|
-
server.tool("
|
|
23877
|
+
server.tool("goodmem_service_identities_create", "Create a service identity\n\nCreates one production-workload identity owned by the authenticated human. No API key, role, grant, or authentication mapping is created implicitly.", {
|
|
23878
|
+
service_identity_id: external_exports.string().describe("Optional client-provided UUID; generated by the server when omitted.").optional(),
|
|
23879
|
+
display_name: external_exports.string().describe("Globally unique, nonblank operator-facing name."),
|
|
23880
|
+
description: external_exports.string().describe("Optional operator description.").optional(),
|
|
23881
|
+
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Optional labels for organization and filtering. At most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional()
|
|
23882
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
23883
|
+
const body = {};
|
|
23884
|
+
if (args.service_identity_id !== void 0)
|
|
23885
|
+
body["serviceIdentityId"] = args.service_identity_id;
|
|
23886
|
+
if (args.display_name !== void 0)
|
|
23887
|
+
body["displayName"] = args.display_name;
|
|
23888
|
+
if (args.description !== void 0)
|
|
23889
|
+
body["description"] = args.description;
|
|
23890
|
+
if (args.labels !== void 0)
|
|
23891
|
+
body["labels"] = args.labels;
|
|
23892
|
+
const result = await callApi("POST", `/v1/service-identities`, body);
|
|
23893
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23894
|
+
});
|
|
23895
|
+
server.tool("goodmem_service_identities_delete", "Delete a service identity\n\nPermanently soft-deletes the principal. Its stored credentials remain audit records but can no longer authenticate because their subject is deleted. Repeating an authorized delete succeeds without rewriting audit data.", {
|
|
23896
|
+
id: external_exports.string().describe("Service-identity UUID")
|
|
23897
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
23898
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
23899
|
+
throw new Error("'id' must be a non-empty string");
|
|
23900
|
+
}
|
|
23901
|
+
await callApi("DELETE", `/v1/service-identities/${encodeURIComponent(String(args.id))}`, void 0);
|
|
23902
|
+
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
23903
|
+
});
|
|
23904
|
+
server.tool("goodmem_service_identities_get", "Get a service identity\n\nReturns a service identity after applying READ_SERVICE_IDENTITY authority. include_deleted permits an authorized caller to inspect a permanent tombstone; it does not grant additional authority.", {
|
|
23905
|
+
id: external_exports.string().describe("Service-identity UUID"),
|
|
23906
|
+
include_deleted: external_exports.boolean().describe("Permit an authorized read of a permanent tombstone").optional()
|
|
23907
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23908
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
23909
|
+
throw new Error("'id' must be a non-empty string");
|
|
23910
|
+
}
|
|
23911
|
+
const query = {};
|
|
23912
|
+
if (args.include_deleted !== void 0)
|
|
23913
|
+
query["includeDeleted"] = String(args.include_deleted);
|
|
23914
|
+
const result = await callApi("GET", `/v1/service-identities/${encodeURIComponent(String(args.id))}`, void 0, query);
|
|
23915
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23916
|
+
});
|
|
23917
|
+
server.tool("goodmem_service_identities_list", "List service identities\n\nRequires LIST_SERVICE_IDENTITY on the GoodMem instance and READ_SERVICE_IDENTITY on each returned row. Owner and label filters, lifecycle filtering, authorization, and keyset pagination execute in PostgreSQL. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production).", {
|
|
23918
|
+
owner_principal_id: external_exports.string().describe("Exact current administrative-owner principal UUID").optional(),
|
|
23919
|
+
include_deleted: external_exports.boolean().describe("Include readable permanent tombstones").optional(),
|
|
23920
|
+
max_results: external_exports.number().int().describe("Page size; defaults to 50 and must be between 1 and 1000").optional(),
|
|
23921
|
+
next_token: external_exports.string().describe("Opaque continuation token").optional(),
|
|
23922
|
+
label: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by label. Each key-value pair is sent as label[key]=value query parameter.").optional()
|
|
23923
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23924
|
+
const query = {};
|
|
23925
|
+
if (args.owner_principal_id !== void 0)
|
|
23926
|
+
query["ownerPrincipalId"] = String(args.owner_principal_id);
|
|
23927
|
+
if (args.include_deleted !== void 0)
|
|
23928
|
+
query["includeDeleted"] = String(args.include_deleted);
|
|
23929
|
+
if (args.max_results !== void 0)
|
|
23930
|
+
query["maxResults"] = String(args.max_results);
|
|
23931
|
+
if (args.next_token !== void 0)
|
|
23932
|
+
query["nextToken"] = String(args.next_token);
|
|
23933
|
+
if (args.label) {
|
|
23934
|
+
for (const [k, v] of Object.entries(args.label))
|
|
23935
|
+
query[`label[${k}]`] = v;
|
|
23936
|
+
}
|
|
23937
|
+
const result = await callApi("GET", `/v1/service-identities`, void 0, query);
|
|
23938
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23939
|
+
});
|
|
23940
|
+
server.tool("goodmem_service_identities_transfer_ownership", "Transfer service-identity ownership\n\nTransfers administrative ownership to another active principal. A service identity cannot own itself. The service identity's subject, immutable creator, credentials, grants, and roles are unchanged.", {
|
|
23941
|
+
id: external_exports.string().describe("Service-identity UUID"),
|
|
23942
|
+
new_owner_id: external_exports.string().describe("Existing principal UUID that will become the new owner.")
|
|
23943
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
23944
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
23945
|
+
throw new Error("'id' must be a non-empty string");
|
|
23946
|
+
}
|
|
23947
|
+
const body = {};
|
|
23948
|
+
if (args.new_owner_id !== void 0)
|
|
23949
|
+
body["newOwnerId"] = args.new_owner_id;
|
|
23950
|
+
const result = await callApi("POST", `/v1/service-identities/${encodeURIComponent(String(args.id))}:transferOwnership`, body);
|
|
23951
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23952
|
+
});
|
|
23953
|
+
server.tool("goodmem_service_identities_update", "Update a service identity\n\nUpdates only fields present in the request. Empty description clears that optional field. Ownership changes use the dedicated transfer endpoint.", {
|
|
23954
|
+
id: external_exports.string().describe("Service-identity UUID"),
|
|
23955
|
+
display_name: external_exports.string().describe("Replacement display name. A present blank value is invalid.").optional(),
|
|
23956
|
+
description: external_exports.string().describe("Replacement description. An empty string clears the description.").optional(),
|
|
23957
|
+
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Complete replacement label map; an empty map clears all labels and is mutually exclusive with merge_labels. At most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional(),
|
|
23958
|
+
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to upsert; must contain at least one entry and is mutually exclusive with replace_labels. The final stored map may contain at most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional()
|
|
23959
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
23960
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
23961
|
+
throw new Error("'id' must be a non-empty string");
|
|
23962
|
+
}
|
|
23963
|
+
const body = {};
|
|
23964
|
+
if (args.display_name !== void 0)
|
|
23965
|
+
body["displayName"] = args.display_name;
|
|
23966
|
+
if (args.description !== void 0)
|
|
23967
|
+
body["description"] = args.description;
|
|
23968
|
+
if (args.replace_labels !== void 0)
|
|
23969
|
+
body["replaceLabels"] = args.replace_labels;
|
|
23970
|
+
if (args.merge_labels !== void 0)
|
|
23971
|
+
body["mergeLabels"] = args.merge_labels;
|
|
23972
|
+
const result = await callApi("PUT", `/v1/service-identities/${encodeURIComponent(String(args.id))}`, body);
|
|
23973
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23974
|
+
});
|
|
23975
|
+
server.tool("goodmem_spaces_create", "Create a new Space\n\nCreates a new space with the provided name, labels, and embedder configuration. A space is a container for organizing related memories. OWNER DEFAULTS: Owner defaults to the authenticated principal unless owner_id is provided; CREATE_SPACE is evaluated against the proposed space and owner. EMBEDDER REQUIREMENTS: At least one embedder configuration must be specified. Every referenced embedder must exist, and the caller must have EXECUTE_EMBEDDER on each one. DUPLICATE DETECTION: Returns ALREADY_EXISTS if another space exists with identical {owner_id, name} (case-sensitive). This operation is NOT idempotent.", {
|
|
23146
23976
|
name: external_exports.string().describe("The desired name for the space. Must be unique within the user's scope."),
|
|
23147
23977
|
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("A set of key-value pairs to categorize or tag the space. Used for filtering and organizational purposes.").optional(),
|
|
23148
23978
|
space_embedders: external_exports.array(external_exports.object({
|
|
23149
23979
|
embedderId: external_exports.string().describe("The UUID for the embedder to associate with the space."),
|
|
23150
23980
|
defaultRetrievalWeight: external_exports.number().describe("Relative weight for this embedder used by default during retrieval. If omitted, defaults to 1.0; values need not sum to 1 and can be overridden per request.").optional()
|
|
23151
23981
|
}).passthrough()).describe("List of embedder configurations to associate with this space. At least one embedder configuration is required. Each specifies an embedder ID and a relative default retrieval weight used when no per-request overrides are provided."),
|
|
23152
|
-
|
|
23153
|
-
owner_id: external_exports.string().describe("Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_SPACE_ANY permission if specified.").optional(),
|
|
23982
|
+
owner_id: external_exports.string().describe("Optional owner principal UUID. If omitted, defaults to the authenticated principal. CREATE_SPACE is evaluated against the proposed space and owner.").optional(),
|
|
23154
23983
|
default_chunking_config: external_exports.object({
|
|
23155
23984
|
none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
|
|
23156
23985
|
recursive: external_exports.object({
|
|
@@ -23169,7 +23998,7 @@ function registerTools() {
|
|
|
23169
23998
|
}).passthrough().describe("Sentence-based chunking strategy with language detection").optional()
|
|
23170
23999
|
}).passthrough().describe("Default chunking strategy for memories in this space"),
|
|
23171
24000
|
space_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional()
|
|
23172
|
-
}, async (args) => {
|
|
24001
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
23173
24002
|
const body = {};
|
|
23174
24003
|
if (args.name !== void 0)
|
|
23175
24004
|
body["name"] = args.name;
|
|
@@ -23177,8 +24006,6 @@ function registerTools() {
|
|
|
23177
24006
|
body["labels"] = args.labels;
|
|
23178
24007
|
if (args.space_embedders !== void 0)
|
|
23179
24008
|
body["spaceEmbedders"] = args.space_embedders;
|
|
23180
|
-
if (args.public_read !== void 0)
|
|
23181
|
-
body["publicRead"] = args.public_read;
|
|
23182
24009
|
if (args.owner_id !== void 0)
|
|
23183
24010
|
body["ownerId"] = args.owner_id;
|
|
23184
24011
|
if (args.default_chunking_config !== void 0)
|
|
@@ -23188,18 +24015,18 @@ function registerTools() {
|
|
|
23188
24015
|
const result = await callApi("POST", `/v1/spaces`, body);
|
|
23189
24016
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23190
24017
|
});
|
|
23191
|
-
server.tool("goodmem_spaces_delete", "Delete a space\n\nPermanently deletes a space and all associated content. This operation cannot be undone. CASCADE DELETION: Removes the space record and cascades deletion to associated memories, chunks, and embedder associations. Requires
|
|
24018
|
+
server.tool("goodmem_spaces_delete", "Delete a space\n\nPermanently deletes a space and all associated content. This operation cannot be undone. CASCADE DELETION: Removes the space record and cascades deletion to associated memories, chunks, and embedder associations. Requires DELETE_SPACE on the requested space. This operation is safe to retry and may return NOT_FOUND if the space was already deleted.", {
|
|
23192
24019
|
id: external_exports.string().describe("The unique identifier of the space to delete")
|
|
23193
|
-
}, async (args) => {
|
|
24020
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
23194
24021
|
if (typeof args.id !== "string" || args.id === "") {
|
|
23195
24022
|
throw new Error("'id' must be a non-empty string");
|
|
23196
24023
|
}
|
|
23197
24024
|
await callApi("DELETE", `/v1/spaces/${encodeURIComponent(String(args.id))}`, void 0);
|
|
23198
24025
|
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
23199
24026
|
});
|
|
23200
|
-
server.tool("goodmem_spaces_get", "Get a space by ID\n\nRetrieves a specific space by its unique identifier. Returns the complete space information, including name, labels, embedder configuration, and metadata.
|
|
24027
|
+
server.tool("goodmem_spaces_get", "Get a space by ID\n\nRetrieves a specific space by its unique identifier. Returns the complete space information, including name, labels, embedder configuration, and metadata. Requires READ_SPACE on the requested space. The service distinguishes a missing space from an existing space the caller cannot read. This is a read-only operation safe to retry.", {
|
|
23201
24028
|
id: external_exports.string().describe("The unique identifier of the space to retrieve")
|
|
23202
|
-
}, async (args) => {
|
|
24029
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23203
24030
|
if (typeof args.id !== "string" || args.id === "") {
|
|
23204
24031
|
throw new Error("'id' must be a non-empty string");
|
|
23205
24032
|
}
|
|
@@ -23207,14 +24034,14 @@ function registerTools() {
|
|
|
23207
24034
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23208
24035
|
});
|
|
23209
24036
|
server.tool("goodmem_spaces_list", "List spaces accessible to the caller, with optional filtering by owner, labels, and name. Results are paginated; pass the response's `next_token` back as a query parameter to fetch subsequent pages.", {
|
|
23210
|
-
owner_id: external_exports.string().describe("Filter
|
|
24037
|
+
owner_id: external_exports.string().describe("Filter the already-authorized result set by owner principal UUID. Omitting this parameter does not bypass per-space READ_SPACE filtering.").optional(),
|
|
23211
24038
|
name_filter: external_exports.string().describe("Filter spaces by name using glob pattern matching").optional(),
|
|
23212
24039
|
max_results: external_exports.number().int().describe("Maximum number of results to return in a single page (defaults to 50, clamped to [1, 1000])").optional(),
|
|
23213
24040
|
next_token: external_exports.string().describe("Pagination token for retrieving the next set of results").optional(),
|
|
23214
24041
|
sort_by: external_exports.enum(["created_time", "updated_time", "name"]).describe("Field to sort by: 'created_time', 'updated_time', or 'name' (default: 'created_time'). Unsupported values return INVALID_ARGUMENT.").optional(),
|
|
23215
24042
|
sort_order: external_exports.enum(["ASCENDING", "DESCENDING", "SORT_ORDER_UNSPECIFIED"]).describe("Sort order (ASCENDING or DESCENDING, default: DESCENDING)").optional(),
|
|
23216
24043
|
label: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by label. Each key-value pair is sent as label[key]=value query parameter.").optional()
|
|
23217
|
-
}, async (args) => {
|
|
24044
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23218
24045
|
const query = {};
|
|
23219
24046
|
if (args.owner_id !== void 0)
|
|
23220
24047
|
query["ownerId"] = String(args.owner_id);
|
|
@@ -23235,13 +24062,25 @@ function registerTools() {
|
|
|
23235
24062
|
const result = await callApi("GET", `/v1/spaces`, void 0, query);
|
|
23236
24063
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23237
24064
|
});
|
|
23238
|
-
server.tool("
|
|
24065
|
+
server.tool("goodmem_spaces_transfer_ownership", "Transfer ownership of a space\n\nTransfers an existing space to another active human or service principal. The current space owner, the GoodMem instance owner, or an instance administrator may transfer it; a space-scoped administrator cannot. Only owner and update-audit fields change. Memories, embedder associations, grants, and role assignments remain unchanged. This operation is not idempotent under response semantics: after an unknown outcome, read the space before retrying.", {
|
|
24066
|
+
id: external_exports.string().describe("UUID of the existing space to transfer"),
|
|
24067
|
+
new_owner_id: external_exports.string().describe("Existing principal UUID that will become the new owner.")
|
|
24068
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
24069
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
24070
|
+
throw new Error("'id' must be a non-empty string");
|
|
24071
|
+
}
|
|
24072
|
+
const body = {};
|
|
24073
|
+
if (args.new_owner_id !== void 0)
|
|
24074
|
+
body["newOwnerId"] = args.new_owner_id;
|
|
24075
|
+
const result = await callApi("POST", `/v1/spaces/${encodeURIComponent(String(args.id))}:transferOwnership`, body);
|
|
24076
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24077
|
+
});
|
|
24078
|
+
server.tool("goodmem_spaces_update", "Update a space\n\nUpdates an existing space with new values for the specified fields. Only name and labels can be updated. Fields not included in the request remain unchanged. IMMUTABLE FIELDS: space_embedders, default_chunking_config, and ownerId cannot be modified after creation. NAME UNIQUENESS: Name must be unique per owner - returns ALREADY_EXISTS if name conflicts with an existing space. Requires UPDATE_SPACE on the requested space. This operation is idempotent.", {
|
|
23239
24079
|
id: external_exports.string().describe("The unique identifier of the space to update"),
|
|
23240
24080
|
name: external_exports.string().describe("The new name for the space.").optional(),
|
|
23241
|
-
public_read: external_exports.boolean().describe("Whether the space is publicly readable by all users.").optional(),
|
|
23242
24081
|
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to replace all existing labels. Mutually exclusive with merge_labels.").optional(),
|
|
23243
24082
|
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to merge with existing labels. Mutually exclusive with replace_labels.").optional()
|
|
23244
|
-
}, async (args) => {
|
|
24083
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
23245
24084
|
if (typeof args.id !== "string" || args.id === "") {
|
|
23246
24085
|
throw new Error("'id' must be a non-empty string");
|
|
23247
24086
|
}
|
|
@@ -23252,8 +24091,6 @@ function registerTools() {
|
|
|
23252
24091
|
const body = {};
|
|
23253
24092
|
if (args.name !== void 0)
|
|
23254
24093
|
body["name"] = args.name;
|
|
23255
|
-
if (args.public_read !== void 0)
|
|
23256
|
-
body["publicRead"] = args.public_read;
|
|
23257
24094
|
if (args.replace_labels !== void 0)
|
|
23258
24095
|
body["replaceLabels"] = args.replace_labels;
|
|
23259
24096
|
if (args.merge_labels !== void 0)
|
|
@@ -23261,18 +24098,80 @@ function registerTools() {
|
|
|
23261
24098
|
const result = await callApi("PUT", `/v1/spaces/${encodeURIComponent(String(args.id))}`, body);
|
|
23262
24099
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23263
24100
|
});
|
|
23264
|
-
server.tool("goodmem_system_info", "Retrieve server build metadata\n\nReturns the server's advertised semantic version, git metadata, build timestamp, and optional capability flags. The endpoint is intentionally unauthenticated so bootstrap tooling can call it before API keys exist.", {}, async (args) => {
|
|
24101
|
+
server.tool("goodmem_system_info", "Retrieve server build metadata\n\nReturns the server's advertised semantic version, git metadata, build timestamp, and optional capability flags. The endpoint is intentionally unauthenticated so bootstrap tooling can call it before API keys exist.", {}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23265
24102
|
const result = await callApi("GET", `/v1/system/info`, void 0);
|
|
23266
24103
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23267
24104
|
});
|
|
23268
|
-
server.tool("goodmem_system_init", "Initialize the system\n\nInitializes the system by creating a root user and API key. This endpoint should only be called once during first-time setup. If the system is already initialized, the endpoint will return a success response without creating new credentials.", {}, async (args) => {
|
|
24105
|
+
server.tool("goodmem_system_init", "Initialize the system\n\nInitializes the system by creating a root user and API key. This endpoint should only be called once during first-time setup. If the system is already initialized, the endpoint will return a success response without creating new credentials.", {}, { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
23269
24106
|
const result = await callApi("POST", `/v1/system/init`, void 0);
|
|
23270
24107
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23271
24108
|
});
|
|
24109
|
+
server.tool("goodmem_user_enrollments_complete", "Complete human-user enrollment\n\nExchanges a one-time enrollment credential for the human's initial self-owned API key. This endpoint does not use ordinary API-key authentication. Omit both optional key fields for server generation; a fresh response discloses the raw key exactly once and cannot be safely retried after an ambiguous outcome. Supply and retain both fields for client mode, where only an exact tuple retry is safe and raw material is never echoed. Status precedence is request-shape errors (400), then the same generic authentication failure for every nonblank unusable enrollment (401); key conflicts or concurrent lifecycle winners return 409, rate limits return 429, and unexpected failures return 500.", {
|
|
24110
|
+
enrollment_token: external_exports.string().describe("Required one-time enrollment credential. Never log or persist it."),
|
|
24111
|
+
api_key_id: external_exports.string().describe("Optional client-generated API-key UUID retained for exact retries. Must be supplied together with raw_api_key, or both fields must be omitted.").optional(),
|
|
24112
|
+
raw_api_key: external_exports.string().describe("Optional canonical client-generated API key. Must be supplied together with api_key_id, never logged, and retained for exact retries; omit both fields for server generation.").optional()
|
|
24113
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
24114
|
+
const body = {};
|
|
24115
|
+
if (args.enrollment_token !== void 0)
|
|
24116
|
+
body["enrollmentToken"] = args.enrollment_token;
|
|
24117
|
+
if (args.api_key_id !== void 0)
|
|
24118
|
+
body["apiKeyId"] = args.api_key_id;
|
|
24119
|
+
if (args.raw_api_key !== void 0)
|
|
24120
|
+
body["rawApiKey"] = args.raw_api_key;
|
|
24121
|
+
const result = await callApi("POST", `/v1/user-enrollments:complete`, body);
|
|
24122
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24123
|
+
});
|
|
24124
|
+
server.tool("goodmem_users_create", "Create a human user\n\nCreates one dormant human user after requiring instance-wide CREATE_USER authority. Creation does not issue a credential or create a role, grant, or authentication mapping.", {
|
|
24125
|
+
user_id: external_exports.string().describe("Optional client-provided user UUID; generated by the server when omitted.").optional(),
|
|
24126
|
+
email: external_exports.string().describe("Unique, nonempty email address."),
|
|
24127
|
+
username: external_exports.string().describe("Optional unique username.").optional(),
|
|
24128
|
+
display_name: external_exports.string().describe("Optional human-facing display name.").optional(),
|
|
24129
|
+
labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Optional labels for organization and filtering. At most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional()
|
|
24130
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
24131
|
+
const body = {};
|
|
24132
|
+
if (args.user_id !== void 0)
|
|
24133
|
+
body["userId"] = args.user_id;
|
|
24134
|
+
if (args.email !== void 0)
|
|
24135
|
+
body["email"] = args.email;
|
|
24136
|
+
if (args.username !== void 0)
|
|
24137
|
+
body["username"] = args.username;
|
|
24138
|
+
if (args.display_name !== void 0)
|
|
24139
|
+
body["displayName"] = args.display_name;
|
|
24140
|
+
if (args.labels !== void 0)
|
|
24141
|
+
body["labels"] = args.labels;
|
|
24142
|
+
const result = await callApi("POST", `/v1/users`, body);
|
|
24143
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24144
|
+
});
|
|
24145
|
+
server.tool("goodmem_users_create_enrollment", "Create a human-user enrollment\n\nCreates a short-lived, one-time enrollment credential for an existing dormant human. Requires MANAGE_USER_ENROLLMENT with ANY or EXACT authority on the target user. The raw credential is returned only once. rotate_existing atomically revokes and replaces a live enrollment; an expired enrollment is replaced automatically.", {
|
|
24146
|
+
user_id: external_exports.string().describe("Human-user UUID"),
|
|
24147
|
+
enrollment_id: external_exports.string().describe("Optional client-provided enrollment UUID; generated when omitted.").optional(),
|
|
24148
|
+
rotate_existing: external_exports.boolean().describe("Whether an existing live enrollment may be revoked and atomically replaced.").optional()
|
|
24149
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }, async (args) => {
|
|
24150
|
+
if (typeof args.user_id !== "string" || args.user_id === "") {
|
|
24151
|
+
throw new Error("'user_id' must be a non-empty string");
|
|
24152
|
+
}
|
|
24153
|
+
const body = {};
|
|
24154
|
+
if (args.enrollment_id !== void 0)
|
|
24155
|
+
body["enrollmentId"] = args.enrollment_id;
|
|
24156
|
+
if (args.rotate_existing !== void 0)
|
|
24157
|
+
body["rotateExisting"] = args.rotate_existing;
|
|
24158
|
+
const result = await callApi("POST", `/v1/users/${encodeURIComponent(String(args.user_id))}/enrollments`, body);
|
|
24159
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24160
|
+
});
|
|
24161
|
+
server.tool("goodmem_users_delete", "Delete a human user\n\nPermanently soft-deletes the user and invalidates credentials acting for that subject. The GoodMem instance owner cannot be deleted; transfer ownership first. Repeating an authorized delete succeeds without rewriting audit data.", {
|
|
24162
|
+
id: external_exports.string().describe("User UUID")
|
|
24163
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
24164
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
24165
|
+
throw new Error("'id' must be a non-empty string");
|
|
24166
|
+
}
|
|
24167
|
+
await callApi("DELETE", `/v1/users/${encodeURIComponent(String(args.id))}`, void 0);
|
|
24168
|
+
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
24169
|
+
});
|
|
23272
24170
|
server.tool("goodmem_users_get", "Retrieves a user by ID or email address. Exactly one of `id` and `email` must be provided. For getting your own profile, use the `goodmem_users_me` tool.", {
|
|
23273
|
-
id: external_exports.string().describe("
|
|
23274
|
-
email: external_exports.string().describe("
|
|
23275
|
-
|
|
24171
|
+
id: external_exports.string().describe("User UUID").optional(),
|
|
24172
|
+
email: external_exports.string().describe("URL-encoded email address").optional(),
|
|
24173
|
+
include_deleted: external_exports.boolean().describe("Permit an authorized read of a permanent tombstone").optional()
|
|
24174
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23276
24175
|
const _hasId = typeof args.id === "string" && args.id !== "";
|
|
23277
24176
|
const _hasEmail = typeof args.email === "string" && args.email !== "";
|
|
23278
24177
|
if (_hasId && _hasEmail)
|
|
@@ -23280,13 +24179,119 @@ function registerTools() {
|
|
|
23280
24179
|
if (!_hasId && !_hasEmail)
|
|
23281
24180
|
throw new Error("Exactly one of 'id', 'email' must be provided (non-empty).");
|
|
23282
24181
|
const url = _hasEmail ? `/v1/users/email/${encodeURIComponent(String(args.email))}` : `/v1/users/${encodeURIComponent(String(args.id))}`;
|
|
23283
|
-
const
|
|
24182
|
+
const query = {};
|
|
24183
|
+
if (args.include_deleted !== void 0)
|
|
24184
|
+
query["includeDeleted"] = String(args.include_deleted);
|
|
24185
|
+
const result = await callApi("GET", url, void 0, query);
|
|
24186
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24187
|
+
});
|
|
24188
|
+
server.tool("goodmem_users_get_by_username", "Get user by username\n\nReturns a user selected by exact username after applying READ_USER authority. include_deleted permits an authorized caller to inspect a permanent tombstone; it does not grant additional authority. Missing and unauthorized matches both return 404 so this guessable identifier cannot reveal whether a user exists.", {
|
|
24189
|
+
username: external_exports.string().describe("Exact username"),
|
|
24190
|
+
include_deleted: external_exports.boolean().describe("Permit an authorized read of a permanent tombstone").optional()
|
|
24191
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
24192
|
+
if (typeof args.username !== "string" || args.username === "") {
|
|
24193
|
+
throw new Error("'username' must be a non-empty string");
|
|
24194
|
+
}
|
|
24195
|
+
const query = {};
|
|
24196
|
+
if (args.include_deleted !== void 0)
|
|
24197
|
+
query["includeDeleted"] = String(args.include_deleted);
|
|
24198
|
+
const result = await callApi("GET", `/v1/users/username/${encodeURIComponent(String(args.username))}`, void 0, query);
|
|
23284
24199
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23285
24200
|
});
|
|
23286
|
-
server.tool("
|
|
24201
|
+
server.tool("goodmem_users_get_enrollment", "Get a human-user enrollment\n\nReturns non-secret metadata for one current or historical enrollment. The target user is resolved before the enrollment, and MANAGE_USER_ENROLLMENT with ANY or EXACT authority on that user is required. Raw enrollment tokens are never returned.", {
|
|
24202
|
+
user_id: external_exports.string().describe("Human-user UUID"),
|
|
24203
|
+
enrollment_id: external_exports.string().describe("Enrollment UUID")
|
|
24204
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
24205
|
+
if (typeof args.user_id !== "string" || args.user_id === "") {
|
|
24206
|
+
throw new Error("'user_id' must be a non-empty string");
|
|
24207
|
+
}
|
|
24208
|
+
if (typeof args.enrollment_id !== "string" || args.enrollment_id === "") {
|
|
24209
|
+
throw new Error("'enrollment_id' must be a non-empty string");
|
|
24210
|
+
}
|
|
24211
|
+
const result = await callApi("GET", `/v1/users/${encodeURIComponent(String(args.user_id))}/enrollments/${encodeURIComponent(String(args.enrollment_id))}`, void 0);
|
|
24212
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24213
|
+
});
|
|
24214
|
+
server.tool("goodmem_users_list", "List human users\n\nRequires LIST_USER on the GoodMem instance and READ_USER on each returned row. Authorization, label filtering, lifecycle filtering, and keyset pagination run in PostgreSQL. include_deleted expands the lifecycle view but grants no access. include_enrollment_summary requests non-secret bootstrap posture only on active rows where MANAGE_USER_ENROLLMENT is independently authorized. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production).", {
|
|
24215
|
+
include_deleted: external_exports.boolean().describe("Include readable permanent tombstones").optional(),
|
|
24216
|
+
include_enrollment_summary: external_exports.boolean().describe("Request non-secret enrollment posture on active rows where the caller also has MANAGE_USER_ENROLLMENT").optional(),
|
|
24217
|
+
max_results: external_exports.number().int().describe("Page size; defaults to 50 and must be between 1 and 1000").optional(),
|
|
24218
|
+
next_token: external_exports.string().describe("Opaque continuation token").optional(),
|
|
24219
|
+
label: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by label. Each key-value pair is sent as label[key]=value query parameter.").optional()
|
|
24220
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
24221
|
+
const query = {};
|
|
24222
|
+
if (args.include_deleted !== void 0)
|
|
24223
|
+
query["includeDeleted"] = String(args.include_deleted);
|
|
24224
|
+
if (args.include_enrollment_summary !== void 0)
|
|
24225
|
+
query["includeEnrollmentSummary"] = String(args.include_enrollment_summary);
|
|
24226
|
+
if (args.max_results !== void 0)
|
|
24227
|
+
query["maxResults"] = String(args.max_results);
|
|
24228
|
+
if (args.next_token !== void 0)
|
|
24229
|
+
query["nextToken"] = String(args.next_token);
|
|
24230
|
+
if (args.label) {
|
|
24231
|
+
for (const [k, v] of Object.entries(args.label))
|
|
24232
|
+
query[`label[${k}]`] = v;
|
|
24233
|
+
}
|
|
24234
|
+
const result = await callApi("GET", `/v1/users`, void 0, query);
|
|
24235
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24236
|
+
});
|
|
24237
|
+
server.tool("goodmem_users_list_enrollments", "List a human user's enrollments\n\nReturns one newest-first page containing pending, expired, consumed, and revoked enrollment metadata. MANAGE_USER_ENROLLMENT with ANY or EXACT authority on the target user is required. The page never contains raw credentials.", {
|
|
24238
|
+
user_id: external_exports.string().describe("Human-user UUID"),
|
|
24239
|
+
max_results: external_exports.number().int().describe("Page size; defaults to 50 and must be between 1 and 1000").optional(),
|
|
24240
|
+
next_token: external_exports.string().describe("Opaque continuation token").optional()
|
|
24241
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
24242
|
+
if (typeof args.user_id !== "string" || args.user_id === "") {
|
|
24243
|
+
throw new Error("'user_id' must be a non-empty string");
|
|
24244
|
+
}
|
|
24245
|
+
const query = {};
|
|
24246
|
+
if (args.max_results !== void 0)
|
|
24247
|
+
query["maxResults"] = String(args.max_results);
|
|
24248
|
+
if (args.next_token !== void 0)
|
|
24249
|
+
query["nextToken"] = String(args.next_token);
|
|
24250
|
+
const result = await callApi("GET", `/v1/users/${encodeURIComponent(String(args.user_id))}/enrollments`, void 0, query);
|
|
24251
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24252
|
+
});
|
|
24253
|
+
server.tool("goodmem_users_me", "Get current user profile\n\nReturns the human-user profile associated with the authenticated principal. Service principals do not have a human-user profile.", {}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
|
|
23287
24254
|
const result = await callApi("GET", `/v1/users/me`, void 0);
|
|
23288
24255
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
23289
24256
|
});
|
|
24257
|
+
server.tool("goodmem_users_revoke_enrollment", "Revoke a human-user enrollment\n\nPermanently revokes one outstanding enrollment after requiring MANAGE_USER_ENROLLMENT on its target user. Repeating an authorized revocation succeeds without replacing its original audit provenance. Consumed enrollments cannot be revoked.", {
|
|
24258
|
+
user_id: external_exports.string().describe("Human-user UUID"),
|
|
24259
|
+
enrollment_id: external_exports.string().describe("Enrollment UUID")
|
|
24260
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
24261
|
+
if (typeof args.user_id !== "string" || args.user_id === "") {
|
|
24262
|
+
throw new Error("'user_id' must be a non-empty string");
|
|
24263
|
+
}
|
|
24264
|
+
if (typeof args.enrollment_id !== "string" || args.enrollment_id === "") {
|
|
24265
|
+
throw new Error("'enrollment_id' must be a non-empty string");
|
|
24266
|
+
}
|
|
24267
|
+
await callApi("DELETE", `/v1/users/${encodeURIComponent(String(args.user_id))}/enrollments/${encodeURIComponent(String(args.enrollment_id))}`, void 0);
|
|
24268
|
+
return { content: [{ type: "text", text: "Deleted successfully." }] };
|
|
24269
|
+
});
|
|
24270
|
+
server.tool("goodmem_users_update", "Update a human user\n\nUpdates only fields present in the request. Empty username or display_name values clear those optional fields. Updating a deleted user fails with 412.", {
|
|
24271
|
+
id: external_exports.string().describe("User UUID"),
|
|
24272
|
+
email: external_exports.string().describe("Replacement email. A present empty value is invalid.").optional(),
|
|
24273
|
+
username: external_exports.string().describe("Replacement username. An empty string clears the username.").optional(),
|
|
24274
|
+
display_name: external_exports.string().describe("Replacement display name. An empty string clears the display name.").optional(),
|
|
24275
|
+
replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Complete replacement label map; an empty map clears all labels and is mutually exclusive with merge_labels. At most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional(),
|
|
24276
|
+
merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to upsert; must contain at least one entry and is mutually exclusive with replace_labels. The final stored map may contain at most 20 entries; keys and values contain at most 255 characters; keys use [a-z0-9._-].").optional()
|
|
24277
|
+
}, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
|
|
24278
|
+
if (typeof args.id !== "string" || args.id === "") {
|
|
24279
|
+
throw new Error("'id' must be a non-empty string");
|
|
24280
|
+
}
|
|
24281
|
+
const body = {};
|
|
24282
|
+
if (args.email !== void 0)
|
|
24283
|
+
body["email"] = args.email;
|
|
24284
|
+
if (args.username !== void 0)
|
|
24285
|
+
body["username"] = args.username;
|
|
24286
|
+
if (args.display_name !== void 0)
|
|
24287
|
+
body["displayName"] = args.display_name;
|
|
24288
|
+
if (args.replace_labels !== void 0)
|
|
24289
|
+
body["replaceLabels"] = args.replace_labels;
|
|
24290
|
+
if (args.merge_labels !== void 0)
|
|
24291
|
+
body["mergeLabels"] = args.merge_labels;
|
|
24292
|
+
const result = await callApi("PUT", `/v1/users/${encodeURIComponent(String(args.id))}`, body);
|
|
24293
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24294
|
+
});
|
|
23290
24295
|
}
|
|
23291
24296
|
registerTools();
|
|
23292
24297
|
async function healthCheck() {
|