MCP
How nikcli connects local and remote Model Context Protocol servers, authenticates OAuth servers, and exposes MCP tools to agent sessions.
Overview
MCP support is implemented in packages/nikcli/src/mcp/index.ts. The service reads
config.mcp, creates local stdio or remote HTTP/SSE clients, records status,
converts server tools into AI SDK dynamic tools, and exposes prompts/resources to sessions.
Local
Runs a command in the current instance directory with environment from the config entry.
Remote
Tries Streamable HTTP first, then SSE, with optional headers and OAuth provider support.
OAuth
Stores tokens in mcp-auth.json, supports dynamic or configured client registration, and can open a browser for auth.
Tools
MCP tool schemas are wrapped as strict dynamic tools with per-call timeout support.
Add a server
Use nikcli mcp add for interactive config patching, or edit
mcp in nikcli.json directly. nikcli mcp list initializes
configured servers and shows status.
nikcli mcp add
nikcli mcp list
nikcli mcp auth remote-docs
nikcli mcp auth list
nikcli mcp logout remote-docs
nikcli mcp debug remote-docs | Command | Purpose |
|---|---|
mcp list | Read config, connect servers, show connected/disabled/failed/auth status. |
mcp add | Add a local or remote MCP entry to global or project config. |
mcp auth | Start OAuth flow for a remote server with OAuth enabled. |
mcp auth list | List OAuth-capable servers and token status. |
mcp logout | Remove stored MCP auth for a server. |
mcp debug | Inspect a configured server with a raw MCP client. |
Local stdio servers
Local servers use StdioClientTransport. The command runs with cwd set to the
current project directory. The environment is process.env plus configured
environment; when the command is nikcli, BUN_BE_BUN=1
is added.
{
"mcp": {
"filesystem": {
"type": "local",
"command": ["bunx", "@modelcontextprotocol/server-filesystem", "."],
"environment": {
"LOG_LEVEL": "info"
},
"timeout": 30000
}
}
} | Field | Required | Meaning |
|---|---|---|
type | Yes | local. |
command | Yes | Command array. First item is executable, rest are args. |
environment | No | Extra environment variables passed to the child process. |
enabled | No | false keeps the server disabled. |
timeout | No | Connect and tool-list timeout in milliseconds. Default is 30000. |
Remote servers
Remote servers use two transports in sequence. nikcli tries
StreamableHTTPClientTransport first, then SSEClientTransport. Both
receive configured headers and the OAuth auth provider when OAuth is enabled.
{
"mcp": {
"remote-docs": {
"type": "remote",
"url": "https://example.com/mcp",
"headers": {
"X-Workspace": "docs"
},
"timeout": 45000
}
}
} | Field | Required | Meaning |
|---|---|---|
type | Yes | remote. |
url | Yes | Remote MCP endpoint URL. |
headers | No | Static request headers for connect and capability calls. |
oauth | No | OAuth config object, false to disable OAuth, or omitted to enable OAuth support. |
enabled | No | Disable without deleting config. |
timeout | No | Connection and capability-list timeout in milliseconds. |
OAuth
Remote MCP OAuth is on by default unless oauth is false. The
McpOAuthProvider supports configured client id, client secret, and scope. Tokens,
client metadata, code verifier, OAuth state, and server URL are stored through
McpAuth.Service in Global.Path.data/mcp-auth.json.
{
"mcp": {
"corp-docs": {
"type": "remote",
"url": "https://mcp.example.com",
"oauth": {
"clientId": "client-id",
"clientSecret": "client-secret",
"scope": "read write"
}
}
}
}
If a server returns an unauthorized error mentioning registration or client id, nikcli reports
needs_client_registration and asks you to add clientId in config.
Status model
| Status | Meaning |
|---|---|
connected | Client connected and listTools succeeded. |
disabled | Config entry has enabled: false or the server was disconnected. |
failed | Connection or initial tool-list failed. Error string is stored. |
needs_auth | Remote server returned unauthorized and OAuth can continue. |
needs_client_registration | Remote server requires configured OAuth client id. |
The service keeps status and clients maps in instance state. When the
instance shuts down, all MCP clients are closed and pending OAuth transports are cleared.
Tools, prompts, resources
Connected MCP servers can contribute tools, prompts, and resources. Tool input schemas are
wrapped as strict JSON schemas with additionalProperties: false. Tool calls use
resetTimeoutOnProgress so long calls can continue when the server sends progress.
| Capability | Service method | Behavior |
|---|---|---|
| Tools | tools | Fetches tool lists from connected clients and converts each MCP tool into an AI SDK dynamic tool. |
| Prompts | prompts | Lists prompts and names them as client:prompt after sanitizing names. |
| Resources | resources | Lists resources and attaches client name to each resource record. |
| Prompt read | getPrompt | Calls the selected client's prompt with optional string args. |
| Resource read | readResource | Reads a resource URI from the selected client. |
| Tool-list changed | mcp.tools.changed | Published when a server sends ToolListChangedNotification. |
API routes
MCP has both classic Hono routes and typed HttpApi handlers.
| Route | Behavior |
|---|---|
GET /mcp | Status map. |
POST /mcp | Add a server config and attempt connection. |
POST /mcp/:name/auth | Start OAuth and return authorization URL in typed API. |
POST /mcp/:name/auth/callback | Finish OAuth with authorization code. |
POST /mcp/:name/auth/authenticate | Run full CLI/TUI OAuth flow where supported. |
DELETE /mcp/:name/auth | Remove stored auth. |
POST /mcp/:name/connect | Connect or reconnect a server. |
POST /mcp/:name/disconnect | Close client and mark disabled. |
POST /mcp/:name/toggle | Patch config enabled state and disconnect when disabling. |
curl http://127.0.0.1:4096/mcp
curl -X POST http://127.0.0.1:4096/mcp/remote-docs/connect
curl -X POST http://127.0.0.1:4096/mcp/remote-docs/toggle \
-H "Content-Type: application/json" \
-d '{"enabled":false}' Timeouts and headers
The default MCP timeout is 30000 ms. A server-specific timeout overrides connect,
initial listTools, and tool-call timeouts. Remote headers are passed
to both Streamable HTTP and SSE transports.
If a connected client later fails to list tools, the MCP service records the failure and that server's tools are not added to the agent tool set until it reconnects successfully.
Failure modes
| Symptom | Likely cause | Fix |
|---|---|---|
needs_auth | Remote server requires OAuth and no valid token is stored. | Run nikcli mcp auth <name>. |
needs_client_registration | Server does not support dynamic client registration. | Add oauth.clientId, and client secret if required. |
| Local server failed | Command missing, bad args, bad cwd, or server did not initialize before timeout. | Run the command manually from the project directory and increase timeout if needed. |
| Connected but no tools | listTools failed after connect. | Check server logs and tool-list response. |
| Browser did not open | Automatic browser open failed. | The CLI prints the auth URL through the mcp.browser.open.failed event path. |
Source anchors
| Need | File |
|---|---|
| MCP service | packages/nikcli/src/mcp/index.ts |
| MCP auth storage | packages/nikcli/src/mcp/auth.ts |
| OAuth provider and callback | packages/nikcli/src/mcp/oauth-provider.ts, packages/nikcli/src/mcp/oauth-callback.ts |
| CLI command | packages/nikcli/src/cli/cmd/mcp.ts |
| Classic routes | packages/nikcli/src/server/httpapi/mcp.ts |
| Typed routes | packages/nikcli/src/server/httpapi/mcp.ts |
| TUI dialog | packages/tui/src/component/dialog-mcp.tsx |