MCP Apps Plumbing (#6286)

Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
Douwe Osinga
2026-01-05 10:34:52 -05:00
committed by GitHub
parent d1f242b69f
commit 85aee9c5b7
21 changed files with 484 additions and 947 deletions
+51 -6
View File
@@ -12,6 +12,7 @@ use axum::{
};
use goose::config::PermissionManager;
use base64::Engine;
use goose::agents::ExtensionConfig;
use goose::config::{Config, GooseMode};
use goose::model::ModelConfig;
@@ -94,9 +95,15 @@ pub struct ReadResourceRequest {
uri: String,
}
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ReadResourceResponse {
html: String,
uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
mime_type: Option<String>,
text: String,
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
meta: Option<serde_json::Map<String, Value>>,
}
#[derive(Deserialize, utoipa::ToSchema)]
@@ -587,13 +594,15 @@ async fn read_resource(
State(state): State<Arc<AppState>>,
Json(payload): Json<ReadResourceRequest>,
) -> Result<Json<ReadResourceResponse>, StatusCode> {
use rmcp::model::ResourceContents;
let agent = state
.get_agent_for_route(payload.session_id.clone())
.await?;
let html = agent
let read_result = agent
.extension_manager
.read_ui_resource(
.read_resource(
&payload.uri,
&payload.extension_name,
CancellationToken::default(),
@@ -601,7 +610,43 @@ async fn read_resource(
.await
.map_err(|_e| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(ReadResourceResponse { html }))
let content = read_result
.contents
.into_iter()
.next()
.ok_or(StatusCode::NOT_FOUND)?;
let (uri, mime_type, text, meta) = match content {
ResourceContents::TextResourceContents {
uri,
mime_type,
text,
meta,
} => (uri, mime_type, text, meta),
ResourceContents::BlobResourceContents {
uri,
mime_type,
blob,
meta,
} => {
let decoded = match base64::engine::general_purpose::STANDARD.decode(&blob) {
Ok(bytes) => {
String::from_utf8(bytes).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
}
Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR),
};
(uri, mime_type, decoded, meta)
}
};
let meta_map = meta.map(|m| m.0);
Ok(Json(ReadResourceResponse {
uri,
mime_type,
text,
meta: meta_map,
}))
}
#[utoipa::path(
@@ -649,7 +694,7 @@ async fn call_tool(
content: result.content,
structured_content: result.structured_content,
is_error: result.is_error.unwrap_or(false),
_meta: None,
_meta: result.meta.and_then(|m| serde_json::to_value(m).ok()),
}))
}