콘텐츠로 이동

Agent Communication Protocol (ACP)

이 문서는 Continuum Router의 ACP 구현을 설명합니다. 이 구현으로 라우터는 JSON-RPC 2.0 프로토콜을 통해 IDE 클라이언트와 코딩 어시스턴트를 위한 에이전트 백엔드로 동작할 수 있습니다.

개요

ACP(Agent Communication Protocol)를 사용하면 IDE 클라이언트(에디터, 터미널, 코딩 어시스턴트)가 Continuum Router를 LLM 에이전트로 삼아 표준 JSON-RPC 2.0 전송 위에서 통신할 수 있습니다. ACP가 활성화되면 라우터는 다음 두 역할을 동시에 수행합니다:

  • OpenAI 호환 요청을 위한 HTTP API 게이트웨이 (기존 기능)
  • ACP를 통한 IDE 통합용 stdio 기반 에이전트 백엔드
┌─────────────────────────────┐
│       IDE 클라이언트 (에디터)       │
└──────────────┬──────────────┘
        JSON-RPC 2.0 (NDJSON)
┌──────────────▼──────────────┐
│    Continuum Router (ACP)   │
│  ┌────────────────────────┐ │
│  │  AcpMethodRouter       │ │
│  │  SessionStore          │ │
│  │  PermissionPolicy      │ │
│  │  ToolExecutor          │ │
│  │  McpConnectionManager  │ │
│  └────────────────────────┘ │
└──────────────┬──────────────┘
    ┌──────────┴──────────┐
    ▼                     ▼
┌────────┐         ┌───────────┐
│ OpenAI │   ...   │ Anthropic │
└────────┘         └───────────┘

프로토콜 스택

ACP는 JSON-RPC 2.0을 와이어 프로토콜로 사용하고, stdin/stdout을 통해 줄바꿈으로 구분된 JSON(NDJSON) 형식으로 통신합니다. 각 줄이 하나의 완전한 JSON-RPC 메시지입니다.

메시지 유형

유형 설명
Request id가 있는 메서드 호출이며, 응답을 기대합니다
Notification id가 없는 메서드 호출이며, 응답을 기대하지 않습니다
Response 요청에 대한 결과 또는 오류

표준 오류 코드

코드 의미
-32700 파싱 오류 (형식이 잘못된 JSON)
-32600 잘못된 요청
-32601 메서드를 찾을 수 없음
-32602 잘못된 매개변수
-32603 내부 오류
-32002 서버가 초기화되지 않음
-32001 애플리케이션 오류 (세션을 찾을 수 없음 등)

프로토콜 라이프사이클

1. 초기화 핸드셰이크

클라이언트는 다른 어떤 메서드보다 먼저 반드시 initialize를 호출해야 합니다. 초기화가 완료될 때까지 다른 모든 메서드는 -32002로 거부됩니다.

요청:

{
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "protocolVersion": 1,
    "clientCapabilities": {
      "readTextFile": true,
      "writeTextFile": true,
      "terminal": false
    },
    "clientInfo": {
      "name": "MyEditor",
      "version": "1.0.0"
    }
  },
  "id": 1
}

응답:

{
  "jsonrpc": "2.0",
  "result": {
    "protocolVersion": 1,
    "agentCapabilities": {
      "loadSession": true,
      "image": false,
      "audio": false,
      "embeddedContext": false,
      "mcp": true,
      "mcpCapabilities": { "acp": true }
    },
    "agentInfo": {
      "name": "Continuum Router",
      "version": "1.3.0-beta.1"
    },
    "authMethods": []
  },
  "id": 1
}

2. 인증 (선택 사항)

authenticate 메서드는 모든 인증 시도를 수락하는 스텁(stub)이며, 라우터의 API 키 시스템과는 연결되어 있지 않습니다. 접근 제어 용도로 이 메서드에 의존하지 마세요.

{
  "jsonrpc": "2.0",
  "method": "authenticate",
  "params": {
    "method": "api_key",
    "token": "your-api-key"
  },
  "id": 2
}

3. 세션 관리

세션 생성

{
  "jsonrpc": "2.0",
  "method": "session/new",
  "params": { "mode": "code" },
  "id": 3
}

응답:

