stitchkit 0.122.0 → 0.122.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -15,6 +15,27 @@ additive**; the first breaking change landed in 0.10.0. Grep the file for
15
15
 
16
16
  ## [Unreleased]
17
17
 
18
+ ## [0.122.1] - 2026-11-10
19
+
20
+ ### Fixed
21
+
22
+ - `stitchkit/tools/mcp` — the MCP server publishes `readOnlyHint: true` for a `GET` tool that
23
+ declared no `readOnlyHint`; it published only declared annotations, so a read was
24
+ indistinguishable from a write to every MCP client. A declared `readOnlyHint` is published as
25
+ written, and a `GET` declaring `destructiveHint: true` gets none. The catalog digest hashes the
26
+ published annotations and moves once on upgrade. A `GET` endpoint with an effect must declare
27
+ `readOnlyHint: false`: a host may run a read-only tool without asking. → ADR 0287
28
+ **Affects:** `stitchkit/tools/mcp` behaviour
29
+ - `stitchkit/tools/connections` — `defineMcpClientConnection` carries the annotations a server
30
+ published onto the tools it mounts; it dropped them, so a CLI built over an MCP surface printed
31
+ a read's complete result on a refused view (`--table` with an unknown column) while the same
32
+ command over the contract printed nothing. A hint of the wrong type is dropped and the tool
33
+ stays. The mounted tool is as read-only as its server says it is. → ADR 0287
34
+ **Affects:** `stitchkit/tools/connections` behaviour
35
+ - `stitchkit/cli` — a `GET` command declaring `destructiveHint: true` without `readOnlyHint`
36
+ keeps its result on stdout after a refused view; it was treated as a read. → ADR 0287
37
+ **Affects:** `stitchkit/cli` behaviour
38
+
18
39
  ## [0.122.0] - 2026-11-10
19
40
 
20
41
  ### ⚠️ Breaking changes
@@ -16,13 +16,14 @@ import {
16
16
  renderCliView2,
17
17
  pollUntilDone2,
18
18
  createCli2
19
- } from "../index-v8yqk4w7.js";
19
+ } from "../index-aswegq1r.js";
20
20
  import"../index-k42ckyzx.js";
21
21
  import"../index-ct75c3at.js";
22
22
  import"../index-x4p3kw1p.js";
23
23
  import"../index-s3yxw6kt.js";
24
24
  import"../index-69t14s4a.js";
25
25
  import"../index-ycqhyars.js";
26
+ import"../index-332d0m9g.js";
26
27
  import"../index-m5m9rmvt.js";
