LSP(Language Server Protocol)の仕組みと背景

テキストエディタやIDEで「定義ジャンプ」「補完」「リネーム」といった言語機能を使うには、各エディタが言語ごとの解析ロジックを個別に実装する必要がありました。エディタがM種類、プログラミング言語がN種類あるとき、M x N個の実装が必要になる問題、いわゆる「M x N問題」が長年の課題でした。

LSP(Language Server Protocol)は、この問題を解消するためにMicrosoftが2016年に策定したオープンプロトコルです。言語固有の解析処理を「Language Server」として独立したプロセスに切り出し、エディタとの通信をJSON-RPCベースの標準プロトコルで行います。各エディタはLSPクライアントさえ実装すれば、あらゆる言語のLanguage Serverと連携できるようになります。

LSPの仕様は現在バージョン3.17が最新です。このバージョンでは型階層(Type Hierarchy)やInlay Hints、ノートブックドキュメントのサポートなどが追加されました。

出典: Microsoft Language Server Protocol

TypeScript用の主要LSP Server実装

TypeScriptの言語サーバーには複数の選択肢があり、それぞれアーキテクチャや対応エディタが異なります。

typescript-language-server

最も広く利用されているTypeScript用LSPサーバーです。npmパッケージとして配布されており、内部ではTypeScriptのtsserverをバックエンドとして起動し、その機能をLSPプロトコルでラップして提供します。Neovim、Emacs、Vim、Helix、Sublime Textなど、VSCode以外のほぼすべてのエディタで標準的に使われており、GitHubでは5,000以上のプロジェクトで利用されています。

npm install -g typescript-language-server typescript
typescript-language-server --stdio

出典: typescript-language-server GitHub

vtsls

VSCodeに組み込まれたTypeScript拡張機能を、スタンドアロンのLSPサーバーとして切り出したプロジェクトです。VSCode内部のAPIを埋めて最小限のパッチを適用することで実現しており、本家VSCode拡張の更新に追従しやすい設計になっています。補完の速度と正確性に優れ、LazyVimではデフォルトのTypeScript LSPとして採用されています。2026年1月にv0.3.0がリリースされ、現在も活発に開発が続いています。

npm install -g @vtsls/language-server
vtsls --stdio

出典: vtsls GitHub

tsserver(VSCode内蔵)

VSCodeに組み込まれている言語サービスの基盤です。tsserverはLSPではなく独自のプロトコルで通信しており、VSCode専用の仕組みとして動作します。補完、診断、リファクタリングなどのあらゆる機能を網羅しており、VSCodeにおけるTypeScript体験のベースラインとなっています。ただし独自プロトコルのため、他のエディタからは直接利用できません。typescript-language-serverやvtslsは、このtsserverの機能をLSP経由で公開する役割を担っています。

Deno LSP

Deno実行環境に組み込まれたLSPサーバーです。deno lspコマンドで起動でき、DenoプロジェクトにおけるTypeScript/JavaScript開発を支援します。npmベースのNode.jsプロジェクトとDenoプロジェクトが混在する環境では、ファイルパスやプロジェクト設定によるLSPの切り替えが必要になります。

TypeScript 7.0(Corsa)の公式LSPサーバー

TypeScript 7.0(開発コードネーム: Corsa)では、コンパイラ全体がGoで再実装され、LSPネイティブの言語サーバーが公式に提供される予定です。従来のtsserver独自プロトコルが不要になり、あらゆるLSP対応エディタから統一的に利用できるようになります。詳細は後述します。

実装比較表

項目typescript-language-servervtslstsserverDeno LSPTypeScript 7.0 LSP
プロトコルLSPLSP独自LSPLSP
バックエンドtsserverVSCode TS拡張TypeScript本体Deno内蔵Go実装
インストールnpmnpmVSCode同梱Deno同梱開発中
対応エディタNeovim/Emacs/Vim等Neovim/Helix/Zed等VSCode専用LSP対応全般LSP対応全般
補完速度良好高速高速良好非常に高速(見込み)
設定の柔軟性高い高いVSCode設定に依存Deno設定に依存未確定
Vue/Svelte対応プラグイン経由VSCode拡張互換VSCode拡張経由非対応未確定

エディタ別の導入手順

Neovimでの設定

Neovim 0.11以降では、組み込みのLSPクライアント設定が大幅に簡素化されました。nvim-lspconfigプラグインを使うと、数行で設定できます。

typescript-language-serverを使う場合:

-- init.lua
local lspconfig = require('lspconfig')

lspconfig.ts_ls.setup({
  on_attach = function(client, bufnr)
    -- キーバインドの設定
    local opts = { buffer = bufnr }
    vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
    vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
    vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
    vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, opts)
    vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, opts)
  end,
  filetypes = {
    'typescript',
    'typescriptreact',
    'javascript',
    'javascriptreact',
  },
})

