Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ target/
# Python
__pycache__/
*.pyc
*.pyo
*.pyd

# Benchmark results (local runs, not committed)
bench-results/
Expand All @@ -34,8 +36,5 @@ trace_*.json
.claude/settings.local.json
.worktrees/

# Python cache
__pycache__/
*.pyc
*.pyo
*.pyd
# JetBrains IDE
.idea
2 changes: 1 addition & 1 deletion channels-src/whatsapp/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 20 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,8 @@ impl AppBuilder {

let mcp_session_manager = Arc::new(McpSessionManager::new());
let mcp_process_manager = Arc::new(McpProcessManager::new());
let companion_mcp_server =
crate::tools::mcp::config::derive_nearai_companion_mcp_server(&self.config);

// Create WASM tool runtime eagerly so extensions installed after startup
// (e.g. via the web UI) can still be activated. The tools directory is only
Expand Down Expand Up @@ -477,14 +479,24 @@ impl AppBuilder {
let mcp_sm = Arc::clone(&mcp_session_manager);
let pm = Arc::clone(&mcp_process_manager);
let owner_id = self.config.owner_id.clone();
let companion_mcp_server = companion_mcp_server.clone();
async move {
let servers_result = if let Some(ref d) = db {
load_mcp_servers_from_db(d.as_ref(), &owner_id).await
} else {
crate::tools::mcp::config::load_mcp_servers().await
};
match servers_result {
Ok(servers) => {
Ok(mut servers) => {
if let Some(companion) = companion_mcp_server {
let companion_name = companion.name.clone();
if !servers.insert_if_absent(companion) {
tracing::debug!(
"Skipping derived MCP companion '{}': an existing config with that name is already present",
companion_name
);
}
}
let enabled: Vec<_> = servers.enabled_servers().cloned().collect();
if !enabled.is_empty() {
tracing::debug!(
Expand All @@ -496,6 +508,8 @@ impl AppBuilder {
let mut join_set = tokio::task::JoinSet::new();
for server in enabled {
let mcp_sm = Arc::clone(&mcp_sm);
let nearai_session = Arc::clone(&self.session);
let nearai_api_key = self.config.llm.nearai.api_key.clone();
let secrets = secrets_store.clone();
let tools = Arc::clone(&tools);
let pm = Arc::clone(&pm);
Expand All @@ -507,6 +521,8 @@ impl AppBuilder {
let client = match crate::tools::mcp::create_client_from_config(
server,
&mcp_sm,
Some(nearai_session),
nearai_api_key,
&pm,
secrets,
&owner_id,
Expand Down Expand Up @@ -644,6 +660,8 @@ impl AppBuilder {
let manager = Arc::new(ExtensionManager::new(
Arc::clone(&mcp_session_manager),
Arc::clone(&mcp_process_manager),
Some(Arc::clone(&self.session)),
self.config.llm.nearai.api_key.clone(),
ext_secrets,
Arc::clone(tools),
Some(Arc::clone(hooks)),
Expand All @@ -653,6 +671,7 @@ impl AppBuilder {
self.config.tunnel.public_url.clone(),
self.config.owner_id.clone(),
self.db.clone(),
companion_mcp_server,
catalog_entries.clone(),
));
tools.register_extension_tools(Arc::clone(&manager));
Expand Down
1 change: 1 addition & 0 deletions src/channels/web/handlers/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub async fn extensions_list_handler(
tools: ext.tools,
needs_setup: ext.needs_setup,
has_auth: ext.has_auth,
derived: ext.derived,
activation_status,
activation_error: ext.activation_error,
version: ext.version,
Expand Down
6 changes: 6 additions & 0 deletions src/channels/web/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1885,6 +1885,7 @@ async fn extensions_list_handler(
tools: ext.tools,
needs_setup: ext.needs_setup,
has_auth: ext.has_auth,
derived: ext.derived,
activation_status,
activation_error: ext.activation_error,
version: ext.version,
Expand Down Expand Up @@ -2795,6 +2796,7 @@ mod tests {
tools: Vec::new(),
needs_setup: true,
has_auth: false,
derived: false,
installed: true,
activation_error: None,
version: None,
Expand Down Expand Up @@ -2832,6 +2834,7 @@ mod tests {
tools: Vec::new(),
needs_setup: true,
has_auth: false,
derived: false,
installed: true,
activation_error: None,
version: None,
Expand Down Expand Up @@ -3490,6 +3493,8 @@ mod tests {
let ext_mgr = Arc::new(ExtensionManager::new(
mcp_sm,
mcp_pm,
None,
None,
secrets,
tool_registry,
None,
Expand All @@ -3499,6 +3504,7 @@ mod tests {
None,
"test".to_string(),
None,
None,
vec![],
));
(ext_mgr, wasm_tools_dir, wasm_channels_dir)
Expand Down
3 changes: 3 additions & 0 deletions src/channels/web/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,9 @@ pub struct ExtensionInfo {
/// Whether this extension has an auth configuration (OAuth or manual token).
#[serde(default)]
pub has_auth: bool,
/// Whether this extension is derived from runtime/provider state.
#[serde(default)]
pub derived: bool,
/// WASM channel activation status.
#[serde(skip_serializing_if = "Option::is_none")]
pub activation_status: Option<ExtensionActivationStatus>,
Expand Down
Loading
Loading