@aexhq/tools-mcp 0.3.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,10 +19,17 @@ const tools = await mcpTools({
19
19
  // await client.close();
20
20
  ```
21
21
 
22
- The client SDK owns transport and protocol negotiation. `connectMcp` disables automatic interactive fulfilment; specify the protocol revision your server supports. A connected client can also be supplied directly. The bridge uses a fixed discovered Tool definition on every call, so an SDK cache refresh cannot change the session's schemas or trigger the header-mismatch resend path. Discovery uses the SDK's bounded pagination. Later list changes do not add or replace placed Tools; authorize a new session for changed definitions.
22
+ The client SDK owns transport and protocol negotiation. `connectMcp` disables automatic interactive fulfilment; specify the protocol revision your server supports. For Tool requests it also disables the MCP SDK's independent timer: Brain's original deadline and cancellation signal own invocation lifetime, including unlimited deadlines. Discovery still uses the SDK's normal timeout. A connected client can be supplied directly for finite deadlines of at most 2,147,483,647 ms; use `connectMcp` for longer or unlimited calls. Unsupported timer ranges fail before dispatch instead of shortening the deadline.
23
+
24
+ The bridge uses a fixed discovered Tool definition on every call, so an SDK cache refresh cannot change the session's schemas or trigger the header-mismatch resend path. Discovery uses the SDK's bounded pagination. Later list changes do not add or replace placed Tools; authorize a new session for changed definitions.
23
25
 
24
26
  ## Results and failures
25
27
 
28
+ The bridge uses Brain SDK 0.28 and explicitly finishes each invocation after committing its
29
+ evidence and normalized result. Return alone does not complete a Brain Tool. A missing deadline
30
+ means no invocation timer; keep the application's host connection and MCP client alive until
31
+ completion or cancellation.
32
+
26
33
  MCP images and embedded image/PDF resources require a caller-supplied
27
34
  `publishMedia({ bytes, mediaType, index }, context)` callback on `mcpTools`. Return an HTTPS URL
28
35
  reachable by the model provider. `context` supplies the session ID, invocation sequence, deadline
package/dist/index.mjs CHANGED
@@ -26,8 +26,13 @@ function toolOutput(content, media = []) {
26
26
  }
27
27
 
28
28
  // src/index.mjs
29
- async function connectMcp(transport, { name = "aex-mcp", version = "0.3.0", ...options } = {}) {
30
- const client = new Client({ name, version }, { ...options, inputRequired: { autoFulfill: false } });
29
+ var SignalClient = class extends Client {
30
+ _setupTimeout(messageId, timeout, ...options) {
31
+ if (timeout !== Infinity) super._setupTimeout(messageId, timeout, ...options);
32
+ }
33
+ };
34
+ async function connectMcp(transport, { name = "aex-mcp", version = "0.4.0", ...options } = {}) {
35
+ const client = new SignalClient({ name, version }, { ...options, inputRequired: { autoFulfill: false } });
31
36
  try {
32
37
  await client.connect(transport);
33
38
  } catch (error) {
@@ -60,11 +65,15 @@ async function mcpTools({ client, names, env, prefix = "", project, publishMedia
60
65
  input,
61
66
  run: async (arguments_, context) => {
62
67
  context.signal.throwIfAborted();
68
+ const timeout = client instanceof SignalClient ? Infinity : context.deadline === void 0 ? Infinity : Math.max(1, context.deadline.getTime() - Date.now());
69
+ if (!(client instanceof SignalClient) && timeout > 2147483647) {
70
+ throw new TypeError("use connectMcp for unlimited or long Tool deadlines; the MCP SDK timer cannot represent them");
71
+ }
63
72
  let response;
64
73
  try {
65
74
  response = await client.callTool({ name: definition.name, arguments: arguments_ }, {
66
75
  signal: context.signal,
67
- timeout: Math.max(1, context.deadline.getTime() - Date.now()),
76
+ timeout,
68
77
  toolDefinition: definition,
69
78
  allowInputRequired: true
70
79
  });
@@ -80,7 +89,7 @@ async function mcpTools({ client, names, env, prefix = "", project, publishMedia
80
89
  message,
81
90
  details: details.data
82
91
  });
83
- return outcome;
92
+ return context.finish(outcome);
84
93
  }
85
94
  const media = [];
86
95
  const content = [];
@@ -98,19 +107,19 @@ async function mcpTools({ client, names, env, prefix = "", project, publishMedia
98
107
  } catch (error) {
99
108
  if (context.signal.aborted) throw error;
100
109
  await context.emit("mcp_media_failed", { tool: definition.name, published: media });
101
- return failure("mcp_media_failed", String(error.message), { published: media });
110
+ return context.finish(failure("mcp_media_failed", String(error.message), { published: media }));
102
111
  }
103
112
  const retained = { ...response, content, ...media.length ? { media } : {} };
104
113
  const evidenceSequence = await context.emit("mcp_result", { tool: definition.name, result: retained });
105
114
  if (response.resultType && response.resultType !== "complete") {
106
- return failure("mcp_unsupported_result", `MCP ${definition.name} requires unsupported continuation (${response.resultType}); evidence ${evidenceSequence}`, retained);
115
+ return context.finish(failure("mcp_unsupported_result", `MCP ${definition.name} requires unsupported continuation (${response.resultType}); evidence ${evidenceSequence}`, retained));
107
116
  }
108
117
  if (response.isError) {
109
118
  const message = content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
110
- return failure("mcp_tool_error", `MCP ${definition.name}: ${message || "Tool failed"}; evidence ${evidenceSequence}`, retained);
119
+ return context.finish(failure("mcp_tool_error", `MCP ${definition.name}: ${message || "Tool failed"}; evidence ${evidenceSequence}`, retained));
111
120
  }
112
121
  const presented = { content, ...response.structuredContent === void 0 ? {} : { structuredContent: response.structuredContent }, evidenceSequence };
113
- return toolOutput(project ? await project(presented, definition.name) : presented, media);
122
+ return context.finish(toolOutput(project ? await project(presented, definition.name) : presented, media));
114
123
  }
115
124
  })({ env });
116
125
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexhq/tools-mcp",
3
- "version": "0.3.5",
3
+ "version": "0.4.0",
4
4
  "description": "Selected MCP Tools in a Brain application host",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,6 +10,6 @@
10
10
  "exports": { ".": { "types": "./index.d.ts", "import": "./dist/index.mjs" }, "./package.json": "./package.json" },
11
11
  "files": ["dist", "index.d.ts", "README.md"],
12
12
  "scripts": { "build": "node ../../tools/build-environment.mjs", "test": "npm run build && node --test test/*.test.mjs", "test:journeys": "node --test test/journeys.mjs", "prepack": "npm run build" },
13
- "dependencies": { "@aexhq/brain": "0.27.0", "@modelcontextprotocol/client": "2.0.0", "zod": "4.4.3" },
13
+ "dependencies": { "@aexhq/brain": "0.28.0", "@modelcontextprotocol/client": "2.0.0", "zod": "4.4.3" },
14
14
  "devDependencies": { "@modelcontextprotocol/server": "2.0.0" }
15
15
  }