vtslsを使う場合:

lspconfig.vtsls.setup({
  on_attach = on_attach,
  settings = {
    typescript = {
      inlayHints = {
        parameterNames = { enabled = 'all' },
        parameterTypes = { enabled = true },
        variableTypes = { enabled = true },
        propertyDeclarationTypes = { enabled = true },
        functionLikeReturnTypes = { enabled = true },
      },
    },
  },
})

LazyVimを使用している場合、lazyvim.plugins.extras.lang.typescriptを有効にするだけでvtslsが自動的に構成されます。

出典: LazyVim TypeScript

VSCodeの内部動作

VSCodeでは、TypeScript/JavaScriptファイルを開くと自動的にtsserverが起動し、言語機能が利用可能になります。ユーザー側で特別な設定は不要です。

TypeScript 7.0のプレビュー版を試すには、VS Code Marketplaceから「TypeScript (Native Preview)」拡張をインストールします。これにより、Goベースの新しい言語サーバーがtsserverに代わって動作し、補完や定義ジャンプ、リネームなどが大幅に高速化されます。

出典: TypeScript Native Previews

Emacsでのセットアップ

Emacsでは、lsp-modeまたはeglotの2つのLSPクライアントから選択できます。

lsp-modeの場合:

;; use-packageを使用
(use-package lsp-mode
  :hook ((typescript-mode . lsp-deferred)
         (tsx-ts-mode . lsp-deferred))
  :commands lsp-deferred)

;; typescript-language-serverがPATHに存在すれば自動検出される

eglot(Emacs 29以降組み込み)の場合:

(add-hook 'typescript-mode-hook 'eglot-ensure)
(add-hook 'tsx-ts-mode-hook 'eglot-ensure)

;; eglotはtypescript-language-serverを自動的に検出して利用する

eglotはEmacs 29からコアに同梱されており、追加パッケージなしでLSPが利用可能です。lsp-modeはより多くのカスタマイズオプションを提供し、UIの統合も豊富です。

出典: Emacs lsp-mode TypeScript

Vimでのセットアップ

Vim(非Neovim)では、vim-lspやcoc.nvimといったプラグインでLSPを利用できます。

vim-lspの場合:

" vim-lsp + vim-lsp-settings を使用
" :LspInstallServer でtypescript-language-serverをインストール

augroup lsp_typescript
  autocmd!
  autocmd User lsp_setup call lsp#register_server({
    \ 'name': 'typescript-language-server',
    \ 'cmd': {server_info->['typescript-language-server', '--stdio']},
    \ 'allowlist': ['typescript', 'typescriptreact', 'javascript'],
    \ })
augroup END

coc.nvimの場合:

// :CocConfig で開く coc-settings.json
{
  "languageserver": {
    "typescript": {
      "command": "typescript-language-server",
      "args": ["--stdio"],
      "filetypes": ["typescript", "typescriptreact", "javascript"],
      "rootPatterns": ["tsconfig.json", "package.json"]
    }
  }
}

coc.nvimはVSCodeの拡張エコシステムとの互換性を持ち、coc-tsserverパッケージをインストールすることでも設定できます。

LSP Serverが提供する主な機能

LSPサーバーは、エディタに対して以下の言語機能を提供します。TypeScript用LSPサーバーはこれらの大半をサポートしています。

補完(textDocument/completion) – 入力中のコード補完候補を提示します。TypeScriptの型情報に基づいて、プロパティ、メソッド、変数名、import文の候補を正確に提示できます。

定義ジャンプ(textDocument/definition) – カーソル位置のシンボルが定義されている場所へ移動します。型定義へのジャンプ(textDocument/typeDefinition)や、実装へのジャンプ(textDocument/implementation)も利用できます。

参照検索(textDocument/references) – シンボルが使用されているすべての箇所を一覧表示します。リファクタリング時に影響範囲を把握するのに有用です。

リネーム(textDocument/rename) – シンボル名を一括変更します。TypeScriptの型情報を利用して、プロジェクト全体にわたる安全なリネームが可能です。

コードアクション(textDocument/codeAction) – 自動修正や提案を提示します。TypeScript固有のアクションとして、未使用のimport削除(source.removeUnused.ts)、不足しているimportの自動追加(source.addMissingImports.ts)、到達不能コードの修正(source.fixAll.ts)などがあります。

Inlay Hints(textDocument/inlayHint) – コード中に推論された型や引数名をインラインで表示します。LSP 3.17で標準化された機能で、TypeScriptでは関数の引数名や戻り値の型を薄い文字で表示できます。

診断(textDocument/publishDiagnostics) – 型エラー、未使用変数、構文エラーなどの問題をリアルタイムに報告します。

