gitbutlerapp/gitbutler · error
MCP Apps capability is an object
Error message
MCP Apps capability is an object
What it means
When the MCP server advertises itself (ServerHandler::get_info), but inserts the MCP Apps UI capability into ExtensionCapabilities by deserializing a hardcoded JSON literal ({"mimeTypes":[MCP_APP_MIME_TYPE]}) into rmcp's capability value type. Since the input is a compile-time constant, the expect can only fail when the installed rmcp crate's extension-capability type no longer accepts that shape — i.e. a dependency upgrade changed the schema.
Source
Thrown at crates/but/src/command/mcp/mod.rs:245
Ok(match result {
Ok(result) => result,
Err(err) => CallToolResult::error(vec![Content::text(format!(
"Could not mark the review as ready: {err:#}"
))]),
})
}
}
#[tool_handler]
impl ServerHandler for Mcp {
fn get_info(&self) -> ServerInfo {
let mut extensions = ExtensionCapabilities::new();
extensions.insert(
"io.modelcontextprotocol/ui".to_owned(),
serde_json::from_value(json!({
"mimeTypes": [MCP_APP_MIME_TYPE]
}))
.expect("MCP Apps capability is an object"),
);
ServerInfo {
instructions: Some(
"Use gitbutler_workspace to inspect a repository's current GitButler workspace. Pass the active repository path when it is available; omit it only when the client is known to expose that repository as a filesystem root. After `but pr new`, call gitbutler_review_card with the returned review numbers so the user can see the created reviews."
.into(),
),
capabilities: ServerCapabilities::builder()
.enable_extensions_with(extensions)
.enable_resources()
.enable_tools()
.build(),
server_info: Implementation {
name: "gitbutler".into(),
title: Some("GitButler".into()),
version: option_env!("VERSION").unwrap_or("dev").into(),
description: Some("GitButler workspace tools and views".into()),
icons: None,View on GitHub (pinned to 2497b8007a)
Solutions
- Align rmcp with the version but was built against — check Cargo.lock for the pinned rmcp and restore it (e.g. git checkout Cargo.lock or cargo update -p rmcp --precise <ver>)
- If the upgrade is intentional, update the json! literal to the capability shape the new rmcp expects
- Pin rmcp exactly (rmcp = "=x.y.z") so silent drift cannot reintroduce this
- Add a smoke test asserting get_info() completes without panicking after dependency changes
Example fix
// before — Cargo.toml allows drift rmcp = "0.x" // after — exact pin so the capability literal and the type stay in sync rmcp = "=0.x.y"
Defensive patterns
Strategy: validation
Validate before calling
// after any rmcp/cargo update, verify server info construction before shipping
#[test]
fn mcp_server_info_smoke() {
let mcp = /* construct Mcp handler */;
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| mcp.get_info()));
assert!(result.is_ok(), "get_info panicked — extension capability schema drifted");
} Try / catch
// degrade gracefully: serve without extensions if the capability literal no longer parses
let extensions = std::panic::catch_unwind(AssertUnwindSafe(build_extensions))
.unwrap_or_default(); // proceed with no advertised UI capability Prevention
- Pin rmcp to an exact version (=x.y.z) so capability schemas cannot drift silently
- Run an MCP handshake smoke test (initialize request) in CI after every dependency bump
- Review rmcp changelogs for ExtensionCapabilities/extension-value type changes before upgrading
- Report but-version + rmcp-version together when this panic appears — it is a version-combination bug
When it happens
Trigger: Starting but's MCP server mode (an MCP client spawning `but mcp`, or any path calling Mcp::get_info) after the rmcp dependency was upgraded/changed so that ExtensionCapabilities::insert's value type rejects an object with a mimeTypes array.
Common situations: cargo update or a version bump of the rmcp SDK in the workspace; building against a fork/patched rmcp; drift between rmcp and the MCP Apps (io.modelcontextprotocol/ui) spec revision.
Related errors
- symbols must always be initialized
- The refreshed reviews were missing from the response.
- textFromToolResult(result)
- The updated review was missing from the response.
- textFromToolResult(result)
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/a806f3a59e427ac0.
Report an issue: GitHub.