Skip to content

Commit 2a0ef02

Browse files
committed
feat(mcp): improve MCP server handling and tool information retrieval
- Refactor CustomMcpServerManager to store server information in a map - Update McpFunctionProvider to handle multiple servers and tools - Enhance toolInfos function to properly assign mcpGroup based on server name - Optimize isApplicable and execute functions for better tool lookup
1 parent 706a47f commit 2a0ef02

File tree

2 files changed

+44
-26
lines changed

2 files changed

+44
-26
lines changed

core/src/main/kotlin/cc/unitmesh/devti/mcp/client/CustomMcpServerManager.kt

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,19 @@ import com.intellij.execution.configurations.GeneralCommandLine
3030

3131
@Service(Service.Level.PROJECT)
3232
class CustomMcpServerManager(val project: Project) {
33-
val cached = mutableMapOf<String, List<Tool>>()
33+
val cached = mutableMapOf<String, Map<String, List<Tool>>>()
3434
val toolClientMap = mutableMapOf<Tool, Client>()
3535

36-
suspend fun collectServerInfos(): List<Tool> {
36+
suspend fun collectServerInfos(): Map<String, List<Tool>> {
3737
val mcpServerConfig = project.customizeSetting.mcpServerConfig
38-
if (mcpServerConfig.isEmpty()) return emptyList()
38+
if (mcpServerConfig.isEmpty()) return emptyMap()
3939
if (cached.containsKey(mcpServerConfig)) return cached[mcpServerConfig]!!
4040
val mcpConfig = McpServer.load(mcpServerConfig)
41-
if (mcpConfig == null) return emptyList()
41+
if (mcpConfig == null) return emptyMap()
4242

43-
val tools: List<Tool> = mcpConfig.mcpServers.map { entry ->
44-
if (entry.value.disabled == true) return@map emptyList<Tool>()
43+
val toolsMap = mutableMapOf<String, List<Tool>>()
44+
mcpConfig.mcpServers.forEach { entry ->
45+
if (entry.value.disabled == true) return@forEach
4546
val resolvedCommand = resolveCommand(entry.value.command)
4647
logger<CustomMcpServerManager>().info("Found MCP command: $resolvedCommand")
4748
val client = Client(clientInfo = Implementation(name = entry.key, version = "1.0.0"))
@@ -62,16 +63,15 @@ class CustomMcpServerManager(val project: Project) {
6263
}
6364
listTools?.tools ?: emptyList()
6465
} catch (e: Exception) {
65-
throw e
6666
logger<CustomMcpServerManager>().warn("Failed to list tools from ${entry.key}: $e")
6767
emptyList<Tool>()
6868
}
69+
70+
toolsMap[entry.key] = tools
71+
}
6972

70-
return@map tools
71-
}.flatMap { it }
72-
73-
cached[mcpServerConfig] = tools
74-
return tools
73+
cached[mcpServerConfig] = toolsMap
74+
return toolsMap
7575
}
7676

7777
fun execute(project: Project, tool: Tool, map: String): String {
@@ -165,3 +165,4 @@ fun resolveCommand(command: String): String {
165165
}
166166
return command
167167
}
168+

core/src/main/kotlin/cc/unitmesh/devti/mcp/client/McpFunctionProvider.kt

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,48 @@ import cc.unitmesh.devti.agent.tool.AgentTool
44
import cc.unitmesh.devti.provider.toolchain.ToolchainFunctionProvider
55
import com.intellij.openapi.project.Project
66
import com.intellij.openapi.project.ProjectManager
7+
import io.modelcontextprotocol.kotlin.sdk.Tool
78
import io.modelcontextprotocol.kotlin.sdk.Tool.Input
89
import kotlinx.serialization.json.Json
910
import kotlinx.serialization.encodeToString
1011

1112
class McpFunctionProvider : ToolchainFunctionProvider {
1213
override suspend fun funcNames(): List<String> {
1314
val project = ProjectManager.getInstance().openProjects.firstOrNull() ?: return emptyList()
14-
return CustomMcpServerManager.instance(project).collectServerInfos().map { it.name }
15+
return CustomMcpServerManager.instance(project).collectServerInfos().values
16+
.flatMap { it }
17+
.map { it.name }
18+
.distinct()
1519
}
1620

1721
override suspend fun toolInfos(project: Project): List<AgentTool> {
1822
val manager = CustomMcpServerManager.instance(project)
19-
return manager.collectServerInfos().map {
20-
val schemaJson = Json.encodeToString<Input>(it.inputSchema)
21-
val mockData = Json.encodeToString(MockDataGenerator.generateMockData(it.inputSchema))
22-
AgentTool(
23-
it.name,
24-
it.description ?: "",
25-
"Here is command and JSON schema\n/${it.name}\n```json\n$schemaJson\n```",
26-
isMcp = true,
27-
mcpGroup = it.name,
28-
completion = mockData
29-
)
23+
val toolsMap = manager.collectServerInfos()
24+
25+
val agentTools = mutableListOf<AgentTool>()
26+
for ((serverName, tools) in toolsMap) {
27+
for (tool in tools) {
28+
val schemaJson = Json.encodeToString<Input>(tool.inputSchema)
29+
val mockData = Json.encodeToString(MockDataGenerator.generateMockData(tool.inputSchema))
30+
agentTools.add(
31+
AgentTool(
32+
tool.name,
33+
tool.description ?: "",
34+
"Here is command and JSON schema\n/${tool.name}\n```json\n$schemaJson\n```",
35+
isMcp = true,
36+
mcpGroup = serverName,
37+
completion = mockData
38+
)
39+
)
40+
}
3041
}
42+
43+
return agentTools
3144
}
3245

3346
override suspend fun isApplicable(project: Project, funcName: String): Boolean {
34-
return CustomMcpServerManager.instance(project).collectServerInfos().any { it.name == funcName }
47+
val toolsMap = CustomMcpServerManager.instance(project).collectServerInfos()
48+
return toolsMap.any { (_, tools) -> tools.any { it.name == funcName } }
3549
}
3650

3751
override suspend fun execute(
@@ -41,7 +55,10 @@ class McpFunctionProvider : ToolchainFunctionProvider {
4155
allVariables: Map<String, Any?>,
4256
commandName: String
4357
): Any {
44-
val tool = CustomMcpServerManager.instance(project).collectServerInfos().firstOrNull { it.name == commandName }
58+
val toolsMap = CustomMcpServerManager.instance(project).collectServerInfos()
59+
val tool = toolsMap.values.flatMap { it }
60+
.firstOrNull { it.name == commandName }
61+
4562
if (tool == null) {
4663
return "No MCP such tool: $prop"
4764
}

0 commit comments

Comments
 (0)