@pairsystems/goodmem-mcp 0.1.4 → 0.1.6

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 +200 -66
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20988,6 +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
20992
  function isConfigured() {
20992
20993
  return goodmemBaseUrl !== "" && goodmemApiKey !== "";
20993
20994
  }
@@ -21049,7 +21050,7 @@ async function callApiNdjson(method, path, body, query) {
21049
21050
  throw new Error(`GoodMem API error ${resp.status}: ${text2}`);
21050
21051
  }
21051
21052
  const text = await resp.text();
21052
- return text.split("\n").filter(Boolean).map((line) => JSON.parse(line));
21053
+ return text.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
21053
21054
  }
21054
21055
  var MODEL_REGISTRY = {
21055
21056
  "embedders": {
@@ -21919,7 +21920,7 @@ function autoInferFromRegistry(registryType, args) {
21919
21920
  }
21920
21921
  var server = new McpServer({
21921
21922
  name: "goodmem",
21922
- version: "0.1.4"
21923
+ version: "0.1.6"
21923
21924
  });
21924
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.", {
21925
21926
  base_url: external_exports.string().describe("GoodMem server URL (e.g., https://your-server.example.com)"),
@@ -21928,22 +21929,22 @@ server.tool("goodmem_configure", "Configure GoodMem server connection. Call this
21928
21929
  if (!/^https?:\/\//i.test(args.base_url)) {
21929
21930
  return { content: [{ type: "text", text: `base_url must include a scheme (e.g., http://${args.base_url} or https://${args.base_url}).` }] };
21930
21931
  }
21931
- goodmemBaseUrl = args.base_url;
21932
- goodmemApiKey = args.api_key;
21933
21932
  try {
21934
- const url = new URL("/v1/system/info", goodmemBaseUrl);
21933
+ const url = new URL("/v1/system/info", args.base_url);
21935
21934
  const resp = await fetch(url.toString(), {
21936
- headers: { "x-api-key": goodmemApiKey },
21935
+ headers: { "x-api-key": args.api_key },
21937
21936
  signal: AbortSignal.timeout(1e4)
21938
21937
  });
21939
21938
  if (!resp.ok) {
21940
21939
  const text = await resp.text();
21941
- return { content: [{ type: "text", text: `Credentials saved but server returned error ${resp.status}: ${text}. Check your base_url and api_key.` }] };
21940
+ return { content: [{ type: "text", text: `Connection failed (${resp.status}): ${text}. Credentials were NOT saved. Check your base_url and api_key.` }] };
21942
21941
  }
21942
+ goodmemBaseUrl = args.base_url;
21943
+ goodmemApiKey = args.api_key;
21943
21944
  const info = await resp.json();
21944
21945
  return { content: [{ type: "text", text: `Connected to GoodMem at ${goodmemBaseUrl}. Server version: ${info.version ?? "unknown"}.` }] };
21945
21946
  } catch (err) {
21946
- return { content: [{ type: "text", text: `Credentials saved but could not connect to ${goodmemBaseUrl}: ${err}. Check your base_url.` }] };
21947
+ return { content: [{ type: "text", text: `Could not connect to ${args.base_url}: ${err}. Credentials were NOT saved. Check your base_url.` }] };
21947
21948
  }
21948
21949
  });
21949
21950
  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.", {
@@ -21967,6 +21968,12 @@ server.tool("goodmem_lookup_model", "Look up a model in the registry to see its
21967
21968
  return { content: [{ type: "text", text: `Model "${args.model_identifier}" not found in registry. Available models:
21968
21969
  ${allModels.join("\n")}` }] };
21969
21970
  });
