From 13fe576ae724b721e6cd86250f62fa5c0d4cc13f Mon Sep 17 00:00:00 2001 From: mfuku Date: Thu, 26 Feb 2026 21:33:29 +0900 Subject: [PATCH 1/3] in progress --- packages/preload/src/index.ts | 13 +++++++++---- .../src/components/AvatarSettingPanel.vue | 17 ++++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/preload/src/index.ts b/packages/preload/src/index.ts index 00ff045..e243e5b 100644 --- a/packages/preload/src/index.ts +++ b/packages/preload/src/index.ts @@ -7,7 +7,7 @@ import { AsMessage, AvatarSetting, type DaemonTriggerSchema, type McpInfo, type MutableSysConfig, - type SysConfig, type ToolCallParam, + type SysConfig, SysConfigMutable, type ToolCallParam, } from '../../common/Def.js'; import {io, Socket} from 'socket.io-client'; import {defaultAvatarSetting, defaultSysSetting} from '../../common/DefaultSetting.js'; @@ -28,7 +28,7 @@ export interface McpResource { } // region --- Variables --- -export let sysConfig: any = {}; +export let sysConfig: SysConfig | undefined = undefined; export let avatarId = ''; export let userName: string | undefined; export let avatarName: string | undefined; @@ -233,10 +233,13 @@ export async function setSysConfig(conf: SysConfig) { */ export async function getSysConfig(): Promise { try { - if (sysConfig && sysConfig?.version) { + if (sysConfig) { // && sysConfig?.version return sysConfig; } sysConfig = await ipcRenderer.invoke('getSysConfig') as any | undefined; + if (!sysConfig) { + sysConfig = defaultSysSetting; + } } catch (_) { sysConfig = defaultSysSetting; } @@ -263,6 +266,7 @@ export async function updateMutableSetting(conf: MutableSysConfig) { * 変更可能なシステム設定を取得する * @returns 設定項目 */ +/* export async function getMutableSetting() { try { sysConfig = await ipcRenderer.invoke('getMutableSetting') as MutableSysConfig | undefined; @@ -271,6 +275,7 @@ export async function getMutableSetting() { } return sysConfig; } +*/ /** * 現在のユーザー名を取得する @@ -343,7 +348,7 @@ export async function readMcpResource(name: string, url: string) { function makeSocket() { if (avatarSetting?.general.remoteServer) { socket = io(avatarSetting?.general.remoteServer); - } else if (sysConfig.websocket.useServer) { + } else if (sysConfig?.websocket.useServer) { socket = io(`http://127.0.0.1:${sysConfig.websocket.serverPort || 3010}`); } } diff --git a/packages/renderer/src/components/AvatarSettingPanel.vue b/packages/renderer/src/components/AvatarSettingPanel.vue index 124e8f4..b074dbe 100644 --- a/packages/renderer/src/components/AvatarSettingPanel.vue +++ b/packages/renderer/src/components/AvatarSettingPanel.vue @@ -11,7 +11,7 @@ import { } from '../../../common/Def.ts'; import {Either, ParseResult, Schema} from 'effect'; import short from 'short-uuid'; -import {getAvatarConfigMcpUpdate, setAvatarConfig, getGeneratorList, getMcpServerInfos} from '@app/preload'; +import {getAvatarConfigMcpUpdate, setAvatarConfig, getGeneratorList, getMcpServerInfos, sysConfig} from '@app/preload'; import {AsClassList, AsContextLinesList, AsRoleList} from '../../../common/DefGenerators.ts'; import {useI18n} from 'vue-i18n'; @@ -68,7 +68,7 @@ const doOpen = async (templateId: string) => { * @param name ツール名 * @returns ツール情報、または空のオブジェクト/文字列 */ -const getMcpInfo = (id:string,name?:string):any => { +const getMcpToolInfo = (id:string,name?:string):any => { const mcp = mcpServers.value.find(value => value.id === id) if(mcp){ return mcp.tools.find(v => v.name === name) || '' @@ -76,6 +76,13 @@ const getMcpInfo = (id:string,name?:string):any => { return {} } +const isDisableMcp(id:string) { + const mcp = mcpServers.value.find(value => value.id === id) + if(!mcp) return false + sysConfig. +} + + /** * MCPツールのラベルを取得する(表示用) * @param id MCPサーバーID @@ -83,7 +90,7 @@ const getMcpInfo = (id:string,name?:string):any => { * @returns ラベル文字列 */ const getMcpLabel = (id:string,name?:string) => { - const mcp = getMcpInfo(id,name) + const mcp = getMcpToolInfo(id,name) if(mcp){ return mcp.title ? `${mcp.title} (${name})` : name } @@ -276,7 +283,7 @@ onMounted(async () => { no-caps class="bg-indigo-8 text-white shadow-2" > - + @@ -305,7 +312,7 @@ onMounted(async () => {
- {{getMcpInfo(mcp[0],tool[0])?.description}} + {{getMcpToolInfo(mcp[0],tool[0])?.description}}
From cd23b2cbbce5ab6f4c242d4131deee9c6e890dfa Mon Sep 17 00:00:00 2001 From: mfuku Date: Sat, 28 Feb 2026 00:20:41 +0900 Subject: [PATCH 2/3] fix mcp registration, refactor MCP server handling for improved validation and error management; standardize schema usage with mutable types; enhance `AvatarSettingPanel` with system-based MCP enable/disable checks and `data-testid` updates; clean up redundant imports and comments --- packages/common/Def.ts | 5 ++- packages/main/src/BuildInMcpService.ts | 3 +- packages/main/src/McpService.ts | 28 +++++++++++----- .../main/src/generators/EmptyGenerator.ts | 1 - packages/preload/src/index.ts | 2 +- .../src/components/AvatarSettingPanel.vue | 32 +++++++++++++------ .../src/components/SysSettingPanel.vue | 2 +- 7 files changed, 50 insertions(+), 23 deletions(-) diff --git a/packages/common/Def.ts b/packages/common/Def.ts index a45d2b1..50f6d86 100644 --- a/packages/common/Def.ts +++ b/packages/common/Def.ts @@ -98,6 +98,7 @@ export type DaemonTrigger = typeof DaemonTrigger.Type export type ContextTrigger = typeof ContextTrigger.Type export type TimerTrigger = typeof TimerTrigger.Type +export const EchoSchedulerId = 'echoDaemon'; // TODO 他のMCPと重ならないユニーク名 /* AsMessage ==================================== @@ -309,6 +310,7 @@ const McpConfig = Schema.Struct({ buildIn: Schema.mutable(Schema.Boolean), }); +const McpConfigMutable = Schema.mutable(McpConfig); const McpConfigList = Schema.mutable(Schema.Array(McpConfig)); export type McpInfo = typeof McpInfo.Type @@ -316,6 +318,7 @@ export type McpToolInfo = typeof McpToolInfo.Type export type McpPromptInfo = typeof McpPromptInfo.Type export type McpResourceInfo = typeof McpResourceInfo.Type export type McpConfig = typeof McpConfig.Type +export type McpConfigMutable = typeof McpConfigMutable.Type export type McpConfigList = typeof McpConfigList.Type export type McpServerDef = typeof McpServerDef.Type @@ -421,7 +424,7 @@ export const AvatarMcpSetting = Schema.Struct({ export type AvatarMcpSetting = typeof AvatarMcpSetting.Type export const AvatarMcpSettingMutable = Schema.mutable(AvatarMcpSetting); -// export type AvatarMcpSettingMutable = typeof AvatarMcpSettingMutable.Type +export type AvatarMcpSettingMutable = typeof AvatarMcpSettingMutable.Type export const AvatarMcpSettingList = Schema.Record({ key: Schema.String, diff --git a/packages/main/src/BuildInMcpService.ts b/packages/main/src/BuildInMcpService.ts index caeb7af..b9bc140 100644 --- a/packages/main/src/BuildInMcpService.ts +++ b/packages/main/src/BuildInMcpService.ts @@ -1,9 +1,8 @@ /*! avatar-shell | Apache-2.0 License | https://github.com/mfukushim/avatar-shell */ import {Effect} from 'effect'; -import {McpConfig, McpToolInfo} from '../../common/Def.js'; +import {EchoSchedulerId, McpConfig, McpToolInfo} from '../../common/Def.js'; import {app} from 'electron'; -export const EchoSchedulerId = 'echoDaemon'; // TODO 他のMCPと重ならないユニーク名 export const setTaskWhenIdling = { def: { diff --git a/packages/main/src/McpService.ts b/packages/main/src/McpService.ts index f567cc6..2d7c4ba 100644 --- a/packages/main/src/McpService.ts +++ b/packages/main/src/McpService.ts @@ -5,10 +5,11 @@ import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js'; import {StreamableHTTPClientTransport} from '@modelcontextprotocol/sdk/client/streamableHttp.js'; import { AlertTask, AvatarMcpSetting, - AvatarMcpSettingList, + AvatarMcpSettingList, AvatarMcpSettingMutable, AvatarSetting, - DaemonTrigger, LabelError, - McpConfigList, + AvatarSettingMutable, + DaemonTrigger, LabelError, McpConfig, + McpConfigList, McpConfigMutable, type McpEnable, McpInfo, McpStdioServerDef, McpStreamHttpServerDef, SysConfig, ToolCallParam, @@ -49,7 +50,7 @@ export class McpService extends Effect.Service()('avatar-shell/McpSe def: value[1].def } }) - serverInfoList = yield *Effect.validateAll(servers, a1 => { + const res = yield* Effect.forEach(servers, a1 => { return Effect.gen(function* () { const client = new Client( { @@ -71,10 +72,10 @@ export class McpService extends Effect.Service()('avatar-shell/McpSe (x) => Either.isRight(Schema.decodeUnknownEither(McpStreamHttpServerDef)(x)), (y) => Effect.succeed(new StreamableHTTPClientTransport(new URL((y as McpStreamHttpServerDef).url))) ), - Match.orElse(() => Effect.fail(new Error('MCP define error'))) + Match.orElse(() => Effect.fail(new Error(`${a1.name} define error`))) ).pipe(Effect.flatMap((transport) =>Effect.tryPromise({ try: () => client.connect(transport), - catch: error => new LabelError(`${a1.name} MCP server Connect Error`,`${error}`,'Please,check MCP System Config.'), + catch: error => new Error(`${a1.name} Connect Error`), }))) const capabilities = client.getServerCapabilities(); const tools = (capabilities?.tools ? yield* Effect.tryPromise(() =>client.listTools()) : {tools: []}); @@ -88,10 +89,18 @@ export class McpService extends Effect.Service()('avatar-shell/McpSe resources: resources.resources, buildIn: false, }; - }); + }).pipe(Effect.catchAll(e => Effect.succeed(e))) }) + const isError = (v: unknown): v is Error => v instanceof Error + const errors = res.filter((r):r is Error => r instanceof Error) + serverInfoList = res.filter((r): r is Exclude => !isError(r)) + const buildInList = yield* BuildInMcpService.getDefines(); serverInfoList.push(...buildInList); + const errorMes = errors.map(e => e.message).join(','); + if (errorMes) { + return yield *Effect.fail(new LabelError(`${errorMes}\nMCP server Error`,'Please,check MCP System Config.')) + } }); } @@ -147,6 +156,7 @@ export class McpService extends Effect.Service()('avatar-shell/McpSe } function updateAvatarMcpSetting(configMcp: AvatarSetting) { + Object.keys(configMcp.mcp).forEach(k =>(configMcp.mcp[k] as unknown as AvatarMcpSettingMutable).serverEnable = undefined) const mcpServers = getMcpServerInfos(); const mcps: Record = {}; mcpServers.forEach(value => { @@ -167,9 +177,11 @@ export class McpService extends Effect.Service()('avatar-shell/McpSe }, }; }); + const deepMerge1: Record = deepMerge(mcps, configMcp.mcp) as Record; + Object.keys(deepMerge1).forEach(k =>(deepMerge1[k] as unknown as AvatarMcpSettingMutable).serverEnable = mcps[k]?.serverEnable) return Effect.succeed({ ...configMcp, - mcp: deepMerge(mcps, configMcp.mcp) as Record, + mcp: deepMerge1, } as AvatarSetting); } diff --git a/packages/main/src/generators/EmptyGenerator.ts b/packages/main/src/generators/EmptyGenerator.ts index 68913ab..b549579 100644 --- a/packages/main/src/generators/EmptyGenerator.ts +++ b/packages/main/src/generators/EmptyGenerator.ts @@ -8,7 +8,6 @@ import {MediaService} from '../MediaService.js'; import {ContextGenerator} from './ContextGenerator.js'; import short from 'short-uuid'; import {SysConfig} from '../../../common/Def.js'; -import {sysConfig} from '@app/preload'; /** diff --git a/packages/preload/src/index.ts b/packages/preload/src/index.ts index e243e5b..7d5a36e 100644 --- a/packages/preload/src/index.ts +++ b/packages/preload/src/index.ts @@ -28,7 +28,7 @@ export interface McpResource { } // region --- Variables --- -export let sysConfig: SysConfig | undefined = undefined; +let sysConfig: SysConfig | undefined = undefined; export let avatarId = ''; export let userName: string | undefined; export let avatarName: string | undefined; diff --git a/packages/renderer/src/components/AvatarSettingPanel.vue b/packages/renderer/src/components/AvatarSettingPanel.vue index b074dbe..24cc32e 100644 --- a/packages/renderer/src/components/AvatarSettingPanel.vue +++ b/packages/renderer/src/components/AvatarSettingPanel.vue @@ -7,11 +7,17 @@ import { AvatarSettingMutable, type SchedulerListMutable, DaemonTriggerList, - type McpInfo, + type McpInfo, type SysConfig, EchoSchedulerId, } from '../../../common/Def.ts'; import {Either, ParseResult, Schema} from 'effect'; import short from 'short-uuid'; -import {getAvatarConfigMcpUpdate, setAvatarConfig, getGeneratorList, getMcpServerInfos, sysConfig} from '@app/preload'; +import { + getAvatarConfigMcpUpdate, + setAvatarConfig, + getGeneratorList, + getMcpServerInfos, + getSysConfig, +} from '@app/preload'; import {AsClassList, AsContextLinesList, AsRoleList} from '../../../common/DefGenerators.ts'; import {useI18n} from 'vue-i18n'; @@ -34,6 +40,7 @@ const errorMes = ref(''); const mcpServers = ref([]) const saving = ref(false); const mcpEnableList = ref<{label:string,value:string}[]>([]) +const sysConfig = ref() // --- Functions --- @@ -58,6 +65,7 @@ const doOpen = async (templateId: string) => { mcpServers.value = await getMcpServerInfos() // TODO ちょっとreadonlyをごまかしているがどうするか mcpEnableList.value = McpEnableList.map(value => ({value,label:t(`mcpPermissionSet.${value}`)})) + sysConfig.value = await getSysConfig() show.value = true; }; @@ -76,10 +84,16 @@ const getMcpToolInfo = (id:string,name?:string):any => { return {} } -const isDisableMcp(id:string) { - const mcp = mcpServers.value.find(value => value.id === id) - if(!mcp) return false - sysConfig. +const isSysEnableMcp = (id:string) => { + // const mcp = mcpServers.value.find(value => value.id === id) + // if(!mcp) return true + if (id === EchoSchedulerId) { + return true; + } + if(sysConfig.value) { + if(sysConfig.value.mcpServers[id]?.enable) return true; + } + return false } @@ -283,7 +297,7 @@ onMounted(async () => { no-caps class="bg-indigo-8 text-white shadow-2" > - + @@ -298,8 +312,8 @@ onMounted(async () => {
{{ mcp[0] }}
- - {{ t('delete') }} + + {{ t('delete') }}
{{ mcp[1].notice }}
diff --git a/packages/renderer/src/components/SysSettingPanel.vue b/packages/renderer/src/components/SysSettingPanel.vue index f4a5b52..9565714 100644 --- a/packages/renderer/src/components/SysSettingPanel.vue +++ b/packages/renderer/src/components/SysSettingPanel.vue @@ -681,7 +681,7 @@ onBeforeUnmount(() => { no-caps class="bg-indigo-8 text-white shadow-2" > - + From 4750826bb84583507a21301d18fd71eb70c5f002 Mon Sep 17 00:00:00 2001 From: mfuku Date: Sat, 28 Feb 2026 00:37:10 +0900 Subject: [PATCH 3/3] clean up unused `SysConfigMutable` import in `preload/index.ts` --- packages/preload/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/preload/src/index.ts b/packages/preload/src/index.ts index 7d5a36e..48ad15e 100644 --- a/packages/preload/src/index.ts +++ b/packages/preload/src/index.ts @@ -7,7 +7,7 @@ import { AsMessage, AvatarSetting, type DaemonTriggerSchema, type McpInfo, type MutableSysConfig, - type SysConfig, SysConfigMutable, type ToolCallParam, + type SysConfig, type ToolCallParam, } from '../../common/Def.js'; import {io, Socket} from 'socket.io-client'; import {defaultAvatarSetting, defaultSysSetting} from '../../common/DefaultSetting.js';