stitchkit 0.25.0 → 0.26.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/dist/browser/client-multipart.d.ts +22 -0
- package/dist/browser/client-multipart.d.ts.map +1 -0
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/contract/define.d.ts +20 -0
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/factory.d.ts +1 -0
- package/dist/contract/factory.d.ts.map +1 -1
- package/dist/contract/index.js +1 -1
- package/dist/{index-4gawbm74.js → index-0d0rb85d.js} +41 -3
- package/dist/{index-g8kyab85.js → index-bkccbx64.js} +10 -3
- package/dist/{index-x62gnfsk.js → index-h4y2wg3n.js} +1 -1
- package/dist/{index-a9n8m4ec.js → index-p6fge9a5.js} +1 -1
- package/dist/{index-h9d1fm0p.js → index-q5w3cvvp.js} +62 -22
- package/dist/index.js +20 -18
- package/dist/internal/errors.d.ts +6 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/write-download.d.ts +17 -0
- package/dist/internal/write-download.d.ts.map +1 -0
- package/dist/node.js +2 -2
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/error-hook.d.ts +14 -3
- package/dist/server/error-hook.d.ts.map +1 -1
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.js +6 -6
- package/dist/server/types.d.ts +13 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/agent.d.ts +2 -0
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools/execute.d.ts +1 -1
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/list-names.d.ts.map +1 -1
- package/dist/tools/mcp.d.ts +10 -3
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/mount-download.d.ts.map +1 -1
- package/dist/tools/mount-upload.d.ts.map +1 -1
- package/dist/tools/mount-wait.d.ts.map +1 -1
- package/dist/tools/mount.d.ts +13 -0
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/names.d.ts +34 -0
- package/dist/tools/names.d.ts.map +1 -1
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools/transports.d.ts.map +1 -1
- package/dist/tools.js +48 -40
- package/llms-full.txt +97 -7
- package/package.json +1 -1
package/llms-full.txt
CHANGED
|
@@ -237,7 +237,7 @@ export const users = defineContract({ prefix: 'users' }, {
|
|
|
237
237
|
| `output` | no | Zod schema for the **response body** |
|
|
238
238
|
| `scope` | no | access scope for this endpoint — see [Auth & errors](./auth-and-errors.md) |
|
|
239
239
|
| `expose` | no | which transports carry this endpoint — see [below](#transports) |
|
|
240
|
-
| `toolName` | no | explicit MCP / agent tool name (
|
|
240
|
+
| `toolName` | no | explicit MCP / agent tool name (default: a verb-aware derivation, see below — not a literal `prefix_key`) |
|
|
241
241
|
| `multipart` | no | field name of a file upload — see [below](#file-uploads) |
|
|
242
242
|
| `timeout` | no | per-endpoint client timeout in ms, for slow endpoints |
|
|
243
243
|
| `idempotent` | no | safe to call twice with the same input (like `PUT`/`DELETE`); a retrying transport reads it — see [Realtime](./realtime.md#bring-your-own-transport) |
|
|
@@ -326,8 +326,41 @@ derivation from the method key + prefix (`users` + `create` ⇒ `create_user`,
|
|
|
326
326
|
{ method: 'POST', path: '/', desc: 'Create a user', toolName: 'create_user', /* … */ }
|
|
327
327
|
```
|
|
328
328
|
|
|
329
|
+
**Every tool name — derived or explicit — must match `[a-zA-Z0-9_-]` and be at
|
|
330
|
+
most 64 characters**, the character class every major provider accepts.
|
|
331
|
+
|
|
332
|
+
Note the two classes differ. What is *accepted* includes the hyphen; what
|
|
333
|
+
derivation *keeps* does not — a derived name normalises everything outside
|
|
334
|
+
`[a-zA-Z0-9_]` to `_`, the hyphen included, so `bot-status` + `get` ⇒
|
|
335
|
+
`get_bot_status` and `admin/analytics` + `get` ⇒ `get_admin_analytics`. A hyphen
|
|
336
|
+
survives only in an explicit `toolName`, which is taken verbatim.
|
|
337
|
+
|
|
338
|
+
A prefix with *no* usable character at all (`'///'`, `'_'`, a fully non-ASCII
|
|
339
|
+
prefix) and any explicit `toolName` outside the accepted class **throw at
|
|
340
|
+
mount**. An unusable prefix is rescued by setting an explicit `toolName` — the
|
|
341
|
+
prefix then never enters the name. An over-long name is fixed by a shorter
|
|
342
|
+
explicit `toolName` (or a shorter prefix / method key). Nothing downstream checks this: the provider rejects the whole
|
|
343
|
+
request, so one bad name takes every tool of that mount down with it.
|
|
344
|
+
→ [ADR 0035](../decisions/0035-tool-name-derivation-and-validation.md).
|
|
345
|
+
|
|
329
346
|
## Endpoint metadata (`meta`)
|
|
330
347
|
|
|
348
|
+
A contract can declare a **default** `meta` that every endpoint inherits, and an
|
|
349
|
+
endpoint's own keys are **shallow-merged over** it:
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
defineContract({ prefix: 'admin', meta: { public: true } }, {
|
|
353
|
+
list: { method: 'GET', path: '/', desc: 'List', /* meta → { public: true } */ },
|
|
354
|
+
purge: { method: 'POST', path: '/purge', desc: 'Purge', meta: { rateTier: 2 } },
|
|
355
|
+
// meta → { public: true, rateTier: 2 }
|
|
356
|
+
})
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
One level deep — no deep merge, no way to unset an inherited key; declare it on
|
|
360
|
+
the endpoint instead. `expose` deliberately has **no** contract-level equivalent
|
|
361
|
+
(→ [ADR 0036](../decisions/0036-contract-level-meta.md)).
|
|
362
|
+
|
|
363
|
+
|
|
331
364
|
`meta` is an **opaque, app-defined** bag the core attaches no meaning to — the
|
|
332
365
|
same escape-hatch spirit as `scope` being a free string ([ADR 0002](../decisions/0002-generic-core.md) /
|
|
333
366
|
[ADR 0021](../decisions/0021-endpoint-meta-passthrough.md)). Declare app concerns
|
|
@@ -1172,7 +1205,14 @@ By default every endpoint is a tool on every transport. `expose` narrows it:
|
|
|
1172
1205
|
`desc` is the tool description the model reads — write it for the model, not
|
|
1173
1206
|
just for a human. A `multipart` endpoint is never a tool. The tool name defaults
|
|
1174
1207
|
to a verb-aware name from the method + prefix (`list` → `list_widgets`, `get` →
|
|
1175
|
-
`get_widget`); set `toolName` for an explicit one.
|
|
1208
|
+
`get_widget`); set `toolName` for an explicit one. Derivation normalises every
|
|
1209
|
+
character outside `[a-zA-Z0-9_]` to `_` — the hyphen included, so `bot-status`
|
|
1210
|
+
derives `get_bot_status` — while a name is *accepted* if it matches
|
|
1211
|
+
`[a-zA-Z0-9_-]`, so a hyphen survives in an explicit `toolName`. A name that
|
|
1212
|
+
still cannot be delivered (illegal explicit `toolName`, over 64 characters, or a
|
|
1213
|
+
prefix with no usable character) throws at mount rather than at the first model
|
|
1214
|
+
call —
|
|
1215
|
+
→ [ADR 0035](../decisions/0035-tool-name-derivation-and-validation.md). See
|
|
1176
1216
|
[Contracts → transports](./contracts.md#transports).
|
|
1177
1217
|
|
|
1178
1218
|
### Pinning tool names — `listToolNames`
|
|
@@ -1196,6 +1236,14 @@ now fails this test instead of silently breaking the clients that call the
|
|
|
1196
1236
|
tool. It is also the mechanical diff when migrating a service: run it before
|
|
1197
1237
|
and after, compare.
|
|
1198
1238
|
|
|
1239
|
+
> **This is also the guard against a forgotten `expose`.** An endpoint that
|
|
1240
|
+
> declares none is a tool on MCP **and** AGENT — the default is fail-open, and
|
|
1241
|
+
> there is no contract-level `expose` to set once (→
|
|
1242
|
+
> [ADR 0036](../decisions/0036-contract-level-meta.md)). A snapshot of
|
|
1243
|
+
> `listToolNames` fails the build the moment an endpoint you meant to keep
|
|
1244
|
+
> HTTP-only shows up in the list, which is the one check that catches it however
|
|
1245
|
+
> many places the line was forgotten.
|
|
1246
|
+
|
|
1199
1247
|
## MCP — `createMcpHandler`
|
|
1200
1248
|
|
|
1201
1249
|
`createMcpHandler` builds a complete Streamable-HTTP MCP server as a single
|
|
@@ -1234,11 +1282,11 @@ createServer({
|
|
|
1234
1282
|
| `hooks` | tool-call observability hooks — `afterToolCall` fires on every result |
|
|
1235
1283
|
| `onIncompatibleSchema` | `'throw'` (default) · `'skip'` · `'warn'` — see below |
|
|
1236
1284
|
| `logger` | a `StitchLogger` for the `'warn'` policy |
|
|
1237
|
-
| `nativeTools` | register non-contract tools directly on the `McpServer` |
|
|
1285
|
+
| `nativeTools` | `(server, auth) => …` — register non-contract tools directly on the `McpServer`; receives the resolved identity, but is **not** a scope gate (`lifecycle` does not run for native tools) |
|
|
1238
1286
|
| `instructions` | a short host-facing usage hint, surfaced to MCP tool-search |
|
|
1239
1287
|
|
|
1240
|
-
`services` and `
|
|
1241
|
-
shown only its own tools and every handler can read `ctx.tenantId`.
|
|
1288
|
+
`services`, `context` and `nativeTools` all receive the resolved identity, so a
|
|
1289
|
+
tenant can be shown only its own tools and every handler can read `ctx.tenantId`.
|
|
1242
1290
|
|
|
1243
1291
|
### Guarding tools — `lifecycle`
|
|
1244
1292
|
|
|
@@ -2479,7 +2527,13 @@ const onError = createErrorHook({
|
|
|
2479
2527
|
CONFLICT: 'conflict', RATE_LIMITED: 'rate_limited',
|
|
2480
2528
|
INTERNAL_SERVER_ERROR: 'internal',
|
|
2481
2529
|
} satisfies Record<StitchErrorCode, string>,
|
|
2482
|
-
|
|
2530
|
+
// `ctx` is the request's RuntimeContext — read `ctx.traceId` for a
|
|
2531
|
+
// correlation id in the envelope. Declaring it is optional.
|
|
2532
|
+
render: (info, ctx) => ({
|
|
2533
|
+
ok: false,
|
|
2534
|
+
error: { code: info.code, message: info.message },
|
|
2535
|
+
traceId: ctx.traceId,
|
|
2536
|
+
}),
|
|
2483
2537
|
})
|
|
2484
2538
|
|
|
2485
2539
|
createServer({ services, hooks: { onError } })
|
|
@@ -3123,6 +3177,42 @@ current one *up to* your target, and apply each snippet.
|
|
|
3123
3177
|
(`STITCH_ERROR_STATUS`, `serveFile`, `scopePrefixes`, `afterToolCall`'s
|
|
3124
3178
|
`MethodDef`, `maxUploadBytes`) are available to adopt, not required.
|
|
3125
3179
|
|
|
3180
|
+
## Your handlers may be returning more than the contract declares
|
|
3181
|
+
|
|
3182
|
+
stitchkit validates every handler's return value against the endpoint's `output`
|
|
3183
|
+
schema and **passes on the parsed result** — so any field the schema does not
|
|
3184
|
+
declare is silently removed. That is deliberate (the contract is the published
|
|
3185
|
+
shape of the response), but when you are moving a *live* API onto stitchkit it is
|
|
3186
|
+
invisible: TypeScript does not reject excess properties, nothing logs it, and the
|
|
3187
|
+
client just receives fewer fields.
|
|
3188
|
+
|
|
3189
|
+
While migrating, turn the diagnostic on:
|
|
3190
|
+
|
|
3191
|
+
```ts
|
|
3192
|
+
createServer({ services, warnOnOutputStrip: true }) // off by default
|
|
3193
|
+
```
|
|
3194
|
+
|
|
3195
|
+
Every removed key is logged as a dot-path with the endpoint that produced it
|
|
3196
|
+
(`notes.get: secret, nested.alsoSecret`). Tool transports strip identically —
|
|
3197
|
+
`mountMcp` / `mountAgent` take `onOutputStrip: (toolName, paths) => …`. Read the
|
|
3198
|
+
list, then either widen the contract or stop returning the field, and turn the
|
|
3199
|
+
flag back off: it is for the migration window, not for production.
|
|
3200
|
+
|
|
3201
|
+
## Tool names may shift between versions
|
|
3202
|
+
|
|
3203
|
+
Derived tool names are part of your public surface — an MCP client config or an
|
|
3204
|
+
agent prompt refers to them by string. Before and after any upgrade that touches
|
|
3205
|
+
name derivation, diff them mechanically:
|
|
3206
|
+
|
|
3207
|
+
```ts
|
|
3208
|
+
import { listToolNames } from 'stitchkit/tools'
|
|
3209
|
+
console.log(JSON.stringify(listToolNames(services), null, 2))
|
|
3210
|
+
```
|
|
3211
|
+
|
|
3212
|
+
`listToolNames` never throws on an illegal name — that is deliberate, so it can
|
|
3213
|
+
show you the offending row when a mount would refuse it. Pin it in a snapshot
|
|
3214
|
+
test and a shift fails your build instead of your clients.
|
|
3215
|
+
|
|
3126
3216
|
## When you author a breaking change in stitchkit
|
|
3127
3217
|
|
|
3128
3218
|
You are on the other side of this flow — see
|
|
@@ -3212,7 +3302,7 @@ from the root `stitchkit`.
|
|
|
3212
3302
|
| `ScopedDefineContract` | _type_ | the `defineContract` `createContractFactory` returns |
|
|
3213
3303
|
| `ALL_TRANSPORTS` | constant | `['HTTP', 'MCP', 'AGENT', 'CLI']` |
|
|
3214
3304
|
| `ContractDef` | _type_ | a defined contract |
|
|
3215
|
-
| `ContractMeta` | _type_ | a contract's `prefix` + optional `scope` |
|
|
3305
|
+
| `ContractMeta` | _type_ | a contract's `prefix` + optional `scope` and `meta` (a default every endpoint shallow-merges over) |
|
|
3216
3306
|
| `EndpointDef` | _type_ | a single endpoint definition |
|
|
3217
3307
|
| `HttpMethod` | _type_ | `GET \| POST \| PUT \| PATCH \| DELETE` |
|
|
3218
3308
|
| `Transport` | _type_ | `HTTP \| MCP \| AGENT \| CLI` |
|
package/package.json
CHANGED