Welcome back! in Chapter 1: CLI Command Architecture, we built the "Switchboard" that routes user commands to the right place.
Now, we will look at what happens when that call is actually answered. specifically, we will explore MCP Server Provisioning.
Think about when you plug a new printer into your computer.
MCP Server Provisioning does the exact same thing for AI tools.
When a user wants to give Claude a new tool (like a Weather API or a Database connector), the CLI needs to know:
We call this process Provisioning. It converts a user's request into a saved configuration file.
We are still focusing on this command:
claude mcp add my-weather-server npx weather-cli
Goal: Take this text and turn it into a JSON configuration that the main application can read later.
Before we look at the code, we need to understand the three "languages" (Transports) an MCP server can speak.
This is like a Direct Cable.
This is like Sending a Letter.
https://api.myserver.com).This is like a Phone Call.
We are working inside the .action() function of addCommand.ts.
First, we decide where to save this printer driver. Is it just for this project folder, or for the whole computer?
// Inside .action()
import { ensureConfigScope } from '../../services/mcp/utils.js'
// 1. Determine Scope (local project vs global user)
const scope = ensureConfigScope(options.scope)
options.scope comes from the -s flag. If the user doesn't specify it, we default to local.Before we do work, we check for common mistakes. For example, if a user provides a URL but forgets to say it's a URL.
// 2. Check if the input looks like a URL
const looksLikeUrl =
actualCommand.startsWith('http://') ||
actualCommand.startsWith('https://') ||
actualCommand.endsWith('/sse')
// We use this later to warn the user if they made a mistake
add my-server https://google.com but forgets --transport http, we want to warn them.
If the user specifies --transport sse or --transport http, we build a configuration object specifically for web communication.
if (transport === 'sse' || transport === 'http') {
// Validate: We need a URL, not a command
if (!actualCommand) {
cliError('Error: URL is required for this transport.')
}
// Create the config object
const serverConfig = {
type: transport, // 'sse' or 'http'
url: actualCommand,
headers: options.header ? parseHeaders(options.header) : undefined
}
// Save it!
await addMcpConfig(name, serverConfig, scope)
}
addMcpConfig, which writes the file.If it's not a web URL, we assume it's a command running on your computer.
else {
// Warn if it looks like a URL but is treated as a command
if (!transportExplicit && looksLikeUrl) {
process.stderr.write('Warning: This looks like a URL, but --transport was not set.\n')
}
// Create the Stdio config object
await addMcpConfig(
name,
{
type: 'stdio',
command: actualCommand,
args: actualArgs,
env: parseEnvVars(options.env)
},
scope,
)
}
command is the program (e.g., npx) and args are the arguments (e.g., weather-cli). We also parse environment variables (-e KEY=VALUE) here.Here is the visual flow of what happens inside the Provisioning logic.
You might see references to "XAA" in the code. This stands for an advanced authentication standard.
// XAA Fail-fast check
if (options.xaa && !isXaaEnabled()) {
cliError('Error: --xaa requires CLAUDE_CODE_ENABLE_XAA=1')
}
The provisioning logic acts as a gatekeeper. It ensures you don't try to configure advanced identity features without the proper environment setup. We will cover exactly what XAA is in Chapter 4: XAA Identity Management.
If a user provides a Client Secret (a password), we do not save it in the plain text configuration file.
const clientSecret = options.clientSecret ? await readClientSecret() : undefined
if (clientSecret) {
// Handled separately from the main config file!
saveMcpClientSecret(name, serverConfig, clientSecret)
}
This splits the sensitive data from the configuration data. We will explore how this works in Chapter 5: Secure Credential Handling.
MCP Server Provisioning is the bridge between a human desire ("I want to use this tool") and a machine configuration (JSON files).
By the end of this process, we have successfully:
However, a command-line tool isn't just about text. Sometimes, we need to show rich, interactive feedback while these servers are running.
Next Chapter: Reactive Terminal UI
Generated by Code IQ