Hmbown/CodeWhale · warning · anyhow::Error
MCP pool has no configuration source to reload
Error message
MCP pool has no configuration source to reload
What it means
reload_from_config_sources(force=true) implements /mcp reload and startup reconnects: it stat's each recorded config source and re-reads when mtimes moved. If the pool has no recorded sources (config_sources empty — an ad-hoc pool built via McpPool::new or a default config with no files) and a forced reload is requested, it bails with this error instead of pretending to reload nothing. With force=false it just returns Ok(false).
Source
Thrown at crates/tui/src/mcp.rs:2522
}
/// If the source config file's mtime has changed since the last check,
/// re-read it and (only when the content hash also changed) drop all
/// existing connections so the next `get_or_connect` reattaches under
/// the new config. No-op when the pool was constructed via [`McpPool::new`]
/// (no source path), when stat fails, or when the file content is
/// byte-identical to what we last loaded. Returns `Ok(true)` if any
/// connections were dropped, `Ok(false)` otherwise.
///
/// This is the lazy half of the auto-reload story for #1267: instead of a
/// long-lived file watcher, the next tool invocation pays a single `stat`
/// call (and only re-reads the file when the mtime moved). On networked
/// or remote filesystems where mtime granularity is poor, the hash
/// compare keeps us from churning connections on every check.
fn reload_from_config_sources(&mut self, force: bool) -> Result<bool> {
if self.config_sources.is_empty() {
if force {
anyhow::bail!("MCP pool has no configuration source to reload");
}
return Ok(false);
}
let current_mtimes: Vec<_> = self
.config_sources
.iter()
.map(|path| mcp_config_mtime(path))
.collect();
if !force && current_mtimes == self.last_mtimes {
return Ok(false);
}
// An mtime moved, or the user explicitly requested a reload: re-read
// the complete global + workspace + plugin-backed config.
let primary = self
.config_sources
.first()
.context("MCP config source list unexpectedly empty")?;
let new_config = if let Some(workspace) = self.workspace.as_deref() {View on GitHub (pinned to 8880682c63)
Solutions
- Construct the pool through from_config_path... / empty_with_workspace_config_sources so config_sources records the real file paths.
- If using a purely programmatic config, don't expose or invoke forced reload — replace the config via the switch/transactional APIs instead.
- Create the expected config file on disk so the reload has a source.
- Guard the UI: disable /mcp reload when no sources are recorded.
Example fix
// before let mut pool = McpPool::new(McpConfig::default()); // later: /mcp reload -> 'MCP pool has no configuration source to reload' // after let mut pool = McpPool::from_config_path_with_workspace(&cfg_path, &workspace)?; // reload now re-reads cfg_path and the workspace/trust candidates
Defensive patterns
Strategy: validation
Validate before calling
// Rust: only offer forced reload when sources exist
fn can_force_reload(pool: &McpPool) -> bool {
!pool.config_sources().is_empty() // expose or inspect recorded sources
}
if can_force_reload(&pool) {
pool.reload_from_config_sources(true)?;
} else {
tracing::info!("no MCP config source recorded; nothing to reload");
} Try / catch
// Rust: degrade gracefully when there is nothing to reload
match pool.reload_from_config_sources(true) {
Err(e) if e.to_string().contains("no configuration source to reload") => {
// informational: programmatic pool, skip the reload action
}
other => other?,
} Prevention
- Build pools from a config file path so reload always has a source.
- In UIs, disable the reload command for programmatic/source-less pools.
- Remember force=false on an empty pool is a no-op Ok(false), not an error.
When it happens
Trigger: Calling the forced-reload entry point (user runs /mcp reload, or a caller passes force=true) on a pool that was constructed directly from an McpConfig value rather than from a config file path, so no source paths were ever recorded.
Common situations: Embedding the pool with a programmatic config in tests or tools and then triggering the reload command; a session that started with a completely absent config file where even fallback sources resolved to nothing; callers assuming reload always has a file to re-read.
Related errors
- invalid JSON payload at key {MCP_SERVER_DEFINITIONS_KEY}; co
- invalid MCP server definition list in key {MCP_SERVER_DEFINI
- Failed to write MCP config {}: {}
- MCP config path cannot be empty
- MCP config path cannot contain '..' components
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/57546bba273a2b00.
Report an issue: GitHub.