source dump of claude code
at main 106 lines 4.0 kB view raw
1/** 2 * Pure string utility functions for MCP tool/server name parsing. 3 * This file has no heavy dependencies to keep it lightweight for 4 * consumers that only need string parsing (e.g., permissionValidation). 5 */ 6 7import { normalizeNameForMCP } from './normalization.js' 8 9/* 10 * Extracts MCP server information from a tool name string 11 * @param toolString The string to parse. Expected format: "mcp__serverName__toolName" 12 * @returns An object containing server name and optional tool name, or null if not a valid MCP rule 13 * 14 * Known limitation: If a server name contains "__", parsing will be incorrect. 15 * For example, "mcp__my__server__tool" would parse as server="my" and tool="server__tool" 16 * instead of server="my__server" and tool="tool". This is rare in practice since server 17 * names typically don't contain double underscores. 18 */ 19export function mcpInfoFromString(toolString: string): { 20 serverName: string 21 toolName: string | undefined 22} | null { 23 const parts = toolString.split('__') 24 const [mcpPart, serverName, ...toolNameParts] = parts 25 if (mcpPart !== 'mcp' || !serverName) { 26 return null 27 } 28 // Join all parts after server name to preserve double underscores in tool names 29 const toolName = 30 toolNameParts.length > 0 ? toolNameParts.join('__') : undefined 31 return { serverName, toolName } 32} 33 34/** 35 * Generates the MCP tool/command name prefix for a given server 36 * @param serverName Name of the MCP server 37 * @returns The prefix string 38 */ 39export function getMcpPrefix(serverName: string): string { 40 return `mcp__${normalizeNameForMCP(serverName)}__` 41} 42 43/** 44 * Builds a fully qualified MCP tool name from server and tool names. 45 * Inverse of mcpInfoFromString(). 46 * @param serverName Name of the MCP server (unnormalized) 47 * @param toolName Name of the tool (unnormalized) 48 * @returns The fully qualified name, e.g., "mcp__server__tool" 49 */ 50export function buildMcpToolName(serverName: string, toolName: string): string { 51 return `${getMcpPrefix(serverName)}${normalizeNameForMCP(toolName)}` 52} 53 54/** 55 * Returns the name to use for permission rule matching. 56 * For MCP tools, uses the fully qualified mcp__server__tool name so that 57 * deny rules targeting builtins (e.g., "Write") don't match unprefixed MCP 58 * replacements that share the same display name. Falls back to `tool.name`. 59 */ 60export function getToolNameForPermissionCheck(tool: { 61 name: string 62 mcpInfo?: { serverName: string; toolName: string } 63}): string { 64 return tool.mcpInfo 65 ? buildMcpToolName(tool.mcpInfo.serverName, tool.mcpInfo.toolName) 66 : tool.name 67} 68 69/* 70 * Extracts the display name from an MCP tool/command name 71 * @param fullName The full MCP tool/command name (e.g., "mcp__server_name__tool_name") 72 * @param serverName The server name to remove from the prefix 73 * @returns The display name without the MCP prefix 74 */ 75export function getMcpDisplayName( 76 fullName: string, 77 serverName: string, 78): string { 79 const prefix = `mcp__${normalizeNameForMCP(serverName)}__` 80 return fullName.replace(prefix, '') 81} 82 83/** 84 * Extracts just the tool/command display name from a userFacingName 85 * @param userFacingName The full user-facing name (e.g., "github - Add comment to issue (MCP)") 86 * @returns The display name without server prefix and (MCP) suffix 87 */ 88export function extractMcpToolDisplayName(userFacingName: string): string { 89 // This is really ugly but our current Tool type doesn't make it easy to have different display names for different purposes. 90 91 // First, remove the (MCP) suffix if present 92 let withoutSuffix = userFacingName.replace(/\s*\(MCP\)\s*$/, '') 93 94 // Trim the result 95 withoutSuffix = withoutSuffix.trim() 96 97 // Then, remove the server prefix (everything before " - ") 98 const dashIndex = withoutSuffix.indexOf(' - ') 99 if (dashIndex !== -1) { 100 const displayName = withoutSuffix.substring(dashIndex + 3).trim() 101 return displayName 102 } 103 104 // If no dash found, return the string without (MCP) 105 return withoutSuffix 106}