Standalone mcp apps (#6458)
Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
@@ -355,11 +355,13 @@ derive_utoipa!(Icon as IconSchema);
|
||||
super::routes::config_management::get_pricing,
|
||||
super::routes::agent::start_agent,
|
||||
super::routes::agent::resume_agent,
|
||||
super::routes::agent::stop_agent,
|
||||
super::routes::agent::restart_agent,
|
||||
super::routes::agent::update_working_dir,
|
||||
super::routes::agent::get_tools,
|
||||
super::routes::agent::read_resource,
|
||||
super::routes::agent::call_tool,
|
||||
super::routes::agent::list_apps,
|
||||
super::routes::agent::update_from_session,
|
||||
super::routes::agent::agent_add_extension,
|
||||
super::routes::agent::agent_remove_extension,
|
||||
@@ -533,8 +535,11 @@ derive_utoipa!(Icon as IconSchema);
|
||||
super::routes::agent::ReadResourceResponse,
|
||||
super::routes::agent::CallToolRequest,
|
||||
super::routes::agent::CallToolResponse,
|
||||
super::routes::agent::ListAppsRequest,
|
||||
super::routes::agent::ListAppsResponse,
|
||||
super::routes::agent::StartAgentRequest,
|
||||
super::routes::agent::ResumeAgentRequest,
|
||||
super::routes::agent::StopAgentRequest,
|
||||
super::routes::agent::RestartAgentRequest,
|
||||
super::routes::agent::UpdateWorkingDirRequest,
|
||||
super::routes::agent::UpdateFromSessionRequest,
|
||||
@@ -547,6 +552,8 @@ derive_utoipa!(Icon as IconSchema);
|
||||
super::tunnel::TunnelInfo,
|
||||
super::tunnel::TunnelState,
|
||||
super::routes::telemetry::TelemetryEventRequest,
|
||||
goose::goose_apps::GooseApp,
|
||||
goose::goose_apps::WindowProps,
|
||||
goose::goose_apps::McpAppResource,
|
||||
goose::goose_apps::CspMetadata,
|
||||
goose::goose_apps::UiMetadata,
|
||||
|
||||
@@ -11,6 +11,7 @@ use axum::{
|
||||
Json, Router,
|
||||
};
|
||||
use goose::agents::ExtensionLoadResult;
|
||||
use goose::goose_apps::{fetch_mcp_apps, GooseApp, McpAppCache};
|
||||
|
||||
use base64::Engine;
|
||||
use goose::agents::ExtensionConfig;
|
||||
@@ -35,7 +36,7 @@ use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::error;
|
||||
use tracing::{error, warn};
|
||||
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct UpdateFromSessionRequest {
|
||||
@@ -933,6 +934,87 @@ async fn call_tool(
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize, utoipa::IntoParams, utoipa::ToSchema)]
|
||||
pub struct ListAppsRequest {
|
||||
session_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, utoipa::ToSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListAppsResponse {
|
||||
pub apps: Vec<GooseApp>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/agent/list_apps",
|
||||
params(
|
||||
ListAppsRequest
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "List of apps retrieved successfully", body = ListAppsResponse),
|
||||
(status = 401, description = "Unauthorized - Invalid or missing API key", body = ErrorResponse),
|
||||
(status = 500, description = "Internal server error", body = ErrorResponse),
|
||||
),
|
||||
security(
|
||||
("api_key" = [])
|
||||
),
|
||||
tag = "Agent"
|
||||
)]
|
||||
async fn list_apps(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Query(params): Query<ListAppsRequest>,
|
||||
) -> Result<Json<ListAppsResponse>, ErrorResponse> {
|
||||
let cache = McpAppCache::new().ok();
|
||||
|
||||
let Some(session_id) = params.session_id else {
|
||||
let apps = cache
|
||||
.as_ref()
|
||||
.and_then(|c| c.list_apps().ok())
|
||||
.unwrap_or_default();
|
||||
return Ok(Json(ListAppsResponse { apps }));
|
||||
};
|
||||
|
||||
let agent = state
|
||||
.get_agent_for_route(session_id)
|
||||
.await
|
||||
.map_err(|status| ErrorResponse {
|
||||
message: "Failed to get agent".to_string(),
|
||||
status,
|
||||
})?;
|
||||
|
||||
let apps = fetch_mcp_apps(&agent.extension_manager)
|
||||
.await
|
||||
.map_err(|e| ErrorResponse {
|
||||
message: format!("Failed to list apps: {}", e.message),
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
})?;
|
||||
|
||||
if let Some(cache) = cache.as_ref() {
|
||||
let active_extensions: std::collections::HashSet<String> = apps
|
||||
.iter()
|
||||
.filter_map(|app| app.mcp_server.clone())
|
||||
.collect();
|
||||
|
||||
for extension_name in active_extensions {
|
||||
if let Err(e) = cache.delete_extension_apps(&extension_name) {
|
||||
warn!(
|
||||
"Failed to clean cache for extension {}: {}",
|
||||
extension_name, e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for app in &apps {
|
||||
if let Err(e) = cache.store_app(app) {
|
||||
warn!("Failed to cache app {}: {}", app.resource.name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Json(ListAppsResponse { apps }))
|
||||
}
|
||||
|
||||
pub fn routes(state: Arc<AppState>) -> Router {
|
||||
Router::new()
|
||||
.route("/agent/start", post(start_agent))
|
||||
@@ -942,6 +1024,7 @@ pub fn routes(state: Arc<AppState>) -> Router {
|
||||
.route("/agent/tools", get(get_tools))
|
||||
.route("/agent/read_resource", post(read_resource))
|
||||
.route("/agent/call_tool", post(call_tool))
|
||||
.route("/agent/list_apps", get(list_apps))
|
||||
.route("/agent/update_provider", post(update_agent_provider))
|
||||
.route("/agent/update_from_session", post(update_from_session))
|
||||
.route("/agent/add_extension", post(agent_add_extension))
|
||||
|
||||
Reference in New Issue
Block a user