stitchkit 0.43.0 → 0.44.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/README.md +12 -4
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/http.d.ts +2 -1
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/browser/request-id.d.ts +3 -0
- package/dist/browser/request-id.d.ts.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/contract/define.d.ts +18 -0
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/{index-310bfer5.js → index-36f1xkdb.js} +1 -1
- package/dist/{index-esqmem78.js → index-4fyn9f09.js} +2 -1
- package/dist/{index-h2wdcsby.js → index-mvjyq9h9.js} +176 -12
- package/dist/{index-gex6gxhe.js → index-yh0p5ddn.js} +34 -2
- package/dist/index.js +19 -7
- package/dist/internal/secure-fetch.d.ts +21 -1
- package/dist/internal/secure-fetch.d.ts.map +1 -1
- package/dist/node.js +2 -2
- package/dist/observability/audit.d.ts.map +1 -1
- package/dist/observability/event.d.ts +16 -0
- package/dist/observability/event.d.ts.map +1 -1
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +30 -1
- package/dist/observability/trace.d.ts +10 -0
- package/dist/observability/trace.d.ts.map +1 -1
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/types.d.ts +14 -2
- package/dist/server/types.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/mcp-app.d.ts +3 -0
- package/dist/tools/mcp-app.d.ts.map +1 -1
- package/dist/tools/mcp-handler.d.ts +34 -23
- package/dist/tools/mcp-handler.d.ts.map +1 -1
- package/dist/tools/mcp-round.d.ts +43 -0
- package/dist/tools/mcp-round.d.ts.map +1 -0
- package/dist/tools/mcp-stdio.d.ts +11 -18
- package/dist/tools/mcp-stdio.d.ts.map +1 -1
- package/dist/tools/mcp-trace.d.ts +4 -0
- package/dist/tools/mcp-trace.d.ts.map +1 -0
- package/dist/tools/mcp.d.ts +24 -3
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/mount-download.d.ts +2 -2
- package/dist/tools/mount-download.d.ts.map +1 -1
- package/dist/tools/mount-upload.d.ts +1 -1
- package/dist/tools/mount-upload.d.ts.map +1 -1
- package/dist/tools/mount-wait.d.ts +3 -3
- package/dist/tools/mount-wait.d.ts.map +1 -1
- package/dist/tools/mount.d.ts +1 -1
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/native-mcp.d.ts +3 -2
- package/dist/tools/native-mcp.d.ts.map +1 -1
- package/dist/tools/oauth-provider.d.ts +77 -7
- package/dist/tools/oauth-provider.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts +27 -20
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools/toolkit.d.ts +5 -5
- package/dist/tools/toolkit.d.ts.map +1 -1
- package/dist/tools/view-file.d.ts +1 -1
- package/dist/tools/view-file.d.ts.map +1 -1
- package/dist/tools.d.ts +5 -5
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +829 -200
- package/llms-full.txt +424 -82
- package/package.json +5 -4
package/llms-full.txt
CHANGED
|
@@ -27,7 +27,7 @@ bun add stitchkit zod
|
|
|
27
27
|
|
|
28
28
|
`zod` is a required peer — schemas are the source of truth everywhere. Other
|
|
29
29
|
peers are optional and pulled in only when you use the matching feature
|
|
30
|
-
(`@modelcontextprotocol/
|
|
30
|
+
(`@modelcontextprotocol/server` for MCP servers, `ai` for agents, `socket.io*` for
|
|
31
31
|
realtime, `@tanstack/react-query` + `react-query-kit` for React). See
|
|
32
32
|
[deps](#dependencies) below.
|
|
33
33
|
|
|
@@ -141,9 +141,9 @@ map — feature → packages:
|
|
|
141
141
|
| anything (validation) | `zod` |
|
|
142
142
|
| `createServer` (Bun) | — (uses `Bun.serve`) |
|
|
143
143
|
| `serveNode` (Node ≥ 22) | `srvx` (+ `@types/bun` dev) |
|
|
144
|
-
| MCP tools (`stitchkit/tools`) | `@modelcontextprotocol/
|
|
144
|
+
| MCP / agent tools (`stitchkit/tools`) | `@modelcontextprotocol/server` `ai` |
|
|
145
|
+
| MCP host/client tests | `@modelcontextprotocol/client` |
|
|
145
146
|
| MCP Apps UI widgets | `@modelcontextprotocol/ext-apps` |
|
|
146
|
-
| agent tools (`stitchkit/tools`) | `ai` |
|
|
147
147
|
| React data layer (`stitchkit/react`) | `@tanstack/react-query` `react-query-kit` |
|
|
148
148
|
| **Socket.IO server on Bun** | `socket.io` `@socket.io/bun-engine` |
|
|
149
149
|
| **Socket.IO server on Node** | `socket.io` |
|
|
@@ -153,9 +153,22 @@ map — feature → packages:
|
|
|
153
153
|
bun add socket.io @socket.io/bun-engine # e.g. the Socket.IO server on Bun
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
Dynamic optional-peer adapters fail with an actionable error naming the package
|
|
157
|
+
and install command. Static entrypoints such as `stitchkit/tools` fail during
|
|
158
|
+
ESM resolution by naming the exact missing package; the feature-to-peer matrix
|
|
159
|
+
below is the canonical install command.
|
|
160
|
+
|
|
161
|
+
The combined tools entry owns MCP and AI-agent adapters, so install both runtime
|
|
162
|
+
peers before importing `stitchkit/tools`:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
bun add @modelcontextprotocol/server@^2 ai@^7
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Browser, HTTP-client and React entrypoints remain usable without either MCP
|
|
169
|
+
package. MCP hosts and client E2E additionally install
|
|
170
|
+
`@modelcontextprotocol/client@^2`; Apps additionally install
|
|
171
|
+
`@modelcontextprotocol/ext-apps`.
|
|
159
172
|
|
|
160
173
|
## Next
|
|
161
174
|
|
|
@@ -1546,10 +1559,16 @@ try {
|
|
|
1546
1559
|
err.message // 'Note not found'
|
|
1547
1560
|
err.details // structured details, if any
|
|
1548
1561
|
err.hint // optional hint
|
|
1562
|
+
err.traceId // x-request-id — correlate this failure with backend logs
|
|
1549
1563
|
}
|
|
1550
1564
|
}
|
|
1551
1565
|
```
|
|
1552
1566
|
|
|
1567
|
+
`traceId` is present when the server returned `x-request-id`. A network error,
|
|
1568
|
+
timeout or abort without an HTTP response cannot carry one. Cross-origin
|
|
1569
|
+
browser code can read it through Stitchkit's default CORS expose list; a custom
|
|
1570
|
+
`cors.exposeHeaders` policy must keep `x-request-id` exposed.
|
|
1571
|
+
|
|
1553
1572
|
The error model is shared with the server — see [Auth & errors](./auth-and-errors.md).
|
|
1554
1573
|
|
|
1555
1574
|
## Auth events
|
|
@@ -1798,27 +1817,28 @@ the invoker is created.
|
|
|
1798
1817
|
|
|
1799
1818
|
## MCP — `createMcpHandler`
|
|
1800
1819
|
|
|
1801
|
-
`createMcpHandler` builds a complete Streamable-HTTP MCP
|
|
1802
|
-
|
|
1803
|
-
|
|
1820
|
+
`createMcpHandler` builds a complete stateless Streamable-HTTP MCP endpoint on
|
|
1821
|
+
the official TypeScript SDK v2 server package. It owns server creation,
|
|
1822
|
+
protocol-era negotiation and shutdown; application code does not import the SDK
|
|
1823
|
+
to mount a normal endpoint.
|
|
1804
1824
|
|
|
1805
1825
|
```ts
|
|
1806
|
-
import { createMcpHandler } from 'stitchkit/tools'
|
|
1826
|
+
import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools'
|
|
1827
|
+
import { createServer } from 'stitchkit/server'
|
|
1807
1828
|
|
|
1808
|
-
const
|
|
1829
|
+
const mcp = createMcpHandler({
|
|
1809
1830
|
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
1810
1831
|
auth: (req) => resolveApiKey(req), // → an identity, or null for 401
|
|
1811
1832
|
services: [usersService, catalogService],
|
|
1812
1833
|
})
|
|
1813
|
-
```
|
|
1814
|
-
|
|
1815
|
-
Mount the returned handler on a raw route — typically `/mcp`:
|
|
1816
1834
|
|
|
1817
|
-
```ts
|
|
1818
1835
|
createServer({
|
|
1819
1836
|
services,
|
|
1820
|
-
rawRoutes: [{
|
|
1837
|
+
rawRoutes: [createMcpHttpRoute({ path: '/mcp', handler: mcp })],
|
|
1821
1838
|
})
|
|
1839
|
+
|
|
1840
|
+
// During graceful shutdown:
|
|
1841
|
+
await mcp.close()
|
|
1822
1842
|
```
|
|
1823
1843
|
|
|
1824
1844
|
### `McpHandlerConfig`
|
|
@@ -1833,6 +1853,7 @@ createServer({
|
|
|
1833
1853
|
| `selectSurface` | `(auth) => declaredKey` — required with `surfaces` |
|
|
1834
1854
|
| `context` | `(auth) => {…}` — values merged into every tool handler's `ctx` |
|
|
1835
1855
|
| `lifecycle` | `beforeHandle` / `afterHandle` — the tool-side auth gate (see below) |
|
|
1856
|
+
| `multiRound` | Typed MRTR state policy for guarded multi-round tool calls |
|
|
1836
1857
|
| `hooks` | tool-call observability hooks — `afterToolCall` fires on every result |
|
|
1837
1858
|
| `extend` | extra advertised arguments resolved into handler context |
|
|
1838
1859
|
| `schemaValidation` | compatibility policy, typed-property guard and portable-format guard |
|
|
@@ -1845,7 +1866,10 @@ createServer({
|
|
|
1845
1866
|
| `errorHint` | add a project-owned hint to failed tool results |
|
|
1846
1867
|
| `onOutputStrip` | observe output keys removed by contract validation |
|
|
1847
1868
|
| `protectedResource` | RFC 9728 metadata used by HTTP `401` responses |
|
|
1848
|
-
| `
|
|
1869
|
+
| `legacy` | `'serve'` (default) or `'reject'` for pre-2026 clients |
|
|
1870
|
+
| `security` | optional Host/Origin allowlists at the Fetch boundary |
|
|
1871
|
+
| `onTransportRejected` | observe HTTP/protocol rejections without entering lifecycle or tool hooks |
|
|
1872
|
+
| `cache` | explicit operation cache hints; omitted means zero/private |
|
|
1849
1873
|
|
|
1850
1874
|
Direct `services` / `runtimeTools` factories, `context`, `selectSurface` and
|
|
1851
1875
|
`rawTools` receive the resolved identity, so a tenant can be shown only its own
|
|
@@ -1870,20 +1894,106 @@ const handleMcp = createMcpHandler({
|
|
|
1870
1894
|
Every declared entry is schema-validated and prepared once when the handler is
|
|
1871
1895
|
constructed. The selected immutable descriptors are shared; the SDK server,
|
|
1872
1896
|
transport, auth-derived context, lifecycle runner and tool-call context are
|
|
1873
|
-
fresh for every
|
|
1897
|
+
fresh for every request. Unknown keys
|
|
1874
1898
|
fail before the server connects. The registry never retains auth values.
|
|
1875
1899
|
|
|
1876
|
-
### Stateless
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
load balancing cannot strand a client on an in-memory session.
|
|
1900
|
+
### Stateless transport and protocol eras
|
|
1901
|
+
|
|
1902
|
+
Every request gets a fresh SDK server, resolved auth/context and tool-call
|
|
1903
|
+
runner. Static direct and finite registry schemas are still prepared once when
|
|
1904
|
+
the handler is constructed. There is no session map, event store,
|
|
1905
|
+
`Mcp-Session-Id` or resumable cross-request SSE state. Process replacement and
|
|
1906
|
+
load balancing therefore cannot strand a client on an in-memory session.
|
|
1907
|
+
|
|
1908
|
+
The default `legacy: 'serve'` lets the official SDK negotiate either modern
|
|
1909
|
+
`2026-07-28` or the supported legacy stateless opening on this same endpoint.
|
|
1910
|
+
Set `legacy: 'reject'` when every host is modern. Legacy support is protocol
|
|
1911
|
+
translation inside the SDK, not a second Stitchkit transport or compatibility
|
|
1912
|
+
API. Stateful MCP and subscriptions are intentionally outside this layer.
|
|
1913
|
+
|
|
1914
|
+
`createMcpHttpRoute` is the framework-owned raw-route adapter. It registers
|
|
1915
|
+
`ALL` because Streamable HTTP uses multiple HTTP methods, delegates only to
|
|
1916
|
+
`handler.fetch`, and leaves lifecycle ownership with the returned handler.
|
|
1917
|
+
|
|
1918
|
+
By default, a present `Host` header must match the request URL and a present
|
|
1919
|
+
browser `Origin` must be same-origin. Non-browser hosts may omit `Origin`. Behind
|
|
1920
|
+
a trusted reverse proxy, reconstruct the public request URL before calling the
|
|
1921
|
+
handler or configure exact `security.allowedHosts` / `allowedOrigins`; never
|
|
1922
|
+
copy arbitrary forwarded headers into the trusted URL. If a browser calls MCP
|
|
1923
|
+
cross-origin, its HTTP server or gateway must also answer CORS preflight and
|
|
1924
|
+
expose the protocol headers. `onTransportRejected` is the audit boundary for
|
|
1925
|
+
HTTP/security rejections; it is deliberately separate from tool lifecycle and
|
|
1926
|
+
must not be used as authorization input.
|
|
1927
|
+
|
|
1928
|
+
### Modern discovery, routing and cache hints
|
|
1929
|
+
|
|
1930
|
+
Stitchkit forwards the negotiated protocol era and validated MCP request data
|
|
1931
|
+
to `RequestEvent.mcp`; untrusted routing headers never become application
|
|
1932
|
+
identity. The SDK validates `MCP-Protocol-Version`, JSON-RPC shape and routing
|
|
1933
|
+
metadata before lifecycle or tool handlers run. Framework-owned tool and
|
|
1934
|
+
resource registration preserves declaration order across HTTP and stdio. Tool
|
|
1935
|
+
manifests preserve mount order; `listToolNames` is a sorted diagnostics view.
|
|
1936
|
+
Consumer-owned raw SDK registrations are outside this guarantee.
|
|
1937
|
+
|
|
1938
|
+
Caching is opt-in. `cache.operations` maps directly to SDK v2 operation cache
|
|
1939
|
+
hints, while each `McpResourceDef` may declare its own `cacheHint`. Omission
|
|
1940
|
+
means zero/private: neither a prepared surface nor a deterministic response is
|
|
1941
|
+
silently treated as public. Unbounded auth-selected surface factories are
|
|
1942
|
+
always forced to zero/private even when an operation policy is present; use a
|
|
1943
|
+
finite `surfaces` registry when identities share a provably immutable surface.
|
|
1944
|
+
Stitchkit never advertises list-change or subscription capabilities
|
|
1945
|
+
without an implementation.
|
|
1946
|
+
|
|
1947
|
+
### Multi-round tool input (`input_required`)
|
|
1948
|
+
|
|
1949
|
+
An MCP-only operation can require typed user input before its final side effect:
|
|
1950
|
+
|
|
1951
|
+
```ts
|
|
1952
|
+
const DeleteConfirmationSchema = z.object({ confirmed: z.boolean() })
|
|
1953
|
+
|
|
1954
|
+
deleteProject: {
|
|
1955
|
+
method: 'DELETE',
|
|
1956
|
+
path: '/projects/:id',
|
|
1957
|
+
expose: ['MCP'],
|
|
1958
|
+
input: DeleteProjectSchema,
|
|
1959
|
+
output: DeleteProjectResultSchema,
|
|
1960
|
+
mcp: {
|
|
1961
|
+
inputRequired: [
|
|
1962
|
+
{
|
|
1963
|
+
key: 'confirmation',
|
|
1964
|
+
schema: DeleteConfirmationSchema,
|
|
1965
|
+
message: 'Confirm permanent deletion',
|
|
1966
|
+
},
|
|
1967
|
+
{
|
|
1968
|
+
key: 'reason',
|
|
1969
|
+
schema: z.object({ value: z.string().min(3) }),
|
|
1970
|
+
message: 'Record the reason',
|
|
1971
|
+
},
|
|
1972
|
+
],
|
|
1973
|
+
},
|
|
1974
|
+
}
|
|
1975
|
+
```
|
|
1883
1976
|
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1977
|
+
Each continuation accepts exactly the currently requested item. Only after the
|
|
1978
|
+
ordered sequence completes does the handler receive the exact aggregate as
|
|
1979
|
+
`ctx.mcpInput.confirmation` and `ctx.mcpInput.reason`; before then the framework
|
|
1980
|
+
returns `input_required` without calling it. Set
|
|
1981
|
+
`multiRound.serving.maxRounds` to the maximum declaration size you accept
|
|
1982
|
+
(default `10`); empty sequences, duplicate keys and overflow fail first. State
|
|
1983
|
+
is bound to principal, full operation identity, current round, accepted
|
|
1984
|
+
aggregate and canonical original-argument digest and is
|
|
1985
|
+
expiry-checked. Tampered, expired, cross-user or cross-tool state fails before
|
|
1986
|
+
the side effect. Output validation applies only to the final result.
|
|
1987
|
+
|
|
1988
|
+
Every attempt re-runs auth/lifecycle and emits its own tool hooks; audit metadata
|
|
1989
|
+
contains the attempt's `mcp.outcome` and `mcp.round`. Stitchkit does not merge
|
|
1990
|
+
separate HTTP attempts into one logical trace. Parallel
|
|
1991
|
+
rounds have isolated context. HTTP/stdio modern hosts and the supported legacy
|
|
1992
|
+
stdio bridge may use this declaration; Agent, CLI and ordinary HTTP invocation
|
|
1993
|
+
remain single-round and unchanged. Hosts without the capability receive an
|
|
1994
|
+
ordinary unsupported result rather than a falsely advertised round. Signed
|
|
1995
|
+
state is tamper-resistant, not an exactly-once replay store; destructive
|
|
1996
|
+
handlers must still be idempotent where retries matter.
|
|
1887
1997
|
|
|
1888
1998
|
### Guarding tools — `lifecycle`
|
|
1889
1999
|
|
|
@@ -1942,9 +2052,9 @@ cannot become a tool. `schemaValidation.policy` decides what happens:
|
|
|
1942
2052
|
startup assertion or a test.
|
|
1943
2053
|
|
|
1944
2054
|
For a static `services` array, collection, schema conversion and every enabled
|
|
1945
|
-
validation guard run once when the handler is created. Each HTTP request
|
|
1946
|
-
|
|
1947
|
-
|
|
2055
|
+
validation guard run once when the handler is created. Each HTTP request still
|
|
2056
|
+
receives a fresh `McpServer`, runner, context and native registration over that
|
|
2057
|
+
immutable prepared surface. A `services(auth)` factory
|
|
1948
2058
|
is deliberately prepared after resolving each identity because its tool set may
|
|
1949
2059
|
change by tenant.
|
|
1950
2060
|
|
|
@@ -2051,11 +2161,14 @@ it can reach the local filesystem.
|
|
|
2051
2161
|
```ts
|
|
2052
2162
|
import { createStdioMcpServer } from 'stitchkit/tools'
|
|
2053
2163
|
|
|
2054
|
-
await createStdioMcpServer({
|
|
2164
|
+
const stdio = await createStdioMcpServer({
|
|
2055
2165
|
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
2056
2166
|
auth: resolveIdentity(), // resolved once at startup, not per request
|
|
2057
2167
|
services: [usersService],
|
|
2058
2168
|
})
|
|
2169
|
+
|
|
2170
|
+
// During graceful shutdown:
|
|
2171
|
+
await stdio.close()
|
|
2059
2172
|
```
|
|
2060
2173
|
|
|
2061
2174
|
A stdio server is a single process serving one client, so `auth` is a value (or
|
|
@@ -2063,6 +2176,11 @@ a promise of one) resolved once at startup — typically from an env var — rat
|
|
|
2063
2176
|
than a per-request `(req) => …`. Keep all logging on **stderr**: stdout is the
|
|
2064
2177
|
JSON-RPC channel.
|
|
2065
2178
|
|
|
2179
|
+
The default `legacy: 'serve'` negotiates the modern or supported legacy opening
|
|
2180
|
+
through the official stdio adapter. Use `legacy: 'reject'` for a modern-only
|
|
2181
|
+
binary. Each invocation builds a fresh server; the returned handle owns
|
|
2182
|
+
transport shutdown.
|
|
2183
|
+
|
|
2066
2184
|
Both transports build the server through the shared `buildMcpServer` — same
|
|
2067
2185
|
contract/runtime pipeline, same surface selection, context, hooks, raw escape
|
|
2068
2186
|
hatch and instructions.
|
|
@@ -2071,41 +2189,45 @@ hatch and instructions.
|
|
|
2071
2189
|
|
|
2072
2190
|
A remote MCP server is connectable from Claude (Desktop / web "custom
|
|
2073
2191
|
connector") only through the MCP authorization spec: OAuth 2.1 with PKCE, plus
|
|
2074
|
-
the discovery documents (RFC 9728 / 8414),
|
|
2075
|
-
|
|
2192
|
+
the discovery documents (RFC 9728 / 8414), Client ID Metadata Documents (CIMD)
|
|
2193
|
+
and resource indicators (RFC 8707). A Bearer-only server returns a
|
|
2076
2194
|
bare `401` and the connector never establishes.
|
|
2077
2195
|
|
|
2078
2196
|
stitchkit ships the OAuth **protocol mechanics**; the app supplies only
|
|
2079
2197
|
**identity and storage**. Three pieces wire it together:
|
|
2080
2198
|
|
|
2081
2199
|
```ts
|
|
2082
|
-
import { createMcpHandler, mountOAuthProvider, oauthProtectedResourceRoute } from 'stitchkit/tools'
|
|
2200
|
+
import { createMcpHandler, createMcpHttpRoute, mountOAuthProvider, oauthProtectedResourceRoute } from 'stitchkit/tools'
|
|
2083
2201
|
import { createServer } from 'stitchkit/server'
|
|
2084
2202
|
|
|
2085
2203
|
const resource = 'https://api.example.com/mcp'
|
|
2086
2204
|
const issuer = 'https://api.example.com'
|
|
2087
2205
|
|
|
2088
2206
|
// 1. Resource server — the 401 now points at the metadata.
|
|
2089
|
-
const
|
|
2207
|
+
const mcp = createMcpHandler({
|
|
2090
2208
|
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
2091
2209
|
auth: resolveOAuthToken, // validate the Bearer JWT (verifyJwt + audience)
|
|
2092
2210
|
services,
|
|
2093
2211
|
protectedResource: { resource, authorizationServers: [issuer] },
|
|
2094
2212
|
})
|
|
2095
2213
|
|
|
2096
|
-
// 2. Authorization server —
|
|
2214
|
+
// 2. Authorization server — CIMD, /authorize (PKCE), /token.
|
|
2097
2215
|
const oauthRoutes = mountOAuthProvider({
|
|
2098
2216
|
issuer,
|
|
2099
2217
|
resource,
|
|
2100
2218
|
signingSecret: env.OAUTH_SECRET,
|
|
2101
|
-
|
|
2102
|
-
|
|
2219
|
+
clientRegistration: {
|
|
2220
|
+
preRegistered: { get: getFirstPartyClient },
|
|
2221
|
+
// CIMD is enabled with secure defaults; DCR remains disabled.
|
|
2222
|
+
},
|
|
2223
|
+
codes, refreshTokens, // your stores (DB or in-memory)
|
|
2224
|
+
authorizeUser, // → { userId, approvedScopes } | Response
|
|
2103
2225
|
})
|
|
2104
2226
|
|
|
2105
2227
|
createServer({
|
|
2106
2228
|
services,
|
|
2107
2229
|
rawRoutes: [
|
|
2108
|
-
{
|
|
2230
|
+
createMcpHttpRoute({ path: '/mcp', handler: mcp }),
|
|
2109
2231
|
oauthProtectedResourceRoute({ resource, authorizationServers: [issuer] }),
|
|
2110
2232
|
...oauthRoutes,
|
|
2111
2233
|
],
|
|
@@ -2116,11 +2238,27 @@ Access tokens are signed HS256 JWTs (`signJwt`) whose `aud` is the resource and
|
|
|
2116
2238
|
whose `iss` is the issuer — validate both in `auth` with
|
|
2117
2239
|
`verifyJwt(token, secret, { audience: resource, issuer })`. `authorizeUser` is
|
|
2118
2240
|
where the app authenticates the user (reuse an existing session) and records
|
|
2119
|
-
consent; return `{ userId }
|
|
2120
|
-
|
|
2241
|
+
consent; return `{ userId, approvedScopes }`, where approved scopes are a subset
|
|
2242
|
+
of the requested/supported values, or a `Response` to redirect the browser to a
|
|
2243
|
+
login page first. The AS and resource server can co-locate or live
|
|
2121
2244
|
on separate origins. See
|
|
2122
2245
|
[ADR 0015](../decisions/0015-oauth-resource-server.md).
|
|
2123
2246
|
|
|
2247
|
+
Client resolution is deterministic: exact pre-registered client, then an HTTPS
|
|
2248
|
+
URL client id resolved as CIMD, then explicitly enabled DCR. CIMD is on by
|
|
2249
|
+
default; DCR is off unless `clientRegistration.dcr` supplies both `register` and
|
|
2250
|
+
`get`. A CIMD-only deployment therefore exposes neither `/register` nor a
|
|
2251
|
+
`registration_endpoint`. The metadata document must declare a `client_id` that
|
|
2252
|
+
exactly equals its URL, explicit redirect URIs and
|
|
2253
|
+
`token_endpoint_auth_method: 'none'`.
|
|
2254
|
+
|
|
2255
|
+
The production fetcher rejects credentials, fragments, non-HTTPS URLs and
|
|
2256
|
+
private/reserved targets. Every redirect is DNS-resolved and IP-pinned again;
|
|
2257
|
+
timeouts, redirect count and body size are bounded. Its bounded cache respects
|
|
2258
|
+
`Cache-Control` (including `no-store`/`no-cache`), `Age`, `Expires`, `ETag` and
|
|
2259
|
+
`Last-Modified`, coalesces concurrent misses and reports sanitized cache events;
|
|
2260
|
+
invalid or unavailable identity receives only a short fail-closed cache entry.
|
|
2261
|
+
|
|
2124
2262
|
### Authorization hardening (MCP 2026-07-28)
|
|
2125
2263
|
|
|
2126
2264
|
- **`iss` on every authorization response (RFC 9207, SEP-2468).** Success *and*
|
|
@@ -2138,9 +2276,9 @@ on separate origins. See
|
|
|
2138
2276
|
behaves exactly as before (loopback allowed); an unknown value is rejected
|
|
2139
2277
|
rather than silently defaulted.
|
|
2140
2278
|
|
|
2141
|
-
> Dynamic Client Registration is
|
|
2142
|
-
>
|
|
2143
|
-
>
|
|
2279
|
+
> Dynamic Client Registration is an explicit interoperability mode, not the
|
|
2280
|
+
> default. Enabling it changes public discovery and adds `/register`; keep it off
|
|
2281
|
+
> unless a client that cannot publish CIMD requires it.
|
|
2144
2282
|
|
|
2145
2283
|
## Proxying a remote API — `implementRemote`
|
|
2146
2284
|
|
|
@@ -2157,11 +2295,14 @@ const http = createHttpClient({
|
|
|
2157
2295
|
headers: () => ({ Authorization: `Bearer ${apiKey}` }),
|
|
2158
2296
|
})
|
|
2159
2297
|
|
|
2160
|
-
await createStdioMcpServer({
|
|
2298
|
+
const stdio = await createStdioMcpServer({
|
|
2161
2299
|
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
2162
2300
|
auth: null,
|
|
2163
2301
|
services: contracts.map((c) => implementRemote(c, http)),
|
|
2164
2302
|
})
|
|
2303
|
+
|
|
2304
|
+
// During graceful shutdown:
|
|
2305
|
+
await stdio.close()
|
|
2165
2306
|
```
|
|
2166
2307
|
|
|
2167
2308
|
This is how you ship a thin **local** MCP server for an API that already runs in
|
|
@@ -2175,9 +2316,16 @@ no duplicated business logic.
|
|
|
2175
2316
|
|
|
2176
2317
|
## Structured output
|
|
2177
2318
|
|
|
2178
|
-
When a contract endpoint
|
|
2179
|
-
that
|
|
2180
|
-
alongside
|
|
2319
|
+
When a contract endpoint or runtime tool declares `output`, its MCP tool
|
|
2320
|
+
registers that exact schema as `outputSchema` and returns the validated value as
|
|
2321
|
+
`structuredContent` alongside a JSON text block. Every JSON root type is kept
|
|
2322
|
+
unchanged: object, array, string, number, boolean and `null`. Stitchkit does not
|
|
2323
|
+
wrap non-object values in `{ result }`; protocol-era adaptation belongs to the
|
|
2324
|
+
official SDK.
|
|
2325
|
+
|
|
2326
|
+
A tool without an output contract advertises no `outputSchema` and returns no
|
|
2327
|
+
invented structured value. Its successful MCP result has an empty `content`
|
|
2328
|
+
list.
|
|
2181
2329
|
|
|
2182
2330
|
## AI agents — `mountAgent`
|
|
2183
2331
|
|
|
@@ -3342,8 +3490,9 @@ Use the exported `zodIssues(error)` to build the same structured list from a
|
|
|
3342
3490
|
### On the client
|
|
3343
3491
|
|
|
3344
3492
|
The client parses that envelope back into an `ApiError` with the same `code`,
|
|
3345
|
-
`status`, `details` and `hint
|
|
3346
|
-
|
|
3493
|
+
`status`, `details` and `hint`, plus the response `x-request-id` as optional
|
|
3494
|
+
readonly `traceId` — see [Typed client → ApiError](./client.md#apierror). The
|
|
3495
|
+
error round-trips without adding correlation data to the response body.
|
|
3347
3496
|
|
|
3348
3497
|
### Stitch codes vs your codes
|
|
3349
3498
|
|
|
@@ -3701,7 +3850,8 @@ locally; you do not need to change `NODE_ENV` or deploy.
|
|
|
3701
3850
|
Every response the stitchkit handler produces carries the resolved id as
|
|
3702
3851
|
**`x-request-id`**. With `cors` configured it is in the default
|
|
3703
3852
|
`Access-Control-Expose-Headers`, so a browser client can read it and quote it in
|
|
3704
|
-
a bug report.
|
|
3853
|
+
a bug report. Stitchkit browser clients retain it as `ApiError.traceId` on
|
|
3854
|
+
response-backed failures. Note the deliberate asymmetry: inbound the id may arrive as
|
|
3705
3855
|
`X-Trace-Id` *or* `X-Request-Id`; outbound there is one name and no alias.
|
|
3706
3856
|
|
|
3707
3857
|
Log the same id from nginx and the two logs join on one key. `log_format` and
|
|
@@ -3751,8 +3901,25 @@ cross-origin `trace: true` client works out of the box. If you set a custom
|
|
|
3751
3901
|
`cors.headers`, extend `DEFAULT_CORS_ALLOW_HEADERS` rather than replacing it, or
|
|
3752
3902
|
the preflight will reject the trace header.
|
|
3753
3903
|
|
|
3904
|
+
MCP tools use the same context. On a modern HTTP or stdio `tools/call`, the
|
|
3905
|
+
official SDK exposes W3C propagation values from request `_meta`; Stitchkit
|
|
3906
|
+
continues a valid `_meta.traceparent` before validation, lifecycle and hooks.
|
|
3907
|
+
If MCP metadata omits `traceparent`, an HTTP call keeps its ambient HTTP trace
|
|
3908
|
+
and a stdio call starts a new root. If the key is present but malformed or
|
|
3909
|
+
all-zero, the call still runs under a fresh local trace instead of trusting the
|
|
3910
|
+
ambient one. This makes explicit MCP propagation authoritative without allowing
|
|
3911
|
+
invalid input to break the tool.
|
|
3912
|
+
|
|
3913
|
+
Bounded `tracestate` and `baggage` are available through
|
|
3914
|
+
`getRequestContext()?.trace` for outbound propagation. Their contents are not
|
|
3915
|
+
copied into the standard `RequestEvent`; never use them for auth, RBAC, tenant
|
|
3916
|
+
selection or rate-limit identity. Every MRTR attempt reads its current request
|
|
3917
|
+
metadata, so callers that want one trace across rounds must propagate it on
|
|
3918
|
+
each request.
|
|
3919
|
+
|
|
3754
3920
|
> **Span ids live in the request context, not on `ctx`.** The handler `ctx`
|
|
3755
|
-
> carries a single `traceId`; the full
|
|
3921
|
+
> carries a single `traceId`; the full
|
|
3922
|
+
> `{ traceId, spanId, parentSpanId, tracestate?, baggage? }` is on
|
|
3756
3923
|
> the observability request context. To stamp `spanId` / `parentSpanId` into an
|
|
3757
3924
|
> audit row read `getRequestContext()?.trace`, not `ctx.spanId`:
|
|
3758
3925
|
>
|
|
@@ -4091,9 +4258,11 @@ an independently built Next.js frontend and Bun/Stitchkit API.
|
|
|
4091
4258
|
|
|
4092
4259
|
### MCP
|
|
4093
4260
|
|
|
4094
|
-
If the app exposes MCP tools, `createMcpHandler`
|
|
4095
|
-
(
|
|
4096
|
-
|
|
4261
|
+
If the app exposes MCP tools, mount `createMcpHandler` with
|
|
4262
|
+
`createMcpHttpRoute({ path: '/mcp', handler })` and close the handler during
|
|
4263
|
+
graceful shutdown. Production needs the `@modelcontextprotocol/server` v2 peer;
|
|
4264
|
+
apps without MCP do not. Only an MCP host or integration-test package needs
|
|
4265
|
+
`@modelcontextprotocol/client`.
|
|
4097
4266
|
|
|
4098
4267
|
|
|
4099
4268
|
==============================================================================
|
|
@@ -4362,6 +4531,174 @@ current one *up to* your target, and apply each snippet.
|
|
|
4362
4531
|
|
|
4363
4532
|
## Unreleased breaking migrations
|
|
4364
4533
|
|
|
4534
|
+
### MCP TypeScript SDK v2 and protocol `2026-07-28`
|
|
4535
|
+
|
|
4536
|
+
This is a hard cut: there is one Stitchkit API and no v1 aliases. Applications
|
|
4537
|
+
that expose MCP install the split server package; applications that implement an
|
|
4538
|
+
MCP host or run client E2E install the split client package.
|
|
4539
|
+
|
|
4540
|
+
```bash
|
|
4541
|
+
bun remove @modelcontextprotocol/sdk
|
|
4542
|
+
bun add @modelcontextprotocol/server@^2 ai@^7
|
|
4543
|
+
# MCP hosts and client-side E2E only:
|
|
4544
|
+
bun add -d @modelcontextprotocol/client@^2
|
|
4545
|
+
```
|
|
4546
|
+
|
|
4547
|
+
Direct SDK imports move to the split packages too:
|
|
4548
|
+
|
|
4549
|
+
```ts
|
|
4550
|
+
// before
|
|
4551
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4552
|
+
|
|
4553
|
+
// after
|
|
4554
|
+
import { McpServer } from '@modelcontextprotocol/server'
|
|
4555
|
+
```
|
|
4556
|
+
|
|
4557
|
+
MCP Apps additionally install `@modelcontextprotocol/ext-apps`. That adapter may
|
|
4558
|
+
carry its own isolated v1-era transitive/peer relationship while the ecosystem
|
|
4559
|
+
finishes its cutover; it does not permit application code to import the removed
|
|
4560
|
+
monolithic SDK. Application-owned MCP server and client code uses the v2 split
|
|
4561
|
+
packages exclusively.
|
|
4562
|
+
|
|
4563
|
+
```ts
|
|
4564
|
+
// before
|
|
4565
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
4566
|
+
import { createMcpHandler } from 'stitchkit/tools'
|
|
4567
|
+
|
|
4568
|
+
const handleMcp = createMcpHandler({
|
|
4569
|
+
serverInfo,
|
|
4570
|
+
auth,
|
|
4571
|
+
services,
|
|
4572
|
+
sessionMode: 'stateless',
|
|
4573
|
+
})
|
|
4574
|
+
rawRoutes: [{ method: 'ALL', path: '/mcp', handler: handleMcp }]
|
|
4575
|
+
|
|
4576
|
+
// after
|
|
4577
|
+
import { Client } from '@modelcontextprotocol/client'
|
|
4578
|
+
import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools'
|
|
4579
|
+
|
|
4580
|
+
const mcp = createMcpHandler({
|
|
4581
|
+
serverInfo,
|
|
4582
|
+
auth,
|
|
4583
|
+
services,
|
|
4584
|
+
legacy: 'serve',
|
|
4585
|
+
})
|
|
4586
|
+
rawRoutes: [createMcpHttpRoute({ path: '/mcp', handler: mcp })]
|
|
4587
|
+
// graceful shutdown: await mcp.close()
|
|
4588
|
+
```
|
|
4589
|
+
|
|
4590
|
+
Keep the owned handle and close it from the same shutdown path as the HTTP
|
|
4591
|
+
server. A minimal runtime smoke should list tools before shutdown and prove the
|
|
4592
|
+
closed handler no longer serves requests:
|
|
4593
|
+
|
|
4594
|
+
```ts
|
|
4595
|
+
const mcp = createMcpHandler(config)
|
|
4596
|
+
const route = createMcpHttpRoute({ path: '/mcp', handler: mcp })
|
|
4597
|
+
|
|
4598
|
+
const beforeClose = await route.handler(listToolsRequest)
|
|
4599
|
+
if (!beforeClose.ok) throw new Error('MCP list-tools smoke failed')
|
|
4600
|
+
|
|
4601
|
+
await mcp.close()
|
|
4602
|
+
```
|
|
4603
|
+
|
|
4604
|
+
Remove `@modelcontextprotocol/sdk`, `sessionMode`, `McpSessionMode`, session
|
|
4605
|
+
stores and all `Mcp-Session-Id` handling. HTTP is always request-isolated and
|
|
4606
|
+
stateless. `legacy: 'serve'` (default) lets the official SDK negotiate supported
|
|
4607
|
+
pre-2026 stateless clients on the same endpoint; `legacy: 'reject'` makes it
|
|
4608
|
+
modern-only. This is not a stateful compatibility transport.
|
|
4609
|
+
|
|
4610
|
+
The stdio helper now returns an owned lifecycle handle:
|
|
4611
|
+
|
|
4612
|
+
```ts
|
|
4613
|
+
// before
|
|
4614
|
+
await createStdioMcpServer(config)
|
|
4615
|
+
|
|
4616
|
+
// after
|
|
4617
|
+
const stdio = await createStdioMcpServer({ ...config, legacy: 'serve' })
|
|
4618
|
+
await stdio.close()
|
|
4619
|
+
```
|
|
4620
|
+
|
|
4621
|
+
OAuth client registration is now one explicit policy object. CIMD is secure and
|
|
4622
|
+
enabled by default; DCR is disabled unless supplied:
|
|
4623
|
+
|
|
4624
|
+
```ts
|
|
4625
|
+
// before
|
|
4626
|
+
mountOAuthProvider({ ...oauth, clients, codes, refreshTokens })
|
|
4627
|
+
|
|
4628
|
+
// after
|
|
4629
|
+
mountOAuthProvider({
|
|
4630
|
+
...oauth,
|
|
4631
|
+
clientRegistration: {
|
|
4632
|
+
preRegistered: { get: clients.get },
|
|
4633
|
+
// optional: dcr: { register: clients.register, get: clients.get }
|
|
4634
|
+
},
|
|
4635
|
+
codes,
|
|
4636
|
+
refreshTokens,
|
|
4637
|
+
})
|
|
4638
|
+
```
|
|
4639
|
+
|
|
4640
|
+
A URL client id must be HTTPS and serve a document whose `client_id` exactly
|
|
4641
|
+
matches that URL, with explicit `redirect_uris` and
|
|
4642
|
+
`token_endpoint_auth_method: 'none'`. Do not keep a consumer-side metadata
|
|
4643
|
+
fetcher or DCR fallback; Stitchkit owns SSRF-safe resolution and caching.
|
|
4644
|
+
|
|
4645
|
+
Multi-round input is opt-in on the operation and does not change Agent, CLI or
|
|
4646
|
+
ordinary HTTP handlers:
|
|
4647
|
+
|
|
4648
|
+
```ts
|
|
4649
|
+
const ConfirmationSchema = z.object({ confirmed: z.boolean() })
|
|
4650
|
+
|
|
4651
|
+
mcp: {
|
|
4652
|
+
inputRequired: [{
|
|
4653
|
+
key: 'confirmation',
|
|
4654
|
+
message: 'Confirm this action',
|
|
4655
|
+
schema: ConfirmationSchema,
|
|
4656
|
+
}],
|
|
4657
|
+
}
|
|
4658
|
+
```
|
|
4659
|
+
|
|
4660
|
+
Configure `multiRound.state` on the MCP server with a key of at least 32 bytes
|
|
4661
|
+
and a stable authenticated `principal`. Read accepted typed content from
|
|
4662
|
+
`ctx.mcpInput.confirmation`. Multiple declarations run in array order, the
|
|
4663
|
+
aggregate remains exactly typed by key, keys must be unique, and declarations
|
|
4664
|
+
must fit `multiRound.serving.maxRounds` (default `10`). Do not execute a
|
|
4665
|
+
destructive side effect before the complete aggregate is accepted. A modern
|
|
4666
|
+
request missing the declared elicitation capability receives JSON-RPC error
|
|
4667
|
+
code `-32021`. The official per-request legacy HTTP bridge cannot issue
|
|
4668
|
+
server-to-client elicitation, so it returns a deterministic failed tool result;
|
|
4669
|
+
multi-round input is never silently treated as complete.
|
|
4670
|
+
|
|
4671
|
+
#### Compatibility matrix
|
|
4672
|
+
|
|
4673
|
+
| Host / transport | Tools and Apps | Multi-round input | Continuity |
|
|
4674
|
+
|---|---|---|---|
|
|
4675
|
+
| `2026-07-28` HTTP | yes | yes | request-isolated |
|
|
4676
|
+
| supported legacy stateless HTTP | yes | unsupported result | request-isolated |
|
|
4677
|
+
| `2026-07-28` stdio | yes | yes | one process connection |
|
|
4678
|
+
| supported legacy stdio | yes | official SDK bridge | one process connection |
|
|
4679
|
+
| Agent / CLI / ordinary HTTP | unchanged | not exposed | unchanged |
|
|
4680
|
+
|
|
4681
|
+
Subscriptions, cross-request progress and resumable stateful SSE are not
|
|
4682
|
+
implemented or advertised.
|
|
4683
|
+
|
|
4684
|
+
#### Consumer checklist
|
|
4685
|
+
|
|
4686
|
+
1. Replace the monolithic SDK with `@modelcontextprotocol/server@^2` and, only
|
|
4687
|
+
for hosts/tests, `@modelcontextprotocol/client@^2`.
|
|
4688
|
+
2. Replace raw MCP route wiring with `createMcpHttpRoute`; retain and close the
|
|
4689
|
+
returned handler/stdio handle during shutdown.
|
|
4690
|
+
3. Delete all session mode, event-store and session-id code.
|
|
4691
|
+
4. Move OAuth client policy under `clientRegistration`; publish CIMD or enable
|
|
4692
|
+
DCR explicitly.
|
|
4693
|
+
5. Snapshot `listToolNames`, run one contract tool, one runtime tool, any raw
|
|
4694
|
+
multimodal tool and every MCP App resource you use.
|
|
4695
|
+
6. Exercise modern HTTP and stdio with protocol `2026-07-28`; exercise legacy
|
|
4696
|
+
only if `legacy: 'serve'` is part of your support policy.
|
|
4697
|
+
7. Run the consumer's typecheck and runtime gates. A browser/HTTP-only consumer
|
|
4698
|
+
must continue to work without either MCP package.
|
|
4699
|
+
|
|
4700
|
+
## Historical breaking migrations through 0.43.1
|
|
4701
|
+
|
|
4365
4702
|
HTTP observability now completes inside the framework handler instead of a
|
|
4366
4703
|
nested fetch wrapper. Configure request and tool sinks explicitly:
|
|
4367
4704
|
|
|
@@ -4709,23 +5046,6 @@ If a tool hook annotated `endpoint` as `MethodDef`, remove that annotation or
|
|
|
4709
5046
|
use `OperationIdentity`: native operations have service/action/scope/method but
|
|
4710
5047
|
no HTTP path.
|
|
4711
5048
|
|
|
4712
|
-
### MCP HTTP sessions
|
|
4713
|
-
|
|
4714
|
-
Finally, replace the MCP HTTP session boolean. Omission changed meaning:
|
|
4715
|
-
|
|
4716
|
-
```ts
|
|
4717
|
-
// before → after
|
|
4718
|
-
stateless: true // → sessionMode: 'stateless'
|
|
4719
|
-
stateless: false // → sessionMode: 'stateful'
|
|
4720
|
-
|
|
4721
|
-
// before: omission was stateful
|
|
4722
|
-
// after: omission is stateless
|
|
4723
|
-
```
|
|
4724
|
-
|
|
4725
|
-
If the client relies on `Mcp-Session-Id`, server push, progress across requests
|
|
4726
|
-
or resumable SSE, set `sessionMode: 'stateful'` explicitly. Synchronous tool
|
|
4727
|
-
servers should omit it and use the new restart-safe default.
|
|
4728
|
-
|
|
4729
5049
|
### Node-facing server types
|
|
4730
5050
|
|
|
4731
5051
|
`stitchkit/server` remains Bun-concrete: an explicitly annotated `RawRoute`
|
|
@@ -4839,7 +5159,7 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
4839
5159
|
| `contractEndpointMatchers` | function | compile exact pathname matchers for selected HTTP contract operations and expected-401 policy |
|
|
4840
5160
|
| `PathPrefixArgs` | _type_ | required string-valued keys exposed to a typed dynamic `pathPrefix` callback |
|
|
4841
5161
|
| `createHttpClient` | function | the Ky-based HTTP transport — [guide](../guide/client.md#createhttpclient) |
|
|
4842
|
-
| `ApiError` | class | a non-2xx response, with `code` / `status` / `details` / `hint` |
|
|
5162
|
+
| `ApiError` | class | a non-2xx response, with `code` / `status` / `details` / `hint` and optional readonly `traceId` from `x-request-id` |
|
|
4843
5163
|
| `HttpClient` | _type_ | the transport interface `createClient` builds on |
|
|
4844
5164
|
| `ConfiguredHttpClient` | _type_ | a framework-created `HttpClient` carrying its readonly `baseUrl` for URL builders |
|
|
4845
5165
|
| `HttpClientConfig` | _type_ | config for `createHttpClient` |
|
|
@@ -4874,7 +5194,7 @@ can emit / propagate a `traceparent` (see `HttpClientConfig.trace`).
|
|
|
4874
5194
|
| `formatTraceparent` | function | render a `traceparent` header value |
|
|
4875
5195
|
| `parseTraceparent` | function | parse a `traceparent` header |
|
|
4876
5196
|
| `childSpan` | function | a child span of a parent trace |
|
|
4877
|
-
| `TraceContext` | _type_ | `{ traceId, spanId, parentSpanId? }` |
|
|
5197
|
+
| `TraceContext` | _type_ | `{ traceId, spanId, parentSpanId?, tracestate?, baggage? }` |
|
|
4878
5198
|
|
|
4879
5199
|
---
|
|
4880
5200
|
|
|
@@ -4921,6 +5241,8 @@ from the root `stitchkit`.
|
|
|
4921
5241
|
| `FileDescriptor` | _type_ | a React Native / Expo file — `{ uri, name, type }` |
|
|
4922
5242
|
| `EndpointToolAnnotations` | _type_ | MCP behavioural hints on an endpoint (`readOnlyHint` / `destructiveHint` / `title`) |
|
|
4923
5243
|
| `EndpointUiMeta` | _type_ | MCP Apps widget metadata on an endpoint |
|
|
5244
|
+
| `EndpointMcpInputRequired` | _type_ | typed MCP multi-round input request (`key`, message and Zod object schema) |
|
|
5245
|
+
| `EndpointMcpPolicy` | _type_ | MCP-only endpoint policy containing `inputRequired` |
|
|
4924
5246
|
|
|
4925
5247
|
### Errors
|
|
4926
5248
|
|
|
@@ -5138,11 +5460,12 @@ audit event. See the [Observability guide](../guide/observability.md).
|
|
|
5138
5460
|
| Export | Kind | Summary |
|
|
5139
5461
|
|--------|------|---------|
|
|
5140
5462
|
| `resolveTraceContext` | function | the trace for a request — `traceparent` continued or fresh |
|
|
5463
|
+
| `resolvePropagationContext` | function | continue bounded MCP/W3C propagation metadata with optional ambient fallback |
|
|
5141
5464
|
| `parseTraceparent` | function | parse a `traceparent` header |
|
|
5142
5465
|
| `formatTraceparent` | function | render a `traceparent` header value |
|
|
5143
5466
|
| `createTraceContext` | function | a fresh root trace |
|
|
5144
5467
|
| `childSpan` | function | a child span of a parent trace |
|
|
5145
|
-
| `TraceContext` | _type_ | `{ traceId, spanId, parentSpanId? }` |
|
|
5468
|
+
| `TraceContext` | _type_ | `{ traceId, spanId, parentSpanId?, tracestate?, baggage? }` |
|
|
5146
5469
|
|
|
5147
5470
|
### Sanitisation
|
|
5148
5471
|
|
|
@@ -5160,12 +5483,19 @@ audit event. See the [Observability guide](../guide/observability.md).
|
|
|
5160
5483
|
|
|
5161
5484
|
## `stitchkit/tools`
|
|
5162
5485
|
|
|
5163
|
-
Server-only. Turns contracts into MCP and AI-agent tools.
|
|
5164
|
-
`@modelcontextprotocol/
|
|
5486
|
+
Server-only. Turns contracts into MCP and AI-agent tools. MCP server surfaces
|
|
5487
|
+
need the `@modelcontextprotocol/server` v2 peer; MCP hosts/tests use the separate
|
|
5488
|
+
`@modelcontextprotocol/client` package. Agent surfaces need the `ai` peer.
|
|
5489
|
+
|
|
5490
|
+
Framework-owned MCP tools advertise the exact declared output schema and return
|
|
5491
|
+
the validated value unchanged as `structuredContent`, including arrays, scalars
|
|
5492
|
+
and `null`. Tools without an output contract advertise and return no structured
|
|
5493
|
+
payload.
|
|
5165
5494
|
|
|
5166
5495
|
| Export | Kind | Summary |
|
|
5167
5496
|
|--------|------|---------|
|
|
5168
|
-
| `createMcpHandler` | function | a
|
|
5497
|
+
| `createMcpHandler` | function | a stateless dual-era Streamable-HTTP MCP handler — [guide](../guide/mcp-and-agents.md#mcp--createmcphandler) |
|
|
5498
|
+
| `createMcpHttpRoute` | function | framework-owned `RawRoute` adapter for an MCP HTTP handler |
|
|
5169
5499
|
| `createStdioMcpServer` | function | a complete stdio MCP server — [guide](../guide/mcp-and-agents.md#mcp-over-stdio--createstdiomcpserver) |
|
|
5170
5500
|
| `buildMcpServer` | function | build an `McpServer` from contract/runtime surfaces — the transport-neutral core |
|
|
5171
5501
|
| `mountMcp` | function | add contract tools to an existing `McpServer` — [guide](../guide/mcp-and-agents.md#mountmcp) |
|
|
@@ -5180,9 +5510,12 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
|
|
|
5180
5510
|
| `resolveMedia` | function | resolve a media reference for a tool result |
|
|
5181
5511
|
| `validateMcpSchemas` | function | object-shaped assertion over the exact advertised schema surface — compatibility, typed properties and portable formats ([guide](../guide/mcp-and-agents.md#mcp-schema-validation-profile)) |
|
|
5182
5512
|
| `listToolNames` | function | every contract/runtime tool name with origin, identity and transports — for stable snapshots — [guide](../guide/mcp-and-agents.md#pinning-tool-names--listtoolnames) |
|
|
5183
|
-
| `McpHandlerConfig` | _type_ |
|
|
5184
|
-
| `McpHttpConfig` | _type_ | HTTP auth, protected-resource and
|
|
5185
|
-
| `
|
|
5513
|
+
| `McpHandlerConfig` | _type_ | server surface plus stateless HTTP transport config |
|
|
5514
|
+
| `McpHttpConfig` | _type_ | HTTP auth, protected-resource, legacy-era and security options |
|
|
5515
|
+
| `McpHttpHandler` | _type_ | framework-owned `{ fetch(request), close() }` lifecycle |
|
|
5516
|
+
| `McpHttpSecurityConfig` | _type_ | Fetch-boundary Host and Origin allowlists |
|
|
5517
|
+
| `McpLegacyPolicy` | _type_ | `'serve' \| 'reject'` protocol-era compatibility policy |
|
|
5518
|
+
| `McpStdioHandle` | _type_ | closeable official stdio transport handle |
|
|
5186
5519
|
| `StdioMcpServerConfig` | _type_ | config for `createStdioMcpServer` |
|
|
5187
5520
|
| `McpServerBuildConfig` | _type_ | shared config for `buildMcpServer` |
|
|
5188
5521
|
| `McpServerSharedConfig` | _type_ | transport-neutral options shared by direct and finite surface configs |
|
|
@@ -5210,6 +5543,15 @@ Server-only. Turns contracts into MCP and AI-agent tools. Needs the
|
|
|
5210
5543
|
| `RuntimeToolOutput` | _type_ | output inferred from a runtime tool's optional Zod schema |
|
|
5211
5544
|
| `RuntimeToolPresenters` | _type_ | optional MCP and AI SDK `toModelOutput` presentation callbacks |
|
|
5212
5545
|
| `RuntimeMcpPresentation` | _type_ | MCP content/metadata result without framework-owned `structuredContent` or `isError` |
|
|
5546
|
+
| `RuntimeMcpInput` | _type_ | typed accepted multi-round input for an opted-in runtime tool |
|
|
5547
|
+
| `OAuthClientRegistrationConfig` | _type_ | deterministic pre-registered → CIMD → explicit-DCR client resolution |
|
|
5548
|
+
| `CimdClientMetadata` | _type_ | validated Client ID Metadata Document |
|
|
5549
|
+
| `CimdClientMetadataFetcher` | _type_ | injectable secure network boundary for metadata loading |
|
|
5550
|
+
| `CimdFetchResponse` | _type_ | bounded metadata fetch result passed across the injectable network boundary |
|
|
5551
|
+
| `CimdFetchPolicy` | _type_ | CIMD timeout, redirect and size limits |
|
|
5552
|
+
| `CimdCachePolicy` | _type_ | bounded HTTP-aware positive/negative cache policy |
|
|
5553
|
+
| `CimdCacheEvent` | _type_ | observable CIMD cache hit, miss, revalidation and eviction event |
|
|
5554
|
+
| `createSecureClientMetadataFetcher` | function | production HTTPS, DNS/IP-pinned CIMD fetcher |
|
|
5213
5555
|
| `RuntimeAgentModelOutput` | _type_ | AI SDK model-facing text/JSON/content output returned by `present.agent` |
|
|
5214
5556
|
| `RuntimeToolTransport` | _type_ | runtime exposure: `'MCP' \| 'AGENT'` |
|
|
5215
5557
|
| `AgentMountConfig` | _type_ | config for `mountAgent` |
|