@pairsystems/goodmem-mcp 0.1.8 → 0.1.10

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 +106 -67
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20988,7 +20988,7 @@ var StdioServerTransport = class {
20988
20988
  // dist/index.js
20989
20989
  var goodmemBaseUrl = process.env.GOODMEM_BASE_URL || "";
20990
20990
  var goodmemApiKey = process.env.GOODMEM_API_KEY || "";
20991
- var BASED_ON_GOODMEM_COMMIT = "55768baed550c339bff8ef3893a8e9a024facc90";
20991
+ var BASED_ON_GOODMEM_COMMIT = "82cedec39260bff105828bed1c1e779d9f1e811f";
20992
20992
  function isConfigured() {
20993
20993
  return goodmemBaseUrl !== "" && goodmemApiKey !== "";
20994
20994
  }
@@ -21023,7 +21023,7 @@ async function callApi(method, path, body, query) {
21023
21023
  }
21024
21024
  return resp.text();
21025
21025
  }
21026
- async function callApiNdjson(method, path, body, query) {
21026
+ async function callApiNdjson(method, path, body, query, timeoutSec) {
21027
21027
  if (!isConfigured()) {
21028
21028
  throw new Error("GoodMem is not configured. Call the goodmem_configure tool first with your base_url and api_key, or set GOODMEM_BASE_URL and GOODMEM_API_KEY environment variables.");
21029
21029
  }
@@ -21042,7 +21042,7 @@ async function callApiNdjson(method, path, body, query) {
21042
21042
  const resp = await fetch(url.toString(), {
21043
21043
  method,
21044
21044
  headers,
21045
- signal: AbortSignal.timeout(2e5),
21045
+ signal: AbortSignal.timeout((timeoutSec ?? 200) * 1e3),
21046
21046
  ...body ? { body: JSON.stringify(body) } : {}
21047
21047
  });
21048
21048
  if (!resp.ok) {
@@ -21920,7 +21920,7 @@ function autoInferFromRegistry(registryType, args) {
21920
21920
  }
21921
21921
  var server = new McpServer({
21922
21922
  name: "goodmem",
21923
- version: "0.1.8"
21923
+ version: "0.1.10"
21924
21924
  });
21925
21925
  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.", {
21926
21926
  base_url: external_exports.string().describe("GoodMem server URL (e.g., https://your-server.example.com)"),
@@ -21944,7 +21944,12 @@ server.tool("goodmem_configure", "Configure GoodMem server connection. Call this
21944
21944
  const info = await resp.json();
21945
21945
  return { content: [{ type: "text", text: `Connected to GoodMem at ${goodmemBaseUrl}. Server version: ${info.version ?? "unknown"}.` }] };
21946
21946
  } catch (err) {
21947
- return { content: [{ type: "text", text: `Could not connect to ${args.base_url}: ${err}. Credentials were NOT saved. Check your base_url.` }] };
21947
+ const msg = err instanceof Error ? err.message : String(err);
21948
+ let hint = "Check your base_url.";
21949
+ if (msg.includes("CERT") || msg.includes("certificate") || msg.includes("self-signed") || msg.includes("self signed") || msg.includes("UNABLE_TO_VERIFY")) {
21950
+ hint = "TLS certificate error. If using self-signed certs, set NODE_TLS_REJECT_UNAUTHORIZED=0 (dev only) or NODE_EXTRA_CA_CERTS=/path/to/rootCA.pem in your MCP server env config.";
21951
+ }
21952
+ return { content: [{ type: "text", text: `Could not connect to ${args.base_url}: ${msg}. Credentials were NOT saved. ${hint}` }] };
21948
21953
  }
21949
21954
  });
21950
21955
  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.", {
@@ -21970,7 +21975,7 @@ ${allModels.join("\n")}` }] };
21970
21975
  });
21971
21976
  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 () => {
21972
21977
  return { content: [{ type: "text", text: JSON.stringify({
21973
- mcpVersion: "0.1.8",
21978
+ mcpVersion: "0.1.10",
21974
21979
  basedOnGoodmemCommit: BASED_ON_GOODMEM_COMMIT
21975
21980
  }, null, 2) }] };
21976
21981
  });
@@ -22013,7 +22018,7 @@ function registerTools() {
22013
22018
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22014
22019
  });
22015
22020
  server.tool("goodmem_apikeys_create", "Create a new API key", {
22016
- labels: external_exports.any().describe("Key-value pairs of metadata associated with the API key. Used for organization and filtering.").optional(),
22021
+ 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.").optional(),
22017
22022
  expires_at: external_exports.number().int().describe("Expiration timestamp in milliseconds since epoch. If not provided, the key does not expire.").optional(),
22018
22023
  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()
22019
22024
  }, async (args) => {
@@ -22040,8 +22045,8 @@ function registerTools() {
22040
22045
  server.tool("goodmem_apikeys_update", "Update an API key", {
22041
22046
  id: external_exports.string().describe("The UUID of the API key to update"),
22042
22047
  status: external_exports.string().describe("New status for the API key. Allowed values: ACTIVE, INACTIVE.").optional(),
22043
- replace_labels: external_exports.any().describe("Replace all existing labels with this set. Mutually exclusive with mergeLabels.").optional(),
22044
- merge_labels: external_exports.any().describe("Merge these labels with existing ones. Mutually exclusive with replaceLabels.").optional()
22048
+ replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with this set. Mutually exclusive with mergeLabels.").optional(),
22049
+ merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones. Mutually exclusive with replaceLabels.").optional()
22045
22050
  }, async (args) => {
22046
22051
  const body = {};
22047
22052
  if (args.status !== void 0)
@@ -22081,7 +22086,7 @@ function registerTools() {
22081
22086
  }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22082
22087
  labels: external_exports.any().describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22083
22088
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider. Required for SaaS providers such as COHERE, JINA, and VOYAGE; optional for local or proxy providers.").optional(),
22084
- labels: external_exports.any().describe("User-defined labels for categorization").optional(),
22089
+ labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
22085
22090
  version: external_exports.string().describe("Version information").optional(),
22086
22091
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
22087
22092
  owner_id: external_exports.string().describe("Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_EMBEDDER_ANY permission if specified.").optional(),
@@ -22126,13 +22131,13 @@ function registerTools() {
22126
22131
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22127
22132
  });
22128
22133
  server.tool("goodmem_embedders_delete", "Delete an embedder", {
22129
- id: external_exports.string().describe("The UUID of the embedder to delete")
22134
+ id: external_exports.string().describe("The unique identifier of the embedder to delete")
22130
22135
  }, async (args) => {
22131
22136
  await callApi("DELETE", `/v1/embedders/${encodeURIComponent(String(args.id))}`, void 0);
22132
22137
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22133
22138
  });
22134
22139
  server.tool("goodmem_embedders_get", "Get an embedder by ID", {
22135
- id: external_exports.string().describe("The UUID of the embedder to retrieve")
22140
+ id: external_exports.string().describe("The unique identifier of the embedder to retrieve")
22136
22141
  }, async (args) => {
22137
22142
  const result = await callApi("GET", `/v1/embedders/${encodeURIComponent(String(args.id))}`, void 0);
22138
22143
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22140,28 +22145,29 @@ function registerTools() {
22140
22145
  server.tool("goodmem_embedders_list", "List embedders", {
22141
22146
  owner_id: external_exports.string().describe("Filter embedders by owner ID. With LIST_EMBEDDER_ANY permission, omitting this shows all accessible embedders; providing it filters by that owner. With LIST_EMBEDDER_OWN permission, only your own embedders are shown regardless of this parameter.").optional(),
22142
22147
  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(),
22143
- labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by labels. Each key-value pair is sent as a label.<key>=<value> query parameter.").optional()
22148
+ 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()
22144
22149
  }, async (args) => {
22145
22150
  const query = {};
22146
22151
  if (args.owner_id !== void 0)
22147
22152
  query["ownerId"] = String(args.owner_id);
22148
22153
  if (args.provider_type !== void 0)
22149
22154
  query["providerType"] = String(args.provider_type);
22150
- if (args.labels) {
22151
- for (const [k, v] of Object.entries(args.labels))
22152
- query[`label.${k}`] = v;
22155
+ if (args.label) {
22156
+ for (const [k, v] of Object.entries(args.label))
22157
+ query[`label[${k}]`] = v;
22153
22158
  }
22154
22159
  const result = await callApi("GET", `/v1/embedders`, void 0, query);
22155
22160
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22156
22161
  });
22157
22162
  server.tool("goodmem_embedders_update", "Update an embedder", {
22158
- id: external_exports.string().describe("The UUID of the embedder to update"),
22163
+ id: external_exports.string().describe("The unique identifier of the embedder to update"),
22159
22164
  display_name: external_exports.string().describe("User-facing name of the embedder").optional(),
22160
22165
  description: external_exports.string().describe("Description of the embedder").optional(),
22161
22166
  endpoint_url: external_exports.string().describe("API endpoint URL").optional(),
22162
22167
  api_path: external_exports.string().describe("API path for embeddings request").optional(),
22163
22168
  model_identifier: external_exports.string().describe("Model identifier").optional(),
22164
22169
  dimensionality: external_exports.number().int().describe("Output vector dimensions").optional(),
22170
+ distribution_type: external_exports.enum(["DENSE", "SPARSE"]).describe("Type of embedding distribution (DENSE or SPARSE)").optional(),
22165
22171
  max_sequence_length: external_exports.number().int().describe("Maximum input sequence length").optional(),
22166
22172
  supported_modalities: external_exports.array(external_exports.enum(["TEXT", "IMAGE", "AUDIO", "VIDEO"])).describe("Supported content modalities").optional(),
22167
22173
  credentials: external_exports.object({
@@ -22181,8 +22187,8 @@ function registerTools() {
22181
22187
  }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22182
22188
  labels: external_exports.any().describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22183
22189
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider").optional(),
22184
- replace_labels: external_exports.any().describe("Replace all existing labels with these (mutually exclusive with mergeLabels)").optional(),
22185
- merge_labels: external_exports.any().describe("Merge these labels with existing ones (mutually exclusive with replaceLabels)").optional(),
22190
+ replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with these (mutually exclusive with mergeLabels)").optional(),
22191
+ merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones (mutually exclusive with replaceLabels)").optional(),
22186
22192
  version: external_exports.string().describe("Version information").optional(),
22187
22193
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
22188
22194
  }, async (args) => {
@@ -22199,6 +22205,8 @@ function registerTools() {
22199
22205
  body["modelIdentifier"] = args.model_identifier;
22200
22206
  if (args.dimensionality !== void 0)
22201
22207
  body["dimensionality"] = args.dimensionality;
22208
+ if (args.distribution_type !== void 0)
22209
+ body["distributionType"] = args.distribution_type;
22202
22210
  if (args.max_sequence_length !== void 0)
22203
22211
  body["maxSequenceLength"] = args.max_sequence_length;
22204
22212
  if (args.supported_modalities !== void 0)
@@ -22241,7 +22249,7 @@ function registerTools() {
22241
22249
  }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22242
22250
  labels: external_exports.any().describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22243
22251
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider. Omit for deployments that do not require credentials.").optional(),
22244
- labels: external_exports.any().describe("User-defined labels for categorization").optional(),
22252
+ labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
22245
22253
  version: external_exports.string().describe("Version information").optional(),
22246
22254
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
22247
22255
  capabilities: external_exports.object({
@@ -22307,13 +22315,13 @@ function registerTools() {
22307
22315
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22308
22316
  });
22309
22317
  server.tool("goodmem_llms_delete", "Delete an LLM", {
22310
- id: external_exports.string().describe("The UUID of the LLM to delete")
22318
+ id: external_exports.string().describe("The unique identifier of the LLM to delete")
22311
22319
  }, async (args) => {
22312
22320
  await callApi("DELETE", `/v1/llms/${encodeURIComponent(String(args.id))}`, void 0);
22313
22321
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22314
22322
  });
22315
22323
  server.tool("goodmem_llms_get", "Get an LLM by ID", {
22316
- id: external_exports.string().describe("The UUID of the LLM to retrieve")
22324
+ id: external_exports.string().describe("The unique identifier of the LLM to retrieve")
22317
22325
  }, async (args) => {
22318
22326
  const result = await callApi("GET", `/v1/llms/${encodeURIComponent(String(args.id))}`, void 0);
22319
22327
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22321,22 +22329,22 @@ function registerTools() {
22321
22329
  server.tool("goodmem_llms_list", "List LLMs", {
22322
22330
  owner_id: external_exports.string().describe("Filter LLMs by owner ID. With LIST_LLM_ANY permission, omitting this shows all accessible LLMs; providing it filters by that owner. With LIST_LLM_OWN permission, only your own LLMs are shown regardless of this parameter.").optional(),
22323
22331
  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(),
22324
- labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by labels. Each key-value pair is sent as a label.<key>=<value> query parameter.").optional()
22332
+ 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()
22325
22333
  }, async (args) => {
22326
22334
  const query = {};
22327
22335
  if (args.owner_id !== void 0)
22328
22336
  query["ownerId"] = String(args.owner_id);
22329
22337
  if (args.provider_type !== void 0)
22330
22338
  query["providerType"] = String(args.provider_type);
22331
- if (args.labels) {
22332
- for (const [k, v] of Object.entries(args.labels))
22333
- query[`label.${k}`] = v;
22339
+ if (args.label) {
22340
+ for (const [k, v] of Object.entries(args.label))
22341
+ query[`label[${k}]`] = v;
22334
22342
  }
22335
22343
  const result = await callApi("GET", `/v1/llms`, void 0, query);
22336
22344
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22337
22345
  });
22338
22346
  server.tool("goodmem_llms_update", "Update an LLM", {
22339
- id: external_exports.string().describe("The UUID of the LLM to update"),
22347
+ id: external_exports.string().describe("The unique identifier of the LLM to update"),
22340
22348
  display_name: external_exports.string().describe("Update display name").optional(),
22341
22349
  description: external_exports.string().describe("Update description").optional(),
22342
22350
  endpoint_url: external_exports.string().describe("Update endpoint base URL (OpenAI-compatible base, typically ends with /v1)").optional(),
@@ -22381,8 +22389,8 @@ function registerTools() {
22381
22389
  }).passthrough().describe("Update default sampling parameters").optional(),
22382
22390
  max_context_length: external_exports.number().int().describe("Update maximum context window size in tokens").optional(),
22383
22391
  client_config: external_exports.any().describe("Update provider-specific client configuration (replaces entire config; no merging)").optional(),
22384
- replace_labels: external_exports.any().describe("Replace all existing labels with this set. Empty map clears all labels. Cannot be used with mergeLabels.").optional(),
22385
- merge_labels: external_exports.any().describe("Merge with existing labels: upserts with overwrite. Labels not mentioned are preserved. Cannot be used with replaceLabels.").optional()
22392
+ 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 mergeLabels.").optional(),
22393
+ 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 replaceLabels.").optional()
22386
22394
  }, async (args) => {
22387
22395
  const body = {};
22388
22396
  if (args.display_name !== void 0)
@@ -22419,7 +22427,34 @@ function registerTools() {
22419
22427
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22420
22428
  });
22421
22429
  server.tool("goodmem_memories_batch_create", "Create multiple memories in a batch", {
22422
- requests: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown()).describe("JsonMemoryCreationRequest object")).describe("Array of memory creation requests.")
22430
+ requests: external_exports.array(external_exports.object({
22431
+ memoryId: external_exports.string().describe("Optional client-provided UUID for the memory. If omitted, the server generates one. Returns ALREADY_EXISTS if the ID is already in use.").optional(),
22432
+ spaceId: external_exports.string().describe("ID of the space where this memory will be stored"),
22433
+ originalContent: external_exports.string().describe("Original content as plain text (use either this or originalContentB64)").optional(),
22434
+ originalContentB64: external_exports.string().describe("Original content as base64-encoded binary data (use either this or originalContent)").optional(),
22435
+ originalContentRef: external_exports.string().describe("Reference to external content location").optional(),
22436
+ contentType: external_exports.string().describe("MIME type of the content"),
22437
+ metadata: external_exports.any().describe("Additional metadata for the memory").optional(),
22438
+ chunkingConfig: external_exports.object({
22439
+ none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
22440
+ recursive: external_exports.object({
22441
+ chunkSize: external_exports.number().int().describe("Maximum size of a chunk (should be \u2264 context window)"),
22442
+ chunkOverlap: external_exports.number().int().describe("Sliding overlap between chunks"),
22443
+ separators: external_exports.any().describe("Hierarchical separator list (order = preference)").optional(),
22444
+ keepStrategy: external_exports.enum(["KEEP_NONE", "KEEP_START", "KEEP_END"]).describe("How to handle separators after splitting. KEEP_NONE is deprecated and behaves as KEEP_END."),
22445
+ separatorIsRegex: external_exports.boolean().describe("Whether separators are regex patterns").optional(),
22446
+ lengthMeasurement: external_exports.enum(["CHARACTER_COUNT", "TOKEN_COUNT", "CUSTOM"]).describe("How to measure chunk length")
22447
+ }).passthrough().describe("Recursive hierarchical chunking strategy with configurable separators").optional(),
22448
+ sentence: external_exports.object({
22449
+ maxChunkSize: external_exports.number().int().describe("Maximum size of a chunk"),
22450
+ minChunkSize: external_exports.number().int().describe("Minimum size before creating a new chunk"),
22451
+ enableLanguageDetection: external_exports.boolean().describe("Whether to detect language for better segmentation").optional(),
22452
+ lengthMeasurement: external_exports.enum(["CHARACTER_COUNT", "TOKEN_COUNT", "CUSTOM"]).describe("How to measure chunk length")
22453
+ }).passthrough().describe("Sentence-based chunking strategy with language detection").optional()
22454
+ }).passthrough().describe("Chunking strategy for this memory (if not provided, uses space default)").optional(),
22455
+ extractPageImages: external_exports.boolean().describe("Optional hint to extract page images for eligible document types (for example, PDFs)").optional(),
22456
+ fileField: external_exports.string().describe("Optional multipart file field name to bind binary content; required when multiple files are uploaded in a batch multipart request.").optional()
22457
+ }).passthrough()).describe("Array of memory creation requests.")
22423
22458
  }, async (args) => {
22424
22459
  const body = {};
22425
22460
  if (args.requests !== void 0)
@@ -22464,7 +22499,7 @@ function registerTools() {
22464
22499
  original_content: external_exports.string().describe("Original content as plain text (use either this or originalContentB64)").optional(),
22465
22500
  original_content_b64: external_exports.string().describe("Original content as base64-encoded binary data (use either this or originalContent)").optional(),
22466
22501
  original_content_ref: external_exports.string().describe("Reference to external content location").optional(),
22467
- content_type: external_exports.string().describe("MIME type of the content"),
22502
+ content_type: external_exports.string().describe("MIME type of the content (defaults to text/plain when original_content is provided)").optional(),
22468
22503
  metadata: external_exports.any().describe("Additional metadata for the memory").optional(),
22469
22504
  chunking_config: external_exports.object({
22470
22505
  none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
@@ -22504,6 +22539,9 @@ function registerTools() {
22504
22539
  body["chunkingConfig"] = args.chunking_config;
22505
22540
  if (args.extract_page_images !== void 0)
22506
22541
  body["extractPageImages"] = args.extract_page_images;
22542
+ if (body["contentType"] === void 0 && body["originalContent"] !== void 0) {
22543
+ body["contentType"] = "text/plain";
22544
+ }
22507
22545
  const result = await callApi("POST", `/v1/memories`, body);
22508
22546
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22509
22547
  });
@@ -22515,8 +22553,8 @@ function registerTools() {
22515
22553
  });
22516
22554
  server.tool("goodmem_memories_get", "Get a memory by ID", {
22517
22555
  id: external_exports.string().describe("The UUID of the memory to retrieve"),
22518
- include_content: external_exports.boolean().describe("Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.").optional(),
22519
- include_processing_history: external_exports.boolean().describe("Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.").optional()
22556
+ include_content: external_exports.boolean().describe("Whether to include the original content in the response (defaults to false).").optional(),
22557
+ include_processing_history: external_exports.boolean().describe("Whether to include background job processing history in the response (defaults to false).").optional()
22520
22558
  }, async (args) => {
22521
22559
  const query = {};
22522
22560
  if (args.include_content !== void 0)
@@ -22528,14 +22566,14 @@ function registerTools() {
22528
22566
  });
22529
22567
  server.tool("goodmem_memories_list", "List memories in a space", {
22530
22568
  space_id: external_exports.string().describe("The UUID of the space containing the memories"),
22531
- include_content: external_exports.boolean().describe("Whether to include the original content in the response (defaults to false). The snake_case alias include_content is also accepted.").optional(),
22532
- include_processing_history: external_exports.boolean().describe("Whether to include background job processing history in the response (defaults to false). The snake_case alias include_processing_history is also accepted.").optional(),
22533
- status_filter: external_exports.string().describe("Filter memories by processing status (PENDING, PROCESSING, COMPLETED, FAILED). The snake_case alias status_filter is also accepted.").optional(),
22569
+ include_content: external_exports.boolean().describe("Whether to include the original content in the response (defaults to false).").optional(),
22570
+ include_processing_history: external_exports.boolean().describe("Whether to include background job processing history in the response (defaults to false).").optional(),
22571
+ status_filter: external_exports.string().describe("Filter memories by processing status (PENDING, PROCESSING, COMPLETED, FAILED).").optional(),
22534
22572
  filter: external_exports.string().describe("Optional metadata filter expression for list results").optional(),
22535
- max_results: external_exports.number().int().describe("Maximum number of results per page (defaults to 50, clamped to [1, 500]). The snake_case alias max_results is also accepted.").optional(),
22536
- next_token: external_exports.string().describe("Opaque pagination token for the next page. URL-safe Base64 without padding; do not parse or construct it. The snake_case alias next_token is also accepted.").optional(),
22537
- sort_by: external_exports.string().describe("Field to sort by (e.g., 'created_at'). The snake_case alias sort_by is also accepted.").optional(),
22538
- sort_order: external_exports.enum(["ASCENDING", "DESCENDING", "SORT_ORDER_UNSPECIFIED"]).describe("Sort direction (ASCENDING or DESCENDING). The snake_case alias sort_order is also accepted.").optional()
22573
+ max_results: external_exports.number().int().describe("Maximum number of results per page (defaults to 50, clamped to [1, 500]).").optional(),
22574
+ 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(),
22575
+ sort_by: external_exports.string().describe("Field to sort by (e.g., 'created_at').").optional(),
22576
+ sort_order: external_exports.enum(["ASCENDING", "DESCENDING", "SORT_ORDER_UNSPECIFIED"]).describe("Sort direction (ASCENDING or DESCENDING).").optional()
22539
22577
  }, async (args) => {
22540
22578
  const query = {};
22541
22579
  if (args.include_content !== void 0)
@@ -22559,12 +22597,12 @@ function registerTools() {
22559
22597
  });
22560
22598
  server.tool("goodmem_memories_pages", "List memory page images", {
22561
22599
  id: external_exports.string().describe("Memory UUID"),
22562
- start_page_index: external_exports.number().int().describe("Optional lower bound for returned page indices, inclusive. The snake_case alias start_page_index is also accepted.").optional(),
22563
- end_page_index: external_exports.number().int().describe("Optional upper bound for returned page indices, inclusive. The snake_case alias end_page_index is also accepted.").optional(),
22600
+ start_page_index: external_exports.number().int().describe("Optional lower bound for returned page indices, inclusive.").optional(),
22601
+ end_page_index: external_exports.number().int().describe("Optional upper bound for returned page indices, inclusive.").optional(),
22564
22602
  dpi: external_exports.number().int().describe("Optional rendition filter for page-image DPI.").optional(),
22565
- content_type: external_exports.string().describe("Optional rendition filter for page-image MIME type, such as image/png. The snake_case alias content_type is also accepted.").optional(),
22566
- max_results: external_exports.number().int().describe("Maximum number of results per page. The snake_case alias max_results is also accepted.").optional(),
22567
- next_token: external_exports.string().describe("Opaque pagination token for the next page. The snake_case alias next_token is also accepted. Do not parse or construct it.").optional()
22603
+ content_type: external_exports.string().describe("Optional rendition filter for page-image MIME type, such as image/png.").optional(),
22604
+ max_results: external_exports.number().int().describe("Maximum number of results per page.").optional(),
22605
+ next_token: external_exports.string().describe("Opaque pagination token for the next page. Do not parse or construct it.").optional()
22568
22606
  }, async (args) => {
22569
22607
  const query = {};
22570
22608
  if (args.start_page_index !== void 0)
@@ -22608,7 +22646,8 @@ function registerTools() {
22608
22646
  post_processor: external_exports.object({
22609
22647
  name: external_exports.string().describe("Fully qualified factory class name of the post-processor to apply."),
22610
22648
  config: 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()
22611
- }).passthrough().describe("Optional post-processor configuration to transform retrieval results.").optional()
22649
+ }).passthrough().describe("Optional post-processor configuration to transform retrieval results.").optional(),
22650
+ timeout_sec: external_exports.number().int().describe("Maximum seconds to wait for the streaming response (default: 200).").optional()
22612
22651
  }, async (args) => {
22613
22652
  const body = {};
22614
22653
  if (args.message !== void 0)
@@ -22627,7 +22666,7 @@ function registerTools() {
22627
22666
  body["hnsw"] = args.hnsw;
22628
22667
  if (args.post_processor !== void 0)
22629
22668
  body["postProcessor"] = args.post_processor;
22630
- const result = await callApiNdjson("POST", `/v1/memories:retrieve`, body);
22669
+ const result = await callApiNdjson("POST", `/v1/memories:retrieve`, body, void 0, args.timeout_sec);
22631
22670
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22632
22671
  });
22633
22672
  server.tool("goodmem_ocr_document", "Run OCR on a document or image", {
@@ -22679,7 +22718,7 @@ function registerTools() {
22679
22718
  }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22680
22719
  labels: external_exports.any().describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22681
22720
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider. Required for SaaS providers; optional for local deployments.").optional(),
22682
- labels: external_exports.any().describe("User-defined labels for categorization").optional(),
22721
+ labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
22683
22722
  version: external_exports.string().describe("Version information").optional(),
22684
22723
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
22685
22724
  owner_id: external_exports.string().describe("Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_RERANKER_ANY permission if specified.").optional(),
@@ -22718,13 +22757,13 @@ function registerTools() {
22718
22757
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22719
22758
  });
22720
22759
  server.tool("goodmem_rerankers_delete", "Delete a reranker", {
22721
- id: external_exports.string().describe("The UUID of the reranker to delete")
22760
+ id: external_exports.string().describe("The unique identifier of the reranker to delete")
22722
22761
  }, async (args) => {
22723
22762
  await callApi("DELETE", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, void 0);
22724
22763
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22725
22764
  });
22726
22765
  server.tool("goodmem_rerankers_get", "Get a reranker by ID", {
22727
- id: external_exports.string().describe("The UUID of the reranker to retrieve")
22766
+ id: external_exports.string().describe("The unique identifier of the reranker to retrieve")
22728
22767
  }, async (args) => {
22729
22768
  const result = await callApi("GET", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, void 0);
22730
22769
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22732,22 +22771,22 @@ function registerTools() {
22732
22771
  server.tool("goodmem_rerankers_list", "List rerankers", {
22733
22772
  owner_id: external_exports.string().describe("Filter rerankers by owner ID. With LIST_RERANKER_ANY permission, omitting this shows all accessible rerankers; providing it filters by that owner. With LIST_RERANKER_OWN permission, only your own rerankers are shown regardless of this parameter (PERMISSION_DENIED if set to another user).").optional(),
22734
22773
  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(),
22735
- labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by labels. Each key-value pair is sent as a label.<key>=<value> query parameter.").optional()
22774
+ 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()
22736
22775
  }, async (args) => {
22737
22776
  const query = {};
22738
22777
  if (args.owner_id !== void 0)
22739
22778
  query["ownerId"] = String(args.owner_id);
22740
22779
  if (args.provider_type !== void 0)
22741
22780
  query["providerType"] = String(args.provider_type);
22742
- if (args.labels) {
22743
- for (const [k, v] of Object.entries(args.labels))
22744
- query[`label.${k}`] = v;
22781
+ if (args.label) {
22782
+ for (const [k, v] of Object.entries(args.label))
22783
+ query[`label[${k}]`] = v;
22745
22784
  }
22746
22785
  const result = await callApi("GET", `/v1/rerankers`, void 0, query);
22747
22786
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22748
22787
  });
22749
22788
  server.tool("goodmem_rerankers_update", "Update a reranker", {
22750
- id: external_exports.string().describe("The UUID of the reranker to update"),
22789
+ id: external_exports.string().describe("The unique identifier of the reranker to update"),
22751
22790
  display_name: external_exports.string().describe("User-facing name of the reranker").optional(),
22752
22791
  description: external_exports.string().describe("Description of the reranker").optional(),
22753
22792
  endpoint_url: external_exports.string().describe("API endpoint URL").optional(),
@@ -22771,8 +22810,8 @@ function registerTools() {
22771
22810
  }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22772
22811
  labels: external_exports.any().describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22773
22812
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider. Omit to keep existing credentials.").optional(),
22774
- replace_labels: external_exports.any().describe("Replace all existing labels with these (mutually exclusive with mergeLabels)").optional(),
22775
- merge_labels: external_exports.any().describe("Merge these labels with existing ones (mutually exclusive with replaceLabels)").optional(),
22813
+ replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with these (mutually exclusive with mergeLabels)").optional(),
22814
+ merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones (mutually exclusive with replaceLabels)").optional(),
22776
22815
  version: external_exports.string().describe("Version information").optional(),
22777
22816
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
22778
22817
  }, async (args) => {
@@ -22804,7 +22843,7 @@ function registerTools() {
22804
22843
  });
22805
22844
  server.tool("goodmem_spaces_create", "Create a new Space", {
22806
22845
  name: external_exports.string().describe("The desired name for the space. Must be unique within the user's scope."),
22807
- labels: external_exports.any().describe("A set of key-value pairs to categorize or tag the space. Used for filtering and organizational purposes.").optional(),
22846
+ 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(),
22808
22847
  space_embedders: external_exports.array(external_exports.object({
22809
22848
  embedderId: external_exports.string().describe("The UUID for the embedder to associate with the space."),
22810
22849
  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()
@@ -22849,13 +22888,13 @@ function registerTools() {
22849
22888
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22850
22889
  });
22851
22890
  server.tool("goodmem_spaces_delete", "Delete a space", {
22852
- id: external_exports.string().describe("The UUID of the space to delete")
22891
+ id: external_exports.string().describe("The unique identifier of the space to delete")
22853
22892
  }, async (args) => {
22854
22893
  await callApi("DELETE", `/v1/spaces/${encodeURIComponent(String(args.id))}`, void 0);
22855
22894
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22856
22895
  });
22857
22896
  server.tool("goodmem_spaces_get", "Get a space by ID", {
22858
- id: external_exports.string().describe("The UUID of the space to retrieve")
22897
+ id: external_exports.string().describe("The unique identifier of the space to retrieve")
22859
22898
  }, async (args) => {
22860
22899
  const result = await callApi("GET", `/v1/spaces/${encodeURIComponent(String(args.id))}`, void 0);
22861
22900
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22867,7 +22906,7 @@ function registerTools() {
22867
22906
  next_token: external_exports.string().describe("Pagination token for retrieving the next set of results").optional(),
22868
22907
  sort_by: external_exports.string().describe("Field to sort by: 'created_time', 'updated_time', or 'name' (default: 'created_time'). Unsupported values return INVALID_ARGUMENT.").optional(),
22869
22908
  sort_order: external_exports.enum(["ASCENDING", "DESCENDING", "SORT_ORDER_UNSPECIFIED"]).describe("Sort order (ASCENDING or DESCENDING, default: DESCENDING)").optional(),
22870
- labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Filter by labels. Each key-value pair is sent as a label.<key>=<value> query parameter.").optional()
22909
+ 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()
22871
22910
  }, async (args) => {
22872
22911
  const query = {};
22873
22912
  if (args.owner_id !== void 0)
@@ -22882,19 +22921,19 @@ function registerTools() {
22882
22921
  query["sortBy"] = String(args.sort_by);
22883
22922
  if (args.sort_order !== void 0)
22884
22923
  query["sortOrder"] = String(args.sort_order);
22885
- if (args.labels) {
22886
- for (const [k, v] of Object.entries(args.labels))
22887
- query[`label.${k}`] = v;
22924
+ if (args.label) {
22925
+ for (const [k, v] of Object.entries(args.label))
22926
+ query[`label[${k}]`] = v;
22888
22927
  }
22889
22928
  const result = await callApi("GET", `/v1/spaces`, void 0, query);
22890
22929
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22891
22930
  });
22892
22931
  server.tool("goodmem_spaces_update", "Update a space", {
22893
- id: external_exports.string().describe("The UUID of the space to update"),
22932
+ id: external_exports.string().describe("The unique identifier of the space to update"),
22894
22933
  name: external_exports.string().describe("The new name for the space.").optional(),
22895
22934
  public_read: external_exports.boolean().describe("Whether the space is publicly readable by all users.").optional(),
22896
- replace_labels: external_exports.any().describe("Labels to replace all existing labels. Mutually exclusive with mergeLabels.").optional(),
22897
- merge_labels: external_exports.any().describe("Labels to merge with existing labels. Mutually exclusive with replaceLabels.").optional()
22935
+ replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to replace all existing labels. Mutually exclusive with mergeLabels.").optional(),
22936
+ merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to merge with existing labels. Mutually exclusive with replaceLabels.").optional()
22898
22937
  }, async (args) => {
22899
22938
  const body = {};
22900
22939
  if (args.name !== void 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pairsystems/goodmem-mcp",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "GoodMem MCP server \u2014 exposes GoodMem API as MCP tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",