TypeScriptでLSP Serverを自作する手順

LSPの仕組みを深く理解するには、簡単なLanguage Serverを自作するのが効果的です。Microsoftのvscode-languageserver-nodeパッケージを使えば、TypeScriptで手軽に実装できます。

プロジェクト初期化

mkdir my-lsp-server && cd my-lsp-server
npm init -y
npm install vscode-languageserver vscode-languageserver-textdocument
npm install -D typescript @types/node
npx tsc --init

ミニマルなサーバー実装

以下は、ファイルを開いたときに簡易的な診断を返すLanguage Serverの実装例です。

// src/server.ts
import {
  createConnection,
  TextDocuments,
  ProposedFeatures,
  InitializeParams,
  InitializeResult,
  TextDocumentSyncKind,
  Diagnostic,
  DiagnosticSeverity,
} from 'vscode-languageserver/node';
import { TextDocument } from 'vscode-languageserver-textdocument';

// 標準入出力でJSON-RPC接続を確立
const connection = createConnection(ProposedFeatures.all);
const documents = new TextDocuments(TextDocument);

connection.onInitialize((params: InitializeParams): InitializeResult => {
  return {
    capabilities: {
      textDocumentSync: TextDocumentSyncKind.Incremental,
      completionProvider: {
        resolveProvider: true,
      },
    },
  };
});

// ドキュメント変更時に診断を実行
documents.onDidChangeContent((change) => {
  validateTextDocument(change.document);
});

async function validateTextDocument(
  textDocument: TextDocument
): Promise<void> {
  const text = textDocument.getText();
  const diagnostics: Diagnostic[] = [];

  // "TODO" を見つけて警告を出す簡易ルール
  const pattern = /\bTODO\b/g;
  let match: RegExpExecArray | null;

  while ((match = pattern.exec(text)) !== null) {
    const diagnostic: Diagnostic = {
      severity: DiagnosticSeverity.Warning,
      range: {
        start: textDocument.positionAt(match.index),
        end: textDocument.positionAt(match.index + match[0].length),
      },
      message: 'TODOコメントが残っています。',
      source: 'my-lsp-server',
    };
    diagnostics.push(diagnostic);
  }

  connection.sendDiagnostics({
    uri: textDocument.uri,
    diagnostics,
  });
}

documents.listen(connection);
connection.listen();

出典: vscode-languageserver-node GitHub

通信の流れ

LSPサーバーとクライアント(エディタ)間の通信は、以下の手順で進行します。

  1. initialize – クライアントがサーバーに接続し、互いの機能(Capabilities)を交換します。
  2. initialized – 初期化完了を通知します。
  3. textDocument/didOpen – ファイルが開かれるとクライアントがドキュメント内容を送信します。
  4. textDocument/publishDiagnostics – サーバーが解析結果の診断情報を返します。
  5. textDocument/completion – ユーザー入力に応じて補完候補をリクエスト/レスポンスします。
  6. shutdown / exit – エディタ終了時にサーバーをクリーンに停止します。

すべてのメッセージはJSON-RPC 2.0形式で、HTTPライクなヘッダ(Content-Length)に続いてJSONボディが送られます。

デバッグ方法

VSCode拡張として開発する場合、launch.jsonに以下の設定を追加してデバッグできます。

{
  "type": "extensionHost",
  "request": "launch",
  "name": "Launch Extension",
  "runtimeExecutable": "${execPath}",
  "args": ["--extensionDevelopmentPath=${workspaceRoot}"]
}

--inspectフラグでNode.jsデバッガーをアタッチし、サーバープロセスのステップ実行も可能です。

出典: VS Code Language Server Extension Guide

TypeScript 7.0(Corsa)がもたらすLSPの転換

TypeScript 7.0(開発コードネーム: Corsa)は、TypeScriptコンパイラ全体をGoで再実装するプロジェクトです。2025年3月にMicrosoftが発表し、2026年前半の安定版リリースを目標としています。

速度の劇的な改善

Goネイティブ実装により、コンパイル速度は従来比で約10倍の高速化が報告されています。プロジェクト規模によっては最大13.5倍(TypeORM、27万行)に達するベンチマーク結果も公開されています。大規模プロジェクトのビルドだけでなく、エディタ上の補完やリネーム、参照検索といった言語サービスの応答速度も劇的に向上します。

出典: A 10x Faster TypeScript

tsserverからLSPネイティブへ

従来のTypeScriptは、tsserverという独自プロトコルのサーバーを介してVSCodeと通信していました。typescript-language-serverやvtslsは、このtsserverをLSPで包むラッパーとして存在していました。

