@pairsystems/goodmem-mcp 0.1.14 → 0.1.16

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 (3) hide show
  1. package/README.md +46 -3
  2. package/dist/index.js +148 -22
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -167,11 +167,13 @@ Memory spaces are containers that associate a set of memories with an embedder.
167
167
  | `goodmem_memories_batch_create` | Create multiple memories in a batch |
168
168
  | `goodmem_memories_batch_delete` | Delete memories in batch |
169
169
  | `goodmem_memories_batch_get` | Get multiple memories by ID |
170
+ | `goodmem_memories_content` | Download memory content |
170
171
  | `goodmem_memories_create` | Create a new memory |
171
172
  | `goodmem_memories_delete` | Delete a memory |
172
173
  | `goodmem_memories_get` | Get a memory by ID |
173
174
  | `goodmem_memories_list` | List memories in a space |
174
175
  | `goodmem_memories_pages` | List memory page images |
176
+ | `goodmem_memories_pages_image` | Download memory page image content |
175
177
  | `goodmem_memories_retrieve` | Advanced semantic memory retrieval with JSON |
176
178
 
177
179
  ### OCR
@@ -208,11 +210,12 @@ Memory spaces are containers that associate a set of memories with an embedder.
208
210
  | Tool | Description |
209
211
  |------|-------------|
210
212
  | `goodmem_admin_background_jobs_purge` | Purge completed background jobs |
211
- | `goodmem_admin_delete` | Delete a RetrieveMemory log policy |
212
213
  | `goodmem_admin_drain` | Request the server to enter drain mode |
213
- | `goodmem_admin_get` | Get a RetrieveMemory log policy |
214
214
  | `goodmem_admin_license_reload` | Reload the active license from disk |
215
- | `goodmem_admin_retrieve_memory_log_policies` | List RetrieveMemory log policies |
215
+ | `goodmem_admin_retrieve_memory_log_policies_create` | Create a RetrieveMemory log policy |
216
+ | `goodmem_admin_retrieve_memory_log_policies_delete` | Delete a RetrieveMemory log policy |
217
+ | `goodmem_admin_retrieve_memory_log_policies_get` | Get a RetrieveMemory log policy |
218
+ | `goodmem_admin_retrieve_memory_log_policies_list` | List RetrieveMemory log policies |
216
219
 
217
220
  ### Ping
218
221
 
@@ -222,6 +225,45 @@ Memory spaces are containers that associate a set of memories with an embedder.
222
225
  | `goodmem_ping_stream` | Stream ping probe results |
223
226
 
224
227
  <!-- AUTO-GENERATED MCP TOOL TABLE END -->
228
+ ## Binary content delivery
229
+
230
+ Two memory tools return raw binary payloads:
231
+
232
+ - `goodmem_memories_content` — original ingested bytes (text, image, PDF, …)
233
+ - `goodmem_memories_pages_image` — one rendered page image as bytes
234
+
235
+ The MCP server wraps the response in the appropriate MCP content block
236
+ based on the response MIME type:
237
+
238
+ | Server `Content-Type` | MCP block | What the agent gets |
239
+ |---|---|---|
240
+ | `image/*` | `image` block | base64 data + `mimeType`; Claude reads as vision input. |
241
+ | `text/*`, `application/json` | embedded `resource` with `text` | MIME-signaled text — preserves `text/markdown`, `text/x-python`, etc. |
242
+ | anything else (PDF, octet-stream, …) | embedded `resource` with `blob` | base64 blob + `mimeType`. Forward-compatible; current Claude models cannot natively render PDF bytes from an MCP block. |
243
+
244
+ ### Size cap
245
+
246
+ Both tools accept an optional `max_inline_bytes` parameter (units:
247
+ bytes) so the agent can self-limit per call:
248
+
249
+ | Knob | Value | Notes |
250
+ |---|---|---|
251
+ | **Hard server ceiling** | 64 MB (67,108,864 bytes) | Baked into the MCP server source. Above this, the tool always errors regardless of `max_inline_bytes`. |
252
+ | **Default cap** | 8 MB (8,388,608 bytes) | Used when the agent doesn't pass `max_inline_bytes`. |
253
+ | **Per-call override** | `max_inline_bytes` argument | The agent can raise it up to the hard ceiling, or lower it for tighter context-budget control. |
254
+
255
+ When the payload exceeds the effective cap, the tool throws an error
256
+ naming both the actual size and the ceiling — the agent can read the
257
+ error, retry with a larger `max_inline_bytes`, and succeed. Above the
258
+ hard ceiling, the only path is to fetch the content via REST directly
259
+ (`GET /v1/memories/{id}/content` or `/pages/{idx}/image`) rather than
260
+ through MCP.
261
+
262
+ These constants are not currently configurable via environment
263
+ variables. If you need to tune them per deployment, edit
264
+ `_clients_gen/mcp/emitter.py` (`ABSOLUTE_MAX_INLINE_BYTES`,
265
+ `DEFAULT_MAX_INLINE_BYTES`) and regenerate.
266
+
225
267
  ## Auto-inference
