Welcome to Chapter 5!
In the previous chapter, Channel Notifications & Permissions, we learned how to securely bridge external chat apps (like Slack) with our local tools.
Now we face a simpler, but messy problem: Nomenclature (Naming Things).
Computer systems hate ambiguity. If you have a server named "My Files" and another named "my-files", are they the same? What if both servers have a tool called read_file? If you ask Claude to "read the file," which tool should it use?
This chapter covers Normalization & Identification Utilities. Think of this as the "Translator" and "Label Maker" of the system. It ensures that every tool and server has a unique, clean, and identifiable name, no matter where it came from.
Imagine you are a librarian.
In MCP, servers come from:
my script.js)http://localhost:3000)Claude.ai Integration)We need a system that:
We will look at how the system takes a messy server name like "My Github Tool!" and a tool named "get_issue", and turns it into a system-safe ID: mcp__my_github_tool___get_issue.
This process strips away "illegal" characters. In our internal system, names should only contain letters, numbers, and underscores.
Visual Studio CodeVisual_Studio_Code
To ensure two tools never have the same ID, we wrap them in a special format using double underscores (__).
mcp__<SERVER_NAME>__<TOOL_NAME>This allows us to look at a tool ID and immediately know which server owns it.
When a new server is loaded, its name goes through a factory line before it can register any tools.
Let's look at the utility files that handle this logic: normalization.ts, mcpStringUtils.ts, and utils.ts.
Located in normalization.ts, this function ensures names are safe to use as programming variables.
// normalization.ts
export function normalizeNameForMCP(name: string): string {
// Replace anything that ISN'T a letter, number, or underscore with '_'
let normalized = name.replace(/[^a-zA-Z0-9_-]/g, '_');
// Special handling for Claude.ai servers to prevent double underscores
if (name.startsWith('claude.ai ')) {
normalized = normalized.replace(/_+/g, '_').replace(/^_|_$/g, '');
}
return normalized;
}
Explanation: If you pass in Hello World.js, the regex replaces the space and the dot with underscores, resulting in Hello_World_js.
Located in mcpStringUtils.ts, this utility creates the unique ID for a tool.
// mcpStringUtils.ts
export function buildMcpToolName(serverName: string, toolName: string): string {
// 1. Get the prefix (e.g., "mcp__server__")
const prefix = `mcp__${normalizeNameForMCP(serverName)}__`;
// 2. Combine with the normalized tool name
return `${prefix}${normalizeNameForMCP(toolName)}`;
}
Explanation: This function combines the server name and tool name into a single string. This is the ID that the AI actually sees.
Sometimes we have the long ID (mcp__github__create_issue) and we need to know: "Which server does this belong to?"
// mcpStringUtils.ts
export function mcpInfoFromString(toolString: string) {
// Split the string by the double underscore separator
const parts = toolString.split('__');
// Check if it starts with 'mcp'
const [mcpPart, serverName, ...toolNameParts] = parts;
if (mcpPart !== 'mcp' || !serverName) {
return null; // Not an MCP tool
}
return { serverName, toolName: toolNameParts.join('__') };
}
Explanation: This parses the string. It verifies the mcp prefix, extracts the middle part as the serverName, and the rest as the toolName.
In utils.ts, we often have a list of all available tools, but we want to show the user only the tools for a specific server.
// utils.ts
export function filterToolsByServer(tools: Tool[], serverName: string): Tool[] {
// 1. Create the prefix we are looking for
const prefix = `mcp__${normalizeNameForMCP(serverName)}__`;
// 2. Keep only tools that start with that prefix
return tools.filter(tool => tool.name?.startsWith(prefix));
}
Explanation: This acts like a search filter. It allows the UI to say, "Show me only the tools provided by GitHub."
Finally, how do we know if a server's configuration has changed? Maybe the user changed an API Key in the config file. We use a Hash to detect changes.
// utils.ts
export function hashMcpConfig(config: ScopedMcpServerConfig): string {
// Remove the 'scope' (because moving a config from User to Project shouldn't restart it)
const { scope: _scope, ...rest } = config;
// Convert the object to a stable string string
const stable = jsonStringify(rest, sortKeys);
// Generate a unique SHA-256 ID
return createHash('sha256').update(stable).digest('hex').slice(0, 16);
}
Explanation: We take the configuration object and turn it into a mathematical fingerprint. If even one letter changes in the config, the fingerprint changes completely. This tells the connection manager (from Chapter 3) that it needs to reconnect.
In this chapter, we learned:
mcp__server__tool format to ensure every tool has a unique ID.We have now covered Configuration, Authentication, Connection Management, Security, and Naming. The final piece of the puzzle is the actual wire that carries the data.
Generated by Code IQ