Problem
MCP tools and CLI wrappers frequently invoke long-running infrastructure operations (BMC reboots, MAAS deploys, firmware updates, etc.). Today, poll_with_progress defaults to timeout_s=600 and each caller picks its own timeout — often a guess. Agents calling these tools have no way to know how long an operation should take, leading to:
- Premature timeouts (agent gives up too early)
- Wasted idle time (agent waits far longer than needed before declaring failure)
- No feedback loop — historical duration data is never captured or reused
For context, real-world operations vary wildly: a Supermicro BMC reboot is ~5 min, a vanilla MAAS deploy is ~20 min, a firmware flash is ~15 min. Each downstream MCP knows its own operations — mcp-common does not and should not.
What mcp-common should provide
mcp-common is a library — it doesn't know about redfish, MAAS, or weka. It should provide primitives and a reference architecture that downstream MCPs use to define, store, report, and consume their own operation timing data.
1. Timing catalog primitives
A typed data structure that any MCP can instantiate to register its operations and their expected durations:
from mcp_common.timing import OperationTiming, TimingCatalog
# Each downstream MCP defines its own catalog
catalog = TimingCatalog([
OperationTiming(
operation_id="power_cycle",
description="Full BMC power cycle via Redfish",
expected_s=300,
timeout_s=600,
tags=["power"],
),
OperationTiming(
operation_id="firmware_update",
description="BMC firmware flash",
expected_s=900,
timeout_s=1800,
tags=["firmware"],
),
])
mcp-common defines OperationTiming, TimingCatalog, and the lookup interface. Each MCP populates its own.
2. Integration with poll_with_progress
Allow callers to pass an operation_id that resolves timeout/interval from a catalog instead of raw numbers:
# Today — caller guesses
result = await poll_with_progress(ctx, check_fn, "status", states, timeout_s=1200)
# Proposed — catalog-driven
result = await poll_with_progress(ctx, check_fn, "status", states, catalog=catalog, operation_id="deploy")
If both timeout_s and operation_id are given, explicit timeout_s wins (escape hatch). The catalog just provides smart defaults.
3. Structured timing telemetry on poll completion
When poll_with_progress completes, emit a structured log event with:
{
"log_channel": "transcript",
"event": "poll_complete",
"operation_id": "deploy",
"expected_s": 1200,
"actual_s": 1087,
"timed_out": false,
"ok": true
}
This uses the existing log_transcript_event / mcp_log_transcript infrastructure from #17. Downstream teams can mine these logs to refine their catalog values over time.
4. Catalog storage format
mcp-common should define a canonical file format (TOML section, or a Python dict) and a loader, so downstream MCPs can store timing data however they prefer:
| Storage pattern |
Who does it |
Notes |
| Python dict in code |
Downstream MCP |
Simplest, versioned with the code |
timing.toml file |
Downstream MCP |
Separates data from code, human-editable |
mcp-plugin.toml section |
Downstream MCP |
Co-located with existing plugin metadata |
| Dynamic / DB-backed |
Downstream MCP (future) |
For teams that want to update without deploys |
mcp-common provides the loader interface; each MCP chooses its own backend.
Design questions to resolve
-
Should OperationTiming include percentiles (p50, p95)? Useful for progress reporting ("you're past the 95th percentile, something may be wrong") but adds complexity before we have real data.
-
How do downstream MCPs collect actual durations?
- Transcript log mining (passive, retrospective)
- Explicit telemetry from
poll_with_progress (proposed above)
- Agent self-report during runs
- Observability pipeline / OTel spans (future)
-
Should agents be able to query the catalog? A dedicated tool (get_expected_duration) or just bake it into tool descriptions / progress messages?
-
How does the agent use this? The agent needs to set block_until_ms when calling MCP tools. Options:
- Progress messages include ETA so the agent can calibrate its own polling
- Tool response metadata includes
expected_duration_s
- Agent reads the catalog before invoking (extra round-trip)
Scope for mcp-common
Not in scope for mcp-common: actual operation timing values, specific MCP domain knowledge, or centralized catalogs of all operations.
Related
References
- Argo Workflows estimated-duration annotations (per-step, defined by the workflow author)
- Temporal Nexus dynamic config for operation timeouts
- AWS Systems Manager
timeoutSeconds per automation action
- Prefect SLA duration thresholds with severity levels
Problem
MCP tools and CLI wrappers frequently invoke long-running infrastructure operations (BMC reboots, MAAS deploys, firmware updates, etc.). Today,
poll_with_progressdefaults totimeout_s=600and each caller picks its own timeout — often a guess. Agents calling these tools have no way to know how long an operation should take, leading to:For context, real-world operations vary wildly: a Supermicro BMC reboot is ~5 min, a vanilla MAAS deploy is ~20 min, a firmware flash is ~15 min. Each downstream MCP knows its own operations — mcp-common does not and should not.
What mcp-common should provide
mcp-common is a library — it doesn't know about redfish, MAAS, or weka. It should provide primitives and a reference architecture that downstream MCPs use to define, store, report, and consume their own operation timing data.
1. Timing catalog primitives
A typed data structure that any MCP can instantiate to register its operations and their expected durations:
mcp-common defines
OperationTiming,TimingCatalog, and the lookup interface. Each MCP populates its own.2. Integration with
poll_with_progressAllow callers to pass an
operation_idthat resolves timeout/interval from a catalog instead of raw numbers:If both
timeout_sandoperation_idare given, explicittimeout_swins (escape hatch). The catalog just provides smart defaults.3. Structured timing telemetry on poll completion
When
poll_with_progresscompletes, emit a structured log event with:{ "log_channel": "transcript", "event": "poll_complete", "operation_id": "deploy", "expected_s": 1200, "actual_s": 1087, "timed_out": false, "ok": true }This uses the existing
log_transcript_event/mcp_log_transcriptinfrastructure from #17. Downstream teams can mine these logs to refine their catalog values over time.4. Catalog storage format
mcp-common should define a canonical file format (TOML section, or a Python dict) and a loader, so downstream MCPs can store timing data however they prefer:
timing.tomlfilemcp-plugin.tomlsectionmcp-common provides the loader interface; each MCP chooses its own backend.
Design questions to resolve
Should
OperationTiminginclude percentiles (p50, p95)? Useful for progress reporting ("you're past the 95th percentile, something may be wrong") but adds complexity before we have real data.How do downstream MCPs collect actual durations?
poll_with_progress(proposed above)Should agents be able to query the catalog? A dedicated tool (
get_expected_duration) or just bake it into tool descriptions / progress messages?How does the agent use this? The agent needs to set
block_until_mswhen calling MCP tools. Options:expected_duration_sScope for mcp-common
OperationTimingdataclass andTimingCatalogwith lookupcatalog+operation_idparams onpoll_with_progresstiming.tomlfilestiming.tomlin docs/examplesNot in scope for mcp-common: actual operation timing values, specific MCP domain knowledge, or centralized catalogs of all operations.
Related
mcp_common.progress.poll_with_progress— current polling primitive to extendReferences
timeoutSecondsper automation action