* 汇总所有已安装插件的工具,并生成适合 MCP 暴露的唯一工具名。
(options?: {
includeDisabled?: boolean
})
| 120 | * 汇总所有已安装插件的工具,并生成适合 MCP 暴露的唯一工具名。 |
| 121 | */ |
| 122 | public getAllDeclaredToolEntries(options?: { |
| 123 | includeDisabled?: boolean |
| 124 | }): DeclaredPluginToolEntry[] { |
| 125 | const plugins = databaseAPI.dbGet('plugins') |
| 126 | if (!Array.isArray(plugins)) { |
| 127 | return [] |
| 128 | } |
| 129 | |
| 130 | const includeDisabled = options?.includeDisabled ?? true |
| 131 | const disabledPluginPaths = this.getDisabledPluginPaths() |
| 132 | const usedMcpNames = new Map<string, number>() |
| 133 | const entries: DeclaredPluginToolEntry[] = [] |
| 134 | for (const plugin of [...plugins].sort((a, b) => |
| 135 | String(a?.name || '').localeCompare(String(b?.name || '')) |
| 136 | )) { |
| 137 | if (!plugin?.path || !plugin?.name) continue |
| 138 | const enabled = !disabledPluginPaths.has(plugin.path) |
| 139 | if (!includeDisabled && !enabled) continue |
| 140 | |
| 141 | const tools = this.getDeclaredToolsByPath(plugin.path) |
| 142 | for (const [toolName, tool] of Object.entries(tools)) { |
| 143 | // MCP 工具名需要全局唯一;插件名冲突时通过后缀消解。 |
| 144 | const baseMcpName = this.buildMcpToolName(plugin.name, toolName) |
| 145 | const collisionCount = usedMcpNames.get(baseMcpName) || 0 |
| 146 | usedMcpNames.set(baseMcpName, collisionCount + 1) |
| 147 | entries.push({ |
| 148 | pluginName: plugin.name, |
| 149 | pluginPath: plugin.path, |
| 150 | pluginLogo: typeof plugin.logo === 'string' ? plugin.logo : undefined, |
| 151 | toolName, |
| 152 | mcpName: collisionCount === 0 ? baseMcpName : `${baseMcpName}_${collisionCount + 1}`, |
| 153 | description: tool.description, |
| 154 | inputSchema: tool.inputSchema, |
| 155 | outputSchema: tool.outputSchema, |
| 156 | enabled |
| 157 | }) |
| 158 | } |
| 159 | } |
| 160 | return entries |
| 161 | } |
| 162 | |
| 163 | /** |
| 164 | * 确保目标插件和目标工具已就绪。 |
no test coverage detected