목차
- LSP가 Claude Code에서 하는 일
- TypeScript 프로젝트 LSP 연동
- Python 프로젝트 LSP 연동
- TypeScript vs Python LSP 설정 상세 비교
- 토큰 사용량 최적화 전략
- LSP 설정 트러블슈팅
- 프로젝트 규모별 최적화 전략
- 언어 서버 선택 기준과 다음 단계
Claude Code LSP 설정은 프로젝트의 언어 서버를 Claude Code에 연결해서 코드 인텔리전스를 강화하는 작업이다. LSP(Language Server Protocol)가 연동되면 Claude Code가 타입 정보, 심볼 참조, 정의 위치를 직접 파악한다. 파일을 하나하나 읽어가며 컨텍스트를 수집하는 대신 언어 서버의 인덱스를 그대로 쓰기 때문에 토큰 소비가 줄고, 응답 정확도는 올라간다.
TypeScript 프로젝트와 Python 프로젝트는 언어 서버의 구조가 다르다. tsserver는 tsconfig.json 기반으로 프로젝트 경계를 잡고, Python 쪽은 Pyright나 Pylsp가 pyrightconfig.json 또는 pyproject.toml을 기준으로 동작한다. 같은 Claude Code LSP 설정이라도 언어별로 잡아야 할 옵션이 다르고, 토큰 최적화 전략도 갈린다. 이 글은 두 언어의 설정 차이를 비교하고, 프로젝트 규모에 따른 최적화 방법을 정리한다.
LSP가 Claude Code에서 하는 일
LSP는 원래 VS Code 같은 에디터와 언어 서버 사이의 통신 프로토콜이다. Microsoft가 2016년에 공개했고, 지금은 거의 모든 에디터가 지원한다. Claude Code도 이 프로토콜을 통해 언어 서버와 통신한다.
LSP 없이 동작하는 경우
LSP가 연결되지 않으면 Claude Code는 파일 시스템을 직접 탐색한다. grep이나 ripgrep으로 심볼을 찾고, 파일을 열어서 컨텍스트를 파악한다. 이 방식은 동작은 하지만 비용이 크다.
- 타입 정보를 알 수 없어서 추론에 의존
- 심볼의 정의 위치를 찾으려면 여러 파일을 읽어야 함
- 읽은 파일 내용이 전부 토큰으로 소비됨
LSP가 연결된 경우

언어 서버가 이미 프로젝트 전체를 인덱싱해 둔 상태이므로, Claude Code는 textDocument/definition, textDocument/references, textDocument/hover 같은 LSP 요청으로 필요한 정보만 가져온다. 파일 전체를 읽지 않아도 해당 심볼의 타입 시그니처와 위치를 바로 알 수 있다.
LSP는 JSON-RPC 기반 프로토콜이다. 클라이언트(Claude Code)가 요청을 보내면 서버(tsserver, Pyright 등)가 응답한다. 통신은 stdin/stdout 또는 TCP 소켓으로 이루어진다.
TypeScript 프로젝트 LSP 연동

