HN 日本語サマリー

← 一覧へ戻る
プログラミング

Microsoft、Language Server Protocolの拡張であるType Server Protocolを発表

Microsoft Announces Type Server Protocol, Extension of Language Server Protocol (github.com)

76 pointsby adamnemecek21 コメント

要約

Microsoftは、Pythonの型解析データを提供するJSON-RPCベースのプロトコルであるType Server Protocol(TSP)を発表しました。TSPは、ワークスペースの型解析状態を管理し、プロトコルバージョン、スナップショット、Python検索パス、インポート解決、型クエリなどの要求に応答します。このプロトコルは、既存のLanguage Server Protocol(LSP)のデータ形式や規約を利用しており、開発者はより効率的にコード解析ツールを構築できるようになります。

全文翻訳

type-server-protocol.md

Type Server Protocol(TSP)は、型サーバーにPython解析データを問い合わせるためのJSON-RPCプロトコルです。型サーバーは、ワークスペースの型解析状態を維持し、プロトコルバージョン、スナップショット、Python検索パス、インポート解決、および型クエリ(計算された型、宣言された型、期待される型)に対する要求に応答します。

このプロトコルは、PositionやRangeのように有用な場所ではLanguage Server Protocol(LSP)のデータ形状と規約を使用し、LSPと同様にURIを文字列として表現します。TSPメソッドはtypeServer/プレフィックスを使用します。

このフォルダ内のプロトコルアーティファクトが権威ある定義です:

  • typeServerProtocol.ts は、TypeScriptインターフェースと要求型を定義します。
  • tsp.json は、機械可読なプロトコルモデルです。
  • tsp.schema.json は、プロトコルモデルのJSONスキーマです。

バージョン履歴

TSPは、クライアント/サーバーの互換性チェックのためにセマンティックバージョニング文字列を使用します。プロトコルが0.xラインにある間は、マイナーバージョンの変更は破壊的である可能性があります。パッチバージョンの変更は、同じマイナーライン内では後方互換性を保ちます。

バージョン変更内容
0.1.0初期のプロトコルバージョン。
0.2.0要求型とフィールドを追加。
0.3.0より複雑な型形状に変更。
0.4.0Typeユニオンとスタブベースの型ペイロードに変更。
0.4.1マルチコネクションネゴシエーションとtypeServer/connection制御要求を追加。

コネクションモデル

クライアントは型サーバーを起動し、標準入出力(stdio)やNode IPCのようなサーバーがサポートするトランスポートを介して、メインのJSON-RPC接続で通信します。標準入出力を使用する場合、標準出力はJSON-RPCプロトコルメッセージのために予約する必要があります。