{
  "jsonrpc": "2.0",
  "result": {
    "sessionId": "550e8400-e29b-41d4-a716-446655440000",
    "createdAt": "2026-03-08T12:00:00Z",
    "updatedAt": "2026-03-08T12:00:00Z",
    "mode": "code",
    "historyLength": 0
  },
  "id": 3
}

기존 세션 로드

loadSession 에이전트 기능이 필요합니다.

{
  "jsonrpc": "2.0",
  "method": "session/load",
  "params": { "sessionId": "550e8400-e29b-41d4-a716-446655440000" },
  "id": 4
}

세션 모드 변경

{
  "jsonrpc": "2.0",
  "method": "session/set_mode",
  "params": { "mode": "architect" },
  "id": 5
}

응답:

{
  "jsonrpc": "2.0",
  "result": {
    "mode": "architect",
    "previousMode": "code"
  },
  "id": 5
}

진행 중인 작업 취소

세션의 취소 토큰을 발동시킵니다. 새 토큰이 다시 설치되므로 세션은 계속 사용할 수 있습니다.

{
  "jsonrpc": "2.0",
  "method": "session/cancel",
  "id": 6
}

4. 프롬프트 전송

LLM에 프롬프트를 보내고 session/update 알림으로 응답을 받습니다.

요청:

{
  "jsonrpc": "2.0",
  "method": "session/prompt",
  "params": {
    "sessionId": "550e8400-...",
    "content": [
      { "type": "text", "text": "Explain the architecture of this project" }
    ],
    "model": "gpt-4o",
    "stream": true,
    "temperature": 0.7,
    "maxTokens": 4096
  },
  "id": 7
}

스트리밍 알림id가 없는 JSON-RPC 알림으로 전송됩니다:

{
  "jsonrpc": "2.0",
  "method": "session/update",
  "params": {
    "sessionId": "550e8400-...",
    "content": [{ "type": "text", "text": "The architecture..." }]
  }
}

최종 응답:

{
  "jsonrpc": "2.0",
  "result": { "stopReason": "end_turn" },
  "id": 7
}

종료 사유

설명
end_turn 모델이 응답을 자연스럽게 완료함
max_tokens 토큰 한도에서 응답이 잘림
refusal 모델이 응답 생성을 거부함
cancelled session/cancel로 작업이 취소됨

콘텐츠 블록 유형

유형 필드 설명
text text 일반 텍스트 콘텐츠
image data, mediaType Base64로 인코딩된 이미지 데이터
resource uri, mediaType (선택 사항) 외부 리소스 참조

도구 호출 보고

LLM이 도구 호출을 생성하면, 에이전트는 도구 호출 상태 업데이트를 담은 session/update 알림으로 이를 클라이언트에 보고합니다.

도구 종류

종류 설명 기본 권한
read 파일 읽기 또는 디렉터리 목록 조회 자동 허용
edit 파일 쓰기 또는 수정 항상 확인
delete 파일 또는 디렉터리 삭제 항상 확인
move 파일 이름 변경 또는 이동 항상 확인
search 파일 내용 검색 자동 허용
execute 셸 명령 실행 항상 확인
think 내부 추론 자동 허용
fetch HTTP 요청 확인
other 분류되지 않은 작업 확인

도구 호출 라이프사이클

                    ┌─────────┐
                    │ Pending │
                    └────┬────┘
                    분류 + 권한 확인
                    ┌────▼────┐
         ┌─────────│   Ask   │─────────┐
         │         └─────────┘         │
    allow/always                  reject/always
         │                             │
    ┌────▼──────┐               ┌──────▼──┐
    │InProgress │               │ Failed  │
    └────┬──────┘               └─────────┘
    도구 실행
    ┌────▼──────┐
    │ Completed │
    └───────────┘

권한 위임

권한 시스템은 클라이언트가 어떤 도구 작업을 허용할지 제어할 수 있게 합니다:

권한 요청 알림:

{
  "jsonrpc": "2.0",
  "method": "session/request_permission",
  "params": {
    "sessionId": "...",
    "toolCallId": "tc-1",
    "title": "Edit File",
    "kind": "edit",
    "locations": [{ "uri": "file:///src/main.rs", "startLine": 42 }]
  }
}

클라이언트 응답 옵션:

  • allow_once: 이 작업 한 번만 허용
  • allow_always: 세션 동안 이 종류의 모든 작업 허용
  • reject_once: 이 작업 한 번만 거부
  • reject_always: 세션 동안 이 종류의 모든 작업 거부