226
268
 
227
269
  When creating embedders, LLMs, or rerankers, provide `model_identifier` and the MCP server fills in `provider_type`, `endpoint_url`, dimensions, and other fields automatically from the built-in registry of 79 models. Inference happens client-side in the MCP layer before the request is sent.
@@ -246,3 +288,4 @@ For self-hosted or local providers (vLLM, TEI, Ollama, custom endpoints), creden
246
288
  - [GoodMem on GitHub](https://github.com/PAIR-Systems-Inc/goodmem)
247
289
  - [Python SDK on PyPI](https://pypi.org/project/goodmem/)
248
290
  - [Claude Code Plugin](https://github.com/PAIR-Systems-Inc/goodmem-claude-code-plugin)
291
+
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 = "62c6d77befdfab1bfe38ef917c6a202f4569eec7";
20991
+ var BASED_ON_GOODMEM_COMMIT = "b5f17ba5a019b3b11860f70609a994b6d2ade6ad";
20992
20992
  function isConfigured() {
20993
20993
  return goodmemBaseUrl !== "";
20994
20994
  }
@@ -21002,6 +21002,8 @@ function _buildUrl(base, path) {
21002
21002
  return baseUrl;
21003
21003
  }
21004
21004
  var DEFAULT_TIMEOUT_MS = 6e4;
21005
+ var ABSOLUTE_MAX_INLINE_BYTES = 67108864;
21006
+ var DEFAULT_MAX_INLINE_BYTES = 8388608;
21005
21007
  function _trimBody(text) {
21006
21008
  return text.length > 500 ? text.slice(0, 500) + "...[truncated]" : text;
21007
21009
  }
@@ -21044,6 +21046,37 @@ async function callApi(method, path, body, query, timeoutMs) {
21044
21046
  }
21045
21047
  return resp.text();
21046
21048
  }
21049
+ async function callApiBinary(method, path, query, timeoutMs) {
21050
+ if (!isConfigured()) {
21051
+ 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.");
21052
+ }
21053
+ const url = _buildUrl(goodmemBaseUrl, path);
21054
+ if (query) {
21055
+ for (const [k, v] of Object.entries(query)) {
21056
+ if (v !== void 0 && v !== null && v !== "")
21057
+ url.searchParams.set(k, v);
21058
+ }
21059
+ }
21060
+ const headers = {};
21061
+ if (goodmemApiKey !== "") {
21062
+ headers["x-api-key"] = goodmemApiKey;
21063
+ }
21064
+ const resp = await fetch(url.toString(), {
21065
+ method,
21066
+ headers,
21067
+ signal: AbortSignal.timeout(timeoutMs ?? DEFAULT_TIMEOUT_MS),
21068
+ // See callApi for the redirect-policy rationale.
21069
+ redirect: "error"
21070
+ });
21071
+ if (!resp.ok) {
21072
+ const text = await resp.text();
21073
+ throw new Error(`GoodMem API error ${resp.status}: ${_trimBody(text)}`);
21074
+ }
21075
+ const buf = await resp.arrayBuffer();
21076
+ const bytes = new Uint8Array(buf);
21077
+ const mimeType = (resp.headers.get("content-type") || "application/octet-stream").split(";")[0].trim();
21078
+ return { bytes, mimeType, sizeBytes: bytes.byteLength };
21079
+ }
21047
21080
  async function callApiNdjson(method, path, body, query, timeoutSec) {
21048
21081
  if (!isConfigured()) {
21049
21082
  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.");
@@ -21843,7 +21876,7 @@ function autoInferFromRegistry(registryType, args) {
21843
21876
  }
21844
21877
  var server = new McpServer({
21845
21878
  name: "goodmem",
21846
- version: "0.1.14"
21879
+ version: "0.1.16"
21847
21880
  });
21848
21881
  server.tool("goodmem_configure", "Configure GoodMem server connection. Call this before using other GoodMem tools if GOODMEM_BASE_URL and GOODMEM_API_KEY environment variables are not set. Session credentials override environment variables. For bootstrap workflows that need to call /v1/system/info or /v1/system/init before keys exist, api_key may be omitted; most other tools will return AuthenticationException until a real key is provided.", {
21849
21882
  base_url: external_exports.string().describe("GoodMem server URL (e.g., https://your-server.example.com)"),
@@ -21925,7 +21958,7 @@ ${allModels.join("\n")}` }] };
21925
21958
  });
21926
21959
  server.tool("goodmem_client_info", "Return the MCP client package version and the goodmem server commit it was built against. No server connection required.", {}, async () => {
21927
21960
  return { content: [{ type: "text", text: JSON.stringify({
21928
- mcp_version: "0.1.14",
21961
+ mcp_version: "0.1.16",
21929
21962
  based_on_goodmem_commit: BASED_ON_GOODMEM_COMMIT
21930
21963
  }, null, 2) }] };
21931
21964
  });
@@ -21948,19 +21981,6 @@ function registerTools() {
21948
21981
  const result = await callApi("POST", `/v1/admin/background-jobs:purge`, body);
21949
21982
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
21950
21983
  });
21951
- server.tool("goodmem_admin_delete", "Delete a RetrieveMemory log policy\n\nIdempotently tombstones an immutable RetrieveMemory log policy.", {
21952
- id: external_exports.string().describe("The UUID of the policy to delete"),
21953
- reason: external_exports.string().describe("Optional tombstone reason.").optional()
21954
- }, async (args) => {
21955
- if (typeof args.id !== "string" || args.id === "") {
21956
- throw new Error("'id' must be a non-empty string");
21957
- }
21958
- const body = {};
21959
- if (args.reason !== void 0)
21960
- body["reason"] = args.reason;
21961
- await callApi("DELETE", `/v1/admin/retrieve-memory-log-policies/${encodeURIComponent(String(args.id))}`, body);
21962
- return { content: [{ type: "text", text: "Deleted successfully." }] };
21963
- });
21964
21984
  server.tool("goodmem_admin_drain", "Request the server to enter drain mode\n\nInitiates drain mode and optionally waits for the server to quiesce.", {
21965
21985
  timeout_sec: external_exports.number().int().describe("Maximum seconds to wait for the server to quiesce before returning.").optional(),
21966
21986
  reason: external_exports.string().describe("Human-readable reason for initiating drain mode.").optional(),
@@ -21976,7 +21996,60 @@ function registerTools() {
21976
21996
  const result = await callApi("POST", `/v1/admin:drain`, body, void 0, ((args.timeout_sec ?? 900) + 30) * 1e3);
21977
21997
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
21978
21998
  });
21979
- server.tool("goodmem_admin_get", "Get a RetrieveMemory log policy\n\nRetrieves a live RetrieveMemory log policy by UUID, or a tombstoned policy when include_deleted is true.", {
21999
+ server.tool("goodmem_admin_license_reload", "Reload the active license from disk\n\nTriggers the server to reload its license file from the configured directory and returns metadata about the currently active license.", {}, async (args) => {
22000
+ const result = await callApi("POST", `/v1/admin/license:reload`, void 0);
22001
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22002
+ });
22003
+ server.tool("goodmem_admin_retrieve_memory_log_policies_create", "Create a RetrieveMemory log policy\n\nCreates an immutable administrative policy that can automatically enable durable RetrieveMemory request logging.", {
22004
+ policy_id: external_exports.string().describe("Optional client-provided policy UUID.").optional(),
22005
+ display_name: external_exports.string().describe("Human-readable policy name."),
22006
+ description: external_exports.string().describe("Optional operator description.").optional(),
22007
+ condition: external_exports.object({
22008
+ matchAll: external_exports.boolean().describe("When true, match every authenticated RetrieveMemory request. Must be omitted or false when anyOf contains clauses. Defaults to false when omitted.").optional(),
22009
+ anyOf: external_exports.array(external_exports.object({
22010
+ requestorUserIds: external_exports.array(external_exports.string()).describe("Authenticated requestor user UUID strings.").optional(),
22011
+ apiKeyIds: external_exports.array(external_exports.string()).describe("API key UUID strings used to authenticate RetrieveMemory requests.").optional(),
22012
+ spaceIds: external_exports.array(external_exports.string()).describe("Post-permission accessible space UUID strings.").optional(),
22013
+ apiKeyLabelSelectors: external_exports.record(external_exports.string(), external_exports.string()).describe("Exact API-key label selectors that must all match.").optional(),
22014
+ spaceLabelSelectors: external_exports.record(external_exports.string(), external_exports.string()).describe("Exact space label selectors that must match at least one accessible space.").optional()
22015
+ }).passthrough()).describe("OR clauses used for scoped matching. Required and non-empty when matchAll is false or omitted. Must be omitted or empty when matchAll is true. Each clause must include at least one match dimension.").optional()
22016
+ }).passthrough().describe("Policy match condition."),
22017
+ active_from: external_exports.number().int().describe("Inclusive activation time in milliseconds since epoch.").optional(),
22018
+ active_until: external_exports.number().int().describe("Exclusive deactivation time in milliseconds since epoch.").optional(),
22019
+ labels: external_exports.record(external_exports.string(), external_exports.string()).describe("Operator labels for listing and administration.").optional()
22020
+ }, async (args) => {
22021
+ const body = {};
22022
+ if (args.policy_id !== void 0)
22023
+ body["policyId"] = args.policy_id;
22024
+ if (args.display_name !== void 0)
22025
+ body["displayName"] = args.display_name;
22026
+ if (args.description !== void 0)
22027
+ body["description"] = args.description;
22028
+ if (args.condition !== void 0)
22029
+ body["condition"] = args.condition;
22030
+ if (args.active_from !== void 0)
22031
+ body["activeFrom"] = args.active_from;
22032
+ if (args.active_until !== void 0)
22033
+ body["activeUntil"] = args.active_until;
22034
+ if (args.labels !== void 0)
22035
+ body["labels"] = args.labels;
22036
+ const result = await callApi("POST", `/v1/admin/retrieve-memory-log-policies`, body);
22037
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22038
+ });
22039
+ server.tool("goodmem_admin_retrieve_memory_log_policies_delete", "Delete a RetrieveMemory log policy\n\nIdempotently tombstones an immutable RetrieveMemory log policy.", {
22040
+ id: external_exports.string().describe("The UUID of the policy to delete"),
22041
+ reason: external_exports.string().describe("Optional tombstone reason.").optional()
22042
+ }, async (args) => {
22043
+ if (typeof args.id !== "string" || args.id === "") {
22044
+ throw new Error("'id' must be a non-empty string");
22045
+ }
22046
+ const body = {};
22047
+ if (args.reason !== void 0)
22048
+ body["reason"] = args.reason;
22049
+ await callApi("DELETE", `/v1/admin/retrieve-memory-log-policies/${encodeURIComponent(String(args.id))}`, body);
22050
+ return { content: [{ type: "text", text: "Deleted successfully." }] };
22051
+ });
22052
+ server.tool("goodmem_admin_retrieve_memory_log_policies_get", "Get a RetrieveMemory log policy\n\nRetrieves a live RetrieveMemory log policy by UUID, or a tombstoned policy when include_deleted is true.", {
21980
22053
  id: external_exports.string().describe("The UUID of the policy to retrieve"),
21981
22054
  include_deleted: external_exports.boolean().describe("Whether to include tombstoned policies. Also accepts include_deleted.").optional()
21982
22055
  }, async (args) => {
@@ -21989,11 +22062,7 @@ function registerTools() {
21989
22062
  const result = await callApi("GET", `/v1/admin/retrieve-memory-log-policies/${encodeURIComponent(String(args.id))}`, void 0, query);
21990
22063
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
21991
22064
  });
21992
- server.tool("goodmem_admin_license_reload", "Reload the active license from disk\n\nTriggers the server to reload its license file from the configured directory and returns metadata about the currently active license.", {}, async (args) => {
21993
- const result = await callApi("POST", `/v1/admin/license:reload`, void 0);
21994
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
21995
- });
21996
- server.tool("goodmem_admin_retrieve_memory_log_policies", "List RetrieveMemory log policies\n\nLists RetrieveMemory log policies with optional tombstone, active-time, name, label, sort, and pagination filters. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production).", {
22065
+ server.tool("goodmem_admin_retrieve_memory_log_policies_list", "List RetrieveMemory log policies\n\nLists RetrieveMemory log policies with optional tombstone, active-time, name, label, sort, and pagination filters. LABEL FILTERS: Label filters accept either label.<key>=<value> or label[key]=value (for example, label.environment=production or label[environment]=production).", {
21997
22066
  include_deleted: external_exports.boolean().describe("Whether to include tombstoned policies. Also accepts include_deleted.").optional(),
21998
22067
  name_filter: external_exports.string().describe("Case-insensitive substring filter on policy display names. Also accepts name_filter.").optional(),
21999
22068
  active_at: external_exports.number().int().describe("Only return policies active at this millisecond epoch timestamp. Also accepts active_at.").optional(),
@@ -22550,6 +22619,29 @@ function registerTools() {
22550
22619
  const result = await callApi("POST", `/v1/memories:batchGet`, body);
22551
22620
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22552
22621
  });
22622
+ server.tool("goodmem_memories_content", "Download memory content\n\nReturns the original binary payload for a memory. The response uses the memory's stored content type when available. Returns 404 when the memory does not have inline content; clients can check originalContentRef from the metadata endpoint to locate external content.", {
22623
+ id: external_exports.string().describe("The UUID of the memory to download"),
22624
+ max_inline_bytes: external_exports.number().int().positive().describe("Maximum bytes to deliver inline as a content block. Defaults to 8388608. Hard server ceiling: 67108864. If the payload exceeds this cap the tool errors with the actual size \u2014 retry with a larger value (up to the ceiling) to receive it.").optional()
22625
+ }, async (args) => {
22626
+ if (typeof args.id !== "string" || args.id === "") {
22627
+ throw new Error("'id' must be a non-empty string");
22628
+ }
22629
+ const _cap = Math.min(args.max_inline_bytes ?? DEFAULT_MAX_INLINE_BYTES, ABSOLUTE_MAX_INLINE_BYTES);
22630
+ const { bytes: _bytes, mimeType: _mimeType, sizeBytes: _sizeBytes } = await callApiBinary("GET", `/v1/memories/${encodeURIComponent(String(args.id))}/content`, void 0);
22631
+ if (_sizeBytes > _cap) {
22632
+ throw new Error(`Content is ${_sizeBytes} bytes, exceeded the inline cap of ${_cap} bytes (cap = min(max_inline_bytes ?? ${DEFAULT_MAX_INLINE_BYTES}, server absolute maximum ${ABSOLUTE_MAX_INLINE_BYTES})). Retry with max_inline_bytes=${_sizeBytes} or higher (up to ${ABSOLUTE_MAX_INLINE_BYTES}) to receive it inline.`);
22633
+ }
22634
+ const _uri = `goodmem://v1/memories/${encodeURIComponent(String(args.id))}/content`;
22635
+ const _b64 = Buffer.from(_bytes).toString("base64");
22636
+ if (_mimeType.startsWith("image/")) {
22637
+ return { content: [{ type: "image", data: _b64, mimeType: _mimeType }] };
22638
+ }
22639
+ if (_mimeType.startsWith("text/") || _mimeType === "application/json") {
22640
+ const _text = new TextDecoder("utf-8").decode(_bytes);
22641
+ return { content: [{ type: "resource", resource: { uri: _uri, mimeType: _mimeType, text: _text } }] };
22642
+ }
22643
+ return { content: [{ type: "resource", resource: { uri: _uri, mimeType: _mimeType, blob: _b64 } }] };
22644
+ });
22553
22645
  server.tool("goodmem_memories_create", "Create a memory from text content or base64-encoded binary content. Provide exactly one of `original_content` or `original_content_b64` per call; if `original_content_b64`, `content_type` is required. `original_content_ref` is a metadata URL pointer (the server does NOT fetch it) and may be set alongside the content source.", {
22554
22646
  memory_id: 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(),
22555
22647
  space_id: external_exports.string().describe("ID of the space where this memory will be stored"),
@@ -22696,6 +22788,40 @@ function registerTools() {
22696
22788
  const result = await callApi("GET", `/v1/memories/${encodeURIComponent(String(args.id))}/pages`, void 0, query);
22697
22789
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
22698
22790
  });
22791
+ server.tool("goodmem_memories_pages_image", "Download memory page image content\n\nDownloads inline bytes for one page image. The page index is required. The optional dpi and content type query parameters act as rendition filters; if omitted, the server returns the unique rendition for that page or rejects ambiguous matches.", {
22792
+ id: external_exports.string().describe("Memory UUID"),
22793
+ page_index: external_exports.number().int().describe("0-based page index"),
22794
+ dpi: external_exports.number().int().describe("Optional rendition filter. If omitted, the unique page-image rendition for the page is returned; if multiple renditions exist, specify dpi and/or content_type.").optional(),
22795
+ content_type: external_exports.string().describe("Optional rendition filter. MIME type of the desired page image, such as image/png.").optional(),
22796
+ max_inline_bytes: external_exports.number().int().positive().describe("Maximum bytes to deliver inline as a content block. Defaults to 8388608. Hard server ceiling: 67108864. If the payload exceeds this cap the tool errors with the actual size \u2014 retry with a larger value (up to the ceiling) to receive it.").optional()
22797
+ }, async (args) => {
22798
+ if (typeof args.id !== "string" || args.id === "") {
22799
+ throw new Error("'id' must be a non-empty string");
22800
+ }
22801
+ if (typeof args.page_index !== "number" || !Number.isFinite(args.page_index)) {
22802
+ throw new Error("'page_index' must be a finite number");
22803
+ }
22804
+ const query = {};
22805
+ if (args.dpi !== void 0)
22806
+ query["dpi"] = String(args.dpi);
22807
+ if (args.content_type !== void 0)
22808
+ query["contentType"] = String(args.content_type);
22809
+ const _cap = Math.min(args.max_inline_bytes ?? DEFAULT_MAX_INLINE_BYTES, ABSOLUTE_MAX_INLINE_BYTES);
22810
+ const { bytes: _bytes, mimeType: _mimeType, sizeBytes: _sizeBytes } = await callApiBinary("GET", `/v1/memories/${encodeURIComponent(String(args.id))}/pages/${encodeURIComponent(String(args.page_index))}/image`, query);
22811
+ if (_sizeBytes > _cap) {
22812
+ throw new Error(`Content is ${_sizeBytes} bytes, exceeded the inline cap of ${_cap} bytes (cap = min(max_inline_bytes ?? ${DEFAULT_MAX_INLINE_BYTES}, server absolute maximum ${ABSOLUTE_MAX_INLINE_BYTES})). Retry with max_inline_bytes=${_sizeBytes} or higher (up to ${ABSOLUTE_MAX_INLINE_BYTES}) to receive it inline.`);
22813
+ }
22814
+ const _uri = `goodmem://v1/memories/${encodeURIComponent(String(args.id))}/pages/${encodeURIComponent(String(args.page_index))}/image`;
22815
+ const _b64 = Buffer.from(_bytes).toString("base64");
22816
+ if (_mimeType.startsWith("image/")) {
22817
+ return { content: [{ type: "image", data: _b64, mimeType: _mimeType }] };
22818
+ }
22819
+ if (_mimeType.startsWith("text/") || _mimeType === "application/json") {
22820
+ const _text = new TextDecoder("utf-8").decode(_bytes);
22821
+ return { content: [{ type: "resource", resource: { uri: _uri, mimeType: _mimeType, text: _text } }] };
22822
+ }
22823
+ return { content: [{ type: "resource", resource: { uri: _uri, mimeType: _mimeType, blob: _b64 } }] };
22824
+ });
22699
22825
  server.tool("goodmem_memories_retrieve", "Performs a streaming semantic search across one or more memory spaces and returns matching chunks ranked by relevance as well as LLM-postprocessed results (like summarization, question-answering, etc.).", {
22700
22826
  message: external_exports.string().describe("Primary query/message for semantic search."),
22701
22827
  context: external_exports.array(external_exports.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pairsystems/goodmem-mcp",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "GoodMem MCP server \u2014 exposes GoodMem API as MCP tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",