@warlock.js/ai-tools 5.29.0 → 5.31.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/CHANGELOG.md +43 -1
- package/README.md +25 -13
- package/cjs/index.cjs +858 -116
- package/cjs/index.cjs.map +1 -1
- package/esm/contracts/http.type.d.mts +1 -1
- package/esm/contracts/http.type.d.mts.map +1 -1
- package/esm/contracts/index.d.mts +2 -1
- package/esm/contracts/mcp-serve.type.d.mts +257 -0
- package/esm/contracts/mcp-serve.type.d.mts.map +1 -0
- package/esm/contracts/mcp.type.d.mts +17 -60
- package/esm/contracts/mcp.type.d.mts.map +1 -1
- package/esm/contracts/utility.type.d.mts +1 -1
- package/esm/contracts/utility.type.d.mts.map +1 -1
- package/esm/contracts/web.type.d.mts +1 -1
- package/esm/contracts/web.type.d.mts.map +1 -1
- package/esm/errors.d.mts +37 -2
- package/esm/errors.d.mts.map +1 -1
- package/esm/errors.mjs +21 -2
- package/esm/errors.mjs.map +1 -1
- package/esm/http/http-request.d.mts +1 -1
- package/esm/http/http-request.d.mts.map +1 -1
- package/esm/http/http-request.mjs +1 -1
- package/esm/http/http-request.mjs.map +1 -1
- package/esm/index.d.mts +6 -4
- package/esm/index.mjs +3 -2
- package/esm/mcp/client.mjs +36 -6
- package/esm/mcp/client.mjs.map +1 -1
- package/esm/mcp/index.d.mts +13 -6
- package/esm/mcp/index.d.mts.map +1 -1
- package/esm/mcp/index.mjs +2 -1
- package/esm/mcp/index.mjs.map +1 -1
- package/esm/mcp/json-schema-to-standard.d.mts +1 -1
- package/esm/mcp/json-schema-to-standard.d.mts.map +1 -1
- package/esm/mcp/json-schema-to-standard.mjs +1 -1
- package/esm/mcp/json-schema-to-standard.mjs.map +1 -1
- package/esm/mcp/protocol.d.mts +16 -0
- package/esm/mcp/protocol.d.mts.map +1 -0
- package/esm/mcp/protocol.mjs +23 -0
- package/esm/mcp/protocol.mjs.map +1 -0
- package/esm/mcp/serve-http.mjs +443 -0
- package/esm/mcp/serve-http.mjs.map +1 -0
- package/esm/mcp/serve.d.mts +46 -27
- package/esm/mcp/serve.d.mts.map +1 -1
- package/esm/mcp/serve.mjs +326 -93
- package/esm/mcp/serve.mjs.map +1 -1
- package/esm/mcp/transport.d.mts +1 -1
- package/esm/mcp/transport.d.mts.map +1 -1
- package/esm/mcp/transport.mjs +1 -1
- package/esm/mcp/transport.mjs.map +1 -1
- package/esm/mcp/transport.type.d.mts +1 -1
- package/esm/mcp/transport.type.d.mts.map +1 -1
- package/esm/register.d.mts +13 -2
- package/esm/register.d.mts.map +1 -1
- package/esm/register.mjs +4 -3
- package/esm/register.mjs.map +1 -1
- package/esm/schema.mjs +1 -1
- package/esm/schema.mjs.map +1 -1
- package/esm/utility/calculator.d.mts +1 -1
- package/esm/utility/calculator.d.mts.map +1 -1
- package/esm/utility/calculator.mjs +1 -1
- package/esm/utility/calculator.mjs.map +1 -1
- package/esm/utility/date-time.d.mts +1 -1
- package/esm/utility/date-time.d.mts.map +1 -1
- package/esm/utility/date-time.mjs +1 -1
- package/esm/utility/date-time.mjs.map +1 -1
- package/esm/utility/schema.mjs +1 -1
- package/esm/utility/schema.mjs.map +1 -1
- package/esm/web/fetch-url.d.mts +1 -1
- package/esm/web/fetch-url.d.mts.map +1 -1
- package/esm/web/fetch-url.mjs +1 -1
- package/esm/web/fetch-url.mjs.map +1 -1
- package/esm/web/schema.mjs +1 -1
- package/esm/web/schema.mjs.map +1 -1
- package/esm/web/web-search.d.mts +1 -1
- package/esm/web/web-search.d.mts.map +1 -1
- package/esm/web/web-search.mjs +1 -1
- package/esm/web/web-search.mjs.map +1 -1
- package/llms-full.txt +194 -57
- package/llms.txt +3 -3
- package/package.json +4 -7
- package/skills/connect-mcp-server/SKILL.md +28 -6
- package/skills/expose-as-mcp-server/SKILL.md +117 -36
- package/skills/index.md +5 -2
- package/skills/use-web-and-http-tools/SKILL.md +49 -15
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,47 @@ All notable changes to `@warlock.js/ai-tools` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 5.31.0 - 2026-10-18
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `ai.mcp(server, { signal })` binds the client to a run: when the signal aborts the client closes its transport, and later handshakes and tool calls fail with an `McpTransportError` of type `"closed"`. Every `tools/call` honors both the client signal and the per-call `ctx.signal`.
|
|
12
|
+
- `ai.tools.measure(tools, { model, mode })` — the `measureTools` helper from `@warlock.js/ai` — measures the input tokens a tool list costs per call.
|
|
13
|
+
- `ai.mcp.serve(source, { transport: { type: "http" } })` serves the MCP Streamable HTTP transport on `node:http` (no extra dependency). It binds `127.0.0.1` on a free port at `/mcp` by default (`host`, `port`, `path` override them), and `start()` resolves `{ url, close }`. `close()` stops accepting connections, waits up to `drainTimeoutMs` (default 5 s) for in-flight calls, then aborts their `ctx.signal` and frees the port. The endpoint is stateless: JSON responses, `202` for notifications, `405` for `GET` / `DELETE`, `400` for batches or an unsupported `MCP-Protocol-Version`.
|
|
14
|
+
- HTTP auth: `auth: { bearer }` accepts one token or a rotation list; `auth: { authorize(request) }` runs a custom check; with both set, a request must pass both. Failures get `401` before the body is read.
|
|
15
|
+
- Tools served over HTTP receive the inbound request on `ctx.request` (`headers`, `remoteAddress`), for per-user tokens, tenant headers or trace ids.
|
|
16
|
+
- Grouped sources: `serve({ groups: { name: tools } }, { prefixToolNames: true })` exposes `<group>_<tool>`; a function builds custom names.
|
|
17
|
+
- Optional MCP resources (`resources: [{ uri, name, read }]`) and prompts (`prompts: [{ name, arguments, get }]`), with their capabilities advertised only when configured. The server also answers `ping`.
|
|
18
|
+
- `McpServeError` (`type`: `"collision"`, `"config"`, `"listen"`), `SUPPORTED_PROTOCOL_VERSIONS`, and the `McpHttpServeTransport`, `McpHttpAuth`, `McpHttpRequestInfo`, `McpServeHandle`, `McpHttpServeHandle`, `McpServeResource`, `McpServePrompt`, `McpServeCallContext`, `McpToolSource`, `McpGroupedToolSource` types. `createServeHandler(...).handle(request, context?)` takes an optional call context.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `initialize` negotiates the protocol version: a client's requested version is echoed when supported (`2025-11-25`, `2025-06-18`, `2025-03-26`), otherwise the newest is offered. It previously always answered `2025-06-18`.
|
|
23
|
+
- `McpServer.start()` resolves a handle (`{ url?, close }`) instead of `void`. The http transport's `port` is optional.
|
|
24
|
+
- `@modelcontextprotocol/sdk` is no longer listed as an optional peer dependency. The MCP client never imported it: it speaks MCP's JSON-RPC itself over a child process (stdio) and `fetch` (http). The SDK is now a development dependency, used only by the interoperability test against the official client. The MCP docs, README and `connect-mcp-server` skill now say so, and name `ajv` as the client's only optional peer.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- The stdio transport of `ai.mcp.serve()` no longer crashes the process when a line is JSON but not a request object (`null`, a number, an array): it answers a JSON-RPC "Invalid Request" error (`-32600`, `id: null`). A failure while answering a line is answered as an internal error and can no longer become an unhandled rejection.
|
|
29
|
+
|
|
30
|
+
### Security
|
|
31
|
+
|
|
32
|
+
- The HTTP transport binds loopback by default and refuses to start on any non-loopback host without `auth` (`McpServeError`, `type: "config"`).
|
|
33
|
+
- Bearer tokens are compared with `crypto.timingSafeEqual` over SHA-256 digests, so neither content nor length leaks through timing; every configured token is checked. Empty tokens are refused, and an `authorize` hook that throws denies the request.
|
|
34
|
+
- `Origin` is validated on every request, per the MCP transport's DNS-rebinding guidance: loopback origins and `allowedOrigins` pass, others (including `null`) get `403`. While bound to loopback, a `Host` header other than `localhost`, `127.0.0.1`, `[::1]` or `allowedHosts` also gets `403`.
|
|
35
|
+
- Request bodies over `maxBodyBytes` (default 1 MiB) get `413` and the connection is closed.
|
|
36
|
+
|
|
37
|
+
### Upgrading
|
|
38
|
+
|
|
39
|
+
- **BREAKING:** `ai.mcp.serve()` throws `McpServeError` (`type: "collision"`) when two exposed tools share a name, and for duplicate resource URIs or prompt names. Previously both tools were listed and every call reached the last one. Rename one tool, or serve a grouped source with `prefixToolNames: true`.
|
|
40
|
+
- `serve(..., { transport: { type: "http" } }).start()` no longer rejects: it binds a real endpoint. Code that implemented `McpServer` itself must return a handle from `start()`.
|
|
41
|
+
|
|
42
|
+
## 5.30.0 - 2026-10-16
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- Lockstep release; package APIs are unchanged.
|
|
47
|
+
|
|
7
48
|
## 5.29.0 - 2026-10-01
|
|
8
49
|
|
|
9
50
|
### Changed
|
|
@@ -75,6 +116,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
75
116
|
### Changed
|
|
76
117
|
|
|
77
118
|
- Lockstep release maintenance and dependency refresh.
|
|
119
|
+
|
|
78
120
|
## 5.20.0 - 2026-09-24
|
|
79
121
|
|
|
80
122
|
### Changed
|
|
@@ -138,7 +180,7 @@ changelogs.
|
|
|
138
180
|
|
|
139
181
|
### Security
|
|
140
182
|
|
|
141
|
-
- **`fetch_url` and `http_request` now deny private-network targets by default and route through `@warlock.js/ai`'s hardened `guardedFetch` instead of a local host check.** Previously `allowHosts` was the
|
|
183
|
+
- **`fetch_url` and `http_request` now deny private-network targets by default and route through `@warlock.js/ai`'s hardened `guardedFetch` instead of a local host check.** Previously `allowHosts` was the _only_ SSRF guardrail and it was opt-in — a bare `ai.tools.fetchUrl()` / `ai.tools.http()` would fetch any `http(s)` URL the model supplied, including `http://169.254.169.254/latest/meta-data/...`, `localhost`, and RFC1918 addresses, and neither tool re-validated redirect targets, so even a configured allowlist could be 302'd into an internal endpoint. Both tools now issue every request through the core outbound policy, which by default refuses private / loopback / link-local / CGNAT / cloud-metadata addresses — resolving hostnames through DNS and checking every returned address, failing closed on resolution failure — and re-validates every redirect `Location` (scheme, allowlist, private-IP deny) before following it, with a hop cap and cross-origin credential-header stripping. Blocks surface as the existing typed errors (`WebToolError` `type: "denied-host"`, `HttpPolicyError` `type: "host-not-allowed"`), so agents still read them as `{ error }` data
|
|
142
184
|
- **New `allowPrivateNetwork` option (default `false`) on both tools** for the deliberate case of a tool that must call an internal service (e.g. a local dev server); `allowHosts` still works and now also constrains redirect targets
|
|
143
185
|
|
|
144
186
|
## 4.12.0
|
package/README.md
CHANGED
|
@@ -14,13 +14,13 @@ All five tools attach onto the shared `ai` object at import time under the `ai.t
|
|
|
14
14
|
(via a `declare module "@warlock.js/ai"` augmentation), so a bare `import "@warlock.js/ai-tools"`
|
|
15
15
|
makes them available and statically typed.
|
|
16
16
|
|
|
17
|
-
| Tool
|
|
18
|
-
|
|
19
|
-
| `ai.tools.webSearch(options)`
|
|
20
|
-
| `ai.tools.fetchUrl(options?)`
|
|
21
|
-
| `ai.tools.http(options?)`
|
|
22
|
-
| `ai.tools.calculator(options?)` | `calculator`
|
|
23
|
-
| `ai.tools.dateTime(options?)`
|
|
17
|
+
| Tool | LLM-visible name | What it does |
|
|
18
|
+
| ------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `ai.tools.webSearch(options)` | `web_search` | Web search via a chosen provider (`tavily` / `brave` / `serpapi`) — ranked title/URL/snippet hits. |
|
|
20
|
+
| `ai.tools.fetchUrl(options?)` | `fetch_url` | Fetch a URL → readability `text` (default), raw `html`, or `markdown`; host allowlist + byte cap. |
|
|
21
|
+
| `ai.tools.http(options?)` | `http_request` | A guarded HTTP/REST client — method + host allowlists, `baseUrl` join, byte/timeout caps. |
|
|
22
|
+
| `ai.tools.calculator(options?)` | `calculator` | A SAFE arithmetic evaluator (shunting-yard; never `eval`/`Function`). |
|
|
23
|
+
| `ai.tools.dateTime(options?)` | `date_time` | `now` / `add` / `diff` / `format` over ISO-8601 instants, IANA time zones. |
|
|
24
24
|
|
|
25
25
|
## MCP — both directions
|
|
26
26
|
|
|
@@ -39,7 +39,7 @@ npm install @warlock.js/ai-tools
|
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
`@warlock.js/ai` is the only required runtime peer. Everything heavy — a search provider, the
|
|
42
|
-
readability scraper,
|
|
42
|
+
readability scraper, and a JSON-Schema validator — is an **optional peer**, lazily
|
|
43
43
|
`import()`ed only when the relevant path runs; a missing one surfaces a curated `npm install` string
|
|
44
44
|
rather than crashing at import time. Beyond `@warlock.js/ai` the package uses only Node built-ins and
|
|
45
45
|
the global `fetch` (Node 18+). Import the package once for its side effect so the surface is
|
|
@@ -54,7 +54,7 @@ import "@warlock.js/ai-tools";
|
|
|
54
54
|
### 1. An agent with web search + HTTP
|
|
55
55
|
|
|
56
56
|
Hand an agent the web tools and let it research, then hit an API — both bounded by a host allowlist.
|
|
57
|
-
A failing tool call comes back as `{ error }`
|
|
57
|
+
A failing tool call comes back as `{ error }` _data_, so the agent self-corrects instead of crashing.
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
60
|
import "@warlock.js/ai-tools"; // registers ai.tools.* + ai.mcp on import
|
|
@@ -114,16 +114,28 @@ so Cursor / Claude Desktop / any MCP client can call these tools.
|
|
|
114
114
|
```ts
|
|
115
115
|
import "@warlock.js/ai-tools";
|
|
116
116
|
|
|
117
|
-
const server = ai.mcp.serve(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
);
|
|
117
|
+
const server = ai.mcp.serve([ai.tools.calculator(), ai.tools.dateTime()], {
|
|
118
|
+
name: "warlock-utils",
|
|
119
|
+
transport: { type: "stdio" },
|
|
120
|
+
});
|
|
121
121
|
|
|
122
122
|
await server.start();
|
|
123
123
|
// ...later:
|
|
124
124
|
await server.stop();
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
Over Streamable HTTP, `start()` binds a loopback endpoint and resolves `{ url, close }`. A
|
|
128
|
+
non-loopback `host` requires `auth`; `Origin` is validated and bodies are size-capped:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const { url, close } = await ai.mcp
|
|
132
|
+
.serve([ai.tools.calculator()], {
|
|
133
|
+
name: "session-tools",
|
|
134
|
+
transport: { type: "http", auth: { bearer: sessionToken } }, // 127.0.0.1, free port, /mcp
|
|
135
|
+
})
|
|
136
|
+
.start();
|
|
137
|
+
```
|
|
138
|
+
|
|
127
139
|
## Errors flow as data, not throws
|
|
128
140
|
|
|
129
141
|
Every tool follows the framework's errors-as-data contract: a guardrail rejection or a failed call is
|