Feature Request: Non-Blocking Session Creation for ACP/SDK Clients

Resolved 💬 3 comments Opened Dec 7, 2025 by jsulopzs Closed Feb 8, 2026

Problem Statement

When using Claude Code via ACP clients (Zed, Neovim, custom TUIs) or the Claude Agent SDK, users cannot interact with Claude until ALL MCP servers finish initializing - which can take 20-35 seconds. This creates a terrible user experience where the client appears frozen.

How This Differs from Existing Issues

| Issue | Focus | This Issue |
|-------|-------|------------|
| #7336 | Reduce context tokens consumed by MCP tools | Reduce startup latency for ACP/SDK clients |
| #6638 | Dynamic /mcp enable/disable during session | Non-blocking session creation |

This issue is specifically about ACP and SDK use cases where:

  • External clients spawn Claude Code as a subprocess
  • session/new (ACP) or query() (SDK) blocks for 20-35 seconds
  • Users cannot type or interact until all MCP servers connect

The Core Issue

The Claude Agent SDK's query() function and ACP's session/new method block until every MCP server is connected. Users stare at a loading screen when they could already be:

  • Typing their prompt
  • Reading Claude's greeting
  • Having a conversation (without tools)
  • Seeing tools become available progressively

Real-World Impact

I built a TUI client using claude-code-acp and measured the initialization timing:

| Step | Time |
|------|------|
| spawn() process | 1.4ms |
| initialize() ACP handshake | 90ms |
| new_session() - blocked on MCP | 32.6 seconds |
| Total | 32.7 seconds |

Testing each MCP server individually:

| MCP Server | Initialization Time |
|------------|---------------------|
| sequential-thinking | 1.2s |
| memory | 1.3s |
| fetch (uvx) | 1.6s |
| context7 (HTTP) | 2.3s |
| toolbox (smithery) | 2.3s |
| iMCP (Bonjour discovery) | 31.1s |

One slow server (iMCP doing Bonjour discovery) blocks the entire session for 31 seconds.

Proposed Solution: Async MCP Initialization

Primary Goal: Immediate Session Availability

session/new should return immediately with:

  • A valid session ID
  • Basic conversation capability (Claude can respond)
  • MCP servers marked as "pending"

Tools become available progressively as servers connect.

Implementation Approach

1. Non-Blocking Session Creation
Client                    ACP Agent                Claude Code
  │                           │                         │
  │─── session/new ──────────>│                         │
  │                           │──── start session ─────>│
  │<── session ready ─────────│  (MCP init in background)
  │                           │                         │
  │─── prompt "hello" ───────>│                         │
  │<── response ──────────────│  (works without tools)  │
  │                           │                         │
  │<── mcp_server_ready ──────│<── server1 connected ───│
  │<── mcp_server_ready ──────│<── server2 connected ───│
  │                           │                         │
  │─── prompt "read file" ───>│                         │
  │<── uses Read tool ────────│  (tools now available)  │
2. New ACP Notifications for MCP Status

Add notifications to inform clients about MCP server status:

// New notification types
interface McpServerStatusNotification {
  sessionUpdate: "mcp_server_status";
  serverName: string;
  status: "connecting" | "connected" | "failed" | "timeout";
  tools?: string[];  // Available tools when connected
  error?: string;    // Error message if failed
}

interface McpServersReadyNotification {
  sessionUpdate: "mcp_servers_ready";
  connectedServers: string[];
  failedServers: { name: string; error: string }[];
}
3. Updated Session Response

The session/new response should indicate MCP status:

interface NewSessionResponse {
  sessionId: string;
  models: SessionModelState;
  modes: SessionModeState;
  // New fields:
  mcpStatus: {
    pending: string[];      // Servers still connecting
    connected: string[];    // Servers ready
    failed: string[];       // Servers that failed
  };
  availableTools: string[]; // Tools available RIGHT NOW
}
4. Graceful Tool Handling

When a user requests a tool that isn't ready yet:

// Option A: Inform and wait
{
  type: "tool_call",
  status: "waiting",
  message: "Waiting for 'memory' server to connect...",
  estimatedWait: 5000
}

// Option B: Offer alternatives
{
  type: "tool_call",
  status: "unavailable",
  message: "The 'memory' server is still connecting. Would you like to wait or proceed without it?"
}

Additional Improvements

Parallel MCP Initialization

Even with async init, servers should connect in parallel:

Current (serial):
Server1 (1s) → Server2 (1s) → Server3 (30s) → All ready
Total: 32s