TypeScript의 언어 서버는 tsserver다. typescript 패키지에 포함되어 있어서 별도 설치가 필요 없다. node_modules/.bin/tsserver로 실행되거나, 글로벌 설치된 TypeScript가 제공하는 서버를 쓴다.
tsconfig.json 설정 확인
Claude Code가 tsserver를 제대로 활용하려면 tsconfig.json이 프로젝트 루트에 있어야 한다. 없으면 tsserver가 프로젝트 경계를 인식하지 못하고, 모든 .ts 파일을 개별 스크립트로 취급한다.
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
include와 exclude 설정이 중요하다. include 범위가 넓으면 tsserver가 인덱싱할 파일이 많아져 초기화가 느려진다. 테스트 파일이나 빌드 결과물은 exclude로 빼는 게 좋다.
Claude Code에서 TypeScript LSP 활성화
Claude Code의 설정 파일(.claude/settings.json 또는 프로젝트 루트의 .claude/settings.local.json)에서 LSP 관련 옵션을 지정한다.
{
"lsp": {
"typescript": {
"enabled": true,
"command": "typescript-language-server",
"args": ["--stdio"],
"initializationOptions": {
"preferences": {
"includeInlayParameterNameHints": "all",
"includeInlayVariableTypeHints": true
}
}
}
}
}
typescript-language-server는 tsserver를 래핑하는 LSP 호환 서버다. tsserver 자체는 LSP 프로토콜을 직접 구현하지 않고 자체 프로토콜을 쓰기 때문에, 이 래퍼가 중간에서 변환 역할을 한다.
`npm install -g typescript-language-server typescript` 명령으로 글로벌 설치한다. 프로젝트 로컬에 TypeScript가 설치되어 있으면 그 버전을 우선 사용한다.
모노레포에서는 tsconfig.json이 여러 개다. 루트에 tsconfig.base.json이 있고 각 패키지에 tsconfig.json이 있는 구조. tsserver는 열린 파일의 위치에서 가장 가까운 tsconfig.json을 자동으로 찾는다. Claude Code가 여러 패키지를 넘나들며 작업할 때 프로젝트 레퍼런스(references 필드)가 설정되어 있지 않으면 패키지 간 타입 참조가 끊길 수 있다.
{
"references": [
{ "path": "../shared" },
{ "path": "../api-types" }
]
}
Python 프로젝트 LSP 연동
Python 언어 서버는 선택지가 둘이다. Pyright와 Pylsp(Python LSP Server). 성격이 다르다.
| 항목 | Pyright | Pylsp |
|---|---|---|
| 개발사 | Microsoft | Python LSP 커뮤니티 |
| 타입 체크 | 엄격한 정적 타입 분석 | 선택적 (mypy 플러그인) |
| 속도 | 빠름 (Node.js 기반) | 상대적으로 느림 (Python 기반) |
| 설정 파일 | pyrightconfig.json | pyproject.toml 또는 설정 파일 |
| 플러그인 | 없음 | rope, mypy, flake8 등 |
Pyright 설정
Pyright는 basedpyright 또는 pyright 패키지로 설치한다. Claude Code에서 연동하는 설정은 다음과 같다.
{
"lsp": {
"python": {
"enabled": true,
"command": "pyright-langserver",
"args": ["--stdio"],
"rootPatterns": ["pyproject.toml", "setup.py", "pyrightconfig.json"]
}
}
}
프로젝트 루트에 pyrightconfig.json을 두면 Pyright의 분석 범위와 엄격도를 제어할 수 있다.
{
"include": ["src"],
"exclude": ["**/node_modules", "**/__pycache__", "**/migrations"],
"pythonVersion": "3.12",
"pythonPlatform": "Linux",
"typeCheckingMode": "basic",
"reportMissingImports": true,
"reportMissingTypeStubs": false
}
typeCheckingMode는 "off", "basic", "standard", "strict" 네 단계다. Claude Code와 함께 쓸 때는 "basic"이면 충분하다. "strict"로 올리면 서드파티 라이브러리의 타입 스텁 누락 경고가 쏟아져서 노이즈가 된다.
Pylsp 설정
Pylsp는 플러그인 생태계가 강점이다. pip install python-lsp-server로 설치하고, 플러그인을 추가로 넣는다.
pip install python-lsp-server[all]
pip install pylsp-mypy pylsp-rope
Claude Code 설정에서 Pylsp를 연결하는 방법:
{
"lsp": {
"python": {
"enabled": true,
"command": "pylsp",
"args": [],
"settings": {
"pylsp": {
"plugins": {
"pycodestyle": { "enabled": false },
"pyflakes": { "enabled": true },
"pylsp_mypy": { "enabled": true, "live_mode": false }
}
}
}
}
}
}
`pylsp_mypy`의 `live_mode`를 `true`로 설정하면 파일 변경 시마다 mypy가 돌아간다. 대규모 프로젝트에서는 응답이 수 초씩 늦어질 수 있다. `live_mode: false`로 두고 저장 시에만 실행되게 하는 편이 낫다.
같은 Claude Code LSP 설정이라도 언어에 따라 체감이 다르다. 핵심 차이를 항목별로 정리한다.
| 비교 항목 | TypeScript (tsserver) | Python (Pyright) | Python (Pylsp) |
|---|---|---|---|
| 초기화 속도 | 중간 (프로젝트 크기 비례) | 빠름 | 느림 |
| 타입 추론 정밀도 | 높음 (TS 자체가 정적 타입) | 높음 | 중간 (mypy 의존) |
| Go to Definition | 정확 | 정확 | 대체로 정확 |
| Find References | 정확 | 정확 | 정확도 낮을 수 있음 |
| 자동완성 품질 | 높음 | 높음 | 중간 |
| 메모리 사용 | 높음 (대규모 시 1GB+) | 중간 | 낮음 |
| 설정 복잡도 | 낮음 | 낮음 | 높음 (플러그인 조합) |
타입 정보의 질이 토큰에 미치는 영향
TypeScript는 모든 심볼에 타입 정보가 붙는다. tsserver가 hover 요청에 대해 돌려주는 응답에는 함수 시그니처, 제네릭 파라미터, 반환 타입이 전부 포함된다. Claude Code가 이 정보를 받으면 해당 함수를 사용하는 파일을 추가로 읽지 않아도 된다.
Python은 동적 타입 언어라 타입 정보가 불완전할 수 있다. 타입 힌트를 쓰지 않은 코드베이스에서는 Pyright도 Unknown 타입을 돌려보낸다. 이 경우 Claude Code가 추가 컨텍스트를 수집하기 위해 관련 파일을 더 읽게 되고, 토큰 사용량이 늘어난다.
타입 힌트를 꼼꼼히 달아둔 Python 프로젝트와 그렇지 않은 프로젝트 사이에 Claude Code의 토큰 소비 차이가 난다. 타입 힌트 커버리지가 높을수록 LSP가 제공하는 정보가 풍부해지고, Claude Code가 파일을 추가로 읽을 필요가 줄어든다.
모노레포 vs 단일 프로젝트
TypeScript 모노레포는 프로젝트 레퍼런스만 잘 잡아두면 tsserver가 패키지 간 의존성을 파악한다. Python 모노레포는 상황이 다르다. Pyright의 extraPaths 설정으로 다른 패키지의 소스 경로를 직접 알려줘야 한다.
{
"extraPaths": ["../shared/src", "../utils/src"],
"executionEnvironments": [
{
"root": "src",
"pythonVersion": "3.12",
"extraPaths": ["../shared/src"]
}
]
}
Pyright의 `executionEnvironments`는 프로젝트 내 하위 디렉터리별로 Python 버전과 경로를 다르게 설정할 수 있다. Lambda 함수(Python 3.9)와 메인 서버(Python 3.12)가 같은 레포에 있을 때 유용하다.
Claude Code LSP 설정의 실질적 목적은 토큰 절약이다. LSP를 켜는 것만으로도 차이가 나지만, 세부 설정을 조정하면 효과가 더 커진다.
exclude 패턴 최적화
언어 서버가 인덱싱하는 파일 범위를 줄이면 두 가지 효과가 있다. 첫째, 서버 초기화가 빨라진다. 둘째, Claude Code가 LSP를 통해 받는 심볼 목록에 노이즈가 줄어든다.
TypeScript에서 자주 제외하는 패턴:
{
"exclude": [
"node_modules",
"dist",
"build",
".next",
"coverage",
"**/*.test.ts",
"**/*.spec.ts",
"**/*.stories.tsx",
"e2e/**"
]
}
Python에서 자주 제외하는 패턴:
{
"exclude": [
"**/node_modules",
"**/__pycache__",
"**/migrations",
"**/.venv",
"**/dist",
"tests/**",
"scripts/**"
]
}
테스트 파일을 제외할지 여부는 상황에 따라 다르다. Claude Code에게 테스트 작성을 요청할 일이 많다면 테스트 디렉터리는 포함시켜야 한다. 반대로 프로덕션 코드 수정이 주 작업이면 제외하는 편이 토큰을 아낀다.
LSP 기능 선택적 비활성화
언어 서버가 제공하는 기능 중 Claude Code가 실제로 쓰는 것은 일부다. 쓰지 않는 기능을 끄면 서버 부하와 응답 시간이 줄어든다.
{
"lsp": {
"typescript": {
"enabled": true,
"command": "typescript-language-server",
"args": ["--stdio"],
"capabilities": {
"textDocument": {
"completion": { "dynamicRegistration": false },
"formatting": { "dynamicRegistration": false },
"codeAction": { "dynamicRegistration": false }
}
}
}
}
}
코드 포매팅(formatting)이나 코드 액션(codeAction)은 Claude Code가 직접 코드를 생성하므로 언어 서버에 위임할 필요가 없다. definition, references, hover 세 가지가 핵심이고, 나머지는 선택이다.
효과가 큰 순서: (1) LSP 자체를 켜기 (2) exclude 패턴으로 인덱싱 범위 줄이기 (3) 불필요한 LSP 기능 비활성화. 1번만으로도 체감 차이가 크다. 2번과 3번은 대규모 프로젝트에서 의미가 있다.
설정을 마쳤는데 LSP가 동작하지 않는 경우가 있다. 흔한 원인과 해결 방법을 정리한다.
언어 서버가 시작되지 않는 경우
Claude Code 로그에서 LSP 관련 에러를 확인한다. claude --debug 모드로 실행하면 언어 서버의 stdin/stdout 통신 내역이 출력된다.
claude --debug 2>&1 | grep -i lsp
자주 나오는 에러:
spawn typescript-language-server ENOENT— 언어 서버가 PATH에 없다.which typescript-language-server로 경로 확인.Connection to server got closed— 언어 서버가 크래시했다.node_modules가 손상되었거나 메모리 부족일 수 있다.Initialization failed—tsconfig.json이나pyrightconfig.json에 문법 오류가 있다.
tsserver 메모리 문제
대규모 TypeScript 프로젝트에서 tsserver가 메모리를 과도하게 소비하면 OOM으로 죽는다. NODE_OPTIONS 환경변수로 힙 사이즈를 올릴 수 있다.
export NODE_OPTIONS="--max-old-space-size=4096"
근본적으로는 tsconfig.json의 include 범위를 줄이거나, 프로젝트 레퍼런스로 분할하는 게 맞다.
Pyright 가상환경 인식 문제
Pyright가 가상환경의 패키지를 못 찾는 경우가 흔하다. pyrightconfig.json에 venvPath와 venv를 명시한다.
{
"venvPath": ".",
"venv": ".venv"
}
또는 pyproject.toml의 [tool.pyright] 섹션에 넣어도 된다.
[tool.pyright]
venvPath = "."
venv = ".venv"
pythonVersion = "3.12"
Pyright가 이 설정을 읽으면 .venv/lib/python3.12/site-packages에서 패키지 타입 정보를 가져온다. 설정이 없으면 import requests에 빨간 줄이 뜨고, Claude Code도 해당 모듈의 타입 정보를 받지 못한다.
프로젝트 규모별 최적화 전략
모든 프로젝트에 같은 설정을 적용하면 안 된다. 규모에 따라 전략이 달라진다.
소규모 프로젝트 (파일 100개 미만)
LSP를 기본 설정으로 켜면 충분하다. exclude 패턴도 node_modules와 dist 정도만 잡으면 된다. tsserver든 Pyright든 초기화가 1~2초면 끝나고, 메모리도 200~300MB 수준이다.
설정 파일 하나면 된다:
{
"lsp": {
"typescript": {
"enabled": true,
"command": "typescript-language-server",
"args": ["--stdio"]
}
}
}
중규모 프로젝트 (파일 100~1000개)
exclude 패턴을 신경 써야 한다. 테스트 파일, 스토리북, e2e 디렉터리를 상황에 맞게 제외한다. TypeScript의 경우 skipLibCheck: true를 tsconfig.json에 넣으면 node_modules 내 .d.ts 파일 검사를 건너뛰어서 tsserver가 가벼워진다.
{
"compilerOptions": {
"skipLibCheck": true
}
}
대규모 프로젝트 (파일 1000개 이상)
프로젝트 레퍼런스로 분할하는 게 사실상 필수다. 단일 tsserver 인스턴스가 파일 수천 개를 처리하면 초기화에 10초 이상, 메모리 1GB 이상을 쓴다.
Python 대규모 프로젝트에서는 Pyright의 typeCheckingMode를 "off"로 두고, definition과 references 기능만 쓰는 방법도 있다. 타입 체크는 CI에서 하고, Claude Code에서는 네비게이션 기능만 활용하는 전략이다.
graph TD
A[프로젝트 규모 판단] --> B{파일 100개 미만?}
B -->|Yes| C[기본 설정으로 충분]
B -->|No| D{파일 1000개 미만?}
D -->|Yes| E[exclude 패턴 최적화 + skipLibCheck]
D -->|No| F[프로젝트 분할 + 기능 선택적 비활성화]
F --> G[TypeScript: 프로젝트 레퍼런스]
F --> H[Python: typeCheckingMode off + 네비게이션만]
언어 서버 선택 기준과 다음 단계
`.claude/settings.json`은 전역 설정이고, `.claude/settings.local.json`은 프로젝트별 로컬 설정이다. LSP 설정은 프로젝트마다 다를 수 있으므로 `.claude/settings.local.json`에 넣는 편이 관리하기 편하다. 이 파일은 `.gitignore`에 추가해서 개인 설정이 레포에 들어가지 않게 한다.
LSP 설정이 잡히면 다음 단계로 Claude Code의 커스텀 슬래시 커맨드를 만들어볼 만하다. 자주 쓰는 작업 — 타입 에러 일괄 수정, 테스트 파일 생성, 리팩토링 패턴 적용 — 을 커맨드로 등록하면 LSP 정보와 결합해서 더 정확한 결과가 나온다. MCP 서버를 직접 붙여서 외부 API 문서나 DB 스키마를 Claude Code에 제공하는 것도 LSP와 시너지가 크다. 프로젝트의 데이터 모델을 MCP 리소스로 노출하면 Claude Code가 타입 정보와 도메인 정보를 동시에 참조할 수 있다.