@toolgrain/mcp 0.3.0-alpha.0 → 0.3.0-alpha.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @toolgrain/mcp
2
2
 
3
+ ## 0.3.0-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Pace request-scoped progress notifications at 100 ms intervals while preserving ordered delivery, backpressure, and prompt cancellation. Reject duplicate active progress tokens on shared message connections, release tokens on completion or cancellation, and preserve isolation between independent HTTP response streams.
8
+ - @toolgrain/protocol@0.3.0-alpha.1
9
+
3
10
  ## 0.3.0-alpha.0
4
11
 
5
12
  ### Minor Changes
package/README.md CHANGED
@@ -70,9 +70,13 @@ Handlers can accept `execute(input, ctx)` to use request information and
70
70
  `ctx.signal` for cooperative cancellation. Report client-requested progress with
71
71
  `await ctx.reportProgress({ progress: 1, total: 10, message: "Processing" })`.
72
72
  The bound method is safe to pass to helpers and becomes a no-op without a
73
- progress token or delivery channel. Use `toolContext()` for direct handler
74
- calls, which bypass server validation and result conversion. Unexpected server
75
- execution failures return generic errors and reach the optional `onError`
73
+ progress token or delivery channel. The first update sends immediately; later
74
+ updates are spaced at least 100 ms apart per invocation, preserving order and
75
+ backpressure. Await each report. Duplicate active progress tokens are rejected
76
+ on shared message connections; independent HTTP response streams remain isolated.
77
+ Use `toolContext()` for direct handler calls, which bypass server validation and
78
+ result conversion. Unexpected server execution failures return generic errors
79
+ and reach the optional `onError`
76
80
  callback. Request-cached dependencies use `createContext()` and inferred
77
81
  accessors; see the
