Add enable-toggles for mcp servers and particular tools

This commit is contained in:
dimitrievgs 2026-06-14 23:15:46 +03:00
parent 1256d64498
commit 5f7f07ee6f

55
main.ts
View File

@ -18,6 +18,7 @@ export interface MCPToolState {
name: string; name: string;
originalDescription: string; originalDescription: string;
customDescription: string; customDescription: string;
isEnabled?: boolean;
} }
export interface MCPServerConfig { export interface MCPServerConfig {
@ -28,6 +29,7 @@ export interface MCPServerConfig {
envString: string; envString: string;
serverInstruction?: string; serverInstruction?: string;
fetchedTools?: MCPToolState[]; fetchedTools?: MCPToolState[];
isEnabled?: boolean;
} }
// ----------------------------------------------- Settings --------------------------------------------------------------- // ----------------------------------------------- Settings ---------------------------------------------------------------
@ -667,12 +669,25 @@ class SampleSettingTab extends PluginSettingTab {
if (!this.plugin.settings.mcpServers) this.plugin.settings.mcpServers = []; if (!this.plugin.settings.mcpServers) this.plugin.settings.mcpServers = [];
this.plugin.settings.mcpServers.forEach((server, index) => { this.plugin.settings.mcpServers.forEach((server, index) => {
if (server.isEnabled === undefined) server.isEnabled = true;
const serverDiv = container.createDiv({ const serverDiv = container.createDiv({
attr: { style: 'border: 1px solid var(--interactive-accent); padding: 10px; margin-bottom: 15px; border-radius: 8px; background-color: var(--background-secondary-alt);' } attr: { style: `border: 1px solid var(--interactive-accent); padding: 10px; margin-bottom: 15px; border-radius: 8px; background-color: var(--background-secondary-alt); transition: opacity 0.3s; opacity: ${server.isEnabled ? '1' : '0.5'}` }
}); });
new Setting(serverDiv) new Setting(serverDiv)
.setName(`Имя сервера`) .setName(`Имя сервера`)
.addToggle(tg => tg
.setTooltip(server.isEnabled ? 'Выключить сервер' : 'Включить сервер')
.setValue(server.isEnabled!)
.onChange(async v => {
server.isEnabled = v;
serverDiv.style.opacity = v ? '1' : '0.5';
tg.setTooltip(v ? 'Выключить сервер' : 'Включить сервер');
await this.plugin.saveSettings();
await this.plugin.syncSettings(); // Мгновенно синхроним с бэкендом
})
)
.addText(t => t.setValue(server.name).onChange(async v => { .addText(t => t.setValue(server.name).onChange(async v => {
server.name = v.replace(/[^a-zA-Z0-9_\-]/g, ''); server.name = v.replace(/[^a-zA-Z0-9_\-]/g, '');
await this.plugin.saveSettings(); await this.plugin.saveSettings();
@ -732,7 +747,7 @@ class SampleSettingTab extends PluginSettingTab {
}); });
new Setting(container).addButton(b => b.setButtonText(' Добавить MCP сервер').setCta().onClick(async () => { new Setting(container).addButton(b => b.setButtonText(' Добавить MCP сервер').setCta().onClick(async () => {
this.plugin.settings.mcpServers.push({ id: uuidv4(), name: 'duckduckgo', command: 'docker', args: 'run -i --rm ddg-mcp-server', envString: '' }); this.plugin.settings.mcpServers.push({ id: uuidv4(), name: 'duckduckgo', command: 'docker', args: 'run -i --rm ddg-mcp-server', envString: '', isEnabled: true });
await this.plugin.saveSettings(); await this.plugin.saveSettings();
this.display(); this.display();
})); }));
@ -767,7 +782,7 @@ class SampleSettingTab extends PluginSettingTab {
const existing = existingMap.get(rt.name)!; const existing = existingMap.get(rt.name)!;
return { ...existing, originalDescription: rt.description }; // обновляем оригинальное описание на всякий случай return { ...existing, originalDescription: rt.description }; // обновляем оригинальное описание на всякий случай
} }
return { name: rt.name, originalDescription: rt.description, customDescription: '' }; return { name: rt.name, originalDescription: rt.description, customDescription: '', isEnabled: true };
}); });
await this.plugin.saveSettings(); await this.plugin.saveSettings();
@ -785,13 +800,39 @@ class SampleSettingTab extends PluginSettingTab {
// Отрисовка списка тулов // Отрисовка списка тулов
if (server.fetchedTools && server.fetchedTools.length > 0) { if (server.fetchedTools && server.fetchedTools.length > 0) {
server.fetchedTools.forEach((tool, tIndex) => { server.fetchedTools.forEach((tool, tIndex) => {
const toolDiv = toolsContainer.createDiv({ attr: { style: 'margin-bottom: 10px; padding: 10px; background: var(--background-primary); border-radius: 6px;' } }); if (tool.isEnabled === undefined) tool.isEnabled = true;
toolDiv.createEl('div', { text: `🛠 ${tool.name}`, attr: { style: 'font-weight: bold; margin-bottom: 5px;' } });
const toolDiv = toolsContainer.createDiv({
attr: { style: `margin-bottom: 10px; padding: 10px; background: var(--background-primary); border-radius: 6px; transition: opacity 0.3s; opacity: ${tool.isEnabled ? '1' : '0.5'}` }
});
// Заголовок тула с переключателем
const headerDiv = toolDiv.createDiv({ attr: { style: 'display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 5px;' } });
headerDiv.createEl('div', { text: `🛠 ${tool.name}`, attr: { style: 'font-weight: bold; margin-top: 5px;' } });
const toggleSetting = new Setting(headerDiv)
.addToggle(tg => tg
.setTooltip(tool.isEnabled ? 'Выключить инструмент' : 'Включить инструмент')
.setValue(tool.isEnabled!)
.onChange(async v => {
tool.isEnabled = v;
toolDiv.style.opacity = v ? '1' : '0.5';
tg.setTooltip(v ? 'Выключить инструмент' : 'Включить инструмент');
await this.plugin.saveSettings();
await this.plugin.syncSettings(); // Мгновенно синхроним с бэкендом
})
);
// Убираем лишние рамки и отступы у элемента Setting для компактности в шапке
toggleSetting.settingEl.style.border = 'none';
toggleSetting.settingEl.style.padding = '0';
toggleSetting.infoEl.remove();
// Описание
toolDiv.createEl('div', { text: tool.originalDescription, attr: { style: 'font-size: 0.85em; color: var(--text-muted); margin-bottom: 8px;' } }); toolDiv.createEl('div', { text: tool.originalDescription, attr: { style: 'font-size: 0.85em; color: var(--text-muted); margin-bottom: 8px;' } });
new Setting(toolDiv) new Setting(toolDiv)
.setName('Кастомное описание (Override)') .setName('Дополнительные инструкции')
.setDesc('Оставьте пустым, чтобы использовать оригинальное.') .setDesc('Этот текст будет добавлен к оригинальному описанию инструмента. Оставьте пустым, если не требуется.')
.addTextArea(t => { .addTextArea(t => {
t.inputEl.style.width = '100%'; t.inputEl.style.width = '100%';
t.setValue(tool.customDescription).onChange(async v => { t.setValue(tool.customDescription).onChange(async v => {