stitchkit 0.122.0 → 0.122.2
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 +34 -0
- package/dist/agent-runtime/deferred-tool-search.d.ts.map +1 -1
- package/dist/agent-runtime/deferred-tool-types.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime.js +4 -3
- package/dist/entrypoints/cli.js +2 -1
- package/dist/entrypoints/tools/connections.js +7 -1
- package/dist/entrypoints/tools/mcp.js +2 -1
- package/dist/entrypoints/tools/toolkit.js +3 -2
- package/dist/index-332d0m9g.js +37 -0
- package/dist/{index-v8yqk4w7.js → index-aswegq1r.js} +3 -5
- package/dist/{index-knmnj11j.js → index-y6ye582c.js} +7 -5
- package/dist/tools/connections/mcp.d.ts.map +1 -1
- package/dist/tools/mcp/catalog.d.ts.map +1 -1
- package/dist/tools/mcp/mount.d.ts.map +1 -1
- package/dist/tools/mcp/register.d.ts +1 -2
- package/dist/tools/mcp/register.d.ts.map +1 -1
- package/dist/tools/mcp/runtime-tools.d.ts.map +1 -1
- package/dist/tools/read-operation.d.ts +21 -0
- package/dist/tools/read-operation.d.ts.map +1 -0
- package/llms/agent-runtime.2.txt +632 -745
- package/llms/agent-runtime.3.txt +733 -492
- package/llms/agent-runtime.4.txt +521 -88
- package/llms/agent-runtime.5.txt +114 -0
- package/llms/agent-runtime.txt +4 -655
- package/llms/cli.txt +12 -3
- package/llms/tools.2.txt +109 -0
- package/llms/tools.txt +30 -109
- package/llms-full.txt +47 -4
- package/llms.txt +3 -3
- package/package.json +1 -1
- package/dist/tools/cli/repeatable-read.d.ts +0 -9
- package/dist/tools/cli/repeatable-read.d.ts.map +0 -1
package/llms/cli.txt
CHANGED
|
@@ -718,9 +718,18 @@ and `details.resultOnStdout` states which case occurred:
|
|
|
718
718
|
| only reads | nothing | repeating the command with a corrected view |
|
|
719
719
|
|
|
720
720
|
A managed command only reads when its tool declares `annotations.readOnlyHint: true`,
|
|
721
|
-
or declares no `readOnlyHint` and its method is `GET`. `readOnlyHint: false
|
|
722
|
-
endpoint keeps the result on stdout. A native
|
|
723
|
-
so a failed `present` always keeps the validated
|
|
721
|
+
or declares no `readOnlyHint` and its method is `GET`. `readOnlyHint: false`, or
|
|
722
|
+
`destructiveHint: true` without a `readOnlyHint`, on a `GET` endpoint keeps the result on stdout. A native
|
|
723
|
+
`defineCliCommand` declares neither fact, so a failed `present` always keeps the validated
|
|
724
|
+
result on stdout.
|
|
725
|
+
|
|
726
|
+
A CLI that mounts a server's tools through `defineMcpClientConnection` never sees the
|
|
727
|
+
method — every MCP call is a `POST` — so it reads the `readOnlyHint` the server
|
|
728
|
+
publishes. A Stitchkit server publishes it for every `GET` by the rule above
|
|
729
|
+
([MCP → `readOnlyHint`](./mcp-and-agents.md#saying-which-tools-only-read--readonlyhint)),
|
|
730
|
+
so the same command behaves the same over the contract and over MCP. The hint is the
|
|
731
|
+
server's word: a server that labels a write as read-only makes the CLI withhold that
|
|
732
|
+
write's result on a refused view, and repeating the command repeats the effect.
|
|
724
733
|
|
|
725
734
|
CLI argument errors detected before execution still exit with `2`
|
|
726
735
|
and have no successful result to preserve.
|
package/llms/tools.2.txt
CHANGED
|
@@ -13,6 +13,115 @@ Parts of this slice:
|
|
|
13
13
|
# Guide: MCP & agents (docs/guide/mcp-and-agents.md) (continued)
|
|
14
14
|
==============================================================================
|
|
15
15
|
|
|
16
|
+
## OAuth 2.1 — a native remote connector
|
|
17
|
+
|
|
18
|
+
A remote MCP server is connectable from Claude (Desktop / web "custom
|
|
19
|
+
connector") only through the MCP authorization spec: OAuth 2.1 with PKCE, plus
|
|
20
|
+
the discovery documents (RFC 9728 / 8414), Client ID Metadata Documents (CIMD)
|
|
21
|
+
and resource indicators (RFC 8707). A Bearer-only server returns a
|
|
22
|
+
bare `401` and the connector never establishes.
|
|
23
|
+
|
|
24
|
+
stitchkit ships the OAuth **protocol mechanics**; the app supplies only
|
|
25
|
+
**identity and storage**. Three pieces wire it together:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { mountOAuthProvider, oauthProtectedResourceRoute } from 'stitchkit/tools'
|
|
29
|
+
import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools/mcp'
|
|
30
|
+
import { createServer } from 'stitchkit/server'
|
|
31
|
+
|
|
32
|
+
const resource = 'https://api.example.com/mcp'
|
|
33
|
+
const issuer = 'https://api.example.com'
|
|
34
|
+
|
|
35
|
+
// 1. Resource server — the 401 now points at the metadata.
|
|
36
|
+
const mcp = createMcpHandler({
|
|
37
|
+
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
38
|
+
auth: resolveOAuthToken, // validate the Bearer JWT (verifyJwt + audience)
|
|
39
|
+
services,
|
|
40
|
+
protectedResource: { resource, authorizationServers: [issuer] },
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// 2. Authorization server — CIMD, /authorize (PKCE), /token.
|
|
44
|
+
const oauthRoutes = mountOAuthProvider({
|
|
45
|
+
issuer,
|
|
46
|
+
resource,
|
|
47
|
+
signingSecret: env.OAUTH_SECRET,
|
|
48
|
+
clientRegistration: {
|
|
49
|
+
preRegistered: { get: getFirstPartyClient },
|
|
50
|
+
// CIMD is enabled with secure defaults; DCR remains disabled.
|
|
51
|
+
},
|
|
52
|
+
codes, refreshTokens, // your stores (DB or in-memory)
|
|
53
|
+
authorizeUser, // → { userId, approvedScopes } | Response
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
createServer({
|
|
57
|
+
services,
|
|
58
|
+
rawRoutes: [
|
|
59
|
+
createMcpHttpRoute({ path: '/mcp', handler: mcp }),
|
|
60
|
+
oauthProtectedResourceRoute({ resource, authorizationServers: [issuer] }),
|
|
61
|
+
...oauthRoutes,
|
|
62
|
+
],
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Access tokens are signed HS256 JWTs (`signJwt`) whose `aud` is the resource and
|
|
67
|
+
whose `iss` is the issuer — validate both in `auth` with
|
|
68
|
+
`verifyJwt(token, secret, { audience: resource, issuer })`. `authorizeUser` is
|
|
69
|
+
where the app authenticates the user (reuse an existing session) and records
|
|
70
|
+
consent; return `{ userId, approvedScopes }`, where approved scopes are a subset
|
|
71
|
+
of the requested/supported values, or a `Response` to redirect the browser to a
|
|
72
|
+
login page first. The AS and resource server can co-locate or live
|
|
73
|
+
on separate origins. See
|
|
74
|
+
[ADR 0015](../decisions/0015-oauth-resource-server.md).
|
|
75
|
+
|
|
76
|
+
Client resolution is deterministic: exact pre-registered client, then an HTTPS
|
|
77
|
+
URL client id resolved as CIMD, then explicitly enabled DCR. CIMD is on by
|
|
78
|
+
default; DCR is off unless `clientRegistration.dcr` supplies both `register` and
|
|
79
|
+
`get`. A CIMD-only deployment therefore exposes neither `/register` nor a
|
|
80
|
+
`registration_endpoint`. The metadata document must declare a `client_id` that
|
|
81
|
+
exactly equals its URL, explicit redirect URIs and
|
|
82
|
+
`token_endpoint_auth_method: 'none'`.
|
|
83
|
+
|
|
84
|
+
The token endpoint and `/register` read at most 64 KiB of a request body, or
|
|
85
|
+
`maxRequestBodyBytes` when you set it; a larger one is answered `413` with
|
|
86
|
+
`invalid_request` and the rest is not read.
|
|
87
|
+
|
|
88
|
+
The production fetcher rejects credentials, fragments, non-HTTPS URLs and
|
|
89
|
+
private/reserved targets. Every redirect is DNS-resolved and IP-pinned again;
|
|
90
|
+
timeouts, redirect count and body size are bounded. Its bounded cache respects
|
|
91
|
+
`Cache-Control` (including `no-store`/`no-cache`), `Age`, `Expires`, `ETag` and
|
|
92
|
+
`Last-Modified`, coalesces concurrent misses and reports sanitized cache events;
|
|
93
|
+
invalid or unavailable identity receives only a short fail-closed cache entry.
|
|
94
|
+
|
|
95
|
+
Resolution itself is rate-limited on two levels (`CimdCachePolicy`):
|
|
96
|
+
`maxResolutionsPerClient` (default 10) bounds ONE `client_id` per
|
|
97
|
+
`resolutionWindowMs` window (default 60 s) — a client whose document disables
|
|
98
|
+
caching burns its own budget, not the server's — while `maxResolutions`
|
|
99
|
+
(default 120) caps the server-wide outbound rate as the flood backstop.
|
|
100
|
+
Positive and negative cache entries keep separate pools of `maxEntries` each,
|
|
101
|
+
so a flood of unresolvable ids cannot evict warmed clients and a burst of
|
|
102
|
+
successes cannot reset a failing client's backoff.
|
|
103
|
+
|
|
104
|
+
### Authorization hardening (MCP 2026-07-28)
|
|
105
|
+
|
|
106
|
+
- **`iss` on every authorization response (RFC 9207, SEP-2468).** Success *and*
|
|
107
|
+
error redirects carry `iss`, and the AS metadata advertises
|
|
108
|
+
`authorization_response_iss_parameter_supported: true`. A client that talks to
|
|
109
|
+
several authorization servers validates `iss` before redeeming the code, which
|
|
110
|
+
closes the **mix-up attack** — an attacker's server cannot pass its response
|
|
111
|
+
off as this issuer's. Additive on the wire: a client that ignores `iss` is
|
|
112
|
+
unaffected.
|
|
113
|
+
- **`application_type` on registration (SEP-837).** A client may declare
|
|
114
|
+
`"native"` (desktop / CLI) or `"web"` in its DCR body. A **native** client may
|
|
115
|
+
register an `http` loopback redirect (`http://127.0.0.1:…`, RFC 8252 §7.3); a
|
|
116
|
+
**web** client is held to `https` only — that mismatch is the usual cause of
|
|
117
|
+
the `redirect_uri` rejection CLI clients hit. Omit the field and registration
|
|
118
|
+
behaves exactly as before (loopback allowed); an unknown value is rejected
|
|
119
|
+
rather than silently defaulted.
|
|
120
|
+
|
|
121
|
+
> Dynamic Client Registration is an explicit interoperability mode, not the
|
|
122
|
+
> default. Enabling it changes public discovery and adds `/register`; keep it off
|
|
123
|
+
> unless a client that cannot publish CIMD requires it.
|
|
124
|
+
|
|
16
125
|
## Proxying a remote API — `implementRemote`
|
|
17
126
|
|
|
18
127
|
`implement` binds a contract to local handlers. `implementRemote` binds it to a
|
package/llms/tools.txt
CHANGED
|
@@ -317,6 +317,36 @@ schema and annotations, and nothing else — it moves when the contract moves an
|
|
|
317
317
|
not when a handler does. Raw SDK registrations stay consumer-owned and are
|
|
318
318
|
outside it.
|
|
319
319
|
|
|
320
|
+
### Saying which tools only read — `readOnlyHint`
|
|
321
|
+
|
|
322
|
+
A host reads a tool's `annotations` to group tools and to choose permission
|
|
323
|
+
defaults, and a CLI mounted over this surface reads them to decide what a
|
|
324
|
+
refused view may withhold ([CLI → views](./cli.md#aggregate-views)). The server publishes the
|
|
325
|
+
annotations the tool declared, and states `readOnlyHint: true` for a read that
|
|
326
|
+
declared none:
|
|
327
|
+
|
|
328
|
+
| The tool | Published `readOnlyHint` |
|
|
329
|
+
|---|---|
|
|
330
|
+
| declares `readOnlyHint`, either way | as declared |
|
|
331
|
+
| `GET` with no `readOnlyHint` | `true` |
|
|
332
|
+
| `GET` declaring `destructiveHint: true` and no `readOnlyHint` | none |
|
|
333
|
+
| any other method with no `readOnlyHint` | none |
|
|
334
|
+
|
|
335
|
+
A runtime tool follows the same rule by its `identity.method`. A raw SDK
|
|
336
|
+
registration (`mountWait`, `mountViewFile` and the like) publishes only what it
|
|
337
|
+
passes. The catalog digest hashes the published annotations, so it moves once
|
|
338
|
+
when a server starts publishing the derived hint.
|
|
339
|
+
|
|
340
|
+
> **A `GET` with an effect must say so.** Hosts may run a tool that publishes
|
|
341
|
+
> `readOnlyHint: true` without asking. An endpoint that changes something on
|
|
342
|
+
> `GET` — marks as seen, rotates a token — declares
|
|
343
|
+
> `tool: { annotations: { readOnlyHint: false } }`.
|
|
344
|
+
|
|
345
|
+
A client connection (`defineMcpClientConnection`) carries the hints a server
|
|
346
|
+
published onto the tools it mounts, field by field: a hint of the wrong type is
|
|
347
|
+
dropped and the tool stays. The mounted tool is as read-only as its server says
|
|
348
|
+
it is, and a surface that re-publishes mounted tools passes those hints on.
|
|
349
|
+
|
|
320
350
|
### Shaping arguments before validation — `beforeToolCall`
|
|
321
351
|
|
|
322
352
|
`beforeToolCall` sees the arguments as they arrived and may **replace** them:
|
|
@@ -865,112 +895,3 @@ OS default disposition instead of reporting a fictional forced result.
|
|
|
865
895
|
Both transports build the server through the shared `buildMcpServer` — same
|
|
866
896
|
contract/runtime pipeline, same surface selection, context, hooks, raw escape
|
|
867
897
|
hatch and instructions.
|
|
868
|
-
|
|
869
|
-
## OAuth 2.1 — a native remote connector
|
|
870
|
-
|
|
871
|
-
A remote MCP server is connectable from Claude (Desktop / web "custom
|
|
872
|
-
connector") only through the MCP authorization spec: OAuth 2.1 with PKCE, plus
|
|
873
|
-
the discovery documents (RFC 9728 / 8414), Client ID Metadata Documents (CIMD)
|
|
874
|
-
and resource indicators (RFC 8707). A Bearer-only server returns a
|
|
875
|
-
bare `401` and the connector never establishes.
|
|
876
|
-
|
|
877
|
-
stitchkit ships the OAuth **protocol mechanics**; the app supplies only
|
|
878
|
-
**identity and storage**. Three pieces wire it together:
|
|
879
|
-
|
|
880
|
-
```ts
|
|
881
|
-
import { mountOAuthProvider, oauthProtectedResourceRoute } from 'stitchkit/tools'
|
|
882
|
-
import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools/mcp'
|
|
883
|
-
import { createServer } from 'stitchkit/server'
|
|
884
|
-
|
|
885
|
-
const resource = 'https://api.example.com/mcp'
|
|
886
|
-
const issuer = 'https://api.example.com'
|
|
887
|
-
|
|
888
|
-
// 1. Resource server — the 401 now points at the metadata.
|
|
889
|
-
const mcp = createMcpHandler({
|
|
890
|
-
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
891
|
-
auth: resolveOAuthToken, // validate the Bearer JWT (verifyJwt + audience)
|
|
892
|
-
services,
|
|
893
|
-
protectedResource: { resource, authorizationServers: [issuer] },
|
|
894
|
-
})
|
|
895
|
-
|
|
896
|
-
// 2. Authorization server — CIMD, /authorize (PKCE), /token.
|
|
897
|
-
const oauthRoutes = mountOAuthProvider({
|
|
898
|
-
issuer,
|
|
899
|
-
resource,
|
|
900
|
-
signingSecret: env.OAUTH_SECRET,
|
|
901
|
-
clientRegistration: {
|
|
902
|
-
preRegistered: { get: getFirstPartyClient },
|
|
903
|
-
// CIMD is enabled with secure defaults; DCR remains disabled.
|
|
904
|
-
},
|
|
905
|
-
codes, refreshTokens, // your stores (DB or in-memory)
|
|
906
|
-
authorizeUser, // → { userId, approvedScopes } | Response
|
|
907
|
-
})
|
|
908
|
-
|
|
909
|
-
createServer({
|
|
910
|
-
services,
|
|
911
|
-
rawRoutes: [
|
|
912
|
-
createMcpHttpRoute({ path: '/mcp', handler: mcp }),
|
|
913
|
-
oauthProtectedResourceRoute({ resource, authorizationServers: [issuer] }),
|
|
914
|
-
...oauthRoutes,
|
|
915
|
-
],
|
|
916
|
-
})
|
|
917
|
-
```
|
|
918
|
-
|
|
919
|
-
Access tokens are signed HS256 JWTs (`signJwt`) whose `aud` is the resource and
|
|
920
|
-
whose `iss` is the issuer — validate both in `auth` with
|
|
921
|
-
`verifyJwt(token, secret, { audience: resource, issuer })`. `authorizeUser` is
|
|
922
|
-
where the app authenticates the user (reuse an existing session) and records
|
|
923
|
-
consent; return `{ userId, approvedScopes }`, where approved scopes are a subset
|
|
924
|
-
of the requested/supported values, or a `Response` to redirect the browser to a
|
|
925
|
-
login page first. The AS and resource server can co-locate or live
|
|
926
|
-
on separate origins. See
|
|
927
|
-
[ADR 0015](../decisions/0015-oauth-resource-server.md).
|
|
928
|
-
|
|
929
|
-
Client resolution is deterministic: exact pre-registered client, then an HTTPS
|
|
930
|
-
URL client id resolved as CIMD, then explicitly enabled DCR. CIMD is on by
|
|
931
|
-
default; DCR is off unless `clientRegistration.dcr` supplies both `register` and
|
|
932
|
-
`get`. A CIMD-only deployment therefore exposes neither `/register` nor a
|
|
933
|
-
`registration_endpoint`. The metadata document must declare a `client_id` that
|
|
934
|
-
exactly equals its URL, explicit redirect URIs and
|
|
935
|
-
`token_endpoint_auth_method: 'none'`.
|
|
936
|
-
|
|
937
|
-
The token endpoint and `/register` read at most 64 KiB of a request body, or
|
|
938
|
-
`maxRequestBodyBytes` when you set it; a larger one is answered `413` with
|
|
939
|
-
`invalid_request` and the rest is not read.
|
|
940
|
-
|
|
941
|
-
The production fetcher rejects credentials, fragments, non-HTTPS URLs and
|
|
942
|
-
private/reserved targets. Every redirect is DNS-resolved and IP-pinned again;
|
|
943
|
-
timeouts, redirect count and body size are bounded. Its bounded cache respects
|
|
944
|
-
`Cache-Control` (including `no-store`/`no-cache`), `Age`, `Expires`, `ETag` and
|
|
945
|
-
`Last-Modified`, coalesces concurrent misses and reports sanitized cache events;
|
|
946
|
-
invalid or unavailable identity receives only a short fail-closed cache entry.
|
|
947
|
-
|
|
948
|
-
Resolution itself is rate-limited on two levels (`CimdCachePolicy`):
|
|
949
|
-
`maxResolutionsPerClient` (default 10) bounds ONE `client_id` per
|
|
950
|
-
`resolutionWindowMs` window (default 60 s) — a client whose document disables
|
|
951
|
-
caching burns its own budget, not the server's — while `maxResolutions`
|
|
952
|
-
(default 120) caps the server-wide outbound rate as the flood backstop.
|
|
953
|
-
Positive and negative cache entries keep separate pools of `maxEntries` each,
|
|
954
|
-
so a flood of unresolvable ids cannot evict warmed clients and a burst of
|
|
955
|
-
successes cannot reset a failing client's backoff.
|
|
956
|
-
|
|
957
|
-
### Authorization hardening (MCP 2026-07-28)
|
|
958
|
-
|
|
959
|
-
- **`iss` on every authorization response (RFC 9207, SEP-2468).** Success *and*
|
|
960
|
-
error redirects carry `iss`, and the AS metadata advertises
|
|
961
|
-
`authorization_response_iss_parameter_supported: true`. A client that talks to
|
|
962
|
-
several authorization servers validates `iss` before redeeming the code, which
|
|
963
|
-
closes the **mix-up attack** — an attacker's server cannot pass its response
|
|
964
|
-
off as this issuer's. Additive on the wire: a client that ignores `iss` is
|
|
965
|
-
unaffected.
|
|
966
|
-
- **`application_type` on registration (SEP-837).** A client may declare
|
|
967
|
-
`"native"` (desktop / CLI) or `"web"` in its DCR body. A **native** client may
|
|
968
|
-
register an `http` loopback redirect (`http://127.0.0.1:…`, RFC 8252 §7.3); a
|
|
969
|
-
**web** client is held to `https` only — that mismatch is the usual cause of
|
|
970
|
-
the `redirect_uri` rejection CLI clients hit. Omit the field and registration
|
|
971
|
-
behaves exactly as before (loopback allowed); an unknown value is rejected
|
|
972
|
-
rather than silently defaulted.
|
|
973
|
-
|
|
974
|
-
> Dynamic Client Registration is an explicit interoperability mode, not the
|
|
975
|
-
> default. Enabling it changes public discovery and adds `/register`; keep it off
|
|
976
|
-
> unless a client that cannot publish CIMD requires it.
|
package/llms-full.txt
CHANGED
|
@@ -4182,6 +4182,36 @@ schema and annotations, and nothing else — it moves when the contract moves an
|
|
|
4182
4182
|
not when a handler does. Raw SDK registrations stay consumer-owned and are
|
|
4183
4183
|
outside it.
|
|
4184
4184
|
|
|
4185
|
+
### Saying which tools only read — `readOnlyHint`
|
|
4186
|
+
|
|
4187
|
+
A host reads a tool's `annotations` to group tools and to choose permission
|
|
4188
|
+
defaults, and a CLI mounted over this surface reads them to decide what a
|
|
4189
|
+
refused view may withhold ([CLI → views](./cli.md#aggregate-views)). The server publishes the
|
|
4190
|
+
annotations the tool declared, and states `readOnlyHint: true` for a read that
|
|
4191
|
+
declared none:
|
|
4192
|
+
|
|
4193
|
+
| The tool | Published `readOnlyHint` |
|
|
4194
|
+
|---|---|
|
|
4195
|
+
| declares `readOnlyHint`, either way | as declared |
|
|
4196
|
+
| `GET` with no `readOnlyHint` | `true` |
|
|
4197
|
+
| `GET` declaring `destructiveHint: true` and no `readOnlyHint` | none |
|
|
4198
|
+
| any other method with no `readOnlyHint` | none |
|
|
4199
|
+
|
|
4200
|
+
A runtime tool follows the same rule by its `identity.method`. A raw SDK
|
|
4201
|
+
registration (`mountWait`, `mountViewFile` and the like) publishes only what it
|
|
4202
|
+
passes. The catalog digest hashes the published annotations, so it moves once
|
|
4203
|
+
when a server starts publishing the derived hint.
|
|
4204
|
+
|
|
4205
|
+
> **A `GET` with an effect must say so.** Hosts may run a tool that publishes
|
|
4206
|
+
> `readOnlyHint: true` without asking. An endpoint that changes something on
|
|
4207
|
+
> `GET` — marks as seen, rotates a token — declares
|
|
4208
|
+
> `tool: { annotations: { readOnlyHint: false } }`.
|
|
4209
|
+
|
|
4210
|
+
A client connection (`defineMcpClientConnection`) carries the hints a server
|
|
4211
|
+
published onto the tools it mounts, field by field: a hint of the wrong type is
|
|
4212
|
+
dropped and the tool stays. The mounted tool is as read-only as its server says
|
|
4213
|
+
it is, and a surface that re-publishes mounted tools passes those hints on.
|
|
4214
|
+
|
|
4185
4215
|
### Shaping arguments before validation — `beforeToolCall`
|
|
4186
4216
|
|
|
4187
4217
|
`beforeToolCall` sees the arguments as they arrived and may **replace** them:
|
|
@@ -5770,7 +5800,11 @@ Selection is a versioned receipt in the ordinary durable tool-result history.
|
|
|
5770
5800
|
The latest valid same-run search replaces the earlier selection; parallel
|
|
5771
5801
|
searches in one step merge in call order. Recovery reconstructs it, while a
|
|
5772
5802
|
different run or finite surface cannot inherit it. Known inactive calls take a
|
|
5773
|
-
recoverable `SEARCH_REQUIRED` search round; unknown names still fail.
|
|
5803
|
+
recoverable `SEARCH_REQUIRED` search round; unknown names still fail. The
|
|
5804
|
+
runtime marks that round with `reason: 'inactive_call'` beside the exact tool
|
|
5805
|
+
name. The field is the runtime's to write; a model that sets it anyway gets
|
|
5806
|
+
the same `SEARCH_REQUIRED` answer with an exact name, and with a query in words
|
|
5807
|
+
the field is ignored and the query is ranked as usual.
|
|
5774
5808
|
|
|
5775
5809
|
Every ceiling is required. `maxSchemaBytes` measures UTF-8 bytes over canonical
|
|
5776
5810
|
name, description and presentation schema. It is useful for before/after
|
|
@@ -10847,9 +10881,18 @@ and `details.resultOnStdout` states which case occurred:
|
|
|
10847
10881
|
| only reads | nothing | repeating the command with a corrected view |
|
|
10848
10882
|
|
|
10849
10883
|
A managed command only reads when its tool declares `annotations.readOnlyHint: true`,
|
|
10850
|
-
or declares no `readOnlyHint` and its method is `GET`. `readOnlyHint: false
|
|
10851
|
-
endpoint keeps the result on stdout. A native
|
|
10852
|
-
so a failed `present` always keeps the validated
|
|
10884
|
+
or declares no `readOnlyHint` and its method is `GET`. `readOnlyHint: false`, or
|
|
10885
|
+
`destructiveHint: true` without a `readOnlyHint`, on a `GET` endpoint keeps the result on stdout. A native
|
|
10886
|
+
`defineCliCommand` declares neither fact, so a failed `present` always keeps the validated
|
|
10887
|
+
result on stdout.
|
|
10888
|
+
|
|
10889
|
+
A CLI that mounts a server's tools through `defineMcpClientConnection` never sees the
|
|
10890
|
+
method — every MCP call is a `POST` — so it reads the `readOnlyHint` the server
|
|
10891
|
+
publishes. A Stitchkit server publishes it for every `GET` by the rule above
|
|
10892
|
+
([MCP → `readOnlyHint`](./mcp-and-agents.md#saying-which-tools-only-read--readonlyhint)),
|
|
10893
|
+
so the same command behaves the same over the contract and over MCP. The hint is the
|
|
10894
|
+
server's word: a server that labels a write as read-only makes the CLI withhold that
|
|
10895
|
+
write's result on a refused view, and repeating the command repeats the effect.
|
|
10853
10896
|
|
|
10854
10897
|
CLI argument errors detected before execution still exit with `2`
|
|
10855
10898
|
and have no successful result to preserve.
|
package/llms.txt
CHANGED
|
@@ -14,21 +14,21 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
|
|
|
14
14
|
- **stitchkit/react**: [llms/react.txt](llms/react.txt) 8.7 KB
|
|
15
15
|
- **stitchkit/react/keyboard**: [llms/react-keyboard.txt](llms/react-keyboard.txt) 22.7 KB
|
|
16
16
|
- **stitchkit/react/keyboard/testing**: [llms/react-keyboard-testing.txt](llms/react-keyboard-testing.txt) 1.9 KB
|
|
17
|
-
- **stitchkit/tools**: [llms/tools.txt](llms/tools.txt)
|
|
17
|
+
- **stitchkit/tools**: [llms/tools.txt](llms/tools.txt) 43.2 KB → [llms/tools.2.txt](llms/tools.2.txt) 35.7 KB → [llms/tools.3.txt](llms/tools.3.txt) 21.0 KB
|
|
18
18
|
- **stitchkit/tools/mcp**: [llms/tools-mcp.txt](llms/tools-mcp.txt) 6.6 KB
|
|
19
19
|
- **stitchkit/tools/agent**: [llms/tools-agent.txt](llms/tools-agent.txt) 1.1 KB
|
|
20
20
|
- **stitchkit/tools/toolkit**: [llms/tools-toolkit.txt](llms/tools-toolkit.txt) 0.9 KB
|
|
21
21
|
- **stitchkit/tools/contract**: [llms/tools-contract.txt](llms/tools-contract.txt) 0.2 KB
|
|
22
22
|
- **stitchkit/tools/invoker**: [llms/tools-invoker.txt](llms/tools-invoker.txt) 0.2 KB
|
|
23
23
|
- **stitchkit/tools/connections**: [llms/tools-connections.txt](llms/tools-connections.txt) 3.9 KB
|
|
24
|
-
- **stitchkit/cli**: [llms/cli.txt](llms/cli.txt) 37.
|
|
24
|
+
- **stitchkit/cli**: [llms/cli.txt](llms/cli.txt) 37.8 KB → [llms/cli.2.txt](llms/cli.2.txt) 36.4 KB
|
|
25
25
|
- **stitchkit/cli/publish**: [llms/cli-publish.txt](llms/cli-publish.txt) 1.5 KB
|
|
26
26
|
- **stitchkit/remote**: [llms/remote.txt](llms/remote.txt) 1.0 KB
|
|
27
27
|
- **stitchkit/contract**: [llms/contract.txt](llms/contract.txt) 33.8 KB
|
|
28
28
|
- **stitchkit/primitives**: [llms/primitives.txt](llms/primitives.txt) 13.2 KB
|
|
29
29
|
- **stitchkit/server**: [llms/server.txt](llms/server.txt) 44.2 KB → [llms/server.2.txt](llms/server.2.txt) 23.1 KB → [llms/server.3.txt](llms/server.3.txt) 47.0 KB → [llms/server.4.txt](llms/server.4.txt) 38.6 KB → [llms/server.5.txt](llms/server.5.txt) 23.5 KB
|
|
30
30
|
- **stitchkit/observability**: [llms/observability.txt](llms/observability.txt) 46.9 KB
|
|
31
|
-
- **stitchkit/agent-runtime**: [llms/agent-runtime.txt](llms/agent-runtime.txt)
|
|
31
|
+
- **stitchkit/agent-runtime**: [llms/agent-runtime.txt](llms/agent-runtime.txt) 5.7 KB → [llms/agent-runtime.2.txt](llms/agent-runtime.2.txt) 44.1 KB → [llms/agent-runtime.3.txt](llms/agent-runtime.3.txt) 42.5 KB → [llms/agent-runtime.4.txt](llms/agent-runtime.4.txt) 45.2 KB → [llms/agent-runtime.5.txt](llms/agent-runtime.5.txt) 11.8 KB
|
|
32
32
|
- **stitchkit/agent-runtime/testing**: [llms/agent-runtime-testing.txt](llms/agent-runtime-testing.txt) 2.6 KB
|
|
33
33
|
- **stitchkit/agent-runtime/harness**: [llms/agent-runtime-harness.txt](llms/agent-runtime-harness.txt) 11.0 KB
|
|
34
34
|
- **stitchkit/agent-runtime/coding-tools**: [llms/agent-runtime-coding-tools.txt](llms/agent-runtime-coding-tools.txt) 5.0 KB
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { OperationIdentity } from '../../server/types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Whether calling the operation again returns its answer without a new effect.
|
|
4
|
-
*
|
|
5
|
-
* The declared `readOnlyHint` decides in either direction; without one, `GET` is
|
|
6
|
-
* the contract's own statement that the endpoint reads.
|
|
7
|
-
*/
|
|
8
|
-
export declare function isRepeatableRead(operation: Pick<OperationIdentity, 'method' | 'annotations'>): boolean;
|
|
9
|
-
//# sourceMappingURL=repeatable-read.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"repeatable-read.d.ts","sourceRoot":"","sources":["../../../src/tools/cli/repeatable-read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,aAAa,CAAC,GAC3D,OAAO,CAET"}
|