
prinfer
io.github.clockblockerv3.1.0更新於 Oct 9, 2026
TypeScript inferred types, completions and type errors for AI coding agents
概覽
讓 AI 程式助理直接向 TypeScript 編譯器查詢推斷型別、補全項目與型別錯誤,而不是憑猜測。
- 功能
- prinfer 透過工具把 TypeScript 編譯器的結果提供給助理:hover_by_name 與 hover 傳回某個符號或詞彙的推斷型別,batch_hover 一次最多做 100 次查詢,completions 列出游標處的候選項目,diagnostics 回報單一檔案的型別錯誤,annotations 標出多餘或過寬的顯式型別標註。結果同時以可讀文字與帶版本的结构化內容回傳,錯誤附有錯誤碼與復原提示。它也提供 CLI、函式庫,以及用於快照推斷型別的測試輔助函式。
- 適用情境
- 當助理編輯 TypeScript 程式碼、需要真實的推斷型別、補全候選或單一檔案型別錯誤而不是猜測時使用。它也適合在快照測試中固定公開 API 推斷出的型別,以及在審查前清理多餘的型別標註。
- 執行需求
- 以 npx 啟動的本機 stdio 程序(npm 套件 prinfer),需要 Node.js >= 20.0.0。不需要驗證或 API 金鑰。它透過最近的 tsconfig.json 或你傳入的 project 路徑讀取原始碼檔案。選用環境變數 PRINFER_BACKEND 與 PRINFER_INCLUDE_TIMING 可變更預設後端並加入耗時資訊。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 prinfer,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
prinfer
prinfer lets AI coding agents ask the TypeScript compiler what it infers (types, completions, type errors) instead of guessing, through an MCP server, a CLI, or a library.
Type regression tests
prinfer/testing returns an inferred type as a string, so a test can pin it with an ordinary snapshot matcher in Vitest, Jest, Bun, or any compatible runner. Use it to lock the types your public API infers: a refactor that changes one fails the test. The example is test/users.test.ts, next to a src/users.ts that exports groupBy, Role, and User.
Write the matcher empty (toMatchInlineSnapshot()) and the runner fills it in; after an intended type change, update it with the runner's snapshot update (vitest -u, bun test --update-snapshots). Unlike expectTypeOf or tsd, you never write the expected type by hand: the snapshot is the type as the editor displays it, so any change shows up, including a literal union widening to string.
The first argument is the file to inspect: import.meta.url for the test file itself, or new URL("../src/users.ts", import.meta.url) for another module. Plain string paths resolve against process.cwd(), not the test file. The source is read through its nearest tsconfig.json, or project when given.
The second argument picks the target:
{ name, line? }: a declaration by name;linepicks among repeats.{ line, text, occurrence? }: the token wheretextstarts on that line, matched like thehovertool'stext.{ line, column }: a 1-based position.
inferredType and inferredTypeInfo (the full hover result: name, kind, return type, docs) are synchronous and use TypeScript 6 by default. Pass backend: "typescript7" for TypeScript 7 output; the call then returns a promise. Types are untruncated by default, so a change deep inside an object or union fails the snapshot; pass full: false for the editor's shortened form ({ ...; }). include_docs adds JSDoc to inferredTypeInfo.
To pin what a function infers for an argument you have no value for, declare the argument in a fixture file and point the helper at it. A declare const in the test file itself has no runtime value, so the test throws a ReferenceError as soon as it runs.
inferredCompletions uses TypeScript 7 and resolves to every completion name, with no prefix filter or limit, so a snapshot catches any added or removed entry. A text target puts the cursor right after the match, so text: "user." lists members and text: '"' lists string-literal union members; pass cursor: "start" to put it before the match instead.
TypeScript 7 calls share one compiler process per project. It doesn't keep the test process alive, so no teardown is needed; await closeTestingSessions() (e.g. in afterAll) shuts it down early.
Failed lookups throw (or reject) with the fix in the message: an unknown name lists the closest declarations in the file, missing text quotes the line, and a missing relative path explains how to resolve it against the test file.
prinfer/vitest remains as a deprecated alias for prinfer/testing.
Install
Pick your client. Every setup command below runs through npx, so nothing has to be installed first. If you install globally (npm i -g prinfer), drop the npx -y prefix and setup registers the prinfer-mcp binary, which skips npx's package check on every launch.
Claude Code
Install the plugin. It bundles the MCP server and a skill that tells Claude when to use it:
Or register only the MCP server:
Codex
This runs codex mcp add prinfer -- npx -y prinfer mcp. The equivalent ~/.codex/config.toml entry:
Cursor
VS Code
Gemini CLI
Any other MCP client
prinfer is a stdio server. Point your client at npx -y prinfer mcp:
prinfer is also listed in the official MCP Registry as io.github.clockblocker/prinfer, and on Smithery for clients that install from there.
Setup options
--printshows the command or config change without applying it.--npxregistersnpx -y prinfer mcpeven whenprinfer-mcpis installed. Use it when the client can't findprinfer-mcp; editors started outside a shell often miss nvm, fnm, or volta paths.- Re-running setup updates the
prinferentry's command and leaves other servers alone. In JSON configs it keeps keys you added to the entry, such asenv. JSON configs that don't parse are left untouched, and setup prints the entry for you to add by hand. - On Windows, setup registers the server as
cmd /c npx -y prinfer mcp(orcmd /c prinfer-mcp), because MCP clients launch it without a shell and can't run npm's.cmdshims directly.
Tell the agent when to use it
MCP tool descriptions only go so far. Agents still reach for tsc or write annotations by hand. Add a short block to your instructions file:
The block sits between <!-- prinfer:start --> and <!-- prinfer:end --> markers. Re-running updates it in place. The Claude Code plugin ships the same guidance as a skill, so plugin users can skip this.
Tools
Lines and columns are 1-based everywhere. file is absolute or relative to the server's working directory, and project (a tsconfig.json path) defaults to the nearest one above the file. Which TypeScript version answers depends on the tool and the surface; see Backends at a glance.
Hover text is capped at 4000 characters per type. A cut type ends with a line such as … truncated: 187 chars total, union of 4 members. Pass max_chars: N to see more (0 for no limit). max_chars raises the cap or, at 0, removes it. full: true turns off TypeScript's own truncation ({ ...; }, ... 12 more ...) and lists every overload. Structured content is never cut.
hover_by_name
Start here when you know the symbol's name.
When the name is declared more than once, the lookup prefers declarations and says which one it picked:
The structured result lists the others as alternatives: [{ line, column, kind }]. A line that matches none of them fails with SYMBOL_NOT_FOUND, a suggestion naming the declaration lines, and declaredAt holding their positions. Overloaded functions show the first signature, then the rest (up to three in the text; full: true lists all, and overloads in structured content always has every one):
hover
Hover a token on a known line, for things hover_by_name can't name: callback parameters, expressions, repeated names. Pass text copied from the line and prinfer finds the column, so the agent doesn't have to count characters. text matches whole identifiers first: on users.map((user) => user.name), text: "user" skips users and hits the callback parameter, and occurrence: 2 picks the next user. Only when the line has no whole-identifier match is text matched as a plain substring. A column still works in place of text.
Generic calls show their instantiated types, the same as an editor hover. If the text isn't on the line, the error quotes the line so the agent can correct itself:
batch_hover
Up to 100 lookups in one call, across any number of files. Each item is {name, line?}, {line, text, occurrence?}, or {line, column}, with an optional file that overrides the shared top-level file. Each program or document loads once per file.
Failures stay per item, including a missing file, so one bad lookup doesn't throw away the rest. A line or column outside the file is an INVALID_ARGUMENT error that gives the valid range, for hover and batch_hover items alike.
Hover results
Every hover returns the same fields on every backend and surface:
signatureis the type text alone, on one line, without the declaration keyword or name an editor hover starts with:string[]for a variable,(value: string): numberfor a function, the instantiated signature for a call. Type aliases keep their name and type parameters (type Event = { kind: "open"; ... } | ...), and interfaces and classes are their name (Box<T>). Optional parameters and properties read astscwrites them in declarations:digits?: number, with| undefinedonly where the source wrote it or the type is not the annotation's (an instantiated generic, aPartial<T>).displayis the editor's hover text (const names: string[], object types over several lines). Only the TypeScript 7 language server reports it.kindis the editor's label:function,method,const,let,var,parameter,property,type,interface,class,enum, and so on, pluscallfor the callee of a call.overloads,unionMembers(members of a union type), andalternativesappear when they apply.
completions
The entries TypeScript offers at a cursor, including string-literal union members. The cursor sits before the character at column. For a string union, put it just inside the opening quote.
Entries come in TypeScript's ranking: locals, members, and literal values first, then globals, with keywords after other entries of the same rank, then auto-imports. At most limit entries are returned (default 50, up to 500). When more match, the text ends with a line such as … 947 more; pass prefix to narrow, or raise limit, and the structured result has total (all matches) and truncated: true.
prefix keeps names that start with it, ignoring case. Without prefix, the text already typed left of the cursor filters the list, as in an editor: with the cursor after use in useSt, only names starting with use come back, and inside "co" only literals starting with co. Pass prefix: "" to turn that off.
At a key of an object literal that accepts any key, such as a Record<string, number>, TypeScript would offer every global name. prinfer returns no entries and a note instead:
completions always runs on TypeScript 6 and takes no backend argument.
diagnostics
Type errors for one file, without type-checking the whole project. Run it on each file you edited; the edit is done when none reports an error.
A clean file returns No type errors.. Errors and warnings are reported by default. include_suggestions adds suggestion diagnostics such as TS6133 (declared but never read).
annotations
Explicit type annotations in one file that TypeScript would infer anyway. Use it when cleaning up types, or to check a file before review.
A redundant annotation can be deleted without changing the type. A widening one is wider than what TypeScript infers, which is often deliberate (a variable that must accept any Drink later, or an exported API contract), so treat it as a question rather than a fix. Only annotations with an initializer or body to infer from are checked. Each structured finding has the range of the : Type text to delete, declared, inferred, exported, and a one-line suggestion. annotations always runs on TypeScript 6.
Backends and environment
Backends at a glance
typescript7runs the native TypeScript 7 language server (the testing helpers use its standalone compiler API). One warm session per project is shared across requests, and its output is closest to what your editor shows.typescript6uses the TypeScript 6 compiler API in-process. If a lookup fails or looks wrong on TypeScript 7, retry that call withtypescript6.
The TypeScript 7 backend is experimental: TypeScript 7.0's programmatic API and hover format may still change. Both backends pick the same symbol for hover_by_name, report the position of its name token, and count lines the way TypeScript does (CR, LF, CRLF, U+2028, and U+2029 end a line; a leading BOM is ignored). Known differences:
signaturehas the same shape on both (see Hover results). Only the language server reportsdisplay.- On TypeScript 7, a
projectthe language server wouldn't pick itself (it uses the tsconfig.json nearest the file, or a project that one references), such as an unreferencedtsconfig.test.json, is opened next to its own projects in the same session. Hovers and type errors in it come from the TypeScript 7 checker API, the way the testing helpers read types, so they carry nodisplay. That tsconfig must include the file, throughinclude,files, or an import; otherwise the call fails withINVALID_ARGUMENT. TypeScript 6 adds the file to any project, so usetypescript6for it. - On TypeScript 7, edits to files reached by relative imports are seen immediately.
diagnosticsalso rescans the tsconfig's include directories (bounded, skippingnode_modules, build output, and dot-directories); any other unopened edit reaches the language server through its file watcher shortly after.
Environment variables on the server process:
Timing appears as Type resolution: 82.06 ms in text and timing: { resolution_ms } in structured content. It covers only the type lookup itself: the in-process checker call on TypeScript 6, the language-server hover exchange on TypeScript 7. Startup, project loading, file reads, and name or text resolution are excluded. In batch_hover each successful item gets its own timing.
Error contract
Every tool returns readable text plus versioned structured content. Successes are { version: 1, ok: true, result }. A failure's text gives the code, the message, and the recovery hints, because many MCP clients show the model only the text:
Its structured content looks like this:
The error codes are INVALID_ARGUMENT, FILE_NOT_FOUND, SYMBOL_NOT_FOUND, TYPESCRIPT_ERROR, and INTERNAL_ERROR. For SYMBOL_NOT_FOUND, candidates lists identifiers from the file that are close to the requested name (keywords and words in comments or strings are skipped), or the identifiers near the requested line; the text shows them as Did you mean: …? for a name lookup and Nearby identifiers: … otherwise. When a name lookup's line misses, declaredAt lists where the name is declared. suggestion is specific to the tool or CLI command that failed. The CLI's --json output and the exported zod schemas (hoverSuccessSchema, diagnosticsSuccessSchema, contractErrorResponseSchema, and the rest) use the same contract.
Each tool's outputSchema describes both outcomes in one envelope (version, ok, and result or error), because MCP clients may validate error results against it too. It lists the error fields an agent recovers with (code, message, candidates, suggestion); the others are still sent.
CLI
The CLI uses TypeScript 6 by default. Pass --backend typescript7 to look up types or run check on the TypeScript 7 language server instead; complete and annotations always use TypeScript 6.
In <file>:<line>:<text>, everything after the line is the text, colons and dots included; whole identifiers match first, as in the hover tool. All-digit text reads as a column, so pass it with --text. A name with a line hint on a line that uses the name, such as prinfer src/box.ts:value:4 where line 4 reads box.value.toUpperCase(), gives the type there, narrowed by the code around it.
Value options take --opt value or --opt=value. An unknown option, or one the command doesn't take, is an error. Single-quote any argument with a $: shells expand $store, and zsh reads $F:r in "$F:root" as a modifier.
Failures print the error, Did you mean: …? candidates, and a suggestion on stderr, and exit 1.
prinfer annotations exits 0 whatever it finds, and 1 only when the check itself fails.
prinfer check exits 0 when the file has no type errors (warnings and suggestions don't count) and 1 when it has errors, so scripts and agents can branch on the exit code alone.
JSON output
--json prints the versioned contract on stdout and nothing on stderr. Type lookups, complete, check, and annotations all support it, and it is never capped:
Failures print {"version":1,"ok":false,"error":{...}}, with the same project and candidates fields as the MCP server, and exit 1. check also exits 1 when it succeeds but finds errors; check ok to tell a failed run from a file with type errors.
Other commands
prinfer mcpstarts the MCP server on stdio, the same as theprinfer-mcpbinary.npx -y prinfer mcpworks without a global install.prinfer setup <codex|claude|cursor|vscode|gemini> [--scope <scope>] [--npx] [--print]registers the server with a client (see Install).prinfer setup agents-md [--file <path>] [--print]adds the usage block to an instructions file.
Run prinfer --help or prinfer setup --help for the full option list.
Programmatic API
The library API is synchronous and uses the TypeScript 6 backend.
Unlike the MCP server, the library throws on failure (batchHover reports bad positions per item and throws only when the file can't be loaded). Pass a caught error to contractError(error) to get the contract shape.
Requirements
- Node.js >= 20.0.0
prinfer bundles its own TypeScript 6 and TypeScript 7 as internal dependencies, so your project's typescript version doesn't matter and doesn't need aliasing or downgrading.
Development
The repository type-checks with TypeScript 7 (bun run typecheck). The TypeScript 6 package also does declaration bundling. Backends at a glance lists which surface uses which compiler.
Releases go through changesets (bun run changeset). bun run version also copies the version into server.json and the Claude Code plugin manifest.
License
MIT
來源:README.md,提交 1cb5b50
工具
0版本歷史
1- v3.1.0最新Oct 9, 2026