캐시된 always_* 결정은 세션이 유지되는 동안 지속됩니다.

MCP-over-ACP 브리지

MCP 브리지는 기존 MCP(Model Context Protocol) 서버를 ACP 채널을 통해 터널링할 수 있게 합니다. 덕분에 IDE 클라이언트는 별도의 연결을 관리하지 않고도 MCP 서버에 접근할 수 있습니다.

IDE 클라이언트 ←→ [ACP stdio] ←→ Continuum Router ←→ [MCP stdio] ←→ MCP 서버

MCP 서버에 연결

{
  "jsonrpc": "2.0",
  "method": "mcp/connect",
  "params": { "id": "filesystem" },
  "id": 10
}

응답:

{
  "jsonrpc": "2.0",
  "result": { "connectionId": "uuid-..." },
  "id": 10
}

메시지 라우팅

{
  "jsonrpc": "2.0",
  "method": "mcp/message",
  "params": {
    "connectionId": "uuid-...",
    "message": {
      "jsonrpc": "2.0",
      "method": "tools/list",
      "id": 1
    }
  },
  "id": 11
}

연결 해제

{
  "jsonrpc": "2.0",
  "method": "mcp/disconnect",
  "params": { "connectionId": "uuid-..." },
  "id": 12
}

서버 ID 검증 규칙

  • 최대 128자
  • ASCII 영숫자, 하이픈, 밑줄, 점만 사용 가능
  • 이중 밑줄 사용 불가 (도구 네임스페이스용으로 예약)
  • 영숫자로 시작하고 끝나야 함

프로세스 라이프사이클

  1. mcp/connect가 stdio 파이프를 연결한 MCP 서버 프로세스를 스폰합니다
  2. 백그라운드 태스크가 stdin/stdout을 양방향으로 브리지합니다 (메시지 버퍼 64개)
  3. stderr는 라우터의 tracing::warn 로그로 전달됩니다
  4. mcp/disconnect는 SIGTERM을 보내고 5초간 기다린 뒤, 필요하면 SIGKILL을 보냅니다

기능 협상

초기화 과정에서 클라이언트와 에이전트는 서로의 기능(capability) 선언을 교환하며, 협상된 결과에 따라 해당 세션에서 사용할 수 있는 기능이 결정됩니다.

클라이언트 기능

기능 설명
readTextFile 클라이언트가 로컬 파일시스템에서 파일 읽기를 지원합니다
writeTextFile 클라이언트가 로컬 파일시스템에 파일 쓰기를 지원합니다
terminal 클라이언트가 터미널 명령 실행을 지원합니다

에이전트 기능

기능 설명
loadSession 에이전트가 이전 세션 재개를 지원합니다
image 에이전트가 이미지 콘텐츠 블록을 지원합니다
audio 에이전트가 오디오 콘텐츠 블록을 지원합니다
embeddedContext 에이전트가 임베디드 컨텍스트 블록을 지원합니다
mcp 에이전트가 MCP-over-ACP 브리지를 지원합니다

에이전트 레지스트리 메타데이터

라우터는 에이전트 레지스트리 디스커버리에 쓰이는 agent.json 메타데이터 문서를 생성하며, GET /admin/acp/agent.json으로 조회할 수 있습니다.

출력 예제:

{
  "name": "continuum-router",
  "displayName": "Continuum Router",
  "version": "1.3.0-beta.1",
  "description": "Local LLM inference agent with multi-backend routing",
  "transport": [
    { "type": "stdio" }
  ],
  "capabilities": {
    "loadSession": true,
    "mcp": true
  }
}

Admin API 엔드포인트

엔드포인트 설명
GET /admin/acp/status ACP 서버 상태 (활성화 여부, 전송, 기능)
GET /admin/acp/sessions 활성 ACP 세션 목록
GET /admin/acp/agent.json 동적 에이전트 레지스트리 메타데이터

설정

ACP는 하위 호환성을 위해 기본적으로 비활성화되어 있습니다. 활성화하려면 config.yaml에 다음을 추가하세요:

