The Type Server Protocol (TSP) is a JSON-RPC protocol for asking a category server for Python inspection data. A category server maintains the type-analysis province for a workspace and answers requests for the protocol version, snapshots, Python hunt paths, import resolution, and category queries (computed, declared, and expected types).
The protocol uses Language Server Protocol (LSP) data shapes and conventions anywhere they are useful, specified as Position and Range, and it represents URIs as strings the identical way LSP does. TSP methods use the typeServer/ prefix.
The protocol artifacts in this directory are the authoritative definitions:
- typeServerProtocol.ts defines the TypeScript interfaces and petition types.
- tsp.json is the machine-readable protocol model.
- tsp.schema.json is the JSON schema for the protocol model.
TSP uses semantic type strings for client/server compatibility checks. While the protocol is in the 0.x line, insignificant type changes may be breaking. Patch type changes remain backward compatible inside the identical insignificant line.
| Version | Changes |
|---|---|
| 0.1.0 | Initial protocol version. |
| 0.2.0 | Added petition types and fields. |
| 0.3.0 | Switched to additional complex category shapes. |
| 0.4.0 | Switched to the Type union and stub-based category payloads. |
| 0.4.1 | Added multi-connection negotiation and the typeServer/connection authority request. |
A client starts a category server and communicates alongside it complete the chief JSON-RPC association using a transport the server supports, specified as stdio or Node IPC. When using stdio, stdout must be reserved for JSON-RPC protocol messages.
A category server is expected to obtain adequate workspace and document province to answer the TSP requests it supports. Clients commonly use normal LSP initialization and document synchronization for this state, afterward dispatch typeServer/* requests on the identical JSON-RPC connection.
TSP additionally supports optional additional read-only connections. The first association remains the chief association and owns initialization, workspace state, document synchronization, state-changing notifications, and association control. Extra connections are opened lone following client and server negotiate assistance during initialization.
A representative meeting follows this order:
- The client starts or connects to the category server.
- The client and server initialize any shared workspace state, commonly through the LSP initialize and initialized messages.
- The client calls typeServer/getSupportedProtocolVersion and verifies that the returned semver cord is compatible alongside the protocol type it expects.
- The client calls typeServer/getSnapshot to get the archetypal snapshot identifier.
- The client sends type-query, import-resolution, or search-path requests that contain the current snapshot whenever required by the petition shape.
- The server sends typeServer/snapshotChanged whenever previous category results are no longer valid.
Multi-connection manner is an optional achievement feature. It lets a client open additional local channels to the identical category server for read-only TSP requests, during the chief association continues to own the mutable workspace state.
Clients should use multi-connection manner lone whenever they can advantage from concurrent read-only work, specified as high-volume category queries or backdrop workers that should not obstacle the chief JSON-RPC connection. A server must motionless activity correctly in single-connection mode. Multi-connection assistance must not be required for protocol correctness.
Multi-connection assistance is negotiated through the normal LSP initialize petition and response. A client that can open additional TSP channels advertises the supported transport kinds under capabilities.experimental.typeServerMultiConnection:
{ "capabilities": { "experimental": { "typeServerMultiConnection": { "supportedTransports": ["ipc"] } } } }A server that can assist additional TSP channels returns the identical capability form in the initialize result:
{ "capabilities": { "experimental": { "typeServerMultiConnection": { "supportedTransports": ["ipc"] } } } }Multi-connection manner is enabled lone whenever the two sides advertise typeServerMultiConnection and the two supportedTransports lists have at smallest one transport in common. If either flank omits the capability, or if there is no average transport, the meeting remains single-connection and the client must not dispatch typeServer/connection.
The currently supported built-in transport benevolent for additional connections is ipc. This negotiation is distinct from the chief connection, which can use stdio or Node IPC.
After initialization and transport negotiation, the client opens an additional conduit by sending typeServer/connection on the chief connection:
{ "type": "open", "kind": "ipc", "args": ["<ipc-endpoint>"] }For ipc, the args gathering identifies the endpoint or endpoints that the server should nexus to. The server should validate the request, nexus to the supplied endpoint promptly, and come back a outcome alongside success: true whenever it accepts the request. If the server cannot open the channel, it should come back success: false and contain a abbreviated communication whenever helpful for logs.
An ipc endpoint is expected to provision a full-duplex JSON-RPC stream whenever the phase IPC scheme supports it. In that case, args contains one endpoint string:
{ "type": "open", "kind": "ipc", "args": ["<full-duplex-ipc-endpoint>"] }If the phase IPC scheme exposes lone one-way endpoints, args contains two endpoint strings. The endpoint names are from the category server's perspective: the archetypal endpoint is the server input stream, and the second endpoint is the server output stream.
{ "type": "open", "kind": "ipc", "args": ["<input-ipc-endpoint>", "<output-ipc-endpoint>"] }The client closes an additional conduit by sending typeServer/connection on the chief association alongside the identical transport benevolent and endpoint identity:
{ "type": "close", "kind": "ipc", "args": ["<ipc-endpoint>"] }The server should halt serving the matching additional conduit and near the transport promptly. A client may additionally tear downward its local transport if the server does not complete the near inside the client's timeout budget.
The near petition should use the identical args form that opened the channel: one endpoint for a full-duplex IPC stream, or the identical input/output endpoint brace for a divided IPC stream.
The chief association owns all state-changing traffic. The following must remain main-connection-only:
- LSP initialization and lifecycle messages.
- Workspace, configuration, file-watcher, and document synchronization notifications.
- Server-to-client snapshot notifications.
- The typeServer/connection authority request.
Extra connections are TSP-only and read-only. They may be used for requests that do not mutate server province and whose results are valid for the snapshot supplied by the client.
The allowed TSP messages on an additional association are border to the negotiated TSP version. If a server reports assistance for a TSP type and advertises multi-connection assistance for that session, it must assistance all extra-connection TSP communication defined for that version.
The array below lists the TSP type that archetypal allows all communication on an additional connection:
| TSP version | Extra-connection message |
|---|---|
| 0.4.1 | typeServer/getSupportedProtocolVersion |
| 0.4.1 | typeServer/getSnapshot |
| 0.4.1 | typeServer/getPythonSearchPaths |
| 0.4.1 | typeServer/resolveImport |
| 0.4.1 | typeServer/getComputedType |
| 0.4.1 | typeServer/getDeclaredType |
| 0.4.1 | typeServer/getExpectedType |
Servers should refuse LSP traffic, state-changing notifications, typeServer/connection, and any TSP communication not allowed for the negotiated TSP type whenever received on an additional connection.
A snapshot is a non-negative entire figure that identifies a point-in-time perspective of the category server's inspection state. Type handles, declarations, symbols, and another returned objects are valid lone for the snapshot in which they were returned unless a petition explicitly says otherwise.
The category server must advancement the snapshot whenever a earlier returned type-analysis outcome may be invalid. Typical invalidating events contain opened-file changes, closed files, configuration changes, watched-file changes, dependency changes, or any cache reset that changes inspection results.
Snapshot rules:
- typeServer/getSnapshot returns the current snapshot identifier.
- Snapshot identifiers must not decrease during a session.
- typeServer/snapshotChanged reports the former and new snapshot identifiers.
- Requests that contain a old snapshot should neglect alongside a JSON-RPC error that lets the client retry alongside a caller snapshot. LSP's ServerCancelled error code (-32802) is the preferred error for this case.
TSP follows LSP stance conventions:
- Lines are zero-based.
- Character offsets are zero-based UTF-16 code units.
- Ranges acknowledge origin spans using a commencement stance and end position.
If a category server stores origin locations in another encoding, it must change locations at the protocol boundary. Incorrect conversion can logic the client to petition data for the incorrect syntax node.
The type-query requests (typeServer/getComputedType, typeServer/getDeclaredType, typeServer/getExpectedType) acknowledge a origin build alongside an arg that is either a node or a declaration. A node is a URI affirmative a origin range. A declaration describes anywhere and how a sign is defined and is either a regular declaration, which is backed by a origin AST node, or a synthesized declaration, which is created by the category checker and has no origin 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 entity identifier.
Type results are JSON-serializable tagged objects. Each category includes a discriminator that tells the client how to construe the remainder of the object. The protocol supports built-in types, declared types, functions, classes, unions, modules, category variables, overload sets, synthesized types, and category references.
Every category entity carries a numeric benevolent discriminator, a numeric id, and a bitfield of flags:
| kind | Type | Description |
|---|---|---|
| 0 | BuiltIn | unknown, any, unbound, ellipsis, never, and similar |
| 1 | Declared | Base for source-declared types (rarely used directly) |
| 2 | Function | Functions and methods from def statements |
| 3 | Class | Classes and their instances |
| 4 | Union | Union types (int | str | None) |
| 5 | Module | Module objects (import os produces a Module category for os) |
| 6 | TypeVar | Type variables (T, P, Ts) |
| 7 | Overloaded | Functions alongside multiple @overload signatures |
| 8 | Synthesized | Types synthesized by the category checker |
| 9 | TypeReference | Reference to another category by id, used for deduplication and cycles |
Type objects are snapshot-bound, and category IDs are response-local:
- A returned category entity is valid lone for the snapshot used by the petition that produced it.
- Type IDs are used to nexus TypeReference objects to before category objects in the identical serialized reply graph.
- Type IDs are not a stable earth character for a snapshot and should not be compared throughout distinct responses.
- Type references have to be used to evade duplicating ample or recursive category graphs inside one response.
The current protocol is intentionally small. The exact parameters and outcome shapes are defined in the protocol artifacts; the array below lists all TSP communication alongside its direction and payload shape.
| Message | Direction | Params | Result |
|---|---|---|---|
| typeServer/getSupportedProtocolVersion | client → server | none | string (semver) |
| typeServer/getSnapshot | client → server | none | number |
| typeServer/snapshotChanged | server → client | { old: number, new: figure } | notification |
| typeServer/connection | client → server | { type: "open" | "close", kind, args? } | { success, message? } |
| typeServer/getPythonSearchPaths | client → server | { fromUri, snapshot } | string[] | undefined |
| typeServer/resolveImport | client → server | { sourceUri, moduleDescriptor, snapshot } | string | undefined |
| typeServer/getComputedType | client → server | { arg: Declaration | Node, snapshot } | Type | undefined |
| typeServer/getDeclaredType | client → server | { arg: Declaration | Node, snapshot } | Type | undefined |
| typeServer/getExpectedType | client → server | { arg: Declaration | Node, snapshot } | Type | undefined |
A category server should execute the messages required by the client it integrates alongside and come back undefined lone anywhere the protocol's outcome category allows it.
The three type-query requests differ by which category they study for the identical node or declaration:
- typeServer/getComputedType returns the category inferred from code flow. After narrowing a to int, the computed category of b in b = a + 1 is int.
- typeServer/getDeclaredType returns the category explicitly written in the source. For def foo(a: int | str), the declared category of a is int | str.
- typeServer/getExpectedType returns the category the surrounding environment expects. For the call foo(4), the expected category of the disagreement is int | str.
Use norm JSON-RPC error responses.
| Situation | Error code | Guidance |
|---|---|---|
| Stale snapshot | -32802 (ServerCancelled) | The client can petition a caller snapshot and retry. |
| Invalid parameters | -32602 (InvalidParams) | Required sectors are missing or malformed. |
| Internal failure | -32603 (InternalError) | The server unsuccessful unexpectedly during handling a valid request. |
Errors should contain adequate communication item for a client log to acknowledge the unsuccessful request, but they should not disclose local secrets or implementation-only state.
A compatible category server should verify these behaviors:
- typeServer/getSupportedProtocolVersion returns a semver cord supported by the client.
- All petition and notification payloads serialize and deserialize according to the protocol artifacts.
- typeServer/getSnapshot returns a non-negative snapshot and snapshots do not go backward.
- Document, configuration, and watched-file changes invalidate snapshots whenever they can alter returned inspection data.
- Requests alongside old snapshots neglect alongside a retryable cancellation error.
- Position and range conversions use LSP zero-based UTF-16 conventions.
- Import-resolution requests come back document URIs or no outcome according to the protocol outcome type.
- Type queries (computed, declared, and expected) come back well-formed Type objects, or undefined, for the snapshot supplied by the client.
- Multi-connection assistance is advertised lone whenever the server can assist the negotiated additional transport.
- Extra connections obtain all TSP petition allowed for the negotiated TSP type and refuse LSP traffic, state-changing notifications, typeServer/connection, and TSP requests not allowed for that version.
Last satisfied update aligned alongside Pylance 2026.4.1.