TypeScript 7.0では、LSPネイティブの言語サーバーが直接提供されます。ラッパーを介さずに標準プロトコルで通信するため、オーバーヘッドが削減され、あらゆるLSP対応エディタからシームレスに利用できるようになります。typescript-language-serverプロジェクト自身も、TypeScript 7.0がこのプロジェクトを将来的に置き換えることを想定しています。

Language Service Pluginへの影響

現行のtsserverベースのアーキテクチャでは、Language Service Pluginを通じてVue(Volar)やSvelte(svelte-language-server)などのフレームワーク統合が実現されています。Go実装への移行に伴い、プラグインの仕組みが変更される可能性があります。フレームワーク側の対応状況は今後注視が必要です。

現在の試用方法

VS Code Marketplaceの「TypeScript (Native Preview)」拡張をインストールすると、エディタ上でGoベースの言語サーバーを試せます。MicrosoftはNightlyビルドを日次で更新しており、補完、定義ジャンプ、型定義、ホバー表示など主要な機能でパリティが達成されています。

出典: Progress on TypeScript 7 - December 2025

MCP連携によるAIとの統合

LSPの言語解析機能をAIエージェントに公開する試みも進んでいます。MCP(Model Context Protocol)は、AIモデルが外部ツールと連携するための標準プロトコルです。

typescript-mcp(mizchi作)は、TypeScript LSPの機能をMCPサーバーとして公開するツールです。AIエージェントに対して、Rename、Move File、Go to Definition、Find Referencesといったリファクタリング操作を提供します。

lsp-mcp(jonrad作)は、任意のLSPサーバーをMCPサーバーとしてブリッジする汎用ツールです。TypeScriptに限らず、LSP対応のあらゆる言語サーバーの機能をAIエージェントに公開できます。

これにより、AIがコードの意味を理解した上で安全にリファクタリングを実行できるようになり、単なるテキスト置換とは異なる精度の高い自動修正が可能になります。

出典: typescript-mcp 出典: lsp-mcp

トラブルシューティング

LSPサーバーが起動しない

最も多い原因は、Language Serverのバイナリにパスが通っていないことです。以下の手順で確認できます。

# typescript-language-serverがインストールされているか確認
which typescript-language-server

# バージョン確認
typescript-language-server --version

# TypeScript本体もグローバルにインストールされているか確認
which tsserver

Neovimの場合、:LspInfoコマンドでLSPクライアントの状態を確認できます。cmdで指定したコマンドがPATH上に存在し、root_dirが正しくプロジェクトルートを指しているか確認します。tsconfig.jsonまたはpackage.jsonがプロジェクトルートに存在しないと、LSPサーバーが起動しないことがあります。

DenoプロジェクトとNode.jsプロジェクトの共存

同じエディタでDenoプロジェクトとNode.jsプロジェクトを扱う場合、LSPサーバーの切り替えが必要です。Neovimでは、root_dirの検出ロジックをカスタマイズして対処できます。

-- deno.jsonがあればDeno LSP、なければtypescript-language-serverを使用
lspconfig.denols.setup({
  root_dir = lspconfig.util.root_pattern('deno.json', 'deno.jsonc'),
})

lspconfig.ts_ls.setup({
  root_dir = lspconfig.util.root_pattern('package.json'),
  single_file_support = false, -- deno.jsonがないディレクトリでの誤起動を防止
})

VSCodeの場合は、Deno拡張のdeno.enablePaths設定で有効化するディレクトリを制限する方法が推奨されています。

メモリ使用量への対処

大規模なTypeScriptプロジェクトでは、tsserverのメモリ使用量が数GBに達することがあります。以下の設定で軽減できる場合があります。

  • tsconfig.jsoninclude/excludeで対象ファイルを絞る
  • プロジェクト参照(Project References)で依存関係を分割する
  • typescript-language-serverの場合、--tsserver-max-old-space-sizeオプションでNode.jsのヒープ上限を設定する

TypeScript 7.0のGoネイティブ実装では、メモリ使用量の削減も目標の一つとなっており、この問題の根本的な改善が期待されています。

まとめ

TypeScript向けのLSP Serverは、用途やエディタに応じて選択肢が分かれます。VSCode以外のエディタで広く使うならtypescript-language-server、補完の速度と正確性を重視するならvtsls、Denoプロジェクトならdeno lspが適しています。

2026年前半にリリースが予定されているTypeScript 7.0(Corsa)は、LSPネイティブの言語サーバーを公式に提供する計画であり、ラッパー型のサーバーが不要になる未来が見えてきています。速度もメモリ効率も大幅に改善されるため、エディタでのTypeScript開発体験は大きく変わる見込みです。

現時点では、typescript-language-serverまたはvtslsを導入し、TypeScript 7.0のNative Previewで新しい言語サーバーの動作を試しておくのが、移行に備える最も実践的な方法です。