Hmbown/CodeWhale · error · anyhow::Error
MCP resource URI '{uri}' was not advertised by server '{serv
Error message
MCP resource URI '{uri}' was not advertised by server '{server_name}' What it means
read_resource_advertised (the guarded read path) first fetches the connection's advertised catalog and checks the requested uri against both literal resource URIs and resource templates (resource_uri_matches_template). Only URIs the server advertised in resources/list or resources/templates/list are allowed through; anything else is rejected before a read is sent, so the server never receives a request for an unadvertised URI. This prevents authority smuggling via crafted URIs.
Source
Thrown at crates/tui/src/mcp.rs:2986
}
prompts
}
/// Read a resource from a specific server
pub async fn read_resource(
&mut self,
server_name: &str,
uri: &str,
) -> Result<serde_json::Value> {
let global_timeouts = self.config.timeouts;
let conn = self.get_or_connect(server_name).await?;
let advertised_literal = conn.resources().iter().any(|resource| resource.uri == uri);
let advertised_template = conn
.resource_templates()
.iter()
.any(|template| resource_uri_matches_template(uri, &template.uri_template));
if !advertised_literal && !advertised_template {
anyhow::bail!("MCP resource URI '{uri}' was not advertised by server '{server_name}'");
}
let timeout = conn.config().effective_read_timeout(&global_timeouts);
conn.read_resource(uri, timeout).await
}
/// Get a prompt from a specific server
pub async fn get_prompt(
&mut self,
server_name: &str,
prompt_name: &str,
arguments: serde_json::Value,
) -> Result<serde_json::Value> {
let global_timeouts = self.config.timeouts;
let conn = self.get_or_connect(server_name).await?;
if !conn
.prompts()
.iter()
.any(|prompt| prompt.name == prompt_name)View on GitHub (pinned to 8880682c63)
Solutions
- List the advertised resources first (list_mcp_resources / conn.resources()) and use an exact advertised URI, or expand a template from resource_templates() verbatim.
- If the catalog may be stale (server restarted or config reloaded), force a reconnect/refresh so resources/list is re-fetched, then retry with the fresh URI.
- For template resources, validate your substitution against the template pattern before calling.
- Fix typos and encoding — the check is exact-match on literals and pattern-match on templates.
Example fix
// before
pool.read_resource_advertised("docs", "file:///proj/readme").await?;
// Err: 'MCP resource URI ... was not advertised' (server advertises project://proj/readme)
// after
let uri = pool.get_or_connect("docs").await?
.resources().iter().find(|r| r.uri.ends_with("readme"))
.map(|r| r.uri.clone()).expect("readme resource");
pool.read_resource_advertised("docs", &uri).await?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: verify the URI is advertised before reading
fn advertised(pool: &McpPool, server: &str, uri: &str) -> Result<()> {
let conn = pool.get_or_connect(server).await?;
let lit = conn.resources().iter().any(|r| r.uri == uri);
let tpl = conn.resource_templates().iter()
.any(|t| resource_uri_matches_template(uri, &t.uri_template));
ensure!(lit || tpl, "URI '{uri}' not advertised");
Ok(())
} Try / catch
// Rust: on failure, refresh the catalog and retry with an advertised URI
match pool.read_resource_advertised(server, uri).await {
Err(e) if e.to_string().contains("was not advertised") => {
let fresh = pool.get_or_connect(server).await?.resources().to_vec();
// re-pick `uri` from `fresh`, then retry
}
o => o,
} Prevention
- Always copy URIs from list_mcp_resources output instead of typing them.
- Expand resource templates with exactly the parameters the template declares.
- Re-list resources after server restarts or config reloads — catalogs go stale.
When it happens
Trigger: Calling the resource-read API with a hand-typed URI that has a typo, a URI built from a template with wrong substitutions (so it matches neither literal nor template), or a URI remembered from an older catalog after the server changed its resource set.
Common situations: The model or user constructs URIs instead of copying them from list_mcp_resources; template parameter formatting drift (missing percent-encoding, wrong case); server restarted with fewer resources while the client cached the old list; URI scheme differences (file:// vs path).
Related errors
- MCP config path cannot be empty
- MCP config path cannot contain '..' components
- invalid environment placeholder in MCP config value
- reviewed plugin MCP endpoint must not contain user informati
- reviewed plugin MCP endpoint must not contain a query or fra
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/1eef524d9f299095.
Report an issue: GitHub.