型サーバーは、TSP要求に応答するために十分なワークスペースとドキュメントの状態を受け取ることが期待されます。クライアントは通常、この状態のために通常のLSP初期化とドキュメント同期を使用し、その後、同じJSON-RPC接続上でtypeServer/*要求を送信します。

TSPは、オプションの追加の読み取り専用接続もサポートします。元の接続はメイン接続として残り、初期化、ワークスペース状態、ドキュメント同期、状態変更通知、および接続制御を所有します。追加の接続は、初期化中にクライアントとサーバーがサポートを交渉した後にのみ開かれます。

起動シーケンス

典型的なセッションは以下の順序で進行します:

  1. クライアントは型サーバーを起動または接続します。
  2. クライアントとサーバーは、通常LSPのinitializeおよびinitializedメッセージを通じて、共有ワークスペース状態を初期化します。
  3. クライアントはtypeServer/getSupportedProtocolVersionを呼び出し、返されたsemver文字列が期待するプロトコルバージョンと互換性があることを確認します。
  4. クライアントはtypeServer/getSnapshotを呼び出し、最初のスナップショット識別子を取得します。
  5. クライアントは、要求の形状によって必要とされる場合に、現在のスナップショットを含む型クエリ、インポート解決、または検索パス要求を送信します。
  6. サーバーは、以前の型結果が無効になった場合にtypeServer/snapshotChangedを送信します。

マルチコネクションモード

マルチコネクションモードはオプションのパフォーマンス機能です。これにより、クライアントは同じ型サーバーに対して追加のローカルチャネルを開いて読み取り専用TSP要求を行うことができますが、メイン接続は変更可能なワークスペース状態を引き続き所有します。

クライアントは、高ボリュームの型クエリやメインのJSON-RPC接続をブロックすべきでないバックグラウンドワーカーなど、並列読み取り専用作業から利益を得られる場合にのみ、マルチコネクションモードを使用すべきです。サーバーは、単一コネクションモードでも正しく動作する必要があります。プロトコルの正当性のためにマルチコネクションサポートを必須とすべきではありません。

機能ハンドシェイク

マルチコネクションサポートは、通常のLSP initialize 要求および応答を通じてネゴシエートされます。追加のTSPチャネルを開くことができるクライアントは、capabilities.experimental.typeServerMultiConnectionの下にサポートされているトランスポートの種類を広告します:

{
    "capabilities": {
        "experimental": {
            "typeServerMultiConnection": {
                "supportedTransports": ["ipc"]
            }
        }
    }
}

追加のTSPチャネルを提供できるサーバーは、initialize結果で同じ機能形状を返します:

{
    "capabilities": {
        "experimental": {
            "typeServerMultiConnection": {
                "supportedTransports": ["ipc"]
            }
        }
    }
}

マルチコネクションモードは、両方の側がtypeServerMultiConnectionを広告し、2つのsupportedTransportsリストに少なくとも1つのトランスポートが共通している場合にのみ有効になります。どちらかの側が機能を省略した場合、または共通のトランスポートがない場合、セッションは単一コネクションのままで、クライアントはtypeServer/connectionを送信してはなりません。

現在サポートされている追加接続の組み込みトランスポートの種類はipcです。このネゴシエーションは、標準入出力またはNode IPCを使用できるメイン接続とは別です。

追加接続のオープン

初期化とトランスポートのネゴシエーションの後、クライアントはメイン接続上でtypeServer/connectionを送信して追加チャネルを開きます:

{
    "type": "open",
    "kind": "ipc",
    "args": ["<ipc-endpoint>"]
}

ipcの場合、args配列は、サーバーが接続すべきエンドポイントまたはエンドポイントを識別します。サーバーは要求を検証し、提供されたエンドポイントに速やかに接続し、要求を受け入れたときにsuccess: trueの結果を返すべきです。サーバーがチャネルを開けない場合は、success: falseを返し、ログに役立つ場合は短いmessageを含めるべきです。

IPCエンドポイント引数

ipcエンドポイントは、プラットフォームのIPCメカニズムがそれをサポートしている場合、フルデュプレックスJSON-RPCストリームを提供することが期待されます。その場合、argsには1つのエンドポイント文字列が含まれます:

{
    "type": "open",
    "kind": "ipc",
    "args": ["<full-duplex-ipc-endpoint>"]
}

プラットフォームのIPCメカニズムが片方向エンドポイントのみを公開する場合、argsには2つのエンドポイント文字列が含まれます。エンドポイント名は型サーバーの観点からのものです:最初のエンドポイントはサーバー入力ストリーム、2番目のエンドポイントはサーバー出力ストリームです。

{
    "type": "open",
    "kind": "ipc",
    "args": ["<input-ipc-endpoint>", "<output-ipc-endpoint>"]
}
追加接続のクローズ

クライアントは、チャネルを開いたときと同じトランスポートの種類とエンドポイント識別子を使用して、メイン接続上でtypeServer/connectionを送信して追加チャネルを閉じます:

{
    "type": "close",
    "kind": "ipc",
    "args": ["<ipc-endpoint>"]
}

サーバーは、一致する追加チャネルの提供を停止し、トランスポートを速やかに閉じるべきです。クライアントがタイムアウト予算内でサーバーがクローズを完了しない場合、ローカルトランスポートを解除することもできます。

close要求は、チャネルを開いたときと同じargs形状を使用すべきです:フルデュプレックスIPCストリームの場合は1つのエンドポイント、分割IPCストリームの場合は同じ入力/出力エンドポイントペアです。

許可されるトラフィック

メイン接続は、すべての状態変更トラフィックを所有します。以下はメイン接続のみでなければなりません:

  • LSPの初期化およびライフサイクルメッセージ。
  • ワークスペース、構成、ファイルウォッチャー、およびドキュメント同期通知。
  • サーバーからクライアントへのスナップショット通知。
  • typeServer/connection制御要求。

追加接続はTSP専用であり、読み取り専用です。これらは、サーバー状態を変更しない要求や、クライアントが提供したスナップショットに対して有効な結果を持つ要求に使用できます。

追加接続で許可されるTSPメッセージは、ネゴシエートされたTSPバージョンにバインドされます。サーバーがTSPバージョンをサポートすると報告し、そのセッションでマルチコネクションサポートを広告する場合、そのバージョンで定義されているすべての追加接続TSPメッセージをサポートする必要があります。

以下の表は、各メッセージが追加接続で最初に許可されるTSPバージョンを示しています:

TSPバージョン追加接続メッセージ
0.4.1typeServer/getSupportedProtocolVersion
0.4.1typeServer/getSnapshot
0.4.1typeServer/getPythonSearchPaths
0.4.1typeServer/resolveImport
0.4.1typeServer/getComputedType
0.4.1typeServer/getDeclaredType
0.4.1typeServer/getExpectedType

サーバーは、統合するクライアントが必要とするLSPトラフィック、状態変更通知、typeServer/connection、およびネゴシエートされたTSPバージョンで許可されていないTSPメッセージを、追加接続で受信した場合に拒否すべきです。

スナップショット

A snapshot is a non-negative integer that identifies a point-in-time view of the type server's analysis state. Type handles, declarations, symbols, and other returned objects are valid only for the snapshot in which they were returned unless a request explicitly says otherwise.

The type server must advance the snapshot whenever a previously returned type-analysis result may be invalid. Typical invalidating events include opened-file changes, closed files, configuration changes, watched-file changes, dependency changes, or any cache reset that changes analysis results.

Snapshot rules:

  • typeServer/getSnapshot returns the current snapshot identifier.
  • Snapshot identifiers must not decrease during a session.
  • typeServer/snapshotChanged reports the previous and new snapshot identifiers.
  • Requests that include a stale snapshot should fail with a JSON-RPC error that lets the client retry with a fresh snapshot. LSP's ServerCancelled error code (-32802) is the preferred error for this case.

Positions And Ranges

TSP follows LSP position conventions:

  • Lines are zero-based.
  • Character offsets are zero-based UTF-16 code units.
  • Ranges identify source spans using a start position and end position.

If a type server stores source locations in another encoding, it must convert locations at the protocol boundary. Incorrect conversion can cause the client to request information for the wrong syntax node.

Nodes, Declarations, And Handles

The type-query requests (typeServer/getComputedType, typeServer/getDeclaredType, typeServer/getExpectedType) identify a source construct with an arg that is either a node or a declaration. A node is a URI plus a source range. A declaration describes where and how a symbol is defined and is either a regular declaration, which is backed by a source AST node, or a synthesized declaration, which is created by the type checker and has no source node.

InvalidHandle is -1 and represents an invalid or unavailable handle. Clients and servers should treat it as a sentinel value, not as a valid object identifier.

Type Results

Type results are JSON-serializable tagged objects. Each type includes a discriminator that tells the client how to interpret the rest of the object. The protocol supports built-in types, declared types, functions, classes, unions, modules, type variables, overload sets, synthesized types, and type references.

Every type object carries a numeric kind discriminator, a numeric id, and a bitfield of flags:

kindTypeDescription
0BuiltInunknown, any, unbound, ellipsis, never, and similar
1DeclaredBase for source-declared types (rarely used directly)
2FunctionFunctions and methods from def statements
3ClassClasses and their instances
4UnionUnion types (`int
5ModuleModule objects (import os produces a Module type for os)
6TypeVarType variables (T, P, Ts)
7OverloadedFunctions with multiple @overload signatures
8SynthesizedTypes synthesized by the type checker
9TypeReferenceReference to another type by id, used for deduplication and cycles

Type objects are snapshot-bound, and type IDs are response-local:

  • A returned type object is valid only for the snapshot used by the request that produced it.
  • Type IDs are used to connect TypeReference objects to earlier type objects in the same serialized response graph.
  • Type IDs are not a stable global identity for a snapshot and should not be compared across separate responses.
  • Type references should be used to avoid duplicating large or recursive type graphs within one response.

Protocol Surface

The current protocol is intentionally small. The exact parameters and result shapes are defined in the protocol artifacts; the table below lists every TSP message with its direction and payload shape.

MessageDirectionParamsResult
typeServer/getSupportedProtocolVersionclient → servernonestring (semver)
typeServer/getSnapshotclient → servernonenumber
typeServer/snapshotChangedserver → client{ old: number, new: number }notification
typeServer/connectionclient → server`{ type: "open""close", kind, args? }`
typeServer/getPythonSearchPathsclient → server{ fromUri, snapshot }`string[]
typeServer/resolveImportclient → server{ sourceUri, moduleDescriptor, snapshot }`string
typeServer/getComputedTypeclient → server`{ arg: DeclarationNode, snapshot }`
typeServer/getDeclaredTypeclient → server`{ arg: DeclarationNode, snapshot }`
typeServer/getExpectedTypeclient → server`{ arg: DeclarationNode, snapshot }`

A type server should implement the messages required by the client it integrates with and return undefined only where the protocol's result type allows it.

Type Queries

The three type-query requests differ by which type they report for the same node or declaration:

  • typeServer/getComputedType returns the type inferred from code flow. After narrowing a to int, the computed type of b in b = a + 1 is int.
  • typeServer/getDeclaredType returns the type explicitly written in the source. For def foo(a: int | str), the declared type of a is int | str.
  • typeServer/getExpectedType returns the type the surrounding context expects. For the call foo(4), the expected type of the argument is int | str.

Error Handling

Use standard JSON-RPC error responses.

SituationError codeGuidance
Stale snapshot-32802 (ServerCancelled)The client can request a fresh snapshot and retry.
Invalid parameters-32602 (InvalidParams)Required fields are missing or malformed.
Internal failure-32603 (InternalError)The server failed unexpectedly while handling a valid request.

Errors should include enough message detail for a client log to identify the failed request, but they should not expose local secrets or implementation-only state.

Compatibility Checklist

A compatible type server should verify these behaviors:

  1. typeServer/getSupportedProtocolVersion returns a semver string supported by the client.
  2. All request and notification payloads serialize and deserialize according to the protocol artifacts.
  3. typeServer/getSnapshot returns a non-negative snapshot and snapshots do not go backward.
  4. Document, configuration, and watched-file changes invalidate snapshots when they can change returned analysis data.
  5. Requests with stale snapshots fail with a retryable cancellation error.
  6. Position and range conversions use LSP zero-based UTF-16 conventions.
  7. Import-resolution requests return document URIs or no result according to the protocol result type.
  8. Type queries (computed, declared, and expected) return well-formed Type objects, or undefined, for the snapshot supplied by the client.
  9. Multi-connection support is advertised only when the server can serve the negotiated extra transport.
  10. Extra connections accept every TSP request allowed for the negotiated TSP version and reject LSP traffic, state-changing notifications, typeServer/connection, and TSP requests not allowed for that version.

Last content update aligned with Pylance 2026.4.1.