27
28
  import {
28
29
  CliBuildSignatureSchema2,
@@ -1,3 +1,6 @@
1
+ import {
2
+ readDiscoveredToolAnnotations
3
+ } from "../../index-332d0m9g.js";
1
4
  import"../../index-69t14s4a.js";
2
5
  import"../../index-ct75c3at.js";
3
6
  import {
@@ -919,6 +922,7 @@ async function mountMcpConnection(connection, instanceId, onSkipped) {
919
922
  name,
920
923
  description,
921
924
  identity: { serviceName: connection.name, action: name, method: "POST" },
925
+ ...tool.annotations && { annotations: tool.annotations },
922
926
  ...connection.transports && { transports: connection.transports },
923
927
  input,
924
928
  output: z2.unknown(),
@@ -945,10 +949,12 @@ function readDiscoveredTools(listed, connectionName) {
945
949
  for (const raw of listed.tools) {
946
950
  if (!isRecord(raw) || typeof raw.name !== "string")
947
951
  continue;
952
+ const annotations = readDiscoveredToolAnnotations(raw.annotations);
948
953
  tools.push({
949
954
  name: raw.name,
950
955
  ...typeof raw.description === "string" && { description: raw.description },
951
- ...isRecord(raw.inputSchema) && { inputSchema: raw.inputSchema }
956
+ ...isRecord(raw.inputSchema) && { inputSchema: raw.inputSchema },
957
+ ...annotations && { annotations }
952
958
  });
953
959
  }
954
960
  return tools;
@@ -1,4 +1,5 @@
1
1
  import"../../index-ct75c3at.js";
2
+ import"../../index-332d0m9g.js";
2
3
  import"../../index-k42ckyzx.js";
3
4
  import"../../index-dsa676h8.js";
4
5
  import"../../index-rbzq0q16.js";
@@ -20,7 +21,7 @@ import {
20
21
  createMcpHandler2,
21
22
  createMcpHttpRoute2,
22
23
  createStdioMcpServer2
23
- } from "../../index-knmnj11j.js";
24
+ } from "../../index-y6ye582c.js";
24
25
  import {
25
26
  DEFAULT_PROCESS_SIGNALS,
26
27
  defaultSignalSource,
@@ -11,14 +11,15 @@ import {
11
11
  } from "../../index-1fyea34p.js";
12
12
  import {
13
13
  createCli2
14
- } from "../../index-v8yqk4w7.js";
14
+ } from "../../index-aswegq1r.js";
15
+ import"../../index-332d0m9g.js";
15
16
  import"../../index-m5m9rmvt.js";
16
17
  import {
17
18
  mountMcp2,
18
19
  buildMcpServer2,
19
20
  createMcpHandler2,
20
21
  createStdioMcpServer2
21
- } from "../../index-knmnj11j.js";
22
+ } from "../../index-y6ye582c.js";
22
23
  import"../../index-aqmadanx.js";
23
24
  import"../../index-eeahxwvg.js";
24
25
  import"../../index-ff39f9dr.js";
@@ -0,0 +1,37 @@
1
+ // src/tools/read-operation.ts
2
+ import { z } from "zod";
3
+ function isRepeatableRead(operation) {
4
+ const declared = operation.annotations;
5
+ if (declared?.readOnlyHint !== undefined)
6
+ return declared.readOnlyHint;
7
+ return operation.method === "GET" && declared?.destructiveHint !== true;
8
+ }
9
+ function publishedToolAnnotations(operation) {
10
+ const declared = operation.annotations;
11
+ if (declared?.readOnlyHint !== undefined || !isRepeatableRead(operation))
12
+ return declared;
13
+ return { ...declared, readOnlyHint: true };
14
+ }
15
+ var DiscoveredToolAnnotationsSchema = z.object({
16
+ title: z.string().optional().catch(undefined),
17
+ readOnlyHint: z.boolean().optional().catch(undefined),
18
+ destructiveHint: z.boolean().optional().catch(undefined),
19
+ idempotentHint: z.boolean().optional().catch(undefined),
20
+ openWorldHint: z.boolean().optional().catch(undefined)
21
+ });
22
+ function readDiscoveredToolAnnotations(raw) {
23
+ const parsed = DiscoveredToolAnnotationsSchema.safeParse(raw);
24
+ if (!parsed.success)
25
+ return;
26
+ const { title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint } = parsed.data;
27
+ const annotations = {
28
+ ...title !== undefined && { title },
29
+ ...readOnlyHint !== undefined && { readOnlyHint },
30
+ ...destructiveHint !== undefined && { destructiveHint },
31
+ ...idempotentHint !== undefined && { idempotentHint },
32
+ ...openWorldHint !== undefined && { openWorldHint }
33
+ };
34
+ return Object.keys(annotations).length > 0 ? annotations : undefined;
35
+ }
36
+
37
+ export { isRepeatableRead, publishedToolAnnotations, readDiscoveredToolAnnotations };
@@ -23,6 +23,9 @@ import {
23
23
  createToolRunner,
24
24
  formatToolError
25
25
  } from "./index-ycqhyars.js";
26
+ import {
27
+ isRepeatableRead
28
+ } from "./index-332d0m9g.js";
26
29
  import {
27
30
  writeContainedFile
28
31
  } from "./index-aqmadanx.js";
@@ -1782,11 +1785,6 @@ async function prepareInvocation(command, commandArgv, descriptor, config, readS
1782
1785
  return { ok: true, toolArgs, options };
1783
1786
  }
1784
1787
 
1785
- // src/tools/cli/repeatable-read.ts
1786
- function isRepeatableRead(operation) {
1787
- return operation.annotations?.readOnlyHint ?? operation.method === "GET";
1788
- }
1789
-
1790
1788
  // src/tools/cli/session.ts
1791
1789
  function nativeDescriptor(definition) {
1792
1790
  return {
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  toJsonSchema
3
3
  } from "./index-ct75c3at.js";
4
+ import {
5
+ publishedToolAnnotations
6
+ } from "./index-332d0m9g.js";
4
7
  import {
5
8
  toolSurfaceOutputSchema,
6
9
  staticInputRounds,
@@ -86,7 +89,7 @@ function toolFingerprint(descriptor) {
86
89
  description: mountable.method.desc,
87
90
  input: descriptor.inputSchema,
88
91
  output: descriptor.outputSchema ? toJsonSchema(descriptor.outputSchema, "output", "any") : null,
89
- annotations: mountable.method.annotations ?? null
92
+ annotations: publishedToolAnnotations(mountable.method) ?? null
90
93
  };
91
94
  }
92
95
  function mcpCatalogStamp(surface) {
@@ -556,8 +559,9 @@ function registerMcpTool(server, presentation, descriptor, config) {
556
559
  };
557
560
  if (descriptor.outputSchema)
558
561
  toolConfig.outputSchema = descriptor.outputSchema;
559
- if (presentation.annotations)
560
- toolConfig.annotations = presentation.annotations;
562
+ const annotations = publishedToolAnnotations(mountable.method);
563
+ if (annotations)
564
+ toolConfig.annotations = annotations;
561
565
  if (presentation.ui) {
562
566
  toolConfig._meta = {
563
567
  ui: presentation.ui,
@@ -665,7 +669,6 @@ function mountPreparedRuntimeMcp(server, tools, config) {
665
669
  registerMcpTool(server, {
666
670
  name: definition.name,
667
671
  description: definition.description,
668
- annotations: definition.annotations,
669
672
  ui: definition.ui,
670
673
  ...present && { present }
671
674
  }, descriptor, {
@@ -716,7 +719,6 @@ function mountPreparedMcp(mcpServer, prepared, config = {}) {
716
719
  registerMcpTool(mcpServer, {
717
720
  name,
718
721
  description: method.desc,
719
- annotations: method.annotations,
720
722
  ui: method.ui
721
723
  }, descriptor, {
722
724
  runTool,
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../../src/tools/connections/mcp.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAIhF,OAAO,EACL,KAAK,0BAA0B,EAIhC,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,SAAS,CAAC;AAQlE,gEAAgE;AAChE,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,mBAAmB,EAC/B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,0BAA0B,GACpC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAsElC"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../../src/tools/connections/mcp.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAIhF,OAAO,EACL,KAAK,0BAA0B,EAIhC,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,SAAS,CAAC;AAUlE,gEAAgE;AAChE,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,mBAAmB,EAC/B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,0BAA0B,GACpC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAyElC"}
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/catalog.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAmB,MAAM,WAAW,CAAC;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAExD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAwBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,wBAAwB,GAAG,eAAe,CAclF;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAQzE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,SAAS;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACvF,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,eAAe,GAAG,SAAS,GACjC,OAAO,CAGT;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACjF,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,eAAe,GAAG,SAAS,GACjC,OAAO,CAGT"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/catalog.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAmB,MAAM,WAAW,CAAC;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAExD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAyBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,wBAAwB,GAAG,eAAe,CAclF;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAQzE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,SAAS;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACvF,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,eAAe,GAAG,SAAS,GACjC,OAAO,CAGT;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACjF,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,eAAe,GAAG,SAAS,GACjC,OAAO,CAGT"}
@@ -1 +1 @@
1
- {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/mount.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/mount.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type CallToolResult, type McpServer } from '@modelcontextprotocol/server';
2
- import type { EndpointToolAnnotations, EndpointUiMeta } from '../../contract/tool-options.js';
2
+ import type { EndpointUiMeta } from '../../contract/tool-options.js';
3
3
  import type { ToolExecutionOptions } from '../execute.js';
4
4
  import type { ToolCallHooks } from '../execute-hooks.js';
5
5
  import { type ToolResult } from '../execute-result.js';
@@ -11,7 +11,6 @@ import { type McpRoundRuntime } from './round.js';
11
11
  export interface McpToolPresentation {
12
12
  name: string;
13
13
  description: string;
14
- annotations?: EndpointToolAnnotations;
15
14
  ui?: EndpointUiMeta;
16
15
  /** A runtime tool's own MCP answer, built from its validated output. */
17
16
  present?(data: unknown): unknown | Promise<unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/register.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,SAAS,EACf,MAAM,8BAA8B,CAAC;AAGtC,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,KAAK,UAAU,EAAuB,MAAM,mBAAmB,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,OAAO,EAAE,KAAK,eAAe,EAA0C,MAAM,WAAW,CAAC;AACzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,KAAK,eAAe,EAAmB,MAAM,SAAS,CAAC;AAIhE,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,wEAAwE;IACxE,OAAO,CAAC,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrD;AAED,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,OAAO,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,KACnD,OAAO,CAAC,UAAU,CAAC,CAAC;AAEzB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,CACZ,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,eAAe,CAAC,YAAY,CAAC,EACnC,QAAQ,EAAE,MAAM,KACb,cAAc,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,iBAAiB,CAAC,EAAE,eAAe,CAAC;IACpC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,mBAAmB,EACjC,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,yBAAyB,GAChC,IAAI,CA8HN"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/register.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,SAAS,EACf,MAAM,8BAA8B,CAAC;AAGtC,OAAO,KAAK,EAA2B,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,KAAK,UAAU,EAAuB,MAAM,mBAAmB,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,OAAO,EAAE,KAAK,eAAe,EAA0C,MAAM,WAAW,CAAC;AACzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,KAAK,eAAe,EAAmB,MAAM,SAAS,CAAC;AAIhE,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,wEAAwE;IACxE,OAAO,CAAC,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrD;AAED,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,OAAO,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,KACnD,OAAO,CAAC,UAAU,CAAC,CAAC;AAEzB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,CACZ,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,eAAe,CAAC,YAAY,CAAC,EACnC,QAAQ,EAAE,MAAM,KACb,cAAc,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,iBAAiB,CAAC,EAAE,eAAe,CAAC;IACpC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,mBAAmB,EACjC,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,yBAAyB,GAChC,IAAI,CAiIN"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/runtime-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,UAAU,sBAAsB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC5D,iBAAiB,CAAC,EAAE,eAAe,CAAC;IACpC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,CACZ,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,sBAAsB,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,EACxD,QAAQ,EAAE,MAAM,KACb,cAAc,CAAC;CACrB;AAaD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,sBAAsB,EAAE,EACxC,MAAM,EAAE,sBAAsB,GAC7B,IAAI,CAkCN"}
1
+ {"version":3,"file":"runtime-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/mcp/runtime-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,UAAU,sBAAsB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC5D,iBAAiB,CAAC,EAAE,eAAe,CAAC;IACpC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,CACZ,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,sBAAsB,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,EACxD,QAAQ,EAAE,MAAM,KACb,cAAc,CAAC;CACrB;AAaD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,sBAAsB,EAAE,EACxC,MAAM,EAAE,sBAAsB,GAC7B,IAAI,CAiCN"}
@@ -0,0 +1,21 @@
1
+ import type { EndpointToolAnnotations } from '../contract/tool-options.js';
2
+ import type { OperationIdentity } from '../server/types.js';
3
+ type Operation = Pick<OperationIdentity, 'method' | 'annotations'>;
4
+ /**
5
+ * Whether calling the operation again returns its answer without a new effect.
6
+ *
7
+ * The declared `readOnlyHint` decides in either direction. Without one, `GET`
8
+ * is the contract's own statement that the endpoint reads — unless it declares
9
+ * `destructiveHint: true`, which says the opposite in the same breath.
10
+ */
11
+ export declare function isRepeatableRead(operation: Operation): boolean;
12
+ /**
13
+ * The annotations a tool surface publishes for the operation: the declared
14
+ * ones, with `readOnlyHint: true` stated for a read that declared none. A
15
+ * declared `readOnlyHint`, either way, is published as written.
16
+ */
17
+ export declare function publishedToolAnnotations(operation: Operation): EndpointToolAnnotations | undefined;
18
+ /** The hints another MCP server published for one of its tools, or `undefined` when it gave none. */
19
+ export declare function readDiscoveredToolAnnotations(raw: unknown): EndpointToolAnnotations | undefined;
20
+ export {};
21
+ //# sourceMappingURL=read-operation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-operation.d.ts","sourceRoot":"","sources":["../../src/tools/read-operation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,KAAK,SAAS,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,aAAa,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAI9D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GACnB,uBAAuB,GAAG,SAAS,CAIrC;AAeD,qGAAqG;AACrG,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,OAAO,GACX,uBAAuB,GAAG,SAAS,CAYrC"}
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` on a `GET`
722
- endpoint keeps the result on stdout. A native `defineCliCommand` declares neither fact,
723
- so a failed `present` always keeps the validated result on stdout.
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:
@@ -10847,9 +10877,18 @@ and `details.resultOnStdout` states which case occurred:
10847
10877
  | only reads | nothing | repeating the command with a corrected view |
10848
10878
 
10849
10879
  A managed command only reads when its tool declares `annotations.readOnlyHint: true`,
10850
- or declares no `readOnlyHint` and its method is `GET`. `readOnlyHint: false` on a `GET`
10851
- endpoint keeps the result on stdout. A native `defineCliCommand` declares neither fact,
10852
- so a failed `present` always keeps the validated result on stdout.
10880
+ or declares no `readOnlyHint` and its method is `GET`. `readOnlyHint: false`, or
10881
+ `destructiveHint: true` without a `readOnlyHint`, on a `GET` endpoint keeps the result on stdout. A native
10882
+ `defineCliCommand` declares neither fact, so a failed `present` always keeps the validated
10883
+ result on stdout.
10884
+
10885
+ A CLI that mounts a server's tools through `defineMcpClientConnection` never sees the
10886
+ method — every MCP call is a `POST` — so it reads the `readOnlyHint` the server
10887
+ publishes. A Stitchkit server publishes it for every `GET` by the rule above
10888
+ ([MCP → `readOnlyHint`](./mcp-and-agents.md#saying-which-tools-only-read--readonlyhint)),
10889
+ so the same command behaves the same over the contract and over MCP. The hint is the
10890
+ server's word: a server that labels a write as read-only makes the CLI withhold that
10891
+ write's result on a refused view, and repeating the command repeats the effect.
10853
10892
 
10854
10893
  CLI argument errors detected before execution still exit with `2`
10855
10894
  and have no successful result to preserve.
package/llms.txt CHANGED
@@ -14,14 +14,14 @@ 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) 47.0 KB → [llms/tools.2.txt](llms/tools.2.txt) 30.5 KB → [llms/tools.3.txt](llms/tools.3.txt) 21.0 KB
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.2 KB → [llms/cli.2.txt](llms/cli.2.txt) 36.4 KB
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.122.0",
3
+ "version": "0.122.1",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",
@@ -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"}