diff --git a/frontend/src/i18n/locales/en-US.ts b/frontend/src/i18n/locales/en-US.ts
index 43767bdc..bec39e97 100755
--- a/frontend/src/i18n/locales/en-US.ts
+++ b/frontend/src/i18n/locales/en-US.ts
@@ -5936,6 +5936,7 @@ export default {
authWaitTimeout: 'Authentication Wait Timeout (s)',
authWaitTimeoutDesc: 'Maximum seconds to wait for you to complete OAuth authentication when prompted during a conversation; the prompt is skipped after it elapses (only affects OAuth MCP services).',
authWaitTimeoutPlaceholder: 'Default 600 seconds',
+ unavailableService: 'Unavailable service',
},
llmCallTimeout: {
label: "LLM Call Timeout",
diff --git a/frontend/src/i18n/locales/ko-KR.ts b/frontend/src/i18n/locales/ko-KR.ts
index 5b3f56f4..a9131acf 100755
--- a/frontend/src/i18n/locales/ko-KR.ts
+++ b/frontend/src/i18n/locales/ko-KR.ts
@@ -5940,6 +5940,7 @@ export default {
authWaitTimeout: '인증 대기 시간(초)',
authWaitTimeoutDesc: '대화 중 OAuth 인증이 필요할 때 인증 완료를 기다리는 최대 시간(초)이며, 초과하면 인증 요청을 건너뜁니다(OAuth를 사용하는 MCP 서비스에만 적용).',
authWaitTimeoutPlaceholder: '기본 600초',
+ unavailableService: '사용할 수 없는 서비스',
},
llmCallTimeout: {
label: "LLM 호출 타임아웃",
diff --git a/frontend/src/i18n/locales/ru-RU.ts b/frontend/src/i18n/locales/ru-RU.ts
index db81516b..874bd2ba 100755
--- a/frontend/src/i18n/locales/ru-RU.ts
+++ b/frontend/src/i18n/locales/ru-RU.ts
@@ -5438,7 +5438,8 @@ export default {
selectDesc: 'Выберите MCP-сервисы для включения',
selectPlaceholder: 'Выберите MCP-сервисы',
authWaitTimeout: 'Тайм-аут ожидания аутентификации (с)',
- authWaitTimeoutDesc: 'Максимальное время ожидания (в секундах) завершения OAuth-аутентификации при запросе во время диалога; по его истечении запрос пропускается (влияет только на MCP-сервисы с OAuth).'
+ authWaitTimeoutDesc: 'Максимальное время ожидания (в секундах) завершения OAuth-аутентификации при запросе во время диалога; по его истечении запрос пропускается (влияет только на MCP-сервисы с OAuth).',
+ unavailableService: 'Недоступный сервис',
},
llmCallTimeout: {
label: 'Таймаут вызова LLM',
diff --git a/frontend/src/i18n/locales/zh-CN.ts b/frontend/src/i18n/locales/zh-CN.ts
index 243a4e95..fe3c4501 100755
--- a/frontend/src/i18n/locales/zh-CN.ts
+++ b/frontend/src/i18n/locales/zh-CN.ts
@@ -5961,6 +5961,7 @@ export default {
authWaitTimeout: "授权等待超时(秒)",
authWaitTimeoutDesc: "对话中触发 OAuth 授权时,等待你完成授权的最长秒数,超时后自动跳过授权提示(仅对使用 OAuth 的 MCP 服务生效)。",
authWaitTimeoutPlaceholder: "默认 600 秒",
+ unavailableService: "不可用服务",
},
llmCallTimeout: {
label: "LLM 调用超时",
diff --git a/frontend/src/views/agent/AgentEditorModal.vue b/frontend/src/views/agent/AgentEditorModal.vue
index 84c76ddd..28371e7d 100644
--- a/frontend/src/views/agent/AgentEditorModal.vue
+++ b/frontend/src/views/agent/AgentEditorModal.vue
@@ -1189,7 +1189,7 @@
-
+
{{ $t('agentEditor.mcp.selectDesc') }}
@@ -1197,7 +1197,8 @@
-
+
@@ -1641,7 +1642,6 @@ import {
} from '@/api/agent';
import { type ModelConfig } from '@/api/model';
import { type AgentNotReadyReasonKey, agentRequiresRerankModel } from '@/utils/agent-readiness';
-import { type MCPService } from '@/api/mcp-service';
import { type SkillInfo } from '@/api/skill';
import { type WebSearchProviderEntity } from '@/api/web-search-provider';
import { type StorageEngineStatusItem, type PromptTemplate, type PromptTemplatesConfig } from '@/api/system';
@@ -1817,7 +1817,43 @@ const agentTypePresets = ref
([]);
// Agent 系统提示词模板缓存(用于切换智能体类型时根据 system_prompt_id 解析出实际文本填入)
const agentSystemPromptTemplates = ref([]);
const intentPromptTemplates = ref([]);
-const mcpOptions = ref<{ label: string; value: string }[]>([]);
+type McpSelectOption = { label: string; value: string; disabled?: boolean };
+
+const mcpOptions = computed(() => {
+ const services = editorResources.mcpServices || [];
+ const selectedIds = new Set(formData.value.config.mcp_services || []);
+ const serviceById = new Map(services.map((mcp) => [mcp.id, mcp]));
+ const options: McpSelectOption[] = [];
+
+ for (const mcp of services) {
+ if (mcp.enabled) {
+ options.push({ label: mcp.name, value: mcp.id });
+ }
+ }
+
+ for (const id of selectedIds) {
+ const mcp = serviceById.get(id);
+ if (mcp && !mcp.enabled) {
+ options.push({
+ label: `${mcp.name} (${t('mcpSettings.disabled')})`,
+ value: mcp.id,
+ disabled: true,
+ });
+ } else if (!mcp) {
+ options.push({
+ label: t('agentEditor.mcp.unavailableService'),
+ value: id,
+ disabled: true,
+ });
+ }
+ }
+
+ return options;
+});
+
+const showMcpServiceSelect = computed(() =>
+ mcpOptions.value.length > 0 || (formData.value.config.mcp_services?.length ?? 0) > 0,
+);
const webSearchProviderList = ref([]);
const skillOptions = ref<{ name: string; description: string }[]>([]);
// 是否允许启用 Skills(取决于后端沙箱是否启用,disabled 时为 false;未请求前为 false 避免闪显)
@@ -3293,10 +3329,6 @@ const loadDependencies = async () => {
.map((shared: any) => mapKbToOption(shared.knowledge_base, true, shared.org_name));
kbOptions.value = [...myKbs, ...sharedKbs];
- mcpOptions.value = editorResources.mcpServices
- .filter((mcp: MCPService) => mcp.enabled)
- .map((mcp: MCPService) => ({ label: mcp.name, value: mcp.id }));
-
skillsAvailable.value = editorResources.skillsAvailable;
skillOptions.value = editorResources.skills;
@@ -4606,8 +4638,10 @@ const handleSave = async () => {
display: flex;
align-items: flex-start;
justify-content: space-between;
+ gap: 24px;
padding: 16px 0;
border-bottom: 1px solid var(--td-component-stroke);
+ min-width: 0;
&:last-child {
border-bottom: none;
@@ -4665,9 +4699,10 @@ const handleSave = async () => {
}
.setting-info {
- flex: 1;
- max-width: 55%;
- padding-right: 24px;
+ flex: 0 0 42%;
+ max-width: 42%;
+ min-width: 0;
+ padding-right: 0;
&.full-width {
max-width: 100%;
@@ -4711,15 +4746,18 @@ const handleSave = async () => {
}
.setting-control {
- flex-shrink: 0;
- min-width: 360px;
+ flex: 1 1 58%;
+ min-width: 0;
+ max-width: 58%;
display: flex;
justify-content: flex-end;
align-items: flex-start;
+ overflow: hidden;
&.setting-control-full {
width: 100%;
min-width: 100%;
+ max-width: 100%;
justify-content: flex-start;
}
@@ -4728,6 +4766,22 @@ const handleSave = async () => {
:deep(.t-input),
:deep(.t-textarea) {
width: 100%;
+ min-width: 0;
+ }
+
+ :deep(.t-select-input) {
+ min-width: 0;
+ }
+
+ :deep(.t-select .t-tag) {
+ max-width: 160px;
+ }
+
+ :deep(.t-select .t-tag__text) {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
:deep(.t-input-number) {