21971
+ 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
+ return { content: [{ type: "text", text: JSON.stringify({
21973
+ mcpVersion: "0.1.6",
21974
+ basedOnGoodmemCommit: BASED_ON_GOODMEM_COMMIT
21975
+ }, null, 2) }] };
21976
+ });
21970
21977
  function registerTools() {
21971
21978
  server.tool("goodmem_admin_background_jobs_purge", "Purge completed background jobs", {
21972
21979
  older_than: external_exports.string().describe("ISO-8601 timestamp cutoff; only terminal jobs older than this instant are eligible.").optional(),
@@ -22006,7 +22013,7 @@ function registerTools() {
22006
22013
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22007
22014
  });
22008
22015
  server.tool("goodmem_apikeys_create", "Create a new API key", {
22009
- 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(),
22016
+ labels: external_exports.any().describe("Key-value pairs of metadata associated with the API key. Used for organization and filtering.").optional(),
22010
22017
  expires_at: external_exports.number().int().describe("Expiration timestamp in milliseconds since epoch. If not provided, the key does not expire.").optional(),
22011
22018
  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()
22012
22019
  }, async (args) => {
@@ -22021,7 +22028,7 @@ function registerTools() {
22021
22028
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22022
22029
  });
22023
22030
  server.tool("goodmem_apikeys_delete", "Delete an API key", {
22024
- id: external_exports.string().describe("The unique identifier of the API key to delete")
22031
+ id: external_exports.string().describe("The UUID of the API key to delete")
22025
22032
  }, async (args) => {
22026
22033
  await callApi("DELETE", `/v1/apikeys/${encodeURIComponent(String(args.id))}`, void 0);
22027
22034
  return { content: [{ type: "text", text: "Deleted successfully." }] };
@@ -22031,10 +22038,10 @@ function registerTools() {
22031
22038
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22032
22039
  });
22033
22040
  server.tool("goodmem_apikeys_update", "Update an API key", {
22034
- id: external_exports.string().describe("The unique identifier of the API key to update"),
22041
+ id: external_exports.string().describe("The UUID of the API key to update"),
22035
22042
  status: external_exports.string().describe("New status for the API key. Allowed values: ACTIVE, INACTIVE.").optional(),
22036
- replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with this set. Mutually exclusive with mergeLabels.").optional(),
22037
- merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones. Mutually exclusive with replaceLabels.").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()
22038
22045
  }, async (args) => {
22039
22046
  const body = {};
22040
22047
  if (args.status !== void 0)
@@ -22059,11 +22066,22 @@ function registerTools() {
22059
22066
  supported_modalities: external_exports.array(external_exports.enum(["TEXT", "IMAGE", "AUDIO", "VIDEO"])).describe("Supported content modalities (defaults to TEXT if not provided) (auto-inferred from model_identifier if omitted)").optional(),
22060
22067
  credentials: external_exports.object({
22061
22068
  kind: external_exports.enum(["CREDENTIAL_KIND_UNSPECIFIED", "CREDENTIAL_KIND_API_KEY", "CREDENTIAL_KIND_GCP_ADC"]).describe("Selected credential strategy"),
22062
- apiKey: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22063
- gcpAdc: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22069
+ apiKey: external_exports.object({
22070
+ inlineSecret: external_exports.string().describe("Secret stored directly in GoodMem (mutually exclusive with secretRef)").optional(),
22071
+ secretRef: external_exports.object({
22072
+ uri: external_exports.string().describe("URI identifying where the secret can be resolved (e.g., vault://, env://)"),
22073
+ hints: external_exports.record(external_exports.string(), external_exports.unknown()).describe('Optional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"})').optional()
22074
+ }).passthrough().describe("Reference to an external secret manager entry (mutually exclusive with inlineSecret)").optional(),
22075
+ headerName: external_exports.string().describe("Desired HTTP header to carry the credential (defaults to Authorization)").optional(),
22076
+ prefix: external_exports.string().describe('Optional prefix prepended to the secret (e.g., "Bearer ")').optional()
22077
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22078
+ gcpAdc: external_exports.object({
22079
+ scopes: external_exports.any().describe("Additional OAuth scopes. Empty list falls back to the default cloud-platform scope.").optional(),
22080
+ quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
22081
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22064
22082
  labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22065
22083
  }).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(),
22066
- labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
22084
+ labels: external_exports.any().describe("User-defined labels for categorization").optional(),
22067
22085
  version: external_exports.string().describe("Version information").optional(),
22068
22086
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
22069
22087
  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(),
@@ -22108,13 +22126,13 @@ function registerTools() {
22108
22126
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22109
22127
  });
22110
22128
  server.tool("goodmem_embedders_delete", "Delete an embedder", {
22111
- id: external_exports.string().describe("The unique identifier of the embedder to delete")
22129
+ id: external_exports.string().describe("The UUID of the embedder to delete")
22112
22130
  }, async (args) => {
22113
22131
  await callApi("DELETE", `/v1/embedders/${encodeURIComponent(String(args.id))}`, void 0);
22114
22132
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22115
22133
  });
22116
22134
  server.tool("goodmem_embedders_get", "Get an embedder by ID", {
22117
- id: external_exports.string().describe("The unique identifier of the embedder to retrieve")
22135
+ id: external_exports.string().describe("The UUID of the embedder to retrieve")
22118
22136
  }, async (args) => {
22119
22137
  const result = await callApi("GET", `/v1/embedders/${encodeURIComponent(String(args.id))}`, void 0);
22120
22138
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22137,7 +22155,7 @@ function registerTools() {
22137
22155
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22138
22156
  });
22139
22157
  server.tool("goodmem_embedders_update", "Update an embedder", {
22140
- id: external_exports.string().describe("The unique identifier of the embedder to update"),
22158
+ id: external_exports.string().describe("The UUID of the embedder to update"),
22141
22159
  display_name: external_exports.string().describe("User-facing name of the embedder").optional(),
22142
22160
  description: external_exports.string().describe("Description of the embedder").optional(),
22143
22161
  endpoint_url: external_exports.string().describe("API endpoint URL").optional(),
@@ -22148,12 +22166,23 @@ function registerTools() {
22148
22166
  supported_modalities: external_exports.array(external_exports.enum(["TEXT", "IMAGE", "AUDIO", "VIDEO"])).describe("Supported content modalities").optional(),
22149
22167
  credentials: external_exports.object({
22150
22168
  kind: external_exports.enum(["CREDENTIAL_KIND_UNSPECIFIED", "CREDENTIAL_KIND_API_KEY", "CREDENTIAL_KIND_GCP_ADC"]).describe("Selected credential strategy"),
22151
- apiKey: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22152
- gcpAdc: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22169
+ apiKey: external_exports.object({
22170
+ inlineSecret: external_exports.string().describe("Secret stored directly in GoodMem (mutually exclusive with secretRef)").optional(),
22171
+ secretRef: external_exports.object({
22172
+ uri: external_exports.string().describe("URI identifying where the secret can be resolved (e.g., vault://, env://)"),
22173
+ hints: external_exports.record(external_exports.string(), external_exports.unknown()).describe('Optional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"})').optional()
22174
+ }).passthrough().describe("Reference to an external secret manager entry (mutually exclusive with inlineSecret)").optional(),
22175
+ headerName: external_exports.string().describe("Desired HTTP header to carry the credential (defaults to Authorization)").optional(),
22176
+ prefix: external_exports.string().describe('Optional prefix prepended to the secret (e.g., "Bearer ")').optional()
22177
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22178
+ gcpAdc: external_exports.object({
22179
+ scopes: external_exports.any().describe("Additional OAuth scopes. Empty list falls back to the default cloud-platform scope.").optional(),
22180
+ quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
22181
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22153
22182
  labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22154
22183
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider").optional(),
22155
- replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with these (mutually exclusive with mergeLabels)").optional(),
22156
- merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones (mutually exclusive with replaceLabels)").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(),
22157
22186
  version: external_exports.string().describe("Version information").optional(),
22158
22187
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
22159
22188
  }, async (args) => {
@@ -22197,11 +22226,22 @@ function registerTools() {
22197
22226
  supported_modalities: external_exports.array(external_exports.enum(["TEXT", "IMAGE", "AUDIO", "VIDEO"])).describe("Supported content modalities (defaults to TEXT if not provided) (auto-inferred from model_identifier if omitted)").optional(),
22198
22227
  credentials: external_exports.object({
22199
22228
  kind: external_exports.enum(["CREDENTIAL_KIND_UNSPECIFIED", "CREDENTIAL_KIND_API_KEY", "CREDENTIAL_KIND_GCP_ADC"]).describe("Selected credential strategy"),
22200
- apiKey: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22201
- gcpAdc: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22229
+ apiKey: external_exports.object({
22230
+ inlineSecret: external_exports.string().describe("Secret stored directly in GoodMem (mutually exclusive with secretRef)").optional(),
22231
+ secretRef: external_exports.object({
22232
+ uri: external_exports.string().describe("URI identifying where the secret can be resolved (e.g., vault://, env://)"),
22233
+ hints: external_exports.record(external_exports.string(), external_exports.unknown()).describe('Optional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"})').optional()
22234
+ }).passthrough().describe("Reference to an external secret manager entry (mutually exclusive with inlineSecret)").optional(),
22235
+ headerName: external_exports.string().describe("Desired HTTP header to carry the credential (defaults to Authorization)").optional(),
22236
+ prefix: external_exports.string().describe('Optional prefix prepended to the secret (e.g., "Bearer ")').optional()
22237
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22238
+ gcpAdc: external_exports.object({
22239
+ scopes: external_exports.any().describe("Additional OAuth scopes. Empty list falls back to the default cloud-platform scope.").optional(),
22240
+ quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
22241
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22202
22242
  labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22203
22243
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider. Omit for deployments that do not require credentials.").optional(),
22204
- labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
22244
+ labels: external_exports.any().describe("User-defined labels for categorization").optional(),
22205
22245
  version: external_exports.string().describe("Version information").optional(),
22206
22246
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
22207
22247
  capabilities: external_exports.object({
@@ -22222,7 +22262,7 @@ function registerTools() {
22222
22262
  stopSequences: external_exports.any().describe("Generation stop sequences (\u226410 sequences; each \u2264100 chars; generation halts on exact match)").optional()
22223
22263
  }).passthrough().describe("Default sampling parameters for generation requests").optional(),
22224
22264
  max_context_length: external_exports.number().int().describe("Maximum context window size in tokens").optional(),
22225
- client_config: external_exports.record(external_exports.string(), external_exports.unknown()).describe("Provider-specific client configuration as flexible JSON structure").optional(),
22265
+ client_config: external_exports.any().describe("Provider-specific client configuration as flexible JSON structure").optional(),
22226
22266
  owner_id: external_exports.string().describe("Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_LLM_ANY permission if specified.").optional(),
22227
22267
  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()
22228
22268
  }, async (args) => {
@@ -22267,13 +22307,13 @@ function registerTools() {
22267
22307
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22268
22308
  });
22269
22309
  server.tool("goodmem_llms_delete", "Delete an LLM", {
22270
- id: external_exports.string().describe("The unique identifier of the LLM to delete")
22310
+ id: external_exports.string().describe("The UUID of the LLM to delete")
22271
22311
  }, async (args) => {
22272
22312
  await callApi("DELETE", `/v1/llms/${encodeURIComponent(String(args.id))}`, void 0);
22273
22313
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22274
22314
  });
22275
22315
  server.tool("goodmem_llms_get", "Get an LLM by ID", {
22276
- id: external_exports.string().describe("The unique identifier of the LLM to retrieve")
22316
+ id: external_exports.string().describe("The UUID of the LLM to retrieve")
22277
22317
  }, async (args) => {
22278
22318
  const result = await callApi("GET", `/v1/llms/${encodeURIComponent(String(args.id))}`, void 0);
22279
22319
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22296,7 +22336,7 @@ function registerTools() {
22296
22336
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22297
22337
  });
22298
22338
  server.tool("goodmem_llms_update", "Update an LLM", {
22299
- id: external_exports.string().describe("The unique identifier of the LLM to update"),
22339
+ id: external_exports.string().describe("The UUID of the LLM to update"),
22300
22340
  display_name: external_exports.string().describe("Update display name").optional(),
22301
22341
  description: external_exports.string().describe("Update description").optional(),
22302
22342
  endpoint_url: external_exports.string().describe("Update endpoint base URL (OpenAI-compatible base, typically ends with /v1)").optional(),
@@ -22305,8 +22345,19 @@ function registerTools() {
22305
22345
  supported_modalities: external_exports.array(external_exports.enum(["TEXT", "IMAGE", "AUDIO", "VIDEO"])).describe("Update supported modalities (if array contains \u22651 elements, replaces stored set; if empty or omitted, no change)").optional(),
22306
22346
  credentials: external_exports.object({
22307
22347
  kind: external_exports.enum(["CREDENTIAL_KIND_UNSPECIFIED", "CREDENTIAL_KIND_API_KEY", "CREDENTIAL_KIND_GCP_ADC"]).describe("Selected credential strategy"),
22308
- apiKey: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22309
- gcpAdc: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22348
+ apiKey: external_exports.object({
22349
+ inlineSecret: external_exports.string().describe("Secret stored directly in GoodMem (mutually exclusive with secretRef)").optional(),
22350
+ secretRef: external_exports.object({
22351
+ uri: external_exports.string().describe("URI identifying where the secret can be resolved (e.g., vault://, env://)"),
22352
+ hints: external_exports.record(external_exports.string(), external_exports.unknown()).describe('Optional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"})').optional()
22353
+ }).passthrough().describe("Reference to an external secret manager entry (mutually exclusive with inlineSecret)").optional(),
22354
+ headerName: external_exports.string().describe("Desired HTTP header to carry the credential (defaults to Authorization)").optional(),
22355
+ prefix: external_exports.string().describe('Optional prefix prepended to the secret (e.g., "Bearer ")').optional()
22356
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22357
+ gcpAdc: external_exports.object({
22358
+ scopes: external_exports.any().describe("Additional OAuth scopes. Empty list falls back to the default cloud-platform scope.").optional(),
22359
+ quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
22360
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22310
22361
  labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22311
22362
  }).passthrough().describe("Update credentials").optional(),
22312
22363
  version: external_exports.string().describe("Update version information").optional(),
@@ -22329,9 +22380,9 @@ function registerTools() {
22329
22380
  stopSequences: external_exports.any().describe("Generation stop sequences (\u226410 sequences; each \u2264100 chars; generation halts on exact match)").optional()
22330
22381
  }).passthrough().describe("Update default sampling parameters").optional(),
22331
22382
  max_context_length: external_exports.number().int().describe("Update maximum context window size in tokens").optional(),
22332
- client_config: external_exports.record(external_exports.string(), external_exports.unknown()).describe("Update provider-specific client configuration (replaces entire config; no merging)").optional(),
22333
- 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(),
22334
- 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()
22383
+ 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()
22335
22386
  }, async (args) => {
22336
22387
  const body = {};
22337
22388
  if (args.display_name !== void 0)
@@ -22379,7 +22430,11 @@ function registerTools() {
22379
22430
  server.tool("goodmem_memories_batch_delete", "Delete memories in batch", {
22380
22431
  requests: external_exports.array(external_exports.object({
22381
22432
  memoryId: external_exports.string().describe("Deletes one specific memory by UUID").optional(),
22382
- filterSelector: external_exports.any().describe("Deletes a filtered set of memories within a specific space").optional()
22433
+ filterSelector: external_exports.object({
22434
+ spaceId: external_exports.string().describe("Space ID scope for the filtered delete"),
22435
+ statusFilter: external_exports.string().describe("Optional processing status filter (PENDING, PROCESSING, COMPLETED, FAILED)").optional(),
22436
+ filter: external_exports.string().describe("Optional metadata filter expression").optional()
22437
+ }).passthrough().describe("Deletes a filtered set of memories within a specific space").optional()
22383
22438
  }).passthrough()).describe("Array of delete selectors")
22384
22439
  }, async (args) => {
22385
22440
  const body = {};
@@ -22410,11 +22465,23 @@ function registerTools() {
22410
22465
  original_content_b64: external_exports.string().describe("Original content as base64-encoded binary data (use either this or originalContent)").optional(),
22411
22466
  original_content_ref: external_exports.string().describe("Reference to external content location").optional(),
22412
22467
  content_type: external_exports.string().describe("MIME type of the content"),
22413
- metadata: external_exports.record(external_exports.string(), external_exports.unknown()).describe("Additional metadata for the memory").optional(),
22468
+ metadata: external_exports.any().describe("Additional metadata for the memory").optional(),
22414
22469
  chunking_config: external_exports.object({
22415
22470
  none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
22416
- recursive: external_exports.any().describe("Recursive hierarchical chunking strategy with configurable separators").optional(),
22417
- sentence: external_exports.any().describe("Sentence-based chunking strategy with language detection").optional()
22471
+ recursive: external_exports.object({
22472
+ chunkSize: external_exports.number().int().describe("Maximum size of a chunk (should be \u2264 context window)"),
22473
+ chunkOverlap: external_exports.number().int().describe("Sliding overlap between chunks"),
22474
+ separators: external_exports.any().describe("Hierarchical separator list (order = preference)").optional(),
22475
+ 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."),
22476
+ separatorIsRegex: external_exports.boolean().describe("Whether separators are regex patterns").optional(),
22477
+ lengthMeasurement: external_exports.enum(["CHARACTER_COUNT", "TOKEN_COUNT", "CUSTOM"]).describe("How to measure chunk length")
22478
+ }).passthrough().describe("Recursive hierarchical chunking strategy with configurable separators").optional(),
22479
+ sentence: external_exports.object({
22480
+ maxChunkSize: external_exports.number().int().describe("Maximum size of a chunk"),
22481
+ minChunkSize: external_exports.number().int().describe("Minimum size before creating a new chunk"),
22482
+ enableLanguageDetection: external_exports.boolean().describe("Whether to detect language for better segmentation").optional(),
22483
+ lengthMeasurement: external_exports.enum(["CHARACTER_COUNT", "TOKEN_COUNT", "CUSTOM"]).describe("How to measure chunk length")
22484
+ }).passthrough().describe("Sentence-based chunking strategy with language detection").optional()
22418
22485
  }).passthrough().describe("Chunking strategy for this memory (if not provided, uses space default)").optional(),
22419
22486
  extract_page_images: external_exports.boolean().describe("Optional hint to extract page images for eligible document types (for example, PDFs)").optional()
22420
22487
  }, async (args) => {
@@ -22441,13 +22508,13 @@ function registerTools() {
22441
22508
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22442
22509
  });
22443
22510
  server.tool("goodmem_memories_delete", "Delete a memory", {
22444
- id: external_exports.string().describe("The unique identifier of the memory to delete")
22511
+ id: external_exports.string().describe("The UUID of the memory to delete")
22445
22512
  }, async (args) => {
22446
22513
  await callApi("DELETE", `/v1/memories/${encodeURIComponent(String(args.id))}`, void 0);
22447
22514
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22448
22515
  });
22449
22516
  server.tool("goodmem_memories_get", "Get a memory by ID", {
22450
- id: external_exports.string().describe("The unique identifier of the memory to retrieve"),
22517
+ id: external_exports.string().describe("The UUID of the memory to retrieve"),
22451
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(),
22452
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()
22453
22520
  }, async (args) => {
@@ -22460,7 +22527,7 @@ function registerTools() {
22460
22527
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22461
22528
  });
22462
22529
  server.tool("goodmem_memories_list", "List memories in a space", {
22463
- space_id: external_exports.string().describe("The unique identifier of the space containing the memories"),
22530
+ space_id: external_exports.string().describe("The UUID of the space containing the memories"),
22464
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(),
22465
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(),
22466
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(),
@@ -22519,10 +22586,13 @@ function registerTools() {
22519
22586
  message: external_exports.string().describe("Primary query/message for semantic search."),
22520
22587
  context: external_exports.array(external_exports.object({
22521
22588
  text: external_exports.string().describe("Text content for this context item.").optional(),
22522
- binary: external_exports.any().describe("Binary content for this context item.").optional()
22589
+ binary: external_exports.object({
22590
+ contentType: external_exports.string().describe("MIME type of the binary content."),
22591
+ data: external_exports.string().describe("Base64-encoded binary data.")
22592
+ }).passthrough().describe("Binary content for this context item.").optional()
22523
22593
  }).passthrough()).describe("Optional context items (text or binary) to provide additional context for the search.").optional(),
22524
22594
  space_keys: external_exports.array(external_exports.object({
22525
- spaceId: external_exports.string().describe("The unique identifier for the space to search."),
22595
+ spaceId: external_exports.string().describe("The UUID for the space to search."),
22526
22596
  embedderWeights: external_exports.any().describe("Optional per-embedder weight overrides for this space. If not specified, database defaults are used.").optional(),
22527
22597
  filter: external_exports.string().describe("Optional filter expression that must evaluate to true for memories in this space.").optional()
22528
22598
  }).passthrough()).describe("List of spaces to search with optional per-embedder weight overrides."),
@@ -22594,11 +22664,22 @@ function registerTools() {
22594
22664
  supported_modalities: external_exports.array(external_exports.enum(["TEXT", "IMAGE", "AUDIO", "VIDEO"])).describe("Supported content modalities (defaults to TEXT if not provided) (auto-inferred from model_identifier if omitted)").optional(),
22595
22665
  credentials: external_exports.object({
22596
22666
  kind: external_exports.enum(["CREDENTIAL_KIND_UNSPECIFIED", "CREDENTIAL_KIND_API_KEY", "CREDENTIAL_KIND_GCP_ADC"]).describe("Selected credential strategy"),
22597
- apiKey: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22598
- gcpAdc: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22667
+ apiKey: external_exports.object({
22668
+ inlineSecret: external_exports.string().describe("Secret stored directly in GoodMem (mutually exclusive with secretRef)").optional(),
22669
+ secretRef: external_exports.object({
22670
+ uri: external_exports.string().describe("URI identifying where the secret can be resolved (e.g., vault://, env://)"),
22671
+ hints: external_exports.record(external_exports.string(), external_exports.unknown()).describe('Optional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"})').optional()
22672
+ }).passthrough().describe("Reference to an external secret manager entry (mutually exclusive with inlineSecret)").optional(),
22673
+ headerName: external_exports.string().describe("Desired HTTP header to carry the credential (defaults to Authorization)").optional(),
22674
+ prefix: external_exports.string().describe('Optional prefix prepended to the secret (e.g., "Bearer ")').optional()
22675
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22676
+ gcpAdc: external_exports.object({
22677
+ scopes: external_exports.any().describe("Additional OAuth scopes. Empty list falls back to the default cloud-platform scope.").optional(),
22678
+ quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
22679
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22599
22680
  labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22600
22681
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider. Required for SaaS providers; optional for local deployments.").optional(),
22601
- labels: external_exports.record(external_exports.string(), external_exports.string()).describe("User-defined labels for categorization").optional(),
22682
+ labels: external_exports.any().describe("User-defined labels for categorization").optional(),
22602
22683
  version: external_exports.string().describe("Version information").optional(),
22603
22684
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional(),
22604
22685
  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(),
@@ -22637,13 +22718,13 @@ function registerTools() {
22637
22718
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22638
22719
  });
22639
22720
  server.tool("goodmem_rerankers_delete", "Delete a reranker", {
22640
- id: external_exports.string().describe("The unique identifier of the reranker to delete")
22721
+ id: external_exports.string().describe("The UUID of the reranker to delete")
22641
22722
  }, async (args) => {
22642
22723
  await callApi("DELETE", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, void 0);
22643
22724
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22644
22725
  });
22645
22726
  server.tool("goodmem_rerankers_get", "Get a reranker by ID", {
22646
- id: external_exports.string().describe("The unique identifier of the reranker to retrieve")
22727
+ id: external_exports.string().describe("The UUID of the reranker to retrieve")
22647
22728
  }, async (args) => {
22648
22729
  const result = await callApi("GET", `/v1/rerankers/${encodeURIComponent(String(args.id))}`, void 0);
22649
22730
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22666,7 +22747,7 @@ function registerTools() {
22666
22747
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22667
22748
  });
22668
22749
  server.tool("goodmem_rerankers_update", "Update a reranker", {
22669
- id: external_exports.string().describe("The unique identifier of the reranker to update"),
22750
+ id: external_exports.string().describe("The UUID of the reranker to update"),
22670
22751
  display_name: external_exports.string().describe("User-facing name of the reranker").optional(),
22671
22752
  description: external_exports.string().describe("Description of the reranker").optional(),
22672
22753
  endpoint_url: external_exports.string().describe("API endpoint URL").optional(),
@@ -22675,12 +22756,23 @@ function registerTools() {
22675
22756
  supported_modalities: external_exports.array(external_exports.enum(["TEXT", "IMAGE", "AUDIO", "VIDEO"])).describe("Supported content modalities").optional(),
22676
22757
  credentials: external_exports.object({
22677
22758
  kind: external_exports.enum(["CREDENTIAL_KIND_UNSPECIFIED", "CREDENTIAL_KIND_API_KEY", "CREDENTIAL_KIND_GCP_ADC"]).describe("Selected credential strategy"),
22678
- apiKey: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22679
- gcpAdc: external_exports.any().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22759
+ apiKey: external_exports.object({
22760
+ inlineSecret: external_exports.string().describe("Secret stored directly in GoodMem (mutually exclusive with secretRef)").optional(),
22761
+ secretRef: external_exports.object({
22762
+ uri: external_exports.string().describe("URI identifying where the secret can be resolved (e.g., vault://, env://)"),
22763
+ hints: external_exports.record(external_exports.string(), external_exports.unknown()).describe('Optional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"})').optional()
22764
+ }).passthrough().describe("Reference to an external secret manager entry (mutually exclusive with inlineSecret)").optional(),
22765
+ headerName: external_exports.string().describe("Desired HTTP header to carry the credential (defaults to Authorization)").optional(),
22766
+ prefix: external_exports.string().describe('Optional prefix prepended to the secret (e.g., "Bearer ")').optional()
22767
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_API_KEY").optional(),
22768
+ gcpAdc: external_exports.object({
22769
+ scopes: external_exports.any().describe("Additional OAuth scopes. Empty list falls back to the default cloud-platform scope.").optional(),
22770
+ quotaProjectId: external_exports.string().describe("Optional quota project used for billing").optional()
22771
+ }).passthrough().describe("Configuration when kind is CREDENTIAL_KIND_GCP_ADC").optional(),
22680
22772
  labels: external_exports.record(external_exports.string(), external_exports.string()).describe('Optional annotations to aid operators (e.g., "owner=vertex")').optional()
22681
22773
  }).passthrough().describe("Structured credential payload describing how to authenticate with the provider. Omit to keep existing credentials.").optional(),
22682
- replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Replace all existing labels with these (mutually exclusive with mergeLabels)").optional(),
22683
- merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Merge these labels with existing ones (mutually exclusive with replaceLabels)").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(),
22684
22776
  version: external_exports.string().describe("Version information").optional(),
22685
22777
  monitoring_endpoint: external_exports.string().describe("Monitoring endpoint URL").optional()
22686
22778
  }, async (args) => {
@@ -22712,17 +22804,29 @@ function registerTools() {
22712
22804
  });
22713
22805
  server.tool("goodmem_spaces_create", "Create a new Space", {
22714
22806
  name: external_exports.string().describe("The desired name for the space. Must be unique within the user's scope."),
22715
- 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(),
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(),
22716
22808
  space_embedders: external_exports.array(external_exports.object({
22717
- embedderId: external_exports.string().describe("The unique identifier for the embedder to associate with the space."),
22809
+ embedderId: external_exports.string().describe("The UUID for the embedder to associate with the space."),
22718
22810
  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()
22719
22811
  }).passthrough()).describe("List of embedder configurations to associate with this space. Each specifies an embedder ID and a relative default retrieval weight used when no per-request overrides are provided."),
22720
22812
  public_read: external_exports.boolean().describe("Indicates if the space and its memories can be read by unauthenticated users or users other than the owner. Defaults to false.").optional(),
22721
22813
  owner_id: external_exports.string().describe("Optional owner ID. If not provided, derived from the authentication context. Requires CREATE_SPACE_ANY permission if specified.").optional(),
22722
22814
  default_chunking_config: external_exports.object({
22723
22815
  none: external_exports.any().describe("No chunking strategy - preserve original content as single unit").optional(),
22724
- recursive: external_exports.any().describe("Recursive hierarchical chunking strategy with configurable separators").optional(),
22725
- sentence: external_exports.any().describe("Sentence-based chunking strategy with language detection").optional()
22816
+ recursive: external_exports.object({
22817
+ chunkSize: external_exports.number().int().describe("Maximum size of a chunk (should be \u2264 context window)"),
22818
+ chunkOverlap: external_exports.number().int().describe("Sliding overlap between chunks"),
22819
+ separators: external_exports.any().describe("Hierarchical separator list (order = preference)").optional(),
22820
+ 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."),
22821
+ separatorIsRegex: external_exports.boolean().describe("Whether separators are regex patterns").optional(),
22822
+ lengthMeasurement: external_exports.enum(["CHARACTER_COUNT", "TOKEN_COUNT", "CUSTOM"]).describe("How to measure chunk length")
22823
+ }).passthrough().describe("Recursive hierarchical chunking strategy with configurable separators").optional(),
22824
+ sentence: external_exports.object({
22825
+ maxChunkSize: external_exports.number().int().describe("Maximum size of a chunk"),
22826
+ minChunkSize: external_exports.number().int().describe("Minimum size before creating a new chunk"),
22827
+ enableLanguageDetection: external_exports.boolean().describe("Whether to detect language for better segmentation").optional(),
22828
+ lengthMeasurement: external_exports.enum(["CHARACTER_COUNT", "TOKEN_COUNT", "CUSTOM"]).describe("How to measure chunk length")
22829
+ }).passthrough().describe("Sentence-based chunking strategy with language detection").optional()
22726
22830
  }).passthrough().describe("Default chunking strategy for memories in this space"),
22727
22831
  space_id: external_exports.string().describe("Optional client-provided UUID for idempotent creation. If not provided, server generates a new UUID. Returns ALREADY_EXISTS if ID is already in use.").optional()
22728
22832
  }, async (args) => {
@@ -22745,13 +22849,13 @@ function registerTools() {
22745
22849
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22746
22850
  });
22747
22851
  server.tool("goodmem_spaces_delete", "Delete a space", {
22748
- id: external_exports.string().describe("The unique identifier of the space to delete")
22852
+ id: external_exports.string().describe("The UUID of the space to delete")
22749
22853
  }, async (args) => {
22750
22854
  await callApi("DELETE", `/v1/spaces/${encodeURIComponent(String(args.id))}`, void 0);
22751
22855
  return { content: [{ type: "text", text: "Deleted successfully." }] };
22752
22856
  });
22753
22857
  server.tool("goodmem_spaces_get", "Get a space by ID", {
22754
- id: external_exports.string().describe("The unique identifier of the space to retrieve")
22858
+ id: external_exports.string().describe("The UUID of the space to retrieve")
22755
22859
  }, async (args) => {
22756
22860
  const result = await callApi("GET", `/v1/spaces/${encodeURIComponent(String(args.id))}`, void 0);
22757
22861
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
@@ -22786,11 +22890,11 @@ function registerTools() {
22786
22890
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22787
22891
  });
22788
22892
  server.tool("goodmem_spaces_update", "Update a space", {
22789
- id: external_exports.string().describe("The unique identifier of the space to update"),
22893
+ id: external_exports.string().describe("The UUID of the space to update"),
22790
22894
  name: external_exports.string().describe("The new name for the space.").optional(),
22791
22895
  public_read: external_exports.boolean().describe("Whether the space is publicly readable by all users.").optional(),
22792
- replace_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to replace all existing labels. Mutually exclusive with mergeLabels.").optional(),
22793
- merge_labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Labels to merge with existing labels. Mutually exclusive with replaceLabels.").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()
22794
22898
  }, async (args) => {
22795
22899
  const body = {};
22796
22900
  if (args.name !== void 0)
@@ -22813,12 +22917,12 @@ function registerTools() {
22813
22917
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22814
22918
  });
22815
22919
  server.tool("goodmem_users_get", "Get a user by ID", {
22816
- id: external_exports.string().describe("The unique identifier of the user to retrieve").optional(),
22920
+ id: external_exports.string().describe("The UUID of the user to retrieve").optional(),
22817
22921
  email: external_exports.string().describe("The email address of the user to retrieve").optional()
22818
22922
  }, async (args) => {
22819
- if (args.id && args.email)
22923
+ if (args.id !== void 0 && args.email !== void 0)
22820
22924
  throw new Error("Exactly one of 'id', 'email' must be provided, not both.");
22821
- if (!args.id && !args.email)
22925
+ if (args.id === void 0 && args.email === void 0)
22822
22926
  throw new Error("Exactly one of 'id', 'email' must be provided.");
22823
22927
  const url = args.email ? `/v1/users/email/${encodeURIComponent(String(args.email))}` : `/v1/users/${encodeURIComponent(String(args.id))}`;
22824
22928
  const result = await callApi("GET", url, void 0);
@@ -22830,9 +22934,39 @@ function registerTools() {
22830
22934
  });
22831
22935
  }
22832
22936
  registerTools();
22937
+ async function healthCheck() {
22938
+ if (!isConfigured()) {
22939
+ console.error("[goodmem-mcp] Not configured \u2014 set GOODMEM_BASE_URL and GOODMEM_API_KEY, or call goodmem_configure.");
22940
+ return;
22941
+ }
22942
+ try {
22943
+ const url = new URL("/v1/system/info", goodmemBaseUrl);
22944
+ const resp = await fetch(url.toString(), {
22945
+ headers: { "x-api-key": goodmemApiKey },
22946
+ signal: AbortSignal.timeout(1e4)
22947
+ });
22948
+ if (resp.ok) {
22949
+ const info = await resp.json();
22950
+ console.error(`[goodmem-mcp] Connected to ${goodmemBaseUrl} (server ${info.version ?? "unknown"}).`);
22951
+ } else {
22952
+ const text = await resp.text();
22953
+ console.error(`[goodmem-mcp] Health check failed (${resp.status}): ${text}`);
22954
+ }
22955
+ } catch (err) {
22956
+ const msg = err instanceof Error ? err.message : String(err);
22957
+ if (msg.includes("CERT") || msg.includes("certificate") || msg.includes("self-signed") || msg.includes("self signed") || msg.includes("UNABLE_TO_VERIFY")) {
22958
+ console.error(`[goodmem-mcp] TLS certificate error: ${msg}
22959
+ If using self-signed certs, set NODE_TLS_REJECT_UNAUTHORIZED=0 (dev only)
22960
+ or NODE_EXTRA_CA_CERTS=/path/to/rootCA.pem in your MCP server env config.`);
22961
+ } else {
22962
+ console.error(`[goodmem-mcp] Cannot reach ${goodmemBaseUrl}: ${msg}`);
22963
+ }
22964
+ }
22965
+ }
22833
22966
  async function main() {
22834
22967
  const transport = new StdioServerTransport();
22835
22968
  await server.connect(transport);
22969
+ healthCheck();
22836
22970
  }
22837
22971
  main().catch((err) => {
22838
22972
  console.error("Fatal:", err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pairsystems/goodmem-mcp",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "GoodMem MCP server \u2014 exposes GoodMem API as MCP tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",