[Protocol] LSP, Language Server Protocol: IDE와 언어 서버가 대화할 때 쓰는 약속

soleil_lucy·2025년 10월 25일

VS Code를 사용하여 열심히 개발하던 당신은 이미 입력된 변수가 자동으로 입력되는 기능이 있었으면 좋겠다고 생각하게 됩니다. 함수명을 클릭하면 정의된 위치로 바로 이동하고, 작성 중인 코드에서 타입 오류가 발생하면 IDE가 빨간 밑줄로 표시해 주면 편리하겠다고 느낍니다.

그래서 당신은 이러한 기능들을 직접 IDE에 맞춰 구현하여 사용하기 시작합니다. 하지만 IDE를 WebStorm으로 바꾸자, VS Code에서 잘 쓰던 기능들을 다시 만들어야 하는 상황이 생겼습니다. IDE마다 API가 다르기 때문에 같은 기능을 반복 구현해야 했던 것입니다.

“한 번만 구현해도 여러 IDE에서 쓸 수 있는 방법은 없을까?” 하는 고민 끝에 등장한 것이 바로 LSP(Language Server Protocol)입니다. IDE와 언어 서버가 통신하는 표준 규약을 정의하여, 한 번 구현한 기능을 다양한 IDE에서 재사용할 수 있도록 해줍니다.

What: LSP란 무엇일까?

언어 서버

언어별 스마트 기능을 제공하며, 프로세스 간 통신을 가능하게 하는 프로토콜을 통해 개발 도구와 연결되는 서버입니다. IDE나 다른 도구는 언어 서버와 통신하여 자동 완성, 정의로 이동, 문서 보기 같은 기능을 사용할 수 있습니다.

LSP, Language Server Protocol

도구와 서버가 통신하는 방식을 표준화한 프로토콜입니다. 이를 통해 단일 언어 서버를 여러 개발 도구에서 재사용할 수 있고, 도구가 최소한의 노력으로 다양한 언어를 지원할 수 있게 합니다.

Why: 왜 필요했을까?

IDE 별로 동일한 언어 기능을 여러 번 만들어야 했던 불편함을 줄이기 위해

자동 완성, 정의로 이동, 문서 보기 같은 언어별 기능을 구현하는 일은 많은 노력과 시간이 필요합니다. 과거에는 IDE마다 제공하는 API가 달라, 동일한 기능을 여러 IDE에서 반복해서 만들어야 했습니다.

LSP는 이러한 반복 작업을 줄이기 위해 등장했습니다. 언어 서버를 IDE에서 분리하고, 표준화된 프로토콜에 맞춰 개발하면 한 번 만든 언어 서버를 여러 IDE에서 그대로 재사용할 수 있습니다. 덕분에 개발자는 IDE마다 기능을 다시 구현할 필요가 없고, 다양한 도구에서도 일관된 언어 기능을 쉽게 제공할 수 있게 되었습니다.

How: 어떻게 동작하는가?

언어 서버와 IDE의 통신 방법: JSON-RPC

언어 서버는 별도의 프로세스로 실행되며, 개발 도구는 JSON-RPC를 통해 언어 프로토콜을 사용하여 서버와 통신합니다.

예시: 일상적인 편집 세션에서의 IDE와 언어 서버 통신

  • 파일 열기(textDocument/didOpen)
    • IDE는 문서가 열렸음을 언어 서버에 알립니다.
    • 이제 문서 내용은 파일 시스템이 아닌 IDE 메모리에서 관리되며, IDE와 언어 서버가 동기화합니다.
  • 파일 편집(textDocument/didChange)
    • IDE가 변경 사항을 언어 서버에 전달하면, 서버는 문서 내용을 업데이트하고 분석합니다.
    • 분석 결과 오류나 경고가 있으면 IDE에 전달됩니다.
  • ‘Go to Definition’(textDocument/definition)
    • IDE는 문서 URI와 커서 위치를 포함한 요청을 서버로 보냅니다.
    • 서버는 해당 변수나 함수가 정의된 위치와 문서 URI를 응답합니다.
  • 파일 닫기(textDocment/didClose)
    • IDE에서 알림을 보내면, 언어 서버는 문서가 더 이상 메모리에 없음을 인지합니다.