Proposed (parallel):
Server1 (1s) ─┐
Server2 (1s) ─┼─→ All ready
Server3 (30s)─┘
Total: 30s (but session usable at 0s!)
Per-Server Configuration
{
  "mcpServers": {
    "critical-server": {
      "command": "fast-mcp",
      "blocking": true       // Wait for this before session/new returns
    },
    "slow-server": {
      "command": "slow-mcp",
      "blocking": false,     // Initialize in background (default)
      "timeout": 10000,      // Give up after 10s
      "optional": true       // Session continues if this fails
    }
  }
}

User Experience Vision

Before (Current)

User opens Claude Code panel
  │
  ├── "Connecting..." (0s)
  │       ↓
  │   [blocked - cannot type]
  │       ↓
  │   [still blocked - 10s]
  │       ↓
  │   [still blocked - 20s]
  │       ↓
  │   [still blocked - 30s]
  │       ↓
  └── "Ready!" (32s) ← Finally can interact

After (Proposed)

User opens Claude Code panel
  │
  ├── "Ready!" (0.1s) ← Can immediately type!
  │       ↓
  │   User: "Hi Claude, what can you help me with?"
  │   Claude: "I can help with coding, writing..."
  │       ↓
  │   [Status: 3/6 tools loading...]
  │       ↓
  │   [Status: 5/6 tools loading...]
  │       ↓
  │   [Status: All tools ready! ✓] (32s, but user didn't wait)
  │       ↓
  └── User: "Read the main.rs file"
      Claude: [uses Read tool]

Use Cases

ACP Clients (Zed, Neovim, Custom TUIs)

ACP clients like Zed spawn claude-code-acp which spawns Claude Code for each session. The 30+ second delay makes the experience painful.

SDK Users

Applications using the Claude Code SDK (@anthropic-ai/claude-agent-sdk) face the same issue when calling query() - each call spawns a new process and waits for full MCP initialization.

Plugin Development

Plugin developers testing their MCP servers alongside other servers get blocked by unrelated slow servers.

Related Issues

  • #7336 - Lazy Loading for MCP Servers (context tokens, not startup latency)
  • #6638 - Dynamic loading/unloading (during session, not at creation)
  • #3044 - SDK mode warmup time on slower devices (related)
  • #8164 - Claude CLI is slow to start (related)
  • #424 - MCP Timeout needs to be configurable (related)

Note: This issue complements #7336 and #6638 but addresses a different problem - the blocking nature of session creation for ACP/SDK clients, not context token usage or mid-session management.

Environment

  • Claude Code version: 1.0.x
  • Platform: macOS (also affects Linux)
  • Using: claude-code-acp v0.12.0

Workaround

Currently, the only workaround is to disable slow MCP servers:

// In settings.json
{
  "enabledPlugins": {
    "archive@personal": false  // Contains slow iMCP server
  }
}

Or remove slow servers from .mcp.json entirely.

This is not ideal because:

  • Users lose access to useful MCP tools
  • No granular control (entire plugins must be disabled)
  • No way to set acceptable timeouts

Implementation Considerations

Where Changes Are Needed

| Component | Change Required |
|-----------|-----------------|
| Claude Code (anthropics/claude-code) | Core async MCP init logic |
| Claude Agent SDK | Expose MCP status events in stream |
| claude-code-acp (zed-industries) | Forward MCP status to ACP clients |
| ACP Protocol | New notification types for MCP status |

Backward Compatibility

  • Clients that don't understand new notifications simply ignore them
  • Default behavior can remain blocking for compatibility
  • New asyncMcpInit: true option to opt-in

SDK Changes Required

The Claude Agent SDK needs to:

  1. Emit mcp_server_status events during initialization
  2. Not block query() on MCP initialization
  3. Allow tools to be used as soon as their server connects
// Current SDK behavior
const q = query({ prompt, options });
// ↑ Blocks here for 30+ seconds until ALL MCP servers ready

// Proposed SDK behavior
const q = query({ prompt, options: { ...options, asyncMcpInit: true } });
// ↑ Returns immediately, MCP servers connect in background

for await (const message of q) {
  if (message.type === 'system' && message.subtype === 'mcp_status') {
    console.log(`MCP ${message.server}: ${message.status}`);
  }
}

Summary

| Feature | Impact | Effort | Priority |
|---------|--------|--------|----------|
| Async MCP init (non-blocking session) | Critical - instant UX | Medium | P0 |
| Parallel MCP init | High - reduces total time | Medium | P1 |
| MCP status notifications | High - progressive loading UX | Low | P1 |
| Per-server timeout/optional | High - resilience | Medium | P2 |
| Per-server blocking config | Medium - fine control | Low | P3 |

The primary ask is: Don't block session/new on MCP initialization. Let users interact with Claude immediately while tools load in the background.

This would transform the ACP experience from "30 second loading screen" to "instant interaction with progressive tool availability."

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