Skip to content

feat: add caller-scoped data spillover for large tool results - #92

Open
jpsiddharth2008 wants to merge 3 commits into
nitrocloudofficial:developfrom
jpsiddharth2008:feature/issue-67-data-spillover
Open

jpsiddharth2008 wants to merge 3 commits into
nitrocloudofficial:developfrom
jpsiddharth2008:feature/issue-67-data-spillover

Conversation

@jpsiddharth2008

Copy link
Copy Markdown
Collaborator

Closes #67.

Large tool results can consume a significant portion of the model’s context.
This PR adds an opt-in interceptor that stores oversized results separately
and returns a bounded preview, a resource URI, and the original payload size.
The caller can retrieve the complete result through MCP resources/read.

Results at or below the configured threshold are returned unchanged.

Changes

  • Added a SpilloverStore protocol with save, retrieve, delete, and expiry
    cleanup operations.
  • Added MemorySpilloverStore with TTL expiry, byte limits, and LRU eviction.
  • Added FileSpilloverStore with persistent ownership and expiry metadata,
    atomic writes, capacity limits, and path traversal and symlink checks.
  • Added DataSpilloverInterceptor, supporting a configurable byte threshold,
    storage backend, and resource URI prefix.
  • Extended @use_interceptors(...) to accept configured interceptor instances
    while preserving existing class-based dependency injection.
  • Added previews for lists, dictionaries, and strings, including head items,
    total counts, and truncated text within a 2 KiB preview budget.
  • Integrated stored results with MCP resource reads. Access is restricted to
    the verified caller or, for anonymous callers, the originating MCP session.
    Missing, expired, and unauthorized results return resource-not-found.
  • Added support for background task results and advertised output schemas
    that allow either the original result or a spillover envelope.
  • Added public API exports, README examples, and an implementation walkthrough.

The default spill threshold is 64 KiB, with a 10 MiB per-payload limit,
100 MiB store capacity, and five-minute TTL. File-store roots are intended
for use by one store instance in one process.

Testing

Feature tests

38 passed, 1 skipped, covering:

  • Threshold boundaries and UTF-8 byte counting.
  • Unchanged small results and bounded previews for large or nested data.
  • Complete payload retrieval through registered MCP resource handlers.
  • Caller, tenant, issuer, and anonymous-session isolation.
  • TTL expiry, deletion, LRU eviction, and storage capacity limits.
  • File persistence, cleanup, path traversal, and symlink rejection.
  • Configured interceptor instances, class-based registration, custom URI
    prefixes, background tasks, OAuth identity, and widget-transformer bypass.

The real filesystem symlink test was skipped because this Windows account
cannot create symlinks. A separate simulated symlink-rejection test passed.

Large-payload checks

24 additional checks passed across memory and file storage, including:

  • 1 MiB, 5 MiB, and 10 MiB text.
  • A list containing 100,000 rows.
  • A dictionary containing 50,000 entries.
  • Approximately 6 MiB of nested data.
  • Multibyte emoji and escaped text.
  • Correct rejection of payloads exceeding the 10 MiB limit, including 20 MiB.

For each spilled result, checks verified byte-for-byte retrieval, the preview
size limit, and denial of access to another caller. These checks exercised
registered MCP handlers in-process rather than a network client.

Full SDK suite

The full suite with coverage reported 868 passed, 1 failed, 1 skipped
and 85.8% coverage.

Full-suite runs encountered Windows localhost connection-aborted errors
in OAuth discovery tests. The entire OAuth test module passed separately,
and an unchanged main-branch baseline also passed its full suite. The cause
of the combined-run failures remains unresolved.

git diff --check passed.

@jpsiddharth2008
jpsiddharth2008 changed the base branch from main to develop October 27, 2026 12:32
@AadarshM07

AadarshM07 commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Hi @jpsiddharth2008, Could you rebase this PR branch with the develop branch and remove the additional commit dependencies?

@manish-wekan

Copy link
Copy Markdown
Collaborator

Rebase to drop the 32 commits inherited from main.

Remove the internal "branch/stash preserved" note from docs/spillover-line-by-line.md.

Spillover behaviour is not tested independently; its 39 tests pass though.

~sent from claude-code

@jpsiddharth2008
jpsiddharth2008 force-pushed the feature/issue-67-data-spillover branch from 3ea98a7 to e591a4e Compare October 30, 2026 12:09

@AadarshM07 AadarshM07 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jpsiddharth2008, the core implementation looks good to me. I tested it locally, and both the tests and CI pass as well.

Before merging, I think pr92-verification.md and the other docs are not something we maintain. So, I suggest:

  • Deleting the docs/ folder.
  • Removing the README.md references to docs/spillover-line-by-line.md and docs/pr92-verification.md.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[interceptors] Data spillover for large tool results

3 participants