Forge
csharpdeeb25a2
1using System.Reflection;
2
3namespace CascadeIDE.Services;
4
5/// <summary>
6/// MCP tool names for Cursor: only <c>[A-Za-z0-9_]</c>; combined server+tool length ≤ 60 (conservative cap on tool part).
7/// <see cref="IdeCommands"/> <c>command_id</c> may contain <c>.</c> — wire name uses <c>_</c>.
8/// </summary>
9internal static class IdeMcpToolNaming
10{
11 /// <summary>Max length of full tool name (<c>ide_*</c>). Leaves room for server names like <c>cascade-ide-debug</c>.</summary>
12 public const int MaxToolNameLength = 45;
13
14 private static readonly Dictionary<string, string> CommandIdToToolName;
15 private static readonly Dictionary<string, string> ToolNameToCommandId;
16
17 static IdeMcpToolNaming()
18 {
19 CommandIdToToolName = new Dictionary<string, string>(StringComparer.Ordinal);
20 ToolNameToCommandId = new Dictionary<string, string>(StringComparer.Ordinal);
21
22 var type = typeof(IdeCommands);
23 foreach (var f in type.GetFields(BindingFlags.Public | BindingFlags.Static))
24 {
25 if (f.FieldType != typeof(string))
26 continue;
27 var commandId = (string?)f.GetValue(null);
28 if (string.IsNullOrWhiteSpace(commandId))
29 continue;
30 Register(commandId);
31 }
32
33 // Shorter wire name (combined server+tool ≤ 60 in Cursor).
34 RegisterAlias(IdeCommands.ChatToggleProductSpineInAgentContext, "chat_toggle_spine_ctx");
35 }
36
37 public static string ToToolName(string commandId)
38 {
39 if (CommandIdToToolName.TryGetValue(commandId, out var name))
40 return name;
41 return Register(commandId);
42 }
43
44 public static bool TryToCommandId(string toolName, out string commandId)
45 {
46 if (ToolNameToCommandId.TryGetValue(toolName, out var id))
47 {
48 commandId = id;
49 return true;
50 }
51
52 commandId = "";
53 return false;
54 }
55
56 /// <summary>Skip auto-proxy when no stable short name fits Cursor limits.</summary>
57 public static bool IsSupportedAutoProxyToolName(string commandId) =>
58 ToToolName(commandId).Length <= MaxToolNameLength;
59
60 private static void RegisterAlias(string commandId, string suffixAfterIde)
61 {
62 var toolName = "ide_" + suffixAfterIde;
63 if (toolName.Length > MaxToolNameLength)
64 throw new InvalidOperationException($"MCP tool name too long: {toolName}");
65
66 CommandIdToToolName[commandId] = toolName;
67 ToolNameToCommandId[toolName] = commandId;
68 }
69
70 private static string Register(string commandId)
71 {
72 if (CommandIdToToolName.TryGetValue(commandId, out var existing))
73 return existing;
74
75 var suffix = commandId.Replace('.', '_');
76 var toolName = "ide_" + suffix;
77 CommandIdToToolName[commandId] = toolName;
78 ToolNameToCommandId[toolName] = commandId;
79 return toolName;
80 }
81}
82
View only · write via MCP/CIDE