JSON-RPC 예시

Request

{
    "jsonrpc": "2.0",
    "id" : 1,
    "method": "textDocument/definition",
    "params": {
        "textDocument": {
            "uri": "file:///p%3A/mseng/VSCode/Playgrounds/cpp/use.cpp"
        },
        "position": {
            "line": 3,
            "character": 12
        }
    }
}

Response

{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "uri": "file:///p%3A/mseng/VSCode/Playgrounds/cpp/provide.cpp",
        "range": {
            "start": {
                "line": 0,
                "character": 4
            },
            "end": {
                "line": 0,
                "character": 11
            }
        }
    }
}

Where: 어디서 쓰이고 있을까?

다양한 IDE와 코드 편집기

각 IDE에서 자동 완성, 정의로 이동, 오류 표시 등 언어 기능을 지원할 때 LSP가 활용됩니다.

  • 활용 사례: VS Code, IntelliJ IDEs(PyCharm, WebStorm, IntelliJ IDEA 등), Eclipse, Neovim 등

온라인 IDE

웹 환경에서도 데스크톱 IDE처럼 언어 기능을 제공하기 위해 LSP를 사용합니다.

  • 활용 사례: GitHub Codespaces, Replit 등

GitHub Codespaces 예시

Replit 예시

AI 코드 도구

코드의 의미와 구조를 분석하고, 토큰 사용량을 줄이며 효율적으로 코드를 처리할 때 LSP 구조를 참고하거나 활용합니다.

  • 활용 사례: Serena MCP 등

회고: LSP를 알아보고 나서

책에서 Serena MCP를 읽다가 LSP 개념을 처음 접했습니다. 글에서 IDE에서 자동 완성, 정의로 이동, 타입 오류 표시 같은 기능이 가능하게 된 배경으로 LSP가 소개된 것을 보고 흥미가 생겨 이번 글을 작성하게 됐습니다.

평소 VS Code를 사용하면서 변수나 함수를 자동 완성하고, 함수 정의로 바로 이동하며, TypeScript 코드에서 타입 오류를 확인하는 기능이 매우 편리하다고 느꼈습니다. 그런데 이런 기능들이 어떻게 구현되는지 궁금했는데, LSP를 공부 하면서 그 궁금증이 해소되었습니다.

마이크로소프트가 만든 LSP는 IDE마다 언어 기능을 반복해서 구현해야 했던 불편함을 해결하기 위해 등장했습니다. 언어 서버에 기능을 구현하고 IDE와 언어 서버가 JSON-RPC로 통신하도록 표준을 정의함으로써, 한 번 구현한 기능을 여러 IDE에서 재사용할 수 있게 한 것입니다. 즉, LSP는 기능 자체를 제공하는 것이 아니라, 기능을 IDE와 독립적으로 구현하고 재사용할 수 있도록 돕는 표준입니다.

LSP를 공부하며 ‘표준’은 중요하다는 생각이 들었습니다. LSP처럼 명확한 규칙과 약속이 있으면 반복 작업을 줄일 수 있고, 개발 생산성이 높아집니다. 마치 팀 단위로 코드 컨벤션을 정해두는 것처럼, 코드 작성 ‘표준’을 정해두면 서로의 코드를 빠르고 편하게 이해할 수 있어 개발 과정에서 불필요한 혼란을 줄일 수 있다고 생각합니다.

‘표준’은 반복 작업의 불편함을 줄이고, 생산성을 높여 준다고 생각이 듭니다.

참고 자료

profile
여행과 책을 좋아하는 개발자입니다.

0개의 댓글