@toolgrain/mcp 0.0.0-stage → 0.1.0-rc.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.
Files changed (248) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -2
  3. package/dist/auth/abort.d.ts +3 -0
  4. package/dist/auth/abort.d.ts.map +1 -0
  5. package/dist/auth/abort.js +14 -0
  6. package/dist/auth/abort.js.map +1 -0
  7. package/dist/auth/audience.d.ts +3 -0
  8. package/dist/auth/audience.d.ts.map +1 -0
  9. package/dist/auth/audience.js +17 -0
  10. package/dist/auth/audience.js.map +1 -0
  11. package/dist/auth/authorization.d.ts +7 -0
  12. package/dist/auth/authorization.d.ts.map +1 -0
  13. package/dist/auth/authorization.js +58 -0
  14. package/dist/auth/authorization.js.map +1 -0
  15. package/dist/auth/context.d.ts +8 -0
  16. package/dist/auth/context.d.ts.map +1 -0
  17. package/dist/auth/context.js +37 -0
  18. package/dist/auth/context.js.map +1 -0
  19. package/dist/auth/errors.d.ts +14 -0
  20. package/dist/auth/errors.d.ts.map +1 -0
  21. package/dist/auth/errors.js +23 -0
  22. package/dist/auth/errors.js.map +1 -0
  23. package/dist/auth/types.d.ts +28 -0
  24. package/dist/auth/types.d.ts.map +1 -0
  25. package/dist/auth/types.js +2 -0
  26. package/dist/auth/types.js.map +1 -0
  27. package/dist/auth/url.d.ts +3 -0
  28. package/dist/auth/url.d.ts.map +1 -0
  29. package/dist/auth/url.js +18 -0
  30. package/dist/auth/url.js.map +1 -0
  31. package/dist/connection.d.ts +12 -0
  32. package/dist/connection.d.ts.map +1 -0
  33. package/dist/connection.js +151 -0
  34. package/dist/connection.js.map +1 -0
  35. package/dist/context/access.d.ts +7 -0
  36. package/dist/context/access.d.ts.map +1 -0
  37. package/dist/context/access.js +22 -0
  38. package/dist/context/access.js.map +1 -0
  39. package/dist/context/definition.d.ts +24 -0
  40. package/dist/context/definition.d.ts.map +1 -0
  41. package/dist/context/definition.js +57 -0
  42. package/dist/context/definition.js.map +1 -0
  43. package/dist/context/registry.d.ts +5 -0
  44. package/dist/context/registry.d.ts.map +1 -0
  45. package/dist/context/registry.js +15 -0
  46. package/dist/context/registry.js.map +1 -0
  47. package/dist/context/scope.d.ts +5 -0
  48. package/dist/context/scope.d.ts.map +1 -0
  49. package/dist/context/scope.js +56 -0
  50. package/dist/context/scope.js.map +1 -0
  51. package/dist/diagnostics.d.ts +10 -0
  52. package/dist/diagnostics.d.ts.map +1 -0
  53. package/dist/diagnostics.js +13 -0
  54. package/dist/diagnostics.js.map +1 -0
  55. package/dist/dispatcher.d.ts +19 -0
  56. package/dist/dispatcher.d.ts.map +1 -0
  57. package/dist/dispatcher.js +23 -0
  58. package/dist/dispatcher.js.map +1 -0
  59. package/dist/execute-request.d.ts +7 -0
  60. package/dist/execute-request.d.ts.map +1 -0
  61. package/dist/execute-request.js +20 -0
  62. package/dist/execute-request.js.map +1 -0
  63. package/dist/index.d.ts +22 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +12 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/legacy/connection.d.ts +26 -0
  68. package/dist/legacy/connection.d.ts.map +1 -0
  69. package/dist/legacy/connection.js +73 -0
  70. package/dist/legacy/connection.js.map +1 -0
  71. package/dist/legacy/dispatcher.d.ts +10 -0
  72. package/dist/legacy/dispatcher.d.ts.map +1 -0
  73. package/dist/legacy/dispatcher.js +41 -0
  74. package/dist/legacy/dispatcher.js.map +1 -0
  75. package/dist/legacy/handlers.d.ts +12 -0
  76. package/dist/legacy/handlers.d.ts.map +1 -0
  77. package/dist/legacy/handlers.js +44 -0
  78. package/dist/legacy/handlers.js.map +1 -0
  79. package/dist/legacy/messages.d.ts +31 -0
  80. package/dist/legacy/messages.d.ts.map +1 -0
  81. package/dist/legacy/messages.js +27 -0
  82. package/dist/legacy/messages.js.map +1 -0
  83. package/dist/legacy/responses.d.ts +5 -0
  84. package/dist/legacy/responses.d.ts.map +1 -0
  85. package/dist/legacy/responses.js +8 -0
  86. package/dist/legacy/responses.js.map +1 -0
  87. package/dist/legacy/results.d.ts +5 -0
  88. package/dist/legacy/results.d.ts.map +1 -0
  89. package/dist/legacy/results.js +19 -0
  90. package/dist/legacy/results.js.map +1 -0
  91. package/dist/modern/dispatcher.d.ts +7 -0
  92. package/dist/modern/dispatcher.d.ts.map +1 -0
  93. package/dist/modern/dispatcher.js +37 -0
  94. package/dist/modern/dispatcher.js.map +1 -0
  95. package/dist/modern/handlers.d.ts +9 -0
  96. package/dist/modern/handlers.d.ts.map +1 -0
  97. package/dist/modern/handlers.js +36 -0
  98. package/dist/modern/handlers.js.map +1 -0
  99. package/dist/modern/messages.d.ts +142 -0
  100. package/dist/modern/messages.d.ts.map +1 -0
  101. package/dist/modern/messages.js +14 -0
  102. package/dist/modern/messages.js.map +1 -0
  103. package/dist/modern/metadata.d.ts +45 -0
  104. package/dist/modern/metadata.d.ts.map +1 -0
  105. package/dist/modern/metadata.js +49 -0
  106. package/dist/modern/metadata.js.map +1 -0
  107. package/dist/modern/responses.d.ts +3 -0
  108. package/dist/modern/responses.d.ts.map +1 -0
  109. package/dist/modern/responses.js +15 -0
  110. package/dist/modern/responses.js.map +1 -0
  111. package/dist/modern/results.d.ts +4 -0
  112. package/dist/modern/results.d.ts.map +1 -0
  113. package/dist/modern/results.js +4 -0
  114. package/dist/modern/results.js.map +1 -0
  115. package/dist/pending-requests.d.ts +12 -0
  116. package/dist/pending-requests.d.ts.map +1 -0
  117. package/dist/pending-requests.js +30 -0
  118. package/dist/pending-requests.js.map +1 -0
  119. package/dist/protocol/decode.d.ts +21 -0
  120. package/dist/protocol/decode.d.ts.map +1 -0
  121. package/dist/protocol/decode.js +40 -0
  122. package/dist/protocol/decode.js.map +1 -0
  123. package/dist/protocol/icon.d.ts +11 -0
  124. package/dist/protocol/icon.d.ts.map +1 -0
  125. package/dist/protocol/icon.js +8 -0
  126. package/dist/protocol/icon.js.map +1 -0
  127. package/dist/protocol/messages.d.ts +19 -0
  128. package/dist/protocol/messages.d.ts.map +1 -0
  129. package/dist/protocol/messages.js +21 -0
  130. package/dist/protocol/messages.js.map +1 -0
  131. package/dist/protocol/responses.d.ts +9 -0
  132. package/dist/protocol/responses.d.ts.map +1 -0
  133. package/dist/protocol/responses.js +20 -0
  134. package/dist/protocol/responses.js.map +1 -0
  135. package/dist/protocol/version-metadata.d.ts +7 -0
  136. package/dist/protocol/version-metadata.d.ts.map +1 -0
  137. package/dist/protocol/version-metadata.js +21 -0
  138. package/dist/protocol/version-metadata.js.map +1 -0
  139. package/dist/server.d.ts +35 -0
  140. package/dist/server.d.ts.map +1 -0
  141. package/dist/server.js +101 -0
  142. package/dist/server.js.map +1 -0
  143. package/dist/tools/adapter.d.ts +12 -0
  144. package/dist/tools/adapter.d.ts.map +1 -0
  145. package/dist/tools/adapter.js +45 -0
  146. package/dist/tools/adapter.js.map +1 -0
  147. package/dist/tools/call.d.ts +8 -0
  148. package/dist/tools/call.d.ts.map +1 -0
  149. package/dist/tools/call.js +9 -0
  150. package/dist/tools/call.js.map +1 -0
  151. package/dist/tools/content.d.ts +181 -0
  152. package/dist/tools/content.d.ts.map +1 -0
  153. package/dist/tools/content.js +54 -0
  154. package/dist/tools/content.js.map +1 -0
  155. package/dist/tools/context.d.ts +36 -0
  156. package/dist/tools/context.d.ts.map +1 -0
  157. package/dist/tools/context.js +50 -0
  158. package/dist/tools/context.js.map +1 -0
  159. package/dist/tools/definition.d.ts +55 -0
  160. package/dist/tools/definition.d.ts.map +1 -0
  161. package/dist/tools/definition.js +44 -0
  162. package/dist/tools/definition.js.map +1 -0
  163. package/dist/tools/errors.d.ts +11 -0
  164. package/dist/tools/errors.d.ts.map +1 -0
  165. package/dist/tools/errors.js +19 -0
  166. package/dist/tools/errors.js.map +1 -0
  167. package/dist/tools/json-value.d.ts +15 -0
  168. package/dist/tools/json-value.d.ts.map +1 -0
  169. package/dist/tools/json-value.js +42 -0
  170. package/dist/tools/json-value.js.map +1 -0
  171. package/dist/tools/name.d.ts +6 -0
  172. package/dist/tools/name.d.ts.map +1 -0
  173. package/dist/tools/name.js +13 -0
  174. package/dist/tools/name.js.map +1 -0
  175. package/dist/tools/registry.d.ts +14 -0
  176. package/dist/tools/registry.d.ts.map +1 -0
  177. package/dist/tools/registry.js +31 -0
  178. package/dist/tools/registry.js.map +1 -0
  179. package/dist/tools/results.d.ts +14 -0
  180. package/dist/tools/results.d.ts.map +1 -0
  181. package/dist/tools/results.js +71 -0
  182. package/dist/tools/results.js.map +1 -0
  183. package/dist/tools/rich-result.d.ts +44 -0
  184. package/dist/tools/rich-result.d.ts.map +1 -0
  185. package/dist/tools/rich-result.js +24 -0
  186. package/dist/tools/rich-result.js.map +1 -0
  187. package/dist/tools/schema.d.ts +18 -0
  188. package/dist/tools/schema.d.ts.map +1 -0
  189. package/dist/tools/schema.js +70 -0
  190. package/dist/tools/schema.js.map +1 -0
  191. package/dist/transport-ownership.d.ts +4 -0
  192. package/dist/transport-ownership.d.ts.map +1 -0
  193. package/dist/transport-ownership.js +13 -0
  194. package/dist/transport-ownership.js.map +1 -0
  195. package/dist/transport.d.ts +24 -0
  196. package/dist/transport.d.ts.map +1 -0
  197. package/dist/transport.js +4 -0
  198. package/dist/transport.js.map +1 -0
  199. package/package.json +65 -4
  200. package/src/auth/abort.ts +14 -0
  201. package/src/auth/audience.ts +22 -0
  202. package/src/auth/authorization.ts +81 -0
  203. package/src/auth/context.ts +43 -0
  204. package/src/auth/errors.ts +35 -0
  205. package/src/auth/types.ts +34 -0
  206. package/src/auth/url.ts +22 -0
  207. package/src/connection.ts +207 -0
  208. package/src/context/access.ts +36 -0
  209. package/src/context/definition.ts +100 -0
  210. package/src/context/registry.ts +25 -0
  211. package/src/context/scope.ts +82 -0
  212. package/src/diagnostics.ts +25 -0
  213. package/src/dispatcher.ts +70 -0
  214. package/src/execute-request.ts +35 -0
  215. package/src/index.ts +41 -0
  216. package/src/legacy/connection.ts +101 -0
  217. package/src/legacy/dispatcher.ts +72 -0
  218. package/src/legacy/handlers.ts +76 -0
  219. package/src/legacy/messages.ts +27 -0
  220. package/src/legacy/responses.ts +20 -0
  221. package/src/legacy/results.ts +20 -0
  222. package/src/modern/dispatcher.ts +77 -0
  223. package/src/modern/handlers.ts +55 -0
  224. package/src/modern/messages.ts +14 -0
  225. package/src/modern/metadata.ts +49 -0
  226. package/src/modern/responses.ts +25 -0
  227. package/src/modern/results.ts +6 -0
  228. package/src/pending-requests.ts +30 -0
  229. package/src/protocol/decode.ts +69 -0
  230. package/src/protocol/icon.ts +8 -0
  231. package/src/protocol/messages.ts +29 -0
  232. package/src/protocol/responses.ts +27 -0
  233. package/src/protocol/version-metadata.ts +42 -0
  234. package/src/server.ts +164 -0
  235. package/src/tools/adapter.ts +76 -0
  236. package/src/tools/call.ts +18 -0
  237. package/src/tools/content.ts +57 -0
  238. package/src/tools/context.ts +119 -0
  239. package/src/tools/definition.ts +144 -0
  240. package/src/tools/errors.ts +21 -0
  241. package/src/tools/json-value.ts +81 -0
  242. package/src/tools/name.ts +13 -0
  243. package/src/tools/registry.ts +52 -0
  244. package/src/tools/results.ts +100 -0
  245. package/src/tools/rich-result.ts +70 -0
  246. package/src/tools/schema.ts +86 -0
  247. package/src/transport-ownership.ts +17 -0
  248. package/src/transport.ts +34 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Keshav Katwe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,87 @@