acp:
  enabled: true

  transport:
    stdio:
      enabled: true

  agent:
    name: "Continuum Router"
    version: "1.0.0"
    description: "Local LLM inference agent"

  capabilities:
    load_session: true
    image: false
    audio: false
    embedded_context: false
    mcp: true

  # ACP 세션의 기본 모델 (선택 사항)
  default_model: "gpt-4o"

  # 시스템 프롬프트 주입 (선택 사항)
  system_prompt: "You are a helpful coding assistant."

  # 코딩 에이전트 모드 활성화
  coding_agent_mode: true

  permissions:
    # 기본 정책: ask_always, allow_read 또는 allow_all
    default_policy: ask_always
    auto_allow:
      - read
      - search
      - think
    always_ask:
      - edit
      - delete
      - execute

  sessions:
    max_concurrent: 10
    idle_timeout: "1h"
    storage: "memory"

  mcp:
    max_connections_per_session: 5
    allowed_servers: []        # 비어 있으면 설정된 모든 서버 허용
    server_spawn_timeout: "10s"

설정 레퍼런스

최상위 옵션

옵션 유형 기본값 설명
enabled bool false ACP 서브시스템 활성화/비활성화
default_model string 없음 ACP 세션의 모델 선택 오버라이드
system_prompt string 없음 모든 ACP 요청에 시스템 프롬프트 주입
coding_agent_mode bool false 코딩 에이전트 시스템 프롬프트 활성화

전송 옵션

옵션 유형 기본값 설명
transport.stdio.enabled bool true stdio 전송 활성화

권한 옵션

옵션 유형 기본값 설명
permissions.default_policy enum ask_always 기본 정책: ask_always, allow_read, allow_all
permissions.auto_allow list [read, search, think] 확인 없이 자동 허용되는 도구 종류
permissions.always_ask list [edit, delete, execute] 항상 권한 확인이 필요한 도구 종류

세션 옵션

옵션 유형 기본값 설명
sessions.max_concurrent int 10 최대 동시 세션 수
sessions.idle_timeout string "1h" 정리 전 유휴 타임아웃
sessions.storage string "memory" 저장소 백엔드: memory 또는 file
sessions.storage_path string 없음 파일 기반 저장소 경로

MCP 브리지 옵션

옵션 유형 기본값 설명
mcp.max_connections_per_session int 5 세션당 최대 MCP 연결 수
mcp.allowed_servers list [] 허용할 서버 ID (비어 있으면 모두 허용)
mcp.server_spawn_timeout string "10s" MCP 서버 프로세스 스폰 타임아웃

모듈 구조

src/acp/
├── mod.rs              # 모듈 루트
├── jsonrpc.rs          # JSON-RPC 2.0 프로토콜 타입
├── types.rs            # ACP 콘텐츠 블록과 메시지
├── error.rs            # 오류 타입
├── capabilities.rs     # 기능 협상
├── config.rs           # 설정 구조체
├── config_validate.rs  # 설정 검증
├── metadata.rs         # 에이전트 레지스트리 메타데이터 (agent.json)
├── transport/
│   ├── mod.rs          # AcpTransport 트레이트
│   └── stdio.rs        # stdin/stdout 위의 NDJSON
├── session.rs          # 세션 라이프사이클과 저장소
├── router.rs           # 메서드 디스패치 라우터
├── handlers/
│   ├── initialize.rs   # 프로토콜 초기화
│   ├── authenticate.rs # 인증 (스텁)
│   ├── session.rs      # session/* 메서드
│   ├── prompt.rs       # session/prompt 핸들러
│   ├── prompt_stream.rs # SSE 스트리밍 프로세서
│   └── translate.rs    # ACP → OpenAI 형식 변환
├── tools/
│   ├── mod.rs          # 도구 호출 타입
│   ├── classifier.rs   # 도구 종류 분류
│   ├── permission.rs   # 권한 정책 엔진
│   ├── executor.rs     # 도구 실행 오케스트레이터
│   └── client_methods.rs # 클라이언트 측 메서드 (fs/*, terminal/*)
├── mcp_bridge/
│   ├── mod.rs          # MCP 기능
│   ├── handlers.rs     # connect/message/disconnect 핸들러
│   ├── connection.rs   # 연결 관리자
│   ├── process.rs      # MCP 서버 프로세스 스폰
│   └── schema_translate.rs # MCP ↔ ACP 스키마 변환
└── admin.rs            # Admin API 엔드포인트