Skip to content

Commit 4889e03

Browse files
committed
fix: display friendly MCP tool names in UI
- Update frontend components to use display_name for user-friendly display - Add display_name field to ToolItem TypeScript interface - Update tool list display in: * PersonaForm.vue - tool selection list and selected tools * PersonaQuickPreview.vue - tool preview display * PersonaManager.vue - persona detail view * ToolTable.vue - function tools management table - Add getToolDisplayName() helper methods in PersonaForm and PersonaManager
1 parent 67184a2 commit 4889e03

7 files changed

Lines changed: 49 additions & 12 deletions

File tree

astrbot/core/agent/mcp_client.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,14 @@ def __init__(
380380
self, mcp_tool: mcp.Tool, mcp_client: MCPClient, mcp_server_name: str, **kwargs
381381
) -> None:
382382
# Add namespace prefix to avoid conflicts with plugin tools
383-
# Format: mcp_<server_name>__<tool_name>
384-
namespaced_name = f"mcp_{mcp_server_name}__{mcp_tool.name}"
383+
# Normalize server name: remove spaces and special characters
384+
normalized_server_name = mcp_server_name.replace(" ", "_").replace("-", "_")
385+
# Remove any other special characters, keep only alphanumeric and underscore
386+
normalized_server_name = "".join(
387+
c for c in normalized_server_name if c.isalnum() or c == "_"
388+
)
389+
# Format: mcp_<normalized_server_name>__<tool_name>
390+
namespaced_name = f"mcp_{normalized_server_name}__{mcp_tool.name}"
385391

386392
super().__init__(
387393
name=namespaced_name,

astrbot/dashboard/routes/tools.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,10 @@ async def get_tool_list(self):
440440
if isinstance(tool, MCPTool):
441441
origin = "mcp"
442442
origin_name = tool.mcp_server_name
443-
# Add original tool name for MCP tools
444-
display_name = getattr(tool, "original_tool_name", tool.name)
443+
# Format: <ServerName>_<ToolName> for MCP tools
444+
# Normalize server name for display
445+
normalized_server = tool.mcp_server_name.replace(" ", "")
446+
display_name = f"{normalized_server}_{tool.original_tool_name}"
445447
elif tool.handler_module_path and star_map.get(
446448
tool.handler_module_path
447449
):
@@ -456,7 +458,7 @@ async def get_tool_list(self):
456458

457459
tool_info = {
458460
"name": tool.name, # Keep namespaced name for internal use
459-
"display_name": display_name, # Original name for display
461+
"display_name": display_name, # Friendly name for display
460462
"description": tool.description,
461463
"parameters": tool.parameters,
462464
"active": tool.active,

dashboard/src/components/extension/componentPanel/components/ToolTable.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const parameterEntries = (tool: ToolItem) => Object.entries(tool.parameters?.pro
4444
{{ item.name.includes(':') ? 'mdi-server-network' : 'mdi-function-variant' }}
4545
</v-icon>
4646
<div>
47-
<div class="text-subtitle-1 font-weight-medium">{{ item.name }}</div>
47+
<div class="text-subtitle-1 font-weight-medium">{{ item.display_name || item.name }}</div>
4848
</div>
4949
</div>
5050
</template>

dashboard/src/components/extension/componentPanel/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export interface ToolParameter {
9292
/** MCP/函数工具对象 */
9393
export interface ToolItem {
9494
name: string;
95+
display_name?: string;
9596
description: string;
9697
active: boolean;
9798
parameters?: {

dashboard/src/components/shared/PersonaForm.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
</template>
9999

100100
<v-list-item-title>
101-
{{ item.name }}
101+
{{ item.display_name || item.name }}
102102

103103
<v-chip v-if="item.origin" size="x-small" color="info" class="mr-2"
104104
variant="tonal">
@@ -158,7 +158,7 @@
158158
<v-chip v-for="toolName in personaForm.tools" :key="toolName" size="small"
159159
color="primary" variant="tonal" closable
160160
@click:close="removeTool(toolName)">
161-
{{ toolName }}
161+
{{ getToolDisplayName(toolName) }}
162162
</v-chip>
163163
</div>
164164
<div v-else class="text-body-2 text-medium-emphasis">
@@ -818,6 +818,12 @@ export default {
818818
// 检查服务器的所有工具是否都已选中
819819
return Array.isArray(this.personaForm.tools) &&
820820
server.tools.every(toolName => this.personaForm.tools.includes(toolName));
821+
},
822+
823+
getToolDisplayName(toolName) {
824+
// Find tool in availableTools and return display_name if available
825+
const tool = this.availableTools.find(t => t.name === toolName);
826+
return tool?.display_name || toolName;
821827
}
822828
}
823829
}

dashboard/src/components/shared/PersonaQuickPreview.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ const resolvedTools = computed(() =>
123123
normalizedTools.value.map((toolName) => {
124124
const meta = toolMetaMap.value[toolName] || {}
125125
return {
126-
name: toolName,
126+
name: meta.display_name || toolName, // Use display_name for showing
127127
origin: meta.origin || '',
128128
origin_name: meta.origin_name || '',
129129
active: meta.active
@@ -142,6 +142,7 @@ async function loadToolsMeta() {
142142
continue
143143
}
144144
nextMap[tool.name] = {
145+
display_name: tool.display_name || tool.name,
145146
origin: tool.origin || '',
146147
origin_name: tool.origin_name || '',
147148
active: tool.active

dashboard/src/views/persona/PersonaManager.vue

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
class="d-flex flex-wrap ga-1">
165165
<v-chip v-for="toolName in viewingPersona.tools" :key="toolName" size="small"
166166
color="primary" variant="tonal">
167-
{{ toolName }}
167+
{{ getToolDisplayName(toolName) }}
168168
</v-chip>
169169
</div>
170170
<div v-else class="text-body-2 text-medium-emphasis">
@@ -265,6 +265,7 @@
265265

266266
<script lang="ts">
267267
import { defineComponent } from 'vue';
268+
import axios from 'axios';
268269
import { useI18n, useModuleI18n } from '@/i18n/composables';
269270
import { usePersonaStore } from '@/stores/personaStore';
270271
import { mapState, mapActions } from 'pinia';
@@ -347,7 +348,10 @@ export default defineComponent({
347348
348349
// 骨架屏延迟显示控制
349350
showSkeleton: false,
350-
skeletonTimer: null as ReturnType<typeof setTimeout> | null
351+
skeletonTimer: null as ReturnType<typeof setTimeout> | null,
352+
353+
// 工具列表用于显示名称
354+
availableTools: [] as any[]
351355
};
352356
},
353357
computed: {
@@ -411,10 +415,27 @@ export default defineComponent({
411415
async initialize() {
412416
await Promise.all([
413417
this.loadFolderTree(),
414-
this.navigateToFolder(null)
418+
this.navigateToFolder(null),
419+
this.loadTools()
415420
]);
416421
},
417422
423+
async loadTools() {
424+
try {
425+
const response = await axios.get('/api/tools/list');
426+
if (response.data.status === 'ok') {
427+
this.availableTools = response.data.data || [];
428+
}
429+
} catch (error) {
430+
console.error('Failed to load tools:', error);
431+
}
432+
},
433+
434+
getToolDisplayName(toolName: string): string {
435+
const tool = this.availableTools.find(t => t.name === toolName);
436+
return tool?.display_name || toolName;
437+
},
438+
418439
// Persona 操作
419440
openCreatePersonaDialog() {
420441
this.editingPersona = null;

0 commit comments

Comments
 (0)