78
82
  [context guide](https://toolgrain.mintlify.site/guides/context).
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOlD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EACV,gBAAgB,EAChB,SAAS,EAEV,MAAM,gBAAgB,CAAC;AAGxB,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,YAAY,EACtB,OAAO,CAAC,EAAE,MAAM,IAAI,GACnB,mBAAmB,CAErB;AAED,UAAU,mBAAmB;IAC3B,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,cAAc,CAAC,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOlD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EACV,gBAAgB,EAChB,SAAS,EAEV,MAAM,gBAAgB,CAAC;AAGxB,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,YAAY,EACtB,OAAO,CAAC,EAAE,MAAM,IAAI,GACnB,mBAAmB,CAErB;AAED,UAAU,mBAAmB;IAC3B,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,cAAc,CAAC,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -1,10 +1,11 @@
1
- import { INVALID_REQUEST, PARSE_ERROR, } from "@toolgrain/protocol";
1
+ import { INVALID_PARAMS, INVALID_REQUEST, PARSE_ERROR, } from "@toolgrain/protocol";
2
2
  import { reportError } from "./diagnostics.js";
3
3
  import { executeRequest } from "./execute-request.js";
4
4
  import { createLegacyConnection } from "./legacy/connection.js";
5
5
  import { createPendingRequests } from "./pending-requests.js";
6
6
  import { decode } from "./protocol/decode.js";
7
7
  import { protocolError } from "./protocol/responses.js";
8
+ import { isProgressToken } from "./tools/progress.js";
8
9
  import { claimTransport } from "./transport-ownership.js";
9
10
  export function createConnection(dispatch, onError, onClose) {
10
11
  return new Connection(dispatch, onError, onClose);
@@ -135,6 +136,13 @@ class Connection {
135
136
  await this.send(protocolError(INVALID_REQUEST, "Request ID is already in use", request.id));
136
137
  return;
137
138
  }
139
+ const token = request.params?._meta
140
+ ?.progressToken;
141
+ if (isProgressToken(token) && !pending.claimProgress(token)) {
142
+ pending.finish();
143
+ await this.send(protocolError(INVALID_PARAMS, "Progress token is already in use", request.id));
144
+ return;
145
+ }
138
146
  const initialization = this.legacy.begin(request, prepared.protocolVersion);
139
147
  try {
140
148
  const response = await executeRequest(this.dispatch, request, {
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
- import type { RequestId } from "@toolgrain/protocol";
1
+ import type { ProgressToken, RequestId } from "@toolgrain/protocol";
2
2
  /** Owns duplicate detection and cancellation signals for in-flight requests. */
3
3
  export declare function createPendingRequests(isOpen: () => boolean): {
4
4
  begin(id: RequestId): {
5
5
  signal: AbortSignal;
6
6
  isActive: () => boolean;
7
+ claimProgress(token: ProgressToken): boolean;
7
8
  finish: () => void;
8
9
  } | undefined;
9
10
  cancel(id: RequestId): void;
@@ -1 +1 @@
1
- {"version":3,"file":"pending-requests.d.ts","sourceRoot":"","sources":["../src/pending-requests.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,OAAO;IAGvD,KAAK,KAAK,SAAS;;;;;IAYnB,MAAM,KAAK,SAAS;IAKpB,KAAK;EAMR"}
1
+ {"version":3,"file":"pending-requests.d.ts","sourceRoot":"","sources":["../src/pending-requests.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEpE,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,OAAO;IAIvD,KAAK,KAAK,SAAS;;;6BAQM,aAAa;;;IAmBtC,MAAM,KAAK,SAAS;IAKpB,KAAK;EAMR"}
@@ -1,16 +1,33 @@
1
1
  /** Owns duplicate detection and cancellation signals for in-flight requests. */
2
2
  export function createPendingRequests(isOpen) {
3
3
  const pending = new Map();
4
+ const progressTokens = new Set();
4
5
  return {
5
6
  begin(id) {
6
7
  if (pending.has(id))
7
8
  return;
8
9
  const controller = new AbortController();
9
10
  pending.set(id, controller);
11
+ let releaseProgress;
10
12
  return {
11
13
  signal: controller.signal,
12
14
  isActive: () => isOpen() && !controller.signal.aborted,
15
+ claimProgress(token) {
16
+ if (progressTokens.has(token))
17
+ return false;
18
+ progressTokens.add(token);
19
+ releaseProgress = () => {
20
+ progressTokens.delete(token);
21
+ controller.signal.removeEventListener("abort", release);
22
+ releaseProgress = undefined;
23
+ };
24
+ // Aborting releases the token even if the cancelled handler keeps running.
25
+ const release = () => releaseProgress?.();
26
+ controller.signal.addEventListener("abort", release, { once: true });
27
+ return true;
28
+ },
13
29
  finish: () => {
30
+ releaseProgress?.();
14
31
  pending.delete(id);
15
32
  },
16
33
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pending-requests.js","sourceRoot":"","sources":["../src/pending-requests.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CAAC,MAAqB;IACzD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;IACtD,OAAO;QACL,KAAK,CAAC,EAAa;YACjB,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,OAAO;YAC5B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YAC5B,OAAO;gBACL,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO;gBACtD,MAAM,EAAE,GAAG,EAAE;oBACX,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACrB,CAAC;aACF,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,EAAa;YAClB,OAAO;iBACJ,GAAG,CAAC,EAAE,CAAC;gBACR,EAAE,KAAK,CAAC,IAAI,YAAY,CAAC,6BAA6B,EAAE,YAAY,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,KAAK;YACH,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE;gBACvC,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC,CAAC;YACxE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"pending-requests.js","sourceRoot":"","sources":["../src/pending-requests.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CAAC,MAAqB;IACzD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;IACtD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAiB,CAAC;IAChD,OAAO;QACL,KAAK,CAAC,EAAa;YACjB,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,OAAO;YAC5B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YAC5B,IAAI,eAAyC,CAAC;YAC9C,OAAO;gBACL,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO;gBACtD,aAAa,CAAC,KAAoB;oBAChC,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;wBAAE,OAAO,KAAK,CAAC;oBAC5C,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAC1B,eAAe,GAAG,GAAG,EAAE;wBACrB,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC7B,UAAU,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;wBACxD,eAAe,GAAG,SAAS,CAAC;oBAC9B,CAAC,CAAC;oBACF,2EAA2E;oBAC3E,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,eAAe,EAAE,EAAE,CAAC;oBAC1C,UAAU,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;oBACrE,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,MAAM,EAAE,GAAG,EAAE;oBACX,eAAe,EAAE,EAAE,CAAC;oBACpB,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACrB,CAAC;aACF,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,EAAa;YAClB,OAAO;iBACJ,GAAG,CAAC,EAAE,CAAC;gBACR,EAAE,KAAK,CAAC,IAAI,YAAY,CAAC,6BAA6B,EAAE,YAAY,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,KAAK;YACH,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE;gBACvC,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC,CAAC;YACxE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -31,8 +31,9 @@ export interface ToolContext {
31
31
  readonly request: ToolRequest;
32
32
  /**
33
33
  * Report request-scoped progress; safe to pass to helpers without binding.
34
- * Await delivery/backpressure. Resolves without sending when no progress token
35
- * or delivery channel exists, or after cancellation/completion. Active updates
34
+ * Await delivery/backpressure; updates are spaced at least 100 ms per invocation.
35
+ * Resolves without sending when no progress token or delivery channel exists,
36
+ * or after cancellation/completion. Active updates
36
37
  * require finite values and strictly increasing progress; invalid updates reject.
37
38
  * Delivery failure cancels the request and reaches transport diagnostics.
38
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAEnB,KAAK,SAAS,EACd,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,kBAAkB,IAAI,wBAAwB,EAC9C,cAAc,IAAI,oBAAoB,EACvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,gGAAgG;AAChG,MAAM,WAAW,UAAU;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,cAAc,GAAG,oBAAoB,CAAC,CAAC;IACpE,sFAAsF;IACtF,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAClC,kBAAkB,GAAG,wBAAwB,CAC9C,CAAC;CACH;AAED,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,gEAAgE;IAChE,QAAQ,CAAC,eAAe,EAAE,wBAAwB,CAAC;IACnD,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,0FAA0F;IAC1F,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAClD;AAED,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED,wFAAwF;AACxF,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gGAAgG;IAChG,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,8FAA8F;IAC9F,OAAO,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAChD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAmBzE;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,WAAW,EACnC,IAAI,CAAC,EAAE,YAAY,EACnB,SAAS,GAAE,eAAyC,EACpD,cAAc,GAAE,WAAW,CAAC,gBAAgB,CAA2B,GACtE,WAAW,CAkBb;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EACxB,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,GACvC,UAAU,CAKZ"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAEnB,KAAK,SAAS,EACd,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,kBAAkB,IAAI,wBAAwB,EAC9C,cAAc,IAAI,oBAAoB,EACvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,gGAAgG;AAChG,MAAM,WAAW,UAAU;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,cAAc,GAAG,oBAAoB,CAAC,CAAC;IACpE,sFAAsF;IACtF,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAClC,kBAAkB,GAAG,wBAAwB,CAC9C,CAAC;CACH;AAED,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,gEAAgE;IAChE,QAAQ,CAAC,eAAe,EAAE,wBAAwB,CAAC;IACnD,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,0FAA0F;IAC1F,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAClD;AAED,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED,wFAAwF;AACxF,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gGAAgG;IAChG,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,8FAA8F;IAC9F,OAAO,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAChD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAmBzE;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,WAAW,EACnC,IAAI,CAAC,EAAE,YAAY,EACnB,SAAS,GAAE,eAAyC,EACpD,cAAc,GAAE,WAAW,CAAC,gBAAgB,CAA2B,GACtE,WAAW,CAkBb;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EACxB,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,GACvC,UAAU,CAKZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAEL,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAoDzD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,OAAO,GAAuB,EAAE;IAC1D,mFAAmF;IACnF,MAAM,EACJ,EAAE,GAAG,CAAC,EACN,eAAe,GAAG,gBAAgB,EAClC,MAAM,EACN,IAAI,GAAG,EAAE,GACV,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IAC1B,OAAO,iBAAiB,CACtB,OAAO,CAAC,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,MAAM,EAC9C;QACE,EAAE;QACF,eAAe;QACf,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3C,IAAI;KACL,EACD,SAAS,EACT,qBAAqB,CAAC,OAAO,CAAC,OAAO,CAAC,CACvC,CAAC;AACJ,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,iBAAiB,CAC/B,MAAmB,EACnB,EAAE,MAAM,EAAE,GAAG,OAAO,EAAe,EACnC,IAAmB,EACnB,SAAS,GAAoB,qBAAqB,EAAE,EACpD,cAAc,GAAkC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;IAEvE,MAAM,GAAG,GAAG,UAAU,CACpB;QACE,MAAM;QACN,cAAc;QACd,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;YACrB,GAAG,OAAO;YACV,GAAG,CAAC,MAAM,KAAK,SAAS;gBACtB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;iBACjE,CAAC;YACN,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;SAC/B,CAAC;KACH,EACD,IAAI,CACL,CAAC;IACF,OAAO,kBAAkB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CACxB,IAAwB,EACxB,YAAwC;IAExC,OAAO;QACL,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAI,KAAQ;IAC7B,OAAO,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,UAAU,CAAI,KAAQ;IAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAEL,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAqDzD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,OAAO,GAAuB,EAAE;IAC1D,mFAAmF;IACnF,MAAM,EACJ,EAAE,GAAG,CAAC,EACN,eAAe,GAAG,gBAAgB,EAClC,MAAM,EACN,IAAI,GAAG,EAAE,GACV,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IAC1B,OAAO,iBAAiB,CACtB,OAAO,CAAC,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,MAAM,EAC9C;QACE,EAAE;QACF,eAAe;QACf,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3C,IAAI;KACL,EACD,SAAS,EACT,qBAAqB,CAAC,OAAO,CAAC,OAAO,CAAC,CACvC,CAAC;AACJ,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,iBAAiB,CAC/B,MAAmB,EACnB,EAAE,MAAM,EAAE,GAAG,OAAO,EAAe,EACnC,IAAmB,EACnB,SAAS,GAAoB,qBAAqB,EAAE,EACpD,cAAc,GAAkC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;IAEvE,MAAM,GAAG,GAAG,UAAU,CACpB;QACE,MAAM;QACN,cAAc;QACd,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;YACrB,GAAG,OAAO;YACV,GAAG,CAAC,MAAM,KAAK,SAAS;gBACtB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;iBACjE,CAAC;YACN,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;SAC/B,CAAC;KACH,EACD,IAAI,CACL,CAAC;IACF,OAAO,kBAAkB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CACxB,IAAwB,EACxB,YAAwC;IAExC,OAAO;QACL,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAI,KAAQ;IAC7B,OAAO,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,UAAU,CAAI,KAAQ;IAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { ProgressNotification } from "@toolgrain/protocol";
1
+ import type { ProgressNotification, ProgressToken } from "@toolgrain/protocol";
2
2
  /** One progress update; values are finite numbers and progress must strictly increase. */
3
3
  export interface ToolProgress {
4
4
  /** Work completed so far, in application-defined units; the first value may be zero. */
@@ -8,8 +8,10 @@ export interface ToolProgress {
8
8
  /** Optional public status message sent to the client. */
9
9
  readonly message?: string;
10
10
  }
11
+ /** Tokens share the request-ID wire format, but have a separate lifetime. */
12
+ export declare function isProgressToken(token: unknown): token is ProgressToken;
11
13
  /** One invocation owns its reporter, ordering, and completion boundary. */
12
- export declare function createProgressReporter(signal: AbortSignal, token: unknown, send?: (message: ProgressNotification) => void | Promise<void>): {
14
+ export declare function createProgressReporter(requestSignal: AbortSignal, token: unknown, send?: (message: ProgressNotification) => void | Promise<void>): {
13
15
  report: (value: ToolProgress) => Promise<void>;
14
16
  finish(): Promise<void>;
15
17
  close(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/tools/progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAiB,MAAM,qBAAqB,CAAC;AAI/E,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAQD,2EAA2E;AAC3E,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;oBAUvC,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;;;EA8CpD"}
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/tools/progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAI/E,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAQD,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAOtE;AAkBD,2EAA2E;AAC3E,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,WAAW,EAC1B,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;oBASvC,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC;;;EA2DpD"}
@@ -5,15 +5,39 @@ const update = z.object({
5
5
  total: z.number().finite().optional(),
6
6
  message: z.string().optional(),
7
7
  });
8
- /** One invocation owns its reporter, ordering, and completion boundary. */
9
- export function createProgressReporter(signal, token, send) {
10
- const validToken = typeof token === "string" ||
8
+ /** Tokens share the request-ID wire format, but have a separate lifetime. */
9
+ export function isProgressToken(token) {
10
+ return (typeof token === "string" ||
11
11
  (typeof token === "number" &&
12
12
  Number.isFinite(token) &&
13
- Number.isInteger(token));
13
+ Number.isInteger(token)));
14
+ }
15
+ /** Cancellation must release the timer as well as the awaiting handler. */
16
+ function waitForProgress(milliseconds, signal) {
17
+ return new Promise((resolve, reject) => {
18
+ const abort = () => {
19
+ clearTimeout(timer);
20
+ reject(signal.reason);
21
+ };
22
+ const timer = setTimeout(() => {
23
+ signal.removeEventListener("abort", abort);
24
+ resolve();
25
+ }, milliseconds);
26
+ if (signal.aborted)
27
+ abort();
28
+ else
29
+ signal.addEventListener("abort", abort, { once: true });
30
+ });
31
+ }
32
+ /** One invocation owns its reporter, ordering, and completion boundary. */
33
+ export function createProgressReporter(requestSignal, token, send) {
34
+ const lifetime = new AbortController();
35
+ const signal = AbortSignal.any([requestSignal, lifetime.signal]);
36
+ const validToken = isProgressToken(token);
14
37
  let open = true;
15
38
  let previous = Number.NEGATIVE_INFINITY;
16
39
  let writes = Promise.resolve();
40
+ let lastSent = Number.NEGATIVE_INFINITY;
17
41
  const report = (value) => {
18
42
  if (!open || signal.aborted || !validToken || !send)
19
43
  return Promise.resolve();
@@ -38,11 +62,20 @@ export function createProgressReporter(signal, token, send) {
38
62
  },
39
63
  };
40
64
  const write = writes.then(async () => {
41
- if (!signal.aborted)
65
+ if (!signal.aborted) {
66
+ // Pace each operation without dropping updates or bypassing backpressure.
67
+ let remaining = 100 - (performance.now() - lastSent);
68
+ while (remaining > 0) {
69
+ await waitForProgress(Math.ceil(remaining), signal);
70
+ remaining = 100 - (performance.now() - lastSent);
71
+ }
42
72
  await abortable(Promise.resolve().then(() => {
43
- if (!signal.aborted)
73
+ if (!signal.aborted) {
74
+ lastSent = performance.now();
44
75
  return send(message);
76
+ }
45
77
  }), signal);
78
+ }
46
79
  });
47
80
  // The awaiting handler observes failures; keep the queue usable for cleanup.
48
81
  writes = write.catch(() => { });
@@ -56,6 +89,7 @@ export function createProgressReporter(signal, token, send) {
56
89
  },
57
90
  close() {
58
91
  open = false;
92
+ lifetime.abort(new DOMException("Progress reporting closed", "AbortError"));
59
93
  },
60
94
  };
61
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/tools/progress.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/tools/progress.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolgrain/mcp",
3
- "version": "0.3.0-alpha.0",
3
+ "version": "0.3.0-alpha.1",
4
4
  "description": "Define reusable, typed MCP tools and servers with Zod validation.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -59,7 +59,7 @@
59
59
  "@toolgrain/repo-tools": "0.0.0"
60
60
  },
61
61
  "dependencies": {
62
- "@toolgrain/protocol": "0.3.0-alpha.0"
62
+ "@toolgrain/protocol": "0.3.0-alpha.1"
63
63
  },
64
64
  "engines": {
65
65
  "node": "^24.20.0",
package/src/connection.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ INVALID_PARAMS,
2
3
  INVALID_REQUEST,
3
4
  PARSE_ERROR,
4
5
  type ProgressNotification,
@@ -13,6 +14,7 @@ import { decode } from "./protocol/decode.js";
13
14
  import type { Request } from "./protocol/messages.js";
14
15
  import { protocolError } from "./protocol/responses.js";
15
16
  import type { Server } from "./server.js";
17
+ import { isProgressToken } from "./tools/progress.js";
16
18
  import type {
17
19
  RequestTransport,
18
20
  Transport,
@@ -189,6 +191,19 @@ class Connection implements ConnectionLifecycle {
189
191
  );
190
192
  return;
191
193
  }
194
+ const token = (request.params?._meta as Record<string, unknown> | undefined)
195
+ ?.progressToken;
196
+ if (isProgressToken(token) && !pending.claimProgress(token)) {
197
+ pending.finish();
198
+ await this.send(
199
+ protocolError(
200
+ INVALID_PARAMS,
201
+ "Progress token is already in use",
202
+ request.id,
203
+ ),
204
+ );
205
+ return;
206
+ }
192
207
  const initialization = this.legacy.begin(request, prepared.protocolVersion);
193
208
  try {
194
209
  const response = await executeRequest(
@@ -1,17 +1,33 @@
1
- import type { RequestId } from "@toolgrain/protocol";
1
+ import type { ProgressToken, RequestId } from "@toolgrain/protocol";
2
2
 
3
3
  /** Owns duplicate detection and cancellation signals for in-flight requests. */
4
4
  export function createPendingRequests(isOpen: () => boolean) {
5
5
  const pending = new Map<RequestId, AbortController>();
6
+ const progressTokens = new Set<ProgressToken>();
6
7
  return {
7
8
  begin(id: RequestId) {
8
9
  if (pending.has(id)) return;
9
10
  const controller = new AbortController();
10
11
  pending.set(id, controller);
12
+ let releaseProgress: (() => void) | undefined;
11
13
  return {
12
14
  signal: controller.signal,
13
15
  isActive: () => isOpen() && !controller.signal.aborted,
16
+ claimProgress(token: ProgressToken) {
17
+ if (progressTokens.has(token)) return false;
18
+ progressTokens.add(token);
19
+ releaseProgress = () => {
20
+ progressTokens.delete(token);
21
+ controller.signal.removeEventListener("abort", release);
22
+ releaseProgress = undefined;
23
+ };
24
+ // Aborting releases the token even if the cancelled handler keeps running.
25
+ const release = () => releaseProgress?.();
26
+ controller.signal.addEventListener("abort", release, { once: true });
27
+ return true;
28
+ },
14
29
  finish: () => {
30
+ releaseProgress?.();
15
31
  pending.delete(id);
16
32
  },
17
33
  };
@@ -50,8 +50,9 @@ export interface ToolContext {
50
50
  readonly request: ToolRequest;
51
51
  /**
52
52
  * Report request-scoped progress; safe to pass to helpers without binding.
53
- * Await delivery/backpressure. Resolves without sending when no progress token
54
- * or delivery channel exists, or after cancellation/completion. Active updates
53
+ * Await delivery/backpressure; updates are spaced at least 100 ms per invocation.
54
+ * Resolves without sending when no progress token or delivery channel exists,
55
+ * or after cancellation/completion. Active updates
55
56
  * require finite values and strictly increasing progress; invalid updates reject.
56
57
  * Delivery failure cancels the request and reaches transport diagnostics.
57
58
  */
@@ -18,20 +18,45 @@ const update = z.object({
18
18
  message: z.string().optional(),
19
19
  });
20
20
 
21
+ /** Tokens share the request-ID wire format, but have a separate lifetime. */
22
+ export function isProgressToken(token: unknown): token is ProgressToken {
23
+ return (
24
+ typeof token === "string" ||
25
+ (typeof token === "number" &&
26
+ Number.isFinite(token) &&
27
+ Number.isInteger(token))
28
+ );
29
+ }
30
+
31
+ /** Cancellation must release the timer as well as the awaiting handler. */
32
+ function waitForProgress(milliseconds: number, signal: AbortSignal) {
33
+ return new Promise<void>((resolve, reject) => {
34
+ const abort = () => {
35
+ clearTimeout(timer);
36
+ reject(signal.reason);
37
+ };
38
+ const timer = setTimeout(() => {
39
+ signal.removeEventListener("abort", abort);
40
+ resolve();
41
+ }, milliseconds);
42
+ if (signal.aborted) abort();
43
+ else signal.addEventListener("abort", abort, { once: true });
44
+ });
45
+ }
46
+
21
47
  /** One invocation owns its reporter, ordering, and completion boundary. */
22
48
  export function createProgressReporter(
23
- signal: AbortSignal,
49
+ requestSignal: AbortSignal,
24
50
  token: unknown,
25
51
  send?: (message: ProgressNotification) => void | Promise<void>,
26
52
  ) {
27
- const validToken =
28
- typeof token === "string" ||
29
- (typeof token === "number" &&
30
- Number.isFinite(token) &&
31
- Number.isInteger(token));
53
+ const lifetime = new AbortController();
54
+ const signal = AbortSignal.any([requestSignal, lifetime.signal]);
55
+ const validToken = isProgressToken(token);
32
56
  let open = true;
33
57
  let previous = Number.NEGATIVE_INFINITY;
34
58
  let writes = Promise.resolve();
59
+ let lastSent = Number.NEGATIVE_INFINITY;
35
60
  const report = (value: ToolProgress): Promise<void> => {
36
61
  if (!open || signal.aborted || !validToken || !send)
37
62
  return Promise.resolve();
@@ -56,13 +81,23 @@ export function createProgressReporter(
56
81
  },
57
82
  };
58
83
  const write = writes.then(async () => {
59
- if (!signal.aborted)
84
+ if (!signal.aborted) {
85
+ // Pace each operation without dropping updates or bypassing backpressure.
86
+ let remaining = 100 - (performance.now() - lastSent);
87
+ while (remaining > 0) {
88
+ await waitForProgress(Math.ceil(remaining), signal);
89
+ remaining = 100 - (performance.now() - lastSent);
90
+ }
60
91
  await abortable(
61
92
  Promise.resolve().then(() => {
62
- if (!signal.aborted) return send(message);
93
+ if (!signal.aborted) {
94
+ lastSent = performance.now();
95
+ return send(message);
96
+ }
63
97
  }),
64
98
  signal,
65
99
  );
100
+ }
66
101
  });
67
102
  // The awaiting handler observes failures; keep the queue usable for cleanup.
68
103
  writes = write.catch(() => {});
@@ -76,6 +111,9 @@ export function createProgressReporter(
76
111
  },
77
112
  close() {
78
113
  open = false;
114
+ lifetime.abort(
115
+ new DOMException("Progress reporting closed", "AbortError"),
116
+ );
79
117
  },
80
118
  };
81
119
  }