Skip to content

Commit cd6e2ab

Browse files
committed
BROKEN: mcp conversion utils, tool name updates
1 parent 0f2cb94 commit cd6e2ab

File tree

4 files changed

+52
-70
lines changed

4 files changed

+52
-70
lines changed

core/commands/slash/mcp.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
22

33
import { PromptMessage } from "@modelcontextprotocol/sdk/types.js";
4-
import { ChatMessage, SlashCommand } from "../../index.js";
4+
import { ChatMessage, MCPPrompt, SlashCommand } from "../../index.js";
55
import { renderChatMessage } from "../../util/messageContent.js";
6-
export function constructMcpSlashCommand(
6+
export function mcpPromptToSlashCommand(
77
client: Client,
8-
name: string,
9-
description?: string,
10-
args?: string[],
8+
prompt: MCPPrompt,
119
): SlashCommand {
1210
return {
13-
name,
14-
description: description ?? "MCP Prompt",
11+
name: prompt.name,
12+
description: prompt.description ?? "MCP Prompt",
1513
params: {},
1614
run: async function* (context) {
1715
const argsObject: { [key: string]: string } = {};
1816
const userInput = context.input.split(" ").slice(1).join(" ");
19-
if (args) {
20-
args.forEach((arg, i) => {
17+
if (prompt.arguments) {
18+
const argNames = prompt.arguments.map((a) => a.name);
19+
argNames.forEach((arg, i) => {
2120
argsObject[arg] = ""; // userInput
2221
});
2322
}
2423

25-
const result = await client.getPrompt({ name, arguments: argsObject });
24+
const result = await client.getPrompt({
25+
name: prompt.name,
26+
arguments: argsObject,
27+
});
2628
const mcpMessages: PromptMessage[] = result.messages;
2729
const messages: ChatMessage[] = mcpMessages.map((msg) => {
2830
if (msg.content.type !== "text") {

core/config/profile/doLoadConfig.ts

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
SerializedContinueConfig,
1818
Tool,
1919
} from "../../";
20-
import { constructMcpSlashCommand } from "../../commands/slash/mcp";
20+
import { mcpPromptToSlashCommand } from "../../commands/slash/mcp";
2121
import { MCPManagerSingleton } from "../../context/mcp/MCPManagerSingleton";
2222
import MCPContextProvider from "../../context/providers/MCPContextProvider";
2323
import { ControlPlaneProxyInfo } from "../../control-plane/analytics/IAnalyticsProvider.js";
@@ -26,8 +26,7 @@ import { getControlPlaneEnv } from "../../control-plane/env.js";
2626
import { TeamAnalytics } from "../../control-plane/TeamAnalytics.js";
2727
import ContinueProxy from "../../llm/llms/stubs/ContinueProxy";
2828
import { getConfigDependentToolDefinitions } from "../../tools";
29-
import { encodeMCPToolUri } from "../../tools/callTool";
30-
import { getMCPToolName } from "../../tools/mcpToolName";
29+
import { mcpToolToTool } from "../../tools/mcpTools";
3130
import { getConfigJsonPath, getConfigYamlPath } from "../../util/paths";
3231
import { localPathOrUriToPath } from "../../util/pathToUri";
3332
import { Telemetry } from "../../util/posthog";
@@ -140,6 +139,13 @@ export default async function doLoadConfig(options: {
140139
// Rectify model selections for each role
141140
newConfig = rectifySelectedModelsFromGlobalContext(newConfig, profileId);
142141

142+
// Add tools that depend on rules etc.
143+
newConfig.tools.push(
144+
...getConfigDependentToolDefinitions({
145+
rules: newConfig.rules,
146+
}),
147+
);
148+
143149
// Add things from MCP servers
144150
const mcpManager = MCPManagerSingleton.getInstance();
145151
const mcpServerStatuses = mcpManager.getStatuses();
@@ -151,31 +157,22 @@ export default async function doLoadConfig(options: {
151157
});
152158
newConfig.mcpServerStatuses = serializableStatuses;
153159

160+
// Keep track of tool names to avoid duplicates
161+
const toolNames = new Set<string>();
162+
163+
newConfig.tools.forEach((tool) => {
164+
toolNames.add(tool.function.name);
165+
});
166+
154167
for (const server of mcpServerStatuses) {
155168
if (server.status === "connected") {
156-
const serverTools: Tool[] = server.tools.map((tool) => ({
157-
displayTitle: server.name + " " + tool.name,
158-
function: {
159-
description: tool.description,
160-
name: getMCPToolName(server, tool),
161-
parameters: tool.inputSchema,
162-
},
163-
faviconUrl: server.faviconUrl,
164-
readonly: false,
165-
type: "function" as const,
166-
uri: encodeMCPToolUri(server.id, tool.name),
167-
group: server.name,
168-
originalFunctionName: tool.name,
169-
}));
169+
const serverTools: Tool[] = server.tools.map((tool) =>
170+
mcpToolToTool(server, tool),
171+
);
170172
newConfig.tools.push(...serverTools);
171173

172174
const serverSlashCommands = server.prompts.map((prompt) =>
173-
constructMcpSlashCommand(
174-
server.client,
175-
prompt.name,
176-
prompt.description,
177-
prompt.arguments?.map((a: any) => a.name),
178-
),
175+
mcpPromptToSlashCommand(server.client, prompt),
179176
);
180177
newConfig.slashCommands.push(...serverSlashCommands);
181178

@@ -205,45 +202,28 @@ export default async function doLoadConfig(options: {
205202
}
206203
}
207204

208-
newConfig.tools.push(
209-
...getConfigDependentToolDefinitions({
210-
rules: newConfig.rules,
211-
}),
212-
);
213-
214-
// Detect duplicate tool names
215-
const counts: Record<string, number> = {};
216-
newConfig.tools.forEach((tool) => {
217-
if (counts[tool.function.name]) {
218-
counts[tool.function.name] = counts[tool.function.name] + 1;
219-
} else {
220-
counts[tool.function.name] = 1;
221-
}
222-
});
223-
224-
Object.entries(counts).forEach(([toolName, count]) => {
225-
if (count > 1) {
226-
errors!.push({
227-
fatal: false,
228-
message: `Duplicate (${count}) tools named "${toolName}" detected. Permissions will conflict and usage may be unpredictable`,
229-
});
230-
}
231-
});
232-
233-
const ruleCounts: Record<string, number> = {};
205+
// Warn user about duplicate tool names
206+
// Could change this behavior in a few ways, e.g. to prepend server name to all tool names from that server if ANY are duplicate
207+
// Object.entries(toolNameCounts).forEach(([toolName, count]) => {
208+
// if (count > 1) {
209+
// errors!.push({
210+
// fatal: false,
211+
// message: `Duplicate (${count}) tools named "${toolName}" detected. Permissions will conflict and usage may be unpredictable`,
212+
// });
213+
// }
214+
// });
215+
216+
// Warn about duplicate rules
217+
const ruleCounts = new Map<string, number>();
234218
newConfig.rules.forEach((rule) => {
235219
if (rule.name) {
236-
if (ruleCounts[rule.name]) {
237-
ruleCounts[rule.name] = ruleCounts[rule.name] + 1;
238-
} else {
239-
ruleCounts[rule.name] = 1;
240-
}
220+
ruleCounts.set(rule.name, (ruleCounts.get(rule.name) || 0) + 1);
241221
}
242222
});
243223

244-
Object.entries(ruleCounts).forEach(([ruleName, count]) => {
224+
ruleCounts.forEach((count, ruleName) => {
245225
if (count > 1) {
246-
errors!.push({
226+
errors.push({
247227
fatal: false,
248228
message: `Duplicate (${count}) rules named "${ruleName}" detected. This may cause unexpected behavior`,
249229
});

core/tools/mcpToolName.vitest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect, test } from "vitest";
22
import { MCPServerStatus, MCPTool } from "..";
3-
import { getMCPToolName } from "./mcpToolName";
3+
import { getMCPToolName } from "./mcpTools";
44

55
const createMcpServer = (name: string): MCPServerStatus => ({
66
name,
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { MCPServerStatus, MCPTool } from "..";
22

33
export function getMCPToolName(server: MCPServerStatus, tool: MCPTool) {
4-
const serverPrefix = server.name.split(" ").join("_").toLowerCase();
5-
if (tool.name.startsWith(serverPrefix)) {
4+
const serverSuffix = server.name.split(" ").join("_").toLowerCase();
5+
if (tool.name.endsWith(serverSuffix)) {
66
return tool.name;
77
}
8-
return `${serverPrefix}_${tool.name}`;
8+
return `${tool.name}_${serverSuffix}`;
99
}

0 commit comments

Comments
 (0)