feat(mcp): hold a tool listing for an hour, and let something end that early #365

Merged
coilyco-ops merged 2 commits from feat/roster-hour-ttl-and-refresh into main 2026-08-13 11:08:59 +00:00
Member

Kai chose a 1 hour TTL plus an agent-invokable refresh, over the boot-only
resolution recorded earlier on 163. This is the TTL half and the seam the
refresh needs.

The interval moves 5 minutes to an hour. Refresh marks every rostered server
stale so the next turn re-lists.

The reason an hour is safe is worth stating, because it is the thing I got
wrong when I argued against removing the TTL entirely. Expiry is not the only
trigger. dropSession nils tools, and needsTools returns true whenever tools is
nil, so a server that failed to list retries on every turn its backoff allows
regardless of the interval. The interval governs only servers that already
answered. Removing the TTL would have broken that; lengthening it does not.

Refresh dials nothing. It sets a flag the next Open reads, so twenty calls
collapse into one listing. That is why it carries no rate limit of its own,
which corrects what I said I would build when I claimed this.

The three tests bind those three claims rather than the implementation: an
unlisted server ignores the interval, a refresh re-lists inside it, and repeated
refreshes cost one listing. Mutation checked by making Refresh mark nothing.

The model-callable half is not here. Every tool Echo offers comes from an MCP
server today, so a refresh the agent can invoke needs the first harness-native
tool, which is a new seam rather than a wiring change. Filed separately.

closes #363

Co-authored-by: Kai Siren coilysiren@gmail.com
Co-authored-by: Claude noreply@anthropic.com
Co-authored-by: Kai Siren coilysiren@gmail.com
Co-authored-by: Claude noreply@anthropic.com

Kai chose a 1 hour TTL plus an agent-invokable refresh, over the boot-only resolution recorded earlier on 163. This is the TTL half and the seam the refresh needs. The interval moves 5 minutes to an hour. Refresh marks every rostered server stale so the next turn re-lists. The reason an hour is safe is worth stating, because it is the thing I got wrong when I argued against removing the TTL entirely. Expiry is not the only trigger. dropSession nils tools, and needsTools returns true whenever tools is nil, so a server that failed to list retries on every turn its backoff allows regardless of the interval. The interval governs only servers that already answered. Removing the TTL would have broken that; lengthening it does not. Refresh dials nothing. It sets a flag the next Open reads, so twenty calls collapse into one listing. That is why it carries no rate limit of its own, which corrects what I said I would build when I claimed this. The three tests bind those three claims rather than the implementation: an unlisted server ignores the interval, a refresh re-lists inside it, and repeated refreshes cost one listing. Mutation checked by making Refresh mark nothing. The model-callable half is not here. Every tool Echo offers comes from an MCP server today, so a refresh the agent can invoke needs the first harness-native tool, which is a new seam rather than a wiring change. Filed separately. closes #363 Co-authored-by: Kai Siren <coilysiren@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Kai Siren <coilysiren@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
feat(mcp): hold a tool listing for an hour, and let something end that early
All checks were successful
ci / test (pull_request) Successful in 30s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 19s
eb1eb1dffd
Kai chose a 1 hour TTL plus an agent-invokable refresh, over the boot-only
resolution recorded earlier on 163. This is the TTL half and the seam the
refresh needs.

The interval moves 5 minutes to an hour. Refresh marks every rostered server
stale so the next turn re-lists.

The reason an hour is safe is worth stating, because it is the thing I got
wrong when I argued against removing the TTL entirely. Expiry is not the only
trigger. dropSession nils tools, and needsTools returns true whenever tools is
nil, so a server that failed to list retries on every turn its backoff allows
regardless of the interval. The interval governs only servers that already
answered. Removing the TTL would have broken that; lengthening it does not.

Refresh dials nothing. It sets a flag the next Open reads, so twenty calls
collapse into one listing. That is why it carries no rate limit of its own,
which corrects what I said I would build when I claimed this.

The three tests bind those three claims rather than the implementation: an
unlisted server ignores the interval, a refresh re-lists inside it, and repeated
refreshes cost one listing. Mutation checked by making Refresh mark nothing.

The model-callable half is not here. Every tool Echo offers comes from an MCP
server today, so a refresh the agent can invoke needs the first harness-native
tool, which is a new seam rather than a wiring change. Filed separately.

closes #363

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Merge branch 'main' into feat/roster-hour-ttl-and-refresh
All checks were successful
ci / test (pull_request) Successful in 30s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 19s
0085d0b5ad
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!365
No description provided.