@pairsystems/goodmem-mcp 0.1.18 → 0.1.20

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.
Files changed (2) hide show
  1. package/dist/index.js +433 -70
  2. 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
- function normalizeComponentEncoding(component, esc2) {
3301
- const func = esc2 !== true ? escape : unescape;
3302
- if (component.scheme !== void 0) {
3303
- component.scheme = func(component.scheme);
3304
- }
3305
- if (component.userinfo !== void 0) {
3306
- component.userinfo = func(component.userinfo);
3307
- }
3308
- if (component.host !== void 0) {
3309
- component.host = func(component.host);
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
- if (component.path !== void 0) {
3312
- component.path = func(component.path);
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
- if (component.query !== void 0) {
3315
- component.query = func(component.query);
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
- if (component.fragment !== void 0) {
3318
- component.fragment = func(component.fragment);
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 component;
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 = component.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
- normalizeComponentEncoding,
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, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
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
- serialize(parse3(uri, options), options);
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 resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
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
- if (typeof uriA === "string") {
3646
- uriA = unescape(uriA);
3647
- uriA = serialize(normalizeComponentEncoding(parse3(uriA, options), true), { ...options, skipEscape: true });
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 = escape(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 = unescape(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
- function parse3(uri, opts) {
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.domainToASCII(parsed.host.toLowerCase());
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 = escape(unescape(parsed.path));
3882
+ parsed.path = normalizePathEncoding(parsed.path);
3796
3883
  }
3797
3884
  if (parsed.fragment) {
3798
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
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,
@@ -21002,7 +21115,7 @@ function _concatBytes(a, b) {
21002
21115
  out.set(b, a.length);
21003
21116
  return out;
21004
21117
  }
21005
- var BASED_ON_GOODMEM_COMMIT = "d868460a59745bd219c2b630d843ef6b555e7d35";
21118
+ var BASED_ON_GOODMEM_COMMIT = "b8e0b5b5b0eb252b5d5f0fcb5439bbe2d12404ba";
21006
21119
  function isConfigured() {
21007
21120
  return goodmemBaseUrl !== "";
21008
21121
  }
@@ -21695,6 +21808,108 @@ var MODEL_REGISTRY = {
21695
21808
  "TEXT"
21696
21809
  ],
21697
21810
  "maxSequenceLength": 32e3
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
+ },
21827
+ "supportedModalities": [
21828
+ "TEXT"
21829
+ ],
21830
+ "maxSequenceLength": 8192
21831
+ },
21832
+ "text-embedding-v3": {
21833
+ "providerType": "DASHSCOPE",
21834
+ "dimensions": {
21835
+ "default": 1024,
21836
+ "allowed": [
21837
+ 512,
21838
+ 768,
21839
+ 1024
21840
+ ]
21841
+ },
21842
+ "supportedModalities": [
21843
+ "TEXT"
21844
+ ],
21845
+ "maxSequenceLength": 8192
21846
+ },
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
+ },
21860
+ "supportedModalities": [
21861
+ "TEXT"
21862
+ ],
21863
+ "maxSequenceLength": 1024
21864
+ },
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
+ },
21877
+ "supportedModalities": [
21878
+ "TEXT"
21879
+ ],
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
21698
21913
  }
21699
21914
  },
21700
21915
  "llms": {
@@ -21847,6 +22062,97 @@ var MODEL_REGISTRY = {
21847
22062
  "TEXT"
21848
22063
  ],
21849
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
21850
22156
  }
21851
22157
  },
21852
22158
  "rerankers": {
@@ -21945,6 +22251,24 @@ var MODEL_REGISTRY = {
21945
22251
  "supportedModalities": [
21946
22252
  "TEXT"
21947
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
+ ]
21948
22272
  }
21949
22273
  }
21950
22274
  };
@@ -21952,7 +22276,8 @@ var PROVIDER_ENDPOINTS = {
21952
22276
  "OPENAI": "https://api.openai.com/v1",
21953
22277
  "COHERE": "https://api.cohere.com",
21954
22278
  "VOYAGE": "https://api.voyageai.com/v1",
21955
- "JINA": "https://api.jina.ai"
22279
+ "JINA": "https://api.jina.ai",
22280
+ "DASHSCOPE": "https://dashscope.aliyuncs.com"
21956
22281
  };
