refactor(client): response cache stores serialized documents; drop structuredClone (#2468)

This commit is contained in:
Felix Weinberger 2026-07-13 17:39:41 +01:00 • committed by GitHub
commit 5db6e38f2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 457 additions and 112 deletions

View file

@ -64,7 +64,7 @@ const store = new InMemoryResponseCacheStore({ maxEntries: 2048 });
const client = new Client({ name: 'my-client', version: '1.0.0' }, { responseCacheStore: store });
```
Every method on the `ResponseCacheStore` interface may return a promise, so a Redis-style store implements the same five methods. Entries are keyed by connected-server identity, so one store can back many clients: connections to different servers never collide.
Every method on the `ResponseCacheStore` interface may return a promise, so a Redis-style store implements the same five methods. `CacheEntry.value` is the JSON-serialized result document — a persistent store persists the string verbatim, no extra serialization step, and behaves identically to the in-memory default. Entries are keyed by connected-server identity, so one store can back many clients: connections to different servers never collide.
## Partition the store per user

View file

@ -30,7 +30,7 @@ A failed tool call is still a result: check `isError` on it before trusting `con
## Let the SDK walk the pages
That `listTools()` already walked every page: when a server splits its list, the SDK follows `nextCursor` page by page and returns one aggregated list with `nextCursor: undefined`. `listPrompts()`, `listResources()`, and `listResourceTemplates()` aggregate the same way.
That `listTools()` already walked every page: when a server splits its list, the SDK follows `nextCursor` page by page and returns one aggregated list with no `nextCursor`. `listPrompts()`, `listResources()`, and `listResourceTemplates()` aggregate the same way.
Pass a `cursor` — a page's `nextCursor` your application held on to — and `listTools` returns exactly that page, raw.

View file

@ -1588,7 +1588,7 @@ rewrite required unless noted.
instead of sending the request. Set `enforceStrictCapabilities: true` in `ClientOptions`
to restore the v1 throw.
- Called **without a `cursor`**, the same methods now **auto-aggregate every page** and
return `nextCursor: undefined`. Passing `{ cursor }` still fetches one page. Manual
return an aggregate with no `nextCursor`. Passing `{ cursor }` still fetches one page. Manual
pagination loops keep working (the first iteration returns everything); replace them
with the bare no-arg call. The walk is capped at `ClientOptions.listMaxPages` (default
64); overrun throws `SdkError(ListPaginationExceeded)`. There is no way to fetch only
@ -1606,6 +1606,9 @@ rewrite required unless noted.
trip. Per-call override: `{ cacheMode: 'refresh' | 'bypass' }`. New `ClientOptions`:
`cachePartition`, `defaultCacheTtlMs`. `ResponseCacheStore` gained `delete(key)`;
`InMemoryResponseCacheStore` is now bounded (`{ maxEntries }`, default 512).
`CacheEntry.value` (and the `set()` entry value) is the JSON-serialized result
document (`string`, not `unknown`): persist and return it verbatim, `JSON.parse`
it to inspect.
#### Server (Streamable HTTP transport)