1
- # Temporary Holding Version
1
+ # @toolgrain/mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Define reusable, typed MCP tools and servers with Zod validation. Toolgrain
4
+ implements MCP directly, independently of `@modelcontextprotocol/sdk`.
5
+
6
+ ## Installation
7
+
8
+ Release candidate for Toolgrain `0.1.0`; use the explicit `next` tag.
9
+ A stable Toolgrain release is not yet available.
10
+
11
+ ```sh
12
+ npm install @toolgrain/mcp@next @toolgrain/node@next zod
13
+ npm install --save-dev typescript @types/node
14
+ ```
15
+
16
+ `@toolgrain/node` supplies the transport in this example. Zod is a required peer
17
+ dependency; version 4 Classic and Mini schemas are supported.
18
+
19
+ ## A typed tool over stdio
20
+
21
+ ```ts
22
+ import { createServer, tool } from "@toolgrain/mcp";
23
+ import { stdio } from "@toolgrain/node";
24
+ import { z } from "zod";
25
+
26
+ const greet = tool({
27
+ title: "Greeting",
28
+ description: "Greet someone by name",
29
+ annotations: { readOnlyHint: true },
30
+ input: z.object({ name: z.string().min(1) }),
31
+ output: z.object({ message: z.string() }),
32
+ execute: ({ name }) => ({ message: `Hello, ${name}!` }),
33
+ });
34
+
35
+ const server = createServer({
36
+ name: "hello-server",
37
+ version: "1.0.0",
38
+ tools: { greet },
39
+ });
40
+
41
+ await server.listen(stdio());
42
+ ```
43
+
44
+ Save the example as `server.mts`, compile it using TypeScript with
45
+ `--strict --module NodeNext --target ES2022`, then run `node server.mjs`.
46
+ Stdio uses stdin and stdout for MCP; write application logs to stderr. EOF
47
+ closes the connection. An MCP client starts the program and sends requests.
48
+
49
+ Registration keys define exposed tool names. Definitions created with `tool()`
50
+ are frozen and reusable across servers. Input types are inferred, and input and
51
+ declared output schemas are parsed asynchronously, including defaults and
52
+ transforms. Ordinary strings and JSON become MCP results. Use `mcpResult()` for
53
+ rich content, explicit public errors, and result metadata.
54
+
55
+ Handlers can accept `execute(input, ctx)` to use request information and
56
+ `ctx.signal` for cooperative cancellation. Use `toolContext()` for direct handler
57
+ calls, which bypass server validation and result conversion. Unexpected server
58
+ execution failures return generic errors and reach the optional `onError`
59
+ callback. Request-cached dependencies use `createContext()` and inferred
60
+ accessors; see the
61
+ [context guide](https://github.com/keshavkatwe/toolgrain/blob/main/docs/context.md).
62
+
63
+ ## Transports and compatibility
64
+
65
+ Use `stdio()` or `http()` from
66
+ [@toolgrain/node](https://github.com/keshavkatwe/toolgrain/tree/main/packages/node#readme),
67
+ or mount a Web handler from
68
+ [@toolgrain/http](https://github.com/keshavkatwe/toolgrain/tree/main/packages/http#readme).
69
+ Both MCP `2026-07-28` and initialization-based `2025-06-18` are supported through
70
+ the same tool API. Current HTTP support uses independent POST requests and JSON
71
+ responses. See the
72
+ [client compatibility notes](https://github.com/keshavkatwe/toolgrain/blob/main/docs/compatibility.md)
73
+ for tested clients and limitations.
74
+
75
+ ## Requirements
76
+
77
+ ESM only. Node.js `^24.20.0` or Bun `>=1.4.4 <2`; Zod `^4.6.6`; TypeScript 5.5.4
78
+ or later with `strict` enabled. Node stack traces can use the included source
79
+ maps with `node --enable-source-maps server.mjs`. See the
80
+ [support policy](https://github.com/keshavkatwe/toolgrain/blob/main/docs/support-policy.md)
81
+ and [full API guide](https://github.com/keshavkatwe/toolgrain#readme).
82
+
83
+ ## License
84
+
85
+ MIT License, copyright 2026 Keshav Katwe. See the
86
+ [license text](https://github.com/keshavkatwe/toolgrain/blob/main/packages/mcp/LICENSE).
87
+ Third-party dependencies retain their own licenses.
@@ -0,0 +1,3 @@
1
+ /** Stop waiting promptly even when an integration cannot cancel its underlying work. */
2
+ export declare function abortable<T>(work: Promise<T>, signal: AbortSignal): Promise<T>;
3
+ //# sourceMappingURL=abort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.d.ts","sourceRoot":"","sources":["../../src/auth/abort.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,wBAAgB,SAAS,CAAC,CAAC,EACzB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAChB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,CAAC,CAAC,CASZ"}
@@ -0,0 +1,14 @@
1
+ /** Stop waiting promptly even when an integration cannot cancel its underlying work. */
2
+ export function abortable(work, signal) {
3
+ return new Promise((resolve, reject) => {
4
+ const abort = () => reject(signal.reason);
5
+ if (signal.aborted)
6
+ abort();
7
+ else
8
+ signal.addEventListener("abort", abort, { once: true });
9
+ work
10
+ .then(resolve, reject)
11
+ .finally(() => signal.removeEventListener("abort", abort));
12
+ });
13
+ }
14
+ //# sourceMappingURL=abort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.js","sourceRoot":"","sources":["../../src/auth/abort.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,MAAM,UAAU,SAAS,CACvB,IAAgB,EAChB,MAAmB;IAEnB,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,MAAM,CAAC,OAAO;YAAE,KAAK,EAAE,CAAC;;YACvB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI;aACD,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;aACrB,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Validate the audience of an already verified token without disclosing its claims. */
2
+ export declare function validateTokenAudience(audience: unknown, resource: string): void;
3
+ //# sourceMappingURL=audience.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audience.d.ts","sourceRoot":"","sources":["../../src/auth/audience.ts"],"names":[],"mappings":"AAEA,wFAAwF;AACxF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,MAAM,GACf,IAAI,CAeN"}
@@ -0,0 +1,17 @@
1
+ import { AuthError } from "./errors.js";
2
+ /** Validate the audience of an already verified token without disclosing its claims. */
3
+ export function validateTokenAudience(audience, resource) {
4
+ if (audience === undefined)
5
+ throw new AuthError("invalid_token", {
6
+ description: `Access token is missing the aud claim. Configure the authorization server to include an audience and request a new token with resource=${resource}.`,
7
+ });
8
+ const audiences = typeof audience === "string" ? [audience] : audience;
9
+ if (!Array.isArray(audiences) ||
10
+ audiences.some((value) => typeof value !== "string"))
11
+ throw new AuthError("invalid_token");
12
+ if (!audiences.includes(resource))
13
+ throw new AuthError("invalid_token", {
14
+ description: `Access token aud claim does not match the expected resource ${resource}. Request a new token with this resource.`,
15
+ });
16
+ }
17
+ //# sourceMappingURL=audience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audience.js","sourceRoot":"","sources":["../../src/auth/audience.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,wFAAwF;AACxF,MAAM,UAAU,qBAAqB,CACnC,QAAiB,EACjB,QAAgB;IAEhB,IAAI,QAAQ,KAAK,SAAS;QACxB,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE;YACnC,WAAW,EAAE,0IAA0I,QAAQ,GAAG;SACnK,CAAC,CAAC;IACL,MAAM,SAAS,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACvE,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QACzB,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;QAEpD,MAAM,IAAI,SAAS,CAAC,eAAe,CAAC,CAAC;IACvC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE;YACnC,WAAW,EAAE,+DAA+D,QAAQ,2CAA2C;SAChI,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { AuthIdentity, AuthMetadata, AuthProvider, AuthScope } from "./types.js";
2
+ export declare function createAuthorization(provider?: AuthProvider): {
3
+ metadata: () => AuthMetadata | undefined;
4
+ authorize(token: string, resource: string, signal: AbortSignal, finish: () => void): Promise<AuthScope>;
5
+ consume(scope?: AuthScope): AuthIdentity | undefined;
6
+ };
7
+ //# sourceMappingURL=authorization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.d.ts","sourceRoot":"","sources":["../../src/auth/authorization.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,SAAS,EACV,MAAM,YAAY,CAAC;AASpB,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,YAAY;IAsBvD,QAAQ;IACF,SAAS,QACN,MAAM,YACH,MAAM,UACR,WAAW,UACX,MAAM,IAAI,GACjB,OAAO,CAAC,SAAS,CAAC;IA0BrB,OAAO,SAAS,SAAS,GAAG,YAAY,GAAG,SAAS;EASvD"}
@@ -0,0 +1,58 @@
1
+ import { abortable } from "./abort.js";
2
+ import { identitySnapshot } from "./context.js";
3
+ import { AuthError } from "./errors.js";
4
+ import { authUrl } from "./url.js";
5
+ export function createAuthorization(provider) {
6
+ const scopes = new WeakMap();
7
+ const metadata = provider && {
8
+ ...(provider.resource === undefined
9
+ ? {}
10
+ : { resource: authUrl(provider.resource) }),
11
+ authorizationServers: provider.authorizationServers.map((issuer) => {
12
+ authUrl(issuer);
13
+ return issuer;
14
+ }),
15
+ };
16
+ if (provider &&
17
+ (typeof provider.type !== "symbol" ||
18
+ !metadata?.authorizationServers.length))
19
+ throw new TypeError("Auth providers require a type symbol and at least one authorization server");
20
+ const verify = provider?.verify.bind(provider);
21
+ const type = provider?.type;
22
+ return {
23
+ metadata: () => metadata && structuredClone(metadata),
24
+ async authorize(token, resource, signal, finish) {
25
+ if (!verify || !type)
26
+ throw new Error("Server has no auth provider");
27
+ signal.throwIfAborted();
28
+ const resolved = metadata?.resource ?? authUrl(resource);
29
+ const identity = {
30
+ type,
31
+ value: identitySnapshot(await abortable(verify(token, { resource: resolved, signal }), signal)),
32
+ };
33
+ signal.throwIfAborted();
34
+ const entry = { identity, consumed: false, disposed: false };
35
+ const scope = Object.freeze({
36
+ signal,
37
+ dispose() {
38
+ if (entry.disposed)
39
+ return;
40
+ entry.disposed = true;
41
+ finish();
42
+ },
43
+ });
44
+ scopes.set(scope, entry);
45
+ return scope;
46
+ },
47
+ consume(scope) {
48
+ if (!metadata && !scope)
49
+ return;
50
+ const entry = scope && scopes.get(scope);
51
+ if (!entry || entry.consumed || entry.disposed)
52
+ throw new AuthError("invalid_token");
53
+ entry.consumed = true;
54
+ return entry.identity;
55
+ },
56
+ };
57
+ }
58
+ //# sourceMappingURL=authorization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../src/auth/authorization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAOxC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAQnC,MAAM,UAAU,mBAAmB,CAAC,QAAuB;IACzD,MAAM,MAAM,GAAG,IAAI,OAAO,EAAoB,CAAC;IAC/C,MAAM,QAAQ,GAA6B,QAAQ,IAAI;QACrD,GAAG,CAAC,QAAQ,CAAC,QAAQ,KAAK,SAAS;YACjC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7C,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YACjE,OAAO,CAAC,MAAM,CAAC,CAAC;YAChB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;KACH,CAAC;IACF,IACE,QAAQ;QACR,CAAC,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;YAChC,CAAC,QAAQ,EAAE,oBAAoB,CAAC,MAAM,CAAC;QAEzC,MAAM,IAAI,SAAS,CACjB,4EAA4E,CAC7E,CAAC;IACJ,MAAM,MAAM,GAAG,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,CAAC;IAC5B,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,IAAI,eAAe,CAAC,QAAQ,CAAC;QACrD,KAAK,CAAC,SAAS,CACb,KAAa,EACb,QAAgB,EAChB,MAAmB,EACnB,MAAkB;YAElB,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;YACrE,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,QAAQ,EAAE,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;YACzD,MAAM,QAAQ,GAAG;gBACf,IAAI;gBACJ,KAAK,EAAE,gBAAgB,CACrB,MAAM,SAAS,CACb,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAC7C,MAAM,CACP,CACF;aACF,CAAC;YACF,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,KAAK,GAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YACpE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;gBAC1B,MAAM;gBACN,OAAO;oBACL,IAAI,KAAK,CAAC,QAAQ;wBAAE,OAAO;oBAC3B,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;oBACtB,MAAM,EAAE,CAAC;gBACX,CAAC;aACF,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACzB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,CAAC,KAAiB;YACvB,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK;gBAAE,OAAO;YAChC,MAAM,KAAK,GAAG,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ;gBAC5C,MAAM,IAAI,SAAS,CAAC,eAAe,CAAC,CAAC;YACvC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;YACtB,OAAO,KAAK,CAAC,QAAQ,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ToolContext } from "../tools/context.js";
2
+ import type { AuthIdentity, AuthReadonly } from "./types.js";
3
+ /** Typed integrations bind their accessor to a stable, registered provider symbol. */
4
+ export declare function createAuthAccessor<Identity extends object>(type: symbol): (ctx: ToolContext) => AuthReadonly<Identity>;
5
+ export declare function attachAuth(ctx: ToolContext, auth?: AuthIdentity): ToolContext;
6
+ /** Auth identities are plain data: copy them before exposing them to handlers. */
7
+ export declare function identitySnapshot(value: object): object;
8
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/auth/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI7D,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,SACzD,WAAW,KAAG,YAAY,CAAC,QAAQ,CAAC,CAQlD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,WAAW,CAG7E;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAmBtD"}
@@ -0,0 +1,37 @@
1
+ const key = Symbol.for("@toolgrain/mcp/auth-context/v1");
2
+ /** Typed integrations bind their accessor to a stable, registered provider symbol. */
3
+ export function createAuthAccessor(type) {
4
+ return (ctx) => {
5
+ const auth = Object.getOwnPropertyDescriptor(ctx, key)?.value;
6
+ if (!auth || auth.type !== type)
7
+ throw new Error("The context has no identity for this auth provider");
8
+ return auth.value;
9
+ };
10
+ }
11
+ export function attachAuth(ctx, auth) {
12
+ if (auth)
13
+ Object.defineProperty(ctx, key, { value: auth });
14
+ return Object.freeze(ctx);
15
+ }
16
+ /** Auth identities are plain data: copy them before exposing them to handlers. */
17
+ export function identitySnapshot(value) {
18
+ if (value === null || typeof value !== "object")
19
+ throw new TypeError("Auth identities must be objects");
20
+ const copy = structuredClone(value);
21
+ const freeze = (item, visited) => {
22
+ if (typeof item !== "object" || item === null || visited.has(item))
23
+ return;
24
+ const prototype = Object.getPrototypeOf(item);
25
+ if (prototype !== Object.prototype &&
26
+ prototype !== Array.prototype &&
27
+ prototype !== null)
28
+ throw new TypeError("Auth identities must contain plain data");
29
+ visited.add(item);
30
+ for (const child of Object.values(item))
31
+ freeze(child, visited);
32
+ Object.freeze(item);
33
+ };
34
+ freeze(copy, new Set());
35
+ return copy;
36
+ }
37
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/auth/context.ts"],"names":[],"mappings":"AAGA,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAEzD,sFAAsF;AACtF,MAAM,UAAU,kBAAkB,CAA0B,IAAY;IACtE,OAAO,CAAC,GAAgB,EAA0B,EAAE;QAClD,MAAM,IAAI,GAAG,MAAM,CAAC,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,KAE3C,CAAC;QACd,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;YAC7B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC,KAA+B,CAAC;IAC9C,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAgB,EAAE,IAAmB;IAC9D,IAAI,IAAI;QAAE,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAC7C,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,CAAC,IAAa,EAAE,OAAoB,EAAE,EAAE;QACrD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QAC3E,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC9C,IACE,SAAS,KAAK,MAAM,CAAC,SAAS;YAC9B,SAAS,KAAK,KAAK,CAAC,SAAS;YAC7B,SAAS,KAAK,IAAI;YAElB,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,CAAC;IACF,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,14 @@
1
+ export type AuthErrorCode = "invalid_request" | "invalid_token" | "access_denied" | "temporarily_unavailable";
2
+ declare const brand: unique symbol;
3
+ /** Only an explicitly public description is exposed; provider causes stay private. */
4
+ export declare class AuthError extends Error {
5
+ readonly code: AuthErrorCode;
6
+ readonly [brand] = true;
7
+ readonly description?: string | undefined;
8
+ constructor(code: AuthErrorCode, options?: ErrorOptions & {
9
+ description?: string;
10
+ });
11
+ }
12
+ export declare function isAuthError(value: unknown): value is AuthError;
13
+ export {};
14
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/auth/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB,iBAAiB,GACjB,eAAe,GACf,eAAe,GACf,yBAAyB,CAAC;AAE9B,QAAA,MAAM,KAAK,eAA4C,CAAC;AAExD,sFAAsF;AACtF,qBAAa,SAAU,SAAQ,KAAK;IAKhC,QAAQ,CAAC,IAAI,EAAE,aAAa;IAJ9B,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1C,YACW,IAAI,EAAE,aAAa,EAC5B,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAclD;CACF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D"}
@@ -0,0 +1,23 @@
1
+ const brand = Symbol.for("@toolgrain/mcp/AuthError/v1");
2
+ /** Only an explicitly public description is exposed; provider causes stay private. */
3
+ export class AuthError extends Error {
4
+ code;
5
+ [brand] = true;
6
+ description;
7
+ constructor(code, options) {
8
+ super(options?.description ??
9
+ {
10
+ invalid_request: "Invalid authorization request",
11
+ invalid_token: "Invalid access token",
12
+ access_denied: "Access denied",
13
+ temporarily_unavailable: "Authorization service unavailable",
14
+ }[code], options);
15
+ this.code = code;
16
+ this.name = "AuthError";
17
+ this.description = options?.description;
18
+ }
19
+ }
20
+ export function isAuthError(value) {
21
+ return value instanceof Error && Reflect.get(value, brand) === true;
22
+ }
23
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/auth/errors.ts"],"names":[],"mappings":"AAMA,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AAExD,sFAAsF;AACtF,MAAM,OAAO,SAAU,SAAQ,KAAK;IAKvB,IAAI;IAJN,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IACf,WAAW,CAAsB;IAE1C,YACW,IAAmB,EAC5B,OAAiD;QAEjD,KAAK,CACH,OAAO,EAAE,WAAW;YAClB;gBACE,eAAe,EAAE,+BAA+B;gBAChD,aAAa,EAAE,sBAAsB;gBACrC,aAAa,EAAE,eAAe;gBAC9B,uBAAuB,EAAE,mCAAmC;aAC7D,CAAC,IAAI,CAAC,EACT,OAAO,CACR,CAAC;oBAZO,IAAI;QAab,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC;AACtE,CAAC"}
@@ -0,0 +1,28 @@
1
+ /** Implemented by integrations; the HTTP adapter supplies the resolved resource. */
2
+ export interface AuthProvider<Identity extends object = object> {
3
+ readonly type: symbol;
4
+ readonly resource?: string;
5
+ readonly authorizationServers: readonly string[];
6
+ verify(accessToken: string, options: AuthVerifyOptions): Promise<Identity>;
7
+ }
8
+ export interface AuthVerifyOptions {
9
+ readonly signal: AbortSignal;
10
+ readonly resource: string;
11
+ }
12
+ export interface AuthMetadata {
13
+ readonly resource?: string;
14
+ readonly authorizationServers: readonly string[];
15
+ }
16
+ /** An opaque, single-use authorization for one server invocation. Always dispose it. */
17
+ export interface AuthScope {
18
+ readonly signal: AbortSignal;
19
+ dispose(): void;
20
+ }
21
+ export type AuthReadonly<T> = T extends readonly (infer Item)[] ? readonly AuthReadonly<Item>[] : T extends object ? {
22
+ readonly [Key in keyof T]: AuthReadonly<T[Key]>;
23
+ } : T;
24
+ export interface AuthIdentity {
25
+ readonly type: symbol;
26
+ readonly value: object;
27
+ }
28
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,WAAW,YAAY,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;CAClD;AAED,wFAAwF;AACxF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,GAC3D,SAAS,YAAY,CAAC,IAAI,CAAC,EAAE,GAC7B,CAAC,SAAS,MAAM,GACd;IAAE,QAAQ,EAAE,GAAG,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;CAAE,GACnD,CAAC,CAAC;AAER,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ /** Canonical external URL; HTTP is permitted only for local development. */
2
+ export declare function authUrl(value: string): string;
3
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/auth/url.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAoB7C"}
@@ -0,0 +1,18 @@
1
+ /** Canonical external URL; HTTP is permitted only for local development. */
2
+ export function authUrl(value) {
3
+ const url = new URL(value);
4
+ if (
5
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: Reject control characters that URL parsing would silently remove.
6
+ /[\u0000-\u0020\u007f]/.test(value) ||
7
+ !/^https?:\/\/[^/]/i.test(value) ||
8
+ (url.protocol !== "https:" &&
9
+ !(url.protocol === "http:" &&
10
+ ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) ||
11
+ url.username ||
12
+ url.password ||
13
+ value.includes("#") ||
14
+ value.includes("?"))
15
+ throw new TypeError("Auth URLs must use HTTPS without credentials, query, or fragment (HTTP loopback is allowed)");
16
+ return value;
17
+ }
18
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/auth/url.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B;IACE,6HAA6H;IAC7H,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC;QACnC,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC;QAChC,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ;YACxB,CAAC,CACC,GAAG,CAAC,QAAQ,KAAK,OAAO;gBACxB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAC3D,CAAC;QACJ,GAAG,CAAC,QAAQ;QACZ,GAAG,CAAC,QAAQ;QACZ,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QACnB,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAEnB,MAAM,IAAI,SAAS,CACjB,6FAA6F,CAC9F,CAAC;IACJ,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type ErrorHandler } from "./diagnostics.js";
2
+ import type { Dispatcher } from "./dispatcher.js";
3
+ import type { Server } from "./server.js";
4
+ import type { RequestTransport, Transport } from "./transport.js";
5
+ export declare function createConnection(dispatch: Dispatcher, onError?: ErrorHandler, onClose?: () => void): ConnectionLifecycle;
6
+ interface ConnectionLifecycle {
7
+ listen(transport: Transport): Promise<void>;
8
+ listenRequests(transport: RequestTransport, server: Server): Promise<void>;
9
+ close(): Promise<void>;
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAKA,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"}
@@ -0,0 +1,151 @@
1
+ import { INVALID_REQUEST, PARSE_ERROR, } from "@toolgrain/protocol";
2
+ import { reportError } from "./diagnostics.js";
3
+ import { executeRequest } from "./execute-request.js";
4
+ import { createLegacyConnection } from "./legacy/connection.js";
5
+ import { createPendingRequests } from "./pending-requests.js";
6
+ import { decode } from "./protocol/decode.js";
7
+ import { protocolError } from "./protocol/responses.js";
8
+ import { claimTransport } from "./transport-ownership.js";
9
+ export function createConnection(dispatch, onError, onClose) {
10
+ return new Connection(dispatch, onError, onClose);
11
+ }
12
+ /** Owns transport attachment, serialized writes, and connection shutdown. */
13
+ class Connection {
14
+ dispatch;
15
+ onError;
16
+ onClose;
17
+ state = "idle";
18
+ transport;
19
+ closePromise;
20
+ writes = Promise.resolve();
21
+ requests = createPendingRequests(() => this.isOpen());
22
+ legacy = createLegacyConnection();
23
+ constructor(dispatch, onError, onClose) {
24
+ this.dispatch = dispatch;
25
+ this.onError = onError;
26
+ this.onClose = onClose;
27
+ }
28
+ // Public methods remain safe to call detached from the returned server.
29
+ listen = (transport) => this.attach(transport, () => transport.start(this.transportCallbacks));
30
+ listenRequests = (transport, server) => this.attach(transport, () => transport.start(server, {
31
+ onError: this.transportCallbacks.onError,
32
+ onClose: this.transportCallbacks.onClose,
33
+ }));
34
+ attach = async (transport, start) => {
35
+ if (this.state !== "idle")
36
+ throw new Error("Server can only attach one transport and cannot restart after closing");
37
+ claimTransport(transport);
38
+ this.state = "starting";
39
+ this.transport = transport;
40
+ try {
41
+ await start();
42
+ if (!this.isOpen())
43
+ throw new Error("Transport closed during startup");
44
+ this.state = "listening";
45
+ }
46
+ catch (error) {
47
+ await this.terminate(error);
48
+ throw error;
49
+ }
50
+ };
51
+ close = () => {
52
+ if (this.closePromise)
53
+ return this.closePromise;
54
+ this.state = "closed";
55
+ this.closePromise = Promise.resolve().then(async () => {
56
+ const transport = this.transport;
57
+ this.transport = undefined;
58
+ await transport?.close();
59
+ });
60
+ // Aborting runs handler listeners synchronously; a nested close reuses this promise.
61
+ this.onClose?.();
62
+ this.requests.clear();
63
+ return this.closePromise;
64
+ };
65
+ transportCallbacks = {
66
+ onMessage: (message) => {
67
+ void this.receive(message).catch((error) => this.terminate(error));
68
+ },
69
+ onParseError: () => {
70
+ if (this.isOpen())
71
+ void this.send(this.legacy.errorResponse(protocolError(PARSE_ERROR, "Parse error")));
72
+ },
73
+ onError: (error) => {
74
+ void this.terminate(error);
75
+ },
76
+ onClose: () => {
77
+ void this.close().catch((error) => this.report(error));
78
+ },
79
+ };
80
+ isOpen() {
81
+ return this.state === "starting" || this.state === "listening";
82
+ }
83
+ report(error) {
84
+ reportError(this.onError, error);
85
+ }
86
+ async terminate(error) {
87
+ this.report(error);
88
+ try {
89
+ await this.close();
90
+ }
91
+ catch (failure) {
92
+ this.report(failure);
93
+ }
94
+ }
95
+ send(message, isActive = () => this.isOpen()) {
96
+ const write = this.writes.then(async () => {
97
+ if (this.isOpen() &&
98
+ isActive() &&
99
+ this.transport &&
100
+ "send" in this.transport)
101
+ await this.transport.send(message);
102
+ });
103
+ this.writes = write.catch((error) => this.terminate(error));
104
+ return this.writes;
105
+ }
106
+ async receive(message) {
107
+ if (!this.isOpen())
108
+ return;
109
+ const incoming = decode(message);
110
+ switch (incoming.kind) {
111
+ case "ignore":
112
+ return;
113
+ case "cancel":
114
+ if (this.legacy.canCancel(incoming.id))
115
+ this.requests.cancel(incoming.id);
116
+ return;
117
+ case "notification":
118
+ this.legacy.notification(incoming.notification);
119
+ return;
120
+ case "error":
121
+ await this.send(this.legacy.errorResponse(incoming.response));
122
+ return;
123
+ case "request":
124
+ await this.handleRequest(incoming.request);
125
+ }
126
+ }
127
+ async handleRequest(request) {
128
+ const prepared = this.legacy.prepare(request);
129
+ if (prepared.error) {
130
+ await this.send(prepared.error);
131
+ return;
132
+ }
133
+ const pending = this.requests.begin(request.id);
134
+ if (!pending) {
135
+ await this.send(protocolError(INVALID_REQUEST, "Request ID is already in use", request.id));
136
+ return;
137
+ }
138
+ const initialization = this.legacy.begin(request, prepared.protocolVersion);
139
+ try {
140
+ const response = await executeRequest(this.dispatch, request, { signal: pending.signal, client: this.legacy.client() }, (error) => this.report(error), prepared.protocolVersion);
141
+ initialization?.respond(response);
142
+ if (response)
143
+ await this.send(response, pending.isActive);
144
+ }
145
+ finally {
146
+ initialization?.finish();
147
+ pending.finish();
148
+ }
149
+ }
150
+ }
151
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ToolContext } from "../tools/context.js";
2
+ type Access = (identity: symbol, name: string) => Promise<unknown>;
3
+ /** Keep own auth properties and shared request data on dependency-aware views. */
4
+ export declare function withContextAccess(ctx: ToolContext, access: Access): ToolContext;
5
+ export declare function readContext<Value>(ctx: ToolContext, identity: symbol, name: string): Promise<Value>;
6
+ export {};
7
+ //# sourceMappingURL=access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../../src/context/access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,KAAK,MAAM,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEnE,kFAAkF;AAClF,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,GACb,WAAW,CAOb;AAED,wBAAgB,WAAW,CAAC,KAAK,EAC/B,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,CAAC,CAahB"}