💰 Calculate Gross-Net Salary→

Type Server Protocol: How Pylance Can Swap Pyright for Pyrefly Behind a JSON-RPC Boundary

· Aloka Technology· 0 views· 7 min read
Type Server Protocol: How Pylance Can Swap Pyright for Pyrefly Behind a JSON-RPC Boundary

Microsoft's Type Server Protocol (TSP) lets Pylance ask an external checker such as Pyrefly for types over JSON-RPC. This article walks through the spec's snapshot model, its limits, and how to evaluate it.

For years, choosing a Python type checker in VS Code also meant choosing a language server. Pylance, the editor layer that provides completions, hover and Copilot context, bundled Pyright as its analysis engine, so using a different checker usually meant running it as a second extension with its own language server. On October 21, 2026, Microsoft announced the Type Server Protocol (TSP), a JSON-RPC interface that lets Pylance keep its editor features while a different engine answers type questions.

The question this article addresses: what exactly crosses that boundary, how does it stay consistent while you type, and when is it worth switching?

Background: one engine, two jobs

A Python language server does two jobs. One is editor intelligence: ranking completions, formatting hover text, managing the selected interpreter. The other is type analysis: inferring what an expression is, resolving imports, reporting errors. Microsoft's announcement says Pylance and Pyright were tightly coupled until now, and describes TSP as an open standard that extends the Language Server Protocol (LSP) so that other checkers can become "first-class backends". The announcement names Pyright (still the default) and Meta's Pyrefly, and does not name other TSP-compatible tools.

Pyrefly support requires Pylance 2026.4.1 or newer and Pyrefly 0.60.0 or newer, per the announcement. The announcement does not say whether the feature is preview or generally available; it only says you can try it in VS Code.

How it works: snapshots over an LSP-shaped connection

The specification (maintained in the pylance-release repository) describes TSP as a JSON-RPC protocol for asking a type server for Python analysis data. It reuses LSP conventions: the same Position and Range shapes, zero-based lines and zero-based UTF-16 character offsets, and URIs as strings. The main connection runs over stdio or Node IPC. Clients normally initialize and synchronize documents with ordinary LSP messages, then send typeServer/* requests on the same connection.

The method list in the spec is short:

MethodPurpose
typeServer/getSupportedProtocolVersionReturns a semver string for compatibility checks
typeServer/getSnapshotReturns the current snapshot number
typeServer/snapshotChangedServer-to-client notification with old and new snapshot
typeServer/getPythonSearchPaths, resolveImportSearch paths for a file; module descriptor to URI
typeServer/getComputedType, getDeclaredType, getExpectedTypeInferred type, explicitly written type, type the context expects

The consistency mechanism is the snapshot: a non-negative integer for a point-in-time view of analysis state. It advances on events that can invalidate results, such as file, configuration or dependency changes, and it must not decrease within a session. The client fetches a snapshot, includes it in each query, and listens for snapshotChanged. A request that carries a stale snapshot fails with error -32802 (ServerCancelled), and the client is expected to fetch a fresh snapshot and retry.

Deep analysis: what the design buys and costs

Type results are tagged JSON objects with a numeric kind, a numeric id and a flags bitfield. Kinds cover built-ins, functions, classes, unions, modules, type variables, overloads, synthesized types and type references. Two details matter for implementers. Type IDs are only meaningful within a single response, and type objects are valid only for the snapshot that produced them. So a client cannot cache a type handle across edits; it must re-query. That keeps servers free to use whatever internal representation they like, at the price of repeated round trips.

The spec also defines an optional multi-connection mode. Both sides must advertise typeServerMultiConnection under experimental in the initialize capabilities. Extra connections are read-only and TSP-only, ipc is the only transport defined, and servers must work correctly without the mode.

The versioning is the main caution. The protocol is in the 0.x line, where minor versions may break compatibility; the history runs from 0.1.0 to 0.4.1, which added multi-connection negotiation, and the page was last aligned with Pylance 2026.4.1. The spec page does not give performance figures. The Pyrefly announcement cites 1.8 million lines per second for the checker, but the text I read gives no hardware or project conditions, and it describes the standalone Pyrefly extension, not the Pylance route, as the lower-overhead path.

Comparison with alternatives

SetupWho does editor intelligenceWho does type analysisNotes
Pylance defaultPylancePyright (bundled)The default; unchanged
Pylance with Pyrefly via TSPPylance (completions, Quick Info, Copilot integration)PyreflyNeeds Pylance 2026.4.1+ and Pyrefly 0.60.0+
Standalone Pyrefly extensionPyrefly language serverPyreflyNo intermediary layer; the Pyrefly post still recommends it for most users
Pyrefly in CINot applicablePyrefly CLIDescribed in the announcement as an excellent choice for CI

The practical difference is where the Copilot-related features live: the announcement says they depend on Pylance, not on the checker, so TSP is the way to keep them while changing engines.

Practical example

Pylance can detect Pyrefly in a virtual environment or through a pyrefly.toml file or a [tool.pyrefly] section in pyproject.toml, and offer to switch. The relevant settings are python.analysis.diagnosticsSource (options: Pylance, Pylance + Pyright, Pylance + Pyrefly) and python.analysis.pyreflyVersion. A pinned configuration might look like this (untested; VS Code settings.json, Pylance 2026.4.1 or newer assumed):

{
  // Select "Pylance + Pyrefly" via Settings UI: Python > Analysis: Diagnostics Source
  "python.analysis.pyreflyVersion": "0.60.0"
}

To see the protocol itself, the spec's connection shape is JSON-RPC 2.0. The following two requests are illustrative, built from the method names above, and not verbatim from the spec; the parameter schemas live in tsp.schema.json:

{"jsonrpc": "2.0", "id": 1, "method": "typeServer/getSupportedProtocolVersion"}
{"jsonrpc": "2.0", "id": 2, "method": "typeServer/getSnapshot"}

A reproducible evaluation does not need invented numbers. Pick one repository you maintain, run the same file edits against each diagnostics source, and record: time from save to updated diagnostics, the number of diagnostics that differ between the two engines, and memory of the language server process. Report the Pylance, Pyright and Pyrefly versions alongside the results.

Limitations and failure modes

  • Pre-1.0 protocol: a minor version bump can break a client or server pairing, so pin Pylance and Pyrefly together.
  • Diagnostic differences: two checkers implement the typing specification independently, so the same code can pass in one and fail in the other. Switching engines is a lint-policy change, not just a speed change.
  • Stale snapshots: a client that ignores -32802 will show results for code that no longer exists.
  • Documentation gaps: neither the announcement nor the Pyrefly post lists which Pylance features are routed through TSP or any known feature gaps.

Engineering recommendations

  • Keep one checker as the CI authority and treat the editor engine as a convenience; run that same checker in CI so editor and pipeline do not disagree silently.
  • Trial Pyrefly through Pylance on a branch, not on the whole team, until the protocol leaves 0.x.
  • If you build tooling, code against the schema files and handle snapshot cancellation from day one.

Conclusion

TSP separates the part of a Python language server that is about the editor from the part that is about types, and the snapshot rule gives that split a clear consistency model. It is early, but it is concrete enough to test. Next step: on one repository, enable Pylance + Pyrefly, diff its diagnostics against Pyright on the same commit, and decide from that diff, not from throughput claims.

Sources

I read the announcement, the TSP spec page and the Pyrefly post; I did not run Pylance, Pyrefly or any TSP message, and the two JSON-RPC lines and the settings snippet are untested illustrations.

Share:

Leave a comment

Explore More

Discover More Articles

Browse Articles
↑Zalo