From 7ad035773a6f4e6aca9ec29d0a759bf8b3b0823f Mon Sep 17 00:00:00 2001 From: Coffee Date: Wed, 25 Mar 2026 10:44:56 +0800 Subject: [PATCH] Improve derived MCP companion UI labels --- src/channels/web/static/app.js | 33 +++++++++++++++++++++++---------- src/extensions/manager.rs | 16 +++++++++++----- src/tools/mcp/config.rs | 4 +--- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/channels/web/static/app.js b/src/channels/web/static/app.js index 6b366482..76f3f823 100644 --- a/src/channels/web/static/app.js +++ b/src/channels/web/static/app.js @@ -1160,7 +1160,7 @@ function addToolCard(name) { const toolName = document.createElement('span'); toolName.className = 'activity-tool-name'; - toolName.textContent = name; + toolName.textContent = humanizeToolName(name); const duration = document.createElement('span'); duration.className = 'activity-tool-duration'; @@ -1344,7 +1344,7 @@ function finalizeActivityGroup() { function humanizeToolName(rawName) { if (!rawName) return ''; - return String(rawName) + return stripDerivedCompanionToolPrefix(String(rawName)) .replace(/[_-]+/g, ' ') .replace(/([a-z0-9])([A-Z])/g, '$1 $2') .replace(/^tool([a-zA-Z])/, 'tool $1') @@ -1352,6 +1352,12 @@ function humanizeToolName(rawName) { .trim(); } +function stripDerivedCompanionToolPrefix(rawName) { + if (!rawName) return ''; + const prefix = '_nearai_companion_mcp_'; + return rawName.startsWith(prefix) ? rawName.slice(prefix.length) : rawName; +} + function shouldShowChannelConnectedMessage(extensionName, success) { if (!success || !extensionName) return false; return String(extensionName).toLowerCase().includes('telegram'); @@ -1871,7 +1877,7 @@ function createToolCallsSummaryElement(toolCalls) { const icon = tc.has_error ? '\u2717' : '\u2713'; const nameSpan = document.createElement('span'); nameSpan.className = 'tool-call-name'; - nameSpan.textContent = icon + ' ' + tc.name; + nameSpan.textContent = icon + ' ' + humanizeToolName(tc.name); item.appendChild(nameSpan); if (tc.result_preview) { @@ -2906,7 +2912,12 @@ function renderExtensionCard(ext) { if (ext.tools && ext.tools.length > 0) { const tools = document.createElement('div'); tools.className = 'ext-tools'; - tools.textContent = 'Tools: ' + ext.tools.join(', '); + const toolNames = ext.tools.map((toolName) => ( + ext.derived && ext.kind === 'mcp_server' + ? stripDerivedCompanionToolPrefix(toolName) + : toolName + )); + tools.textContent = 'Tools: ' + toolNames.join(', '); card.appendChild(tools); } @@ -2967,7 +2978,7 @@ function renderExtensionCard(ext) { // Skip when has_auth is true but needs_setup is false and not yet authenticated — // this means OAuth credentials resolve automatically (builtin/env) and the user // just needs to complete the OAuth flow, not fill in a config form. - if (ext.needs_setup || (ext.has_auth && ext.authenticated)) { + if (!ext.derived && (ext.needs_setup || (ext.has_auth && ext.authenticated))) { const configBtn = document.createElement('button'); configBtn.className = 'btn-ext configure'; configBtn.textContent = ext.authenticated ? I18n.t('ext.reconfigure') : I18n.t('ext.configure'); @@ -2976,11 +2987,13 @@ function renderExtensionCard(ext) { } } - const removeBtn = document.createElement('button'); - removeBtn.className = 'btn-ext remove'; - removeBtn.textContent = I18n.t('ext.remove'); - removeBtn.addEventListener('click', () => removeExtension(ext.name)); - actions.appendChild(removeBtn); + if (!ext.derived) { + const removeBtn = document.createElement('button'); + removeBtn.className = 'btn-ext remove'; + removeBtn.textContent = I18n.t('ext.remove'); + removeBtn.addEventListener('click', () => removeExtension(ext.name)); + actions.appendChild(removeBtn); + } card.appendChild(actions); diff --git a/src/extensions/manager.rs b/src/extensions/manager.rs index 85609e39..4fd479d9 100644 --- a/src/extensions/manager.rs +++ b/src/extensions/manager.rs @@ -1335,11 +1335,17 @@ impl ExtensionManager { Vec::new() }; - let display_name = self - .registry - .get_with_kind(&server.name, Some(ExtensionKind::McpServer)) - .await - .map(|e| e.display_name); + let display_name = + if crate::tools::mcp::config::is_nearai_companion_server_name( + &server.name, + ) { + Some("NEAR AI Companion".to_string()) + } else { + self.registry + .get_with_kind(&server.name, Some(ExtensionKind::McpServer)) + .await + .map(|e| e.display_name) + }; extensions.push(InstalledExtension { name: server.name.clone(), kind: ExtensionKind::McpServer, diff --git a/src/tools/mcp/config.rs b/src/tools/mcp/config.rs index cd5a18ac..eedce0ba 100644 --- a/src/tools/mcp/config.rs +++ b/src/tools/mcp/config.rs @@ -357,9 +357,7 @@ pub fn derive_nearai_companion_mcp_server_from_llm( Some( McpServerConfig::new(NEARAI_COMPANION_MCP_NAME, format!("{mcp_base}/mcp")) .with_auth_source(McpAuthSource::NearAi) - .with_description( - "Companion chat-api MCP server derived from the active NEAR AI provider", - ), + .with_description("Companion MCP server derived from the active NEAR AI provider"), ) }