21957
22282
  var PROVIDER_CREDENTIAL_REQUIREMENTS = {
21958
22283
  "OPENAI": [
@@ -21969,6 +22294,12 @@ var PROVIDER_CREDENTIAL_REQUIREMENTS = {
21969
22294
  ],
21970
22295
  "JINA": [
21971
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"
21972
22303
  ]
21973
22304
  };
21974
22305
  function checkCredentialRequired(args) {
@@ -22027,7 +22358,7 @@ function autoInferFromRegistry(registryType, args) {
22027
22358
  }
22028
22359
  var server = new McpServer({
22029
22360
  name: "goodmem",
22030
- version: "0.1.18"
22361
+ version: "0.1.20"
22031
22362
  });
22032
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.", {
22033
22364
  base_url: external_exports.string().describe("GoodMem server URL (e.g., https://your-server.example.com)"),
@@ -22113,7 +22444,7 @@ ${allModels.join("\n")}` }] };
22113
22444
  });
22114
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 () => {
22115
22446
  return { content: [{ type: "text", text: JSON.stringify({
22116
- mcp_version: "0.1.18",
22447
+ mcp_version: "0.1.20",
22117
22448
  based_on_goodmem_commit: BASED_ON_GOODMEM_COMMIT
22118
22449
  }, null, 2) }] };
22119
22450
  });
@@ -22504,12 +22835,12 @@ function registerTools() {
22504
22835
  const result = await callApi("PUT", `/v1/apikeys/${encodeURIComponent(String(args.id))}`, body);
22505
22836
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22506
22837
  });
22507
- server.tool("goodmem_embedders_create", "Create a new embedder\n\nCreates a new embedder configuration for vectorizing content. Embedders represent connections to different embedding API services (like OpenAI, vLLM, etc.) and include all the necessary configuration to use them with memory spaces. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if another embedder exists with identical {owner_id, provider_type, endpoint_url, api_path, model_identifier, dimensionality, distribution_type, credentialsFingerprint} after URL canonicalization. Uniqueness is enforced per-owner, allowing different users to have identical configurations. A SHA-256 credential fingerprint participates in uniqueness checking. The api_path field defaults to '/v2/embed' for Cohere, '/v1/embeddings' for Jina, '/embed' for TEI, and '/embeddings' for other providers when omitted. OWNER DEFAULTS: Owner defaults to the authenticated principal unless owner_id is provided; CREATE_EMBEDDER is evaluated against the proposed embedder and owner.", {
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://docs.goodmem.ai/docs/how-to/endpoint-registration) for provider-specific configuration.", {
22508
22839
  display_name: external_exports.string().describe("User-facing name of the embedder"),
22509
22840
  description: external_exports.string().describe("Description of the embedder").optional(),
22510
- 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(),
22511
- endpoint_url: external_exports.string().describe("API endpoint URL (auto-inferred from model_identifier if omitted)").optional(),
22512
- api_path: external_exports.string().describe("API path for embeddings requests (defaults: Cohere /v2/embed, Jina /v1/embeddings, TEI /embed, others /embeddings)").optional(),
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(),
22513
22844
  model_identifier: external_exports.string().describe("Model identifier"),
22514
22845
  dimensionality: external_exports.number().int().describe("Output vector dimensions (auto-inferred from model_identifier if omitted)").optional(),
22515
22846
  distribution_type: external_exports.enum(["DENSE", "SPARSE"]).describe("Type of embedding distribution (DENSE or SPARSE) (auto-inferred from model_identifier if omitted)").optional(),
@@ -22536,7 +22867,13 @@ function registerTools() {
22536
22867
  version: external_exports.string().describe("Version information").optional(),
22537
22868
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
22538
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(),
22539
- 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()
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()
22540
22877
  }, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
22541
22878
  const inferred = autoInferFromRegistry("embedders", args);
22542
22879
  checkCredentialRequired(inferred);
@@ -22573,6 +22910,10 @@ function registerTools() {
22573
22910
  body["ownerId"] = inferred.owner_id;
22574
22911
  if (inferred.embedder_id !== void 0)
22575
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;
22576
22917
  const result = await callApi("POST", `/v1/embedders`, body);
22577
22918
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22578
22919
  });
@@ -22600,7 +22941,7 @@ function registerTools() {
22600
22941
  });
22601
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.", {
22602
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(),
22603
- 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(),
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(),
22604
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()
22605
22946
  }, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
22606
22947
  const query = {};
@@ -22615,12 +22956,12 @@ function registerTools() {
22615
22956
  const result = await callApi("GET", `/v1/embedders`, void 0, query);
22616
22957
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22617
22958
  });
22618
- server.tool("goodmem_embedders_update", "Update an embedder\n\nUpdates an existing embedder configuration including display information, endpoint configuration, model parameters, credentials, and labels. All fields are optional - only specified fields will be updated. Omitting api_path preserves the existing path; setting it blank resets it to '/v2/embed' for Cohere, '/v1/embeddings' for Jina, '/embed' for TEI, or '/embeddings' for other providers. IMPORTANT: providerType is IMMUTABLE after creation and cannot be changed. CRITICAL: Returns HTTP 412 Precondition Failed (FAILED_PRECONDITION) if attempting to update core fields (dimensionality, distribution_type, model_identifier) while the embedder is actively referenced by spaces or ingestion jobs. DUPLICATE DETECTION: Returns HTTP 409 Conflict (ALREADY_EXISTS) if the update would create a duplicate embedder with the same provider, endpoint, model, dimensionality, distribution, and credentials for this owner. Requires UPDATE_EMBEDDER on the requested embedder.", {
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://docs.goodmem.ai/docs/how-to/endpoint-registration) for provider-specific configuration.", {
22619
22960
  id: external_exports.string().describe("The unique identifier of the embedder to update"),
22620
22961
  display_name: external_exports.string().describe("User-facing name of the embedder").optional(),
22621
22962
  description: external_exports.string().describe("Description of the embedder").optional(),
22622
- endpoint_url: external_exports.string().describe("API endpoint URL").optional(),
22623
- api_path: external_exports.string().describe("API path for embeddings requests. Omit to keep the existing path; set blank to reset to the provider default (Cohere /v2/embed, Jina /v1/embeddings, TEI /embed, others /embeddings).").optional(),
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(),
22624
22965
  model_identifier: external_exports.string().describe("Model identifier").optional(),
22625
22966
  dimensionality: external_exports.number().int().describe("Output vector dimensions").optional(),
22626
22967
  distribution_type: external_exports.enum(["DENSE", "SPARSE"]).describe("Type of embedding distribution (DENSE or SPARSE)").optional(),
@@ -22645,7 +22986,13 @@ function registerTools() {
22645
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(),
22646
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(),
22647
22988
  version: external_exports.string().describe("Version information").optional(),
22648
- monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
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()
22649
22996
  }, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
22650
22997
  if (typeof args.id !== "string" || args.id === "") {
22651
22998
  throw new Error("'id' must be a non-empty string");
@@ -22681,6 +23028,10 @@ function registerTools() {
22681
23028
  body["version"] = args.version;
22682
23029
  if (args.monitoring_endpoint !== void 0)
22683
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;
22684
23035
  const result = await callApi("PUT", `/v1/embedders/${encodeURIComponent(String(args.id))}`, body);
22685
23036
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22686
23037
  });
@@ -22688,10 +23039,10 @@ function registerTools() {
22688
23039
  const result = await callApi("GET", `/v1/instance`, void 0);
22689
23040
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22690
23041
  });
22691
- 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 identical {owner_id, provider_type, endpoint_url, api_path, model_identifier, credentialsFingerprint} after URL canonicalization. Uniqueness is enforced per-owner. Credentials are hashed (SHA-256) for uniqueness while remaining encrypted. 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.", {
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.", {
22692
23043
  display_name: external_exports.string().describe("User-facing name of the LLM"),
22693
23044
  description: external_exports.string().describe("Description of the LLM").optional(),
22694
- 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(),
22695
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(),
22696
23047
  api_path: external_exports.string().describe("API path for chat/completions request (defaults to /chat/completions if not provided)").optional(),
22697
23048
  model_identifier: external_exports.string().describe("Model identifier"),
@@ -22736,7 +23087,8 @@ function registerTools() {
22736
23087
  max_context_length: external_exports.number().int().describe("Maximum context window size in tokens").optional(),
22737
23088
  client_config: external_exports.record(external_exports.string(), external_exports.any()).describe("Provider-specific client configuration as flexible JSON structure").optional(),
22738
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(),
22739
- 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()
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()
22740
23092
  }, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
22741
23093
  const inferred = autoInferFromRegistry("llms", args);
22742
23094
  checkCredentialRequired(inferred);
@@ -22775,6 +23127,8 @@ function registerTools() {
22775
23127
  body["ownerId"] = inferred.owner_id;
22776
23128
  if (inferred.llm_id !== void 0)
22777
23129
  body["llmId"] = inferred.llm_id;
23130
+ if (inferred.dashscope_api_dialect !== void 0)
23131
+ body["dashscopeApiDialect"] = inferred.dashscope_api_dialect;
22778
23132
  const result = await callApi("POST", `/v1/llms`, body);
22779
23133
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22780
23134
  });
@@ -22802,7 +23156,7 @@ function registerTools() {
22802
23156
  });
22803
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.", {
22804
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(),
22805
- 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(),
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(),
22806
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()
22807
23161
  }, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
22808
23162
  const query = {};
@@ -22864,7 +23218,8 @@ function registerTools() {
22864
23218
  max_context_length: external_exports.number().int().describe("Update maximum context window size in tokens").optional(),
22865
23219
  client_config: external_exports.record(external_exports.string(), external_exports.any()).describe("Update provider-specific client configuration (replaces entire config; no merging)").optional(),
22866
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(),
22867
- 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()
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()
22868
23223
  }, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
22869
23224
  if (typeof args.id !== "string" || args.id === "") {
22870
23225
  throw new Error("'id' must be a non-empty string");
@@ -22904,6 +23259,8 @@ function registerTools() {
22904
23259
  body["replaceLabels"] = args.replace_labels;
22905
23260
  if (args.merge_labels !== void 0)
22906
23261
  body["mergeLabels"] = args.merge_labels;
23262
+ if (args.dashscope_api_dialect !== void 0)
23263
+ body["dashscopeApiDialect"] = args.dashscope_api_dialect;
22907
23264
  const result = await callApi("PUT", `/v1/llms/${encodeURIComponent(String(args.id))}`, body);
22908
23265
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22909
23266
  });
@@ -22915,7 +23272,7 @@ function registerTools() {
22915
23272
  originalContentB64: external_exports.string().describe("Original content as base64-encoded binary data (use either this or originalContent)").optional(),
22916
23273
  originalContentRef: external_exports.string().describe("Reference to external content location").optional(),
22917
23274
  contentType: external_exports.string().describe("MIME type of the content").optional(),
22918
- 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(),
22919
23276
  chunkingConfig: external_exports.object({
22920
23277
  none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
22921
23278
  recursive: external_exports.object({
@@ -23020,7 +23377,7 @@ function registerTools() {
23020
23377
  original_content_b64: external_exports.string().describe("Original content as base64-encoded binary data (use either this or original_content)").optional(),
23021
23378
  original_content_ref: external_exports.string().describe("Reference to external content location").optional(),
23022
23379
  content_type: external_exports.string().describe("MIME type of the content (defaults to text/plain when original_content is provided)").optional(),
23023
- 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(),
23024
23381
  chunking_config: external_exports.object({
23025
23382
  none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
23026
23383
  recursive: external_exports.object({
@@ -23346,10 +23703,10 @@ function registerTools() {
23346
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));
23347
23704
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
23348
23705
  });
23349
- 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 identical {owner_id, provider_type, endpoint_url, api_path, model_identifier, credentialsFingerprint} after URL canonicalization. Uniqueness is enforced per-owner, allowing different users to have identical configurations. A SHA-256 credential fingerprint participates in uniqueness checking. 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.", {
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.", {
23350
23707
  display_name: external_exports.string().describe("User-facing name of the reranker"),
23351
23708
  description: external_exports.string().describe("Description of the reranker").optional(),
23352
- provider_type: external_exports.enum(["OPENAI", "VLLM", "TEI", "LLAMA_CPP", "VOYAGE", "COHERE", "JINA"]).describe("Type of reranking provider (auto-inferred from model_identifier if omitted)").optional(),
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(),
23353
23710
  endpoint_url: external_exports.string().describe("API endpoint URL (auto-inferred from model_identifier if omitted)").optional(),
23354
23711
  api_path: external_exports.string().describe("API path for reranking request (defaults: Cohere /v2/rerank, Jina /v1/rerank, others /rerank)").optional(),
23355
23712
  model_identifier: external_exports.string().describe("Model identifier"),
@@ -23375,7 +23732,8 @@ function registerTools() {
23375
23732
  version: external_exports.string().describe("Version information").optional(),
23376
23733
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
23377
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(),
23378
- 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()
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()
23379
23737
  }, { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, async (args) => {
23380
23738
  const inferred = autoInferFromRegistry("rerankers", args);
23381
23739
  checkCredentialRequired(inferred);
@@ -23406,6 +23764,8 @@ function registerTools() {
23406
23764
  body["ownerId"] = inferred.owner_id;
23407
23765
  if (inferred.reranker_id !== void 0)
23408
23766
  body["rerankerId"] = inferred.reranker_id;
23767
+ if (inferred.dashscope_api_dialect !== void 0)
23768
+ body["dashscopeApiDialect"] = inferred.dashscope_api_dialect;
23409
23769
  const result = await callApi("POST", `/v1/rerankers`, body);
23410
23770
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
23411
23771
  });
@@ -23433,7 +23793,7 @@ function registerTools() {
23433
23793
  });
23434
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.", {
23435
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(),
23436
- 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(),
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(),
23437
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()
23438
23798
  }, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => {
23439
23799
  const query = {};
@@ -23448,7 +23808,7 @@ function registerTools() {
23448
23808
  const result = await callApi("GET", `/v1/rerankers`, void 0, query);
23449
23809
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
23450
23810
  });
23451
- 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 duplicate with same {ownerId, providerType, endpoint_url, api_path, model_identifier, credentialsFingerprint} after URL canonicalization (HTTP 409 Conflict / ALREADY_EXISTS). Requires UPDATE_RERANKER on the requested reranker. This operation is idempotent.", {
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.", {
23452
23812
  id: external_exports.string().describe("The unique identifier of the reranker to update"),
23453
23813
  display_name: external_exports.string().describe("User-facing name of the reranker").optional(),
23454
23814
  description: external_exports.string().describe("Description of the reranker").optional(),
@@ -23476,7 +23836,8 @@ function registerTools() {
23476
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(),
23477
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(),
23478
23838
  version: external_exports.string().describe("Version information").optional(),
23479
- monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
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()
23480
23841
  }, { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (args) => {
23481
23842
  if (typeof args.id !== "string" || args.id === "") {
23482
23843
  throw new Error("'id' must be a non-empty string");
@@ -23508,6 +23869,8 @@ function registerTools() {
23508
23869
  body["version"] = args.version;
23509
23870
  if (args.monitoring_endpoint !== void 0)
23510
23871
  body["monitoringEndpoint"] = args.monitoring_endpoint;
23872
+ if (args.dashscope_api_dialect !== void 0)
23873
+ body["dashscopeApiDialect"] = args.dashscope_api_dialect;
23511
23874
  const result = await callApi("PUT", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, body);
23512
23875
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
23513
23876
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pairsystems/goodmem-mcp",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "GoodMem MCP server \u2014 exposes GoodMem API as MCP tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,6 +14,8 @@
14
14
  ],
15
15
  "scripts": {
16
16
  "build": "tsc && esbuild dist/index.js --bundle --platform=node --format=esm --outfile=dist/index.js --allow-overwrite",
17
+ "test": "npm run build && npm run test:package",
18
+ "test:package": "node --test tests/package/*.test.mjs",
17
19
  "start": "node dist/index.js",
18
20
  "dev": "tsx src/index.ts"
19
21
  },