Skip to main content

Overview

Sessions represent independent conversation contexts with their own history and state. Each session has a unique ID and maintains its own conversation history, working directory, and MCP server connections.

Creating Sessions

The newSession method creates a new conversation session:
async newSession(
  params: NewSessionRequest
): Promise<NewSessionResponse>
params.workingDirectory
string
Optional working directory for the session
params.mcpServers
MCPServerConfig[]
MCP servers to connect to for this session
sessionId
string
required
A unique identifier for the new session
availableModes
Mode[]
Optional list of available modes for this session
currentMode
string
The initial mode for this session
See protocol docs: Session Setup

Example

interface AgentSession {
  workingDirectory?: string;
  history: acp.Message[];
  pendingPrompt: AbortController | null;
  mcpServers: MCPServerConnection[];
}

class MyAgent implements acp.Agent {
  private sessions: Map<string, AgentSession> = new Map();

  async newSession(params: acp.NewSessionRequest): Promise<acp.NewSessionResponse> {
    const sessionId = crypto.randomUUID();
    
    // Create session state
    this.sessions.set(sessionId, {
      workingDirectory: params.workingDirectory,
      history: [],
      pendingPrompt: null,
      mcpServers: await this.connectToMCPServers(params.mcpServers),
    });

    return {
      sessionId,
      currentMode: "code",
    };
  }

  private async connectToMCPServers(
    configs: acp.MCPServerConfig[] = []
  ): Promise<MCPServerConnection[]> {
    // Connect to each MCP server
    return Promise.all(configs.map(config => this.connectMCPServer(config)));
  }
}
May throw an auth_required error if the agent requires authentication before creating sessions.

Loading Sessions

The optional loadSession method loads an existing session to resume a previous conversation:
loadSession?(
  params: LoadSessionRequest
): Promise<LoadSessionResponse>
params.sessionId
string
required
The session ID to load
params.mcpServers
MCPServerConfig[]
MCP servers to connect to for this session
availableModes
Mode[]
Optional list of available modes for this session
currentMode
string
The current mode for this session
This method is only available if the agent advertises the loadSession capability during initialization. The agent should:
  • Restore the session context and conversation history
  • Connect to the specified MCP servers
  • Stream the entire conversation history back to the client via sessionUpdate notifications
See protocol docs: Loading Sessions

Example

async loadSession(params: acp.LoadSessionRequest): Promise<acp.LoadSessionResponse> {
  // Load session from storage
  const sessionData = await this.storage.loadSession(params.sessionId);
  
  if (!sessionData) {
    throw acp.RequestError.resourceNotFound(params.sessionId);
  }

  // Restore session state
  this.sessions.set(params.sessionId, {
    workingDirectory: sessionData.workingDirectory,
    history: sessionData.history,
    pendingPrompt: null,
    mcpServers: await this.connectToMCPServers(params.mcpServers),
  });

  // Stream conversation history to client
  for (const message of sessionData.history) {
    await this.connection.sessionUpdate({
      sessionId: params.sessionId,
      update: {
        sessionUpdate: "agent_message_chunk",
        content: message.content,
      },
    });
  }

  return {
    currentMode: sessionData.mode,
  };
}

Session Modes

Session modes allow switching between different agent behaviors (e.g., “ask”, “architect”, “code”) that affect system prompts, tool availability, and permission behaviors.
setSessionMode?(
  params: SetSessionModeRequest
): Promise<SetSessionModeResponse | void>
params.sessionId
string
required
The session ID to update
params.mode
string
required
The mode to switch to (must be one of the advertised modes)
The mode must be one of the modes advertised in availableModes during session creation or loading. Agents may also change modes autonomously and notify the client via current_mode_update notifications. This method can be called at any time during a session, whether the agent is idle or actively generating a turn. See protocol docs: Session Modes

Example

async initialize(params: acp.InitializeRequest): Promise<acp.InitializeResponse> {
  return {
    protocolVersion: acp.PROTOCOL_VERSION,
    agentCapabilities: {
      sessionModes: true,
    },
    availableModes: [
      {
        id: "code",
        name: "Code",
        description: "Full coding capabilities with all tools",
      },
      {
        id: "ask",
        name: "Ask",
        description: "Question answering without code modifications",
      },
      {
        id: "architect",
        name: "Architect",
        description: "High-level design and planning",
      },
    ],
  };
}

async setSessionMode(params: acp.SetSessionModeRequest): Promise<void> {
  const session = this.sessions.get(params.sessionId);
  if (!session) {
    throw new Error(`Session ${params.sessionId} not found`);
  }

  // Validate mode
  if (!this.isValidMode(params.mode)) {
    throw acp.RequestError.invalidParams({ mode: params.mode });
  }

  // Update session mode
  session.mode = params.mode;

  // Update system prompt based on mode
  await this.updateSystemPrompt(session, params.mode);
}

Forking and Resuming Sessions (Unstable)

These methods are marked as UNSTABLE and may be removed or changed at any point.

Forking Sessions

The unstable_forkSession method creates a new session based on an existing one:
unstable_forkSession?(
  params: ForkSessionRequest
): Promise<ForkSessionResponse>
params.sessionId
string
required
The session ID to fork from
params.mcpServers
MCPServerConfig[]
MCP servers to connect to for the new session
sessionId
string
required
The ID of the newly created session
This allows operations like generating summaries without affecting the original session’s history.

Example

async unstable_forkSession(params: acp.ForkSessionRequest): Promise<acp.ForkSessionResponse> {
  const originalSession = this.sessions.get(params.sessionId);
  if (!originalSession) {
    throw new Error(`Session ${params.sessionId} not found`);
  }

  const newSessionId = crypto.randomUUID();
  
  // Create new session with copied state
  this.sessions.set(newSessionId, {
    workingDirectory: originalSession.workingDirectory,
    history: [...originalSession.history], // Copy history
    pendingPrompt: null,
    mcpServers: await this.connectToMCPServers(params.mcpServers),
  });

  return { sessionId: newSessionId };
}

Resuming Sessions

The unstable_resumeSession method resumes an existing session without replaying the message history:
unstable_resumeSession?(
  params: ResumeSessionRequest
): Promise<ResumeSessionResponse>
params.sessionId
string
required
The session ID to resume
params.mcpServers
MCPServerConfig[]
MCP servers to connect to for this session
Unlike loadSession, this method does not stream the conversation history to the client.

Example

async unstable_resumeSession(params: acp.ResumeSessionRequest): Promise<void> {
  const sessionData = await this.storage.loadSession(params.sessionId);
  
  if (!sessionData) {
    throw acp.RequestError.resourceNotFound(params.sessionId);
  }

  // Restore session state WITHOUT streaming history
  this.sessions.set(params.sessionId, {
    workingDirectory: sessionData.workingDirectory,
    history: sessionData.history,
    pendingPrompt: null,
    mcpServers: await this.connectToMCPServers(params.mcpServers),
  });
}

Session Persistence

To support session loading, you’ll need to persist session data:
interface SessionStorage {
  saveSession(sessionId: string, data: SessionData): Promise<void>;
  loadSession(sessionId: string): Promise<SessionData | null>;
  listSessions(): Promise<SessionMetadata[]>;
}

class MyAgent implements acp.Agent {
  constructor(
    private connection: acp.AgentSideConnection,
    private storage: SessionStorage
  ) {}

  async prompt(params: acp.PromptRequest): Promise<acp.PromptResponse> {
    const session = this.sessions.get(params.sessionId);
    if (!session) {
      throw new Error(`Session ${params.sessionId} not found`);
    }

    // Process prompt...
    const response = await this.processPrompt(params, session);

    // Persist updated session
    await this.storage.saveSession(params.sessionId, {
      workingDirectory: session.workingDirectory,
      history: session.history,
      mode: session.mode,
    });

    return response;
  }
}

Best Practices

Generate Unique IDs

Use crypto.randomUUID() or similar to generate unique session IDs

Clean Up Resources

Disconnect from MCP servers and clean up resources when sessions end

Persist State

Save session state after each prompt to support session loading

Validate Modes

Validate that requested modes are in your list of available modes

Build docs developers (and LLMs) love