feat(mcp): Connectors — catalog + global vs per-user runtimes (§7/§14/§15)
Re-architects MCP from one owner table + agent-written registration into an admin-curated catalog with two runtimes unioned per session, surfaced in the UI as "Connectors" (mcp/schema stays neutral, §0.1). Two runtimes behind one seam (§7): - Global runtime: shared, stateless connectors (web-search, Tavily…) on the HOST, connected at boot from mcp_global_servers, access-filtered per user via mcp_global_access. - Per-user runtime: a user's activated connectors run INSIDE their container, started at first login from mcp_user_servers and living until restart (§9); docker exec -i children die via kill_on_drop when the UserContext drops. - McpProvider trait (mcp/provider.rs): the session round-loop never learns which runtime owns a server. McpManager implements it directly (inert ownerless bundle); UserMcpView implements global ∪ user with an accessible_global snapshot. Both share McpManager::connect_all; McpServerSpec + global_row_spec/user_row_spec turn a DB row into a connectable spec. - mcp-client: McpServerConfig.launch_in runs a stdio command inside a container via docker exec -i (set at runtime, never parsed from config). Authorization is a capability on the role, not `if role==admin` (§0.1/§14): role_capabilities table + db/role_capabilities.rs — register_remote and register_local_from_catalog are self-service (seeded on every new role), while register_local_script and manage_catalog are admin-only. admin holds every capability by construction. This removes the agent-facing register_mcp/delete_mcp tools and the mcp kinds of list_items/toggle_item, closing the §14 RCE vector. Schema: - Registry: mcp_catalog (vetted templates — schema only, no live creds), mcp_global_servers + mcp_global_access, role_capabilities. - Owner: mcp_user_servers (per-user activations; api_key encrypted at rest, catalog_name a bare TEXT snapshot, never an owner→registry FK). - Drops the old owner table mcp_servers. API + UI: src/frontend/api/mcp.rs (admin catalog/global/access + user available/activate/activated, all capability-gated via require_cap); web/components/connectors.js (<connectors-page>) renders the user view always and the admin view for role_id === 'admin'. Deferred: interactive per-user auth (OAuth callback / QR / SSH elicitation, §15) — only none/api_key wired; no boot seed of catalog presets; per-(user, session) MCP grant model still open.
This commit is contained in:
@@ -3,7 +3,7 @@ use std::sync::{Arc, RwLock};
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::mcp::McpManager;
|
||||
use crate::mcp::McpProvider;
|
||||
use crate::tools::Tool;
|
||||
use crate::tools::tool_names as tn;
|
||||
|
||||
@@ -51,8 +51,9 @@ pub struct AgentRunConfig {
|
||||
pub memory_tools: Vec<Arc<dyn Tool>>,
|
||||
/// Image generation tools — present only when at least one provider is registered.
|
||||
pub image_tools: Vec<Arc<dyn Tool>>,
|
||||
/// MCP manager — used by `all_tool_defs()` to resolve which tools to include.
|
||||
pub mcp: Arc<McpManager>,
|
||||
/// MCP provider (global ∪ per-user) — used by `all_tool_defs()` to resolve
|
||||
/// which tools to include.
|
||||
pub mcp: Arc<dyn McpProvider>,
|
||||
/// Set of MCP server names currently granted (activated) for this agent run.
|
||||
///
|
||||
/// - Root agents: pre-populated from `session_mcp_grants` DB at config-build time;
|
||||
|
||||
@@ -7,7 +7,7 @@ use sqlx::SqlitePool;
|
||||
use crate::compactor::{ContextCompactor, SUMMARY_PREFIX};
|
||||
use crate::config::DatetimeConfig;
|
||||
use crate::db::{chat_history, chat_llm_tools, chat_summaries};
|
||||
use crate::mcp::McpManager;
|
||||
use crate::mcp::McpProvider;
|
||||
use crate::tools::tool_names as tn;
|
||||
|
||||
/// Registry of installed skills, relative to Skald's process cwd. Injected into agents
|
||||
@@ -38,7 +38,7 @@ pub struct MessageBuilder {
|
||||
/// owner `pool` above backs `user-memory/`.
|
||||
pub shared_pool: Arc<SqlitePool>,
|
||||
pub session_id: i64,
|
||||
pub mcp: Arc<McpManager>,
|
||||
pub mcp: Arc<dyn McpProvider>,
|
||||
pub datetime_config: DatetimeConfig,
|
||||
pub max_history_messages: usize,
|
||||
pub max_tool_result_chars: Option<usize>,
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::events::ServerEvent;
|
||||
use core_api::message_meta::MessageMetadata;
|
||||
use core_api::user_fs::UserFs;
|
||||
use crate::llm::LlmManager;
|
||||
use crate::mcp::McpManager;
|
||||
use crate::mcp::McpProvider;
|
||||
use crate::image_generate::ImageGeneratorManager;
|
||||
use crate::memory::MemoryManager;
|
||||
use crate::tool_discovery::ToolDiscovery;
|
||||
@@ -292,7 +292,7 @@ pub struct ChatSessionHandler {
|
||||
/// True for short-lived automated sessions (cron, tic).
|
||||
pub(super) is_ephemeral: bool,
|
||||
pub(super) tools: Arc<ToolRegistry>,
|
||||
pub(super) mcp: Arc<McpManager>,
|
||||
pub(super) mcp: Arc<dyn McpProvider>,
|
||||
/// Records tools offered to the LLM each round so the Security-groups UI can
|
||||
/// list/gate dynamically-injected tools (interface/plugin/provider tools).
|
||||
pub(super) tool_discovery: Arc<ToolDiscovery>,
|
||||
@@ -354,7 +354,7 @@ impl ChatSessionHandler {
|
||||
is_interactive: bool,
|
||||
is_ephemeral: bool,
|
||||
tools: Arc<ToolRegistry>,
|
||||
mcp: Arc<McpManager>,
|
||||
mcp: Arc<dyn McpProvider>,
|
||||
approval: Arc<ApprovalManager>,
|
||||
clarification: Arc<ClarificationManager>,
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::compactor::ContextCompactor;
|
||||
use crate::config::DatetimeConfig;
|
||||
use crate::db::{chat_sessions, chat_sessions_stack};
|
||||
use crate::llm::LlmManager;
|
||||
use crate::mcp::McpManager;
|
||||
use crate::mcp::McpProvider;
|
||||
use crate::image_generate::ImageGeneratorManager;
|
||||
use crate::memory::MemoryManager;
|
||||
use crate::run_context::{RunContext, RunContextManager};
|
||||
@@ -38,7 +38,9 @@ pub struct ChatSessionManager {
|
||||
max_tool_result_chars: Option<usize>,
|
||||
datetime_config: DatetimeConfig,
|
||||
tools: Arc<ToolRegistry>,
|
||||
mcp: Arc<McpManager>,
|
||||
/// The MCP tools visible to this owner: the access-filtered global runtime
|
||||
/// unioned with their per-user runtime (blueprint §7), behind one trait.
|
||||
mcp: Arc<dyn McpProvider>,
|
||||
approval: Arc<ApprovalManager>,
|
||||
clarification: Arc<ClarificationManager>,
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
@@ -66,7 +68,7 @@ impl ChatSessionManager {
|
||||
max_tool_result_chars: Option<usize>,
|
||||
datetime_config: DatetimeConfig,
|
||||
tools: Arc<ToolRegistry>,
|
||||
mcp: Arc<McpManager>,
|
||||
mcp: Arc<dyn McpProvider>,
|
||||
approval: Arc<ApprovalManager>,
|
||||
clarification: Arc<ClarificationManager>,
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
|
||||
Reference in New Issue
Block a user