Skip to main content

poly-mcp

The poly MCP server — the fourteen tools and which are read-only vs mutating, the paths/exclude/config/install/format params, component downloads, async Tasks, and the isError contract

소스 정보

저장소
Goldziher/poly
최근 소스 활동
2026년 11월 7일 22:41
감지된 SKILL.md 언어
영어
스타
20
포크
1

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
description
The poly MCP server — the fourteen tools and which are read-only vs mutating, the paths/exclude/config/install/format params, component downloads, async Tasks, and the isError contract
name
poly-mcp
license
MIT
metadata
{"author":"Goldziher","repository":"https://github.com/Goldziher/poly"}
<!-- AI-RULEZ :: GENERATED FILE — DO NOT EDIT Content-Hash: blake3:6c31e1f5ea74423cf0f61265220d539d6333c0b6967a8baa23f3e94d799a91bc Source-Hash: blake3:e7ab877d931980c90f1404cb645dfa2e45d36c8e6ce966690ca12f6407d95f00 Schema-Version: v1 --> # poly MCP `poly mcp` is a stdio MCP server exposing poly's lint/format/cache/rules/config surface as tools. Prefer it over shelling out to the CLI when working through MCP — every tool returns typed `structured_content` (with a declared output schema) plus one text block that mirrors the CLI's `--format json`, or the compact TOON encoding when asked. `poly mcp --config <PATH>` pins a fallback config file for requests that do not name one. ## Tool surface Fourteen tools, no more. Read-only (never touch the tree): - `lint` — run the linters and return diagnostics. Mirrors `poly lint`, per-file tier only (as `--workspace never`); the whole-project phase is the separate `workspace_lint` tool. May download a missing engine component (see "Components" below). - `format_check` — report formatting drift without writing. Mirrors `poly fmt`. May download. - `components` — the downloadable engine components and where each stands (`bundled`, `installed`, `not installed`, `unavailable`). Given `paths`, only the components they need, which are `missing`, and which a run would `would_download`. Never downloads. Mirrors `poly components list` / `status`. - `cache_stats` — result-cache footprint (entries, bytes, format version) per namespace. - `rules` — list every ast-grep rule a run would apply — poly's built-in pack plus the user rules from `[engines.astgrep] rule_dirs` — and optionally run their `*-test.yml` snippets. Mirrors `poly rules list` / `poly rules test`. Each rule carries its language, `source` (`builtin`/`user`), `default_severity`, the `severity` it reports at under the resolved config, and `enabled`. - `config_show` — the merged effective configuration. Mirrors `poly config show`, and is **network-free**: remote `extends` bases are not fetched. - `version` — which poly binary is serving this session (version, build id, channel, executable, pid, uptime), the full compiled-in engine → wrapped-tool-version map, and whether that executable is still the file on disk. It answers even when the binary has moved, which is what makes it the tool that explains why the others stopped. Mutating (write to the tree): - `lint_fix` — apply lint autofixes. Mirrors `poly lint --fix`. May download. - `format_write` — format files in place. Mirrors `poly fmt --fix`. May download. - `cache_clean` — clear the result cache and report freed bytes. - `components_install` — download and verify components by `names` (components or presets), `languages` and/or `paths` (everything those paths need); `dry_run` reports the plan. Writes only the component cache. Mirrors `poly components install`. - `components_uninstall` — remove components by `names`, and with `stale: true` the cached archives nothing references or used recently. Refuses a component loaded in this process (`refused`, and `isError`). Mirrors `poly components uninstall` / `prune`. Whole-project (long-running): - `workspace_lint` — the whole-project phase in check mode: `cargo clippy` / `cargo-sort` / `cargo-machete` / `cargo-deny` and configured inline whole-project jobs, over the whole repository (it takes no `paths`). - `workspace_lint_fix` — the same phase in fix mode; writes files. Both are exposed as async Tasks (SEP-2663): the call returns a task handle and the client polls `tasks/get`, optionally `tasks/cancel`, with an unlimited TTL. A client that does not declare the tasks capability gets a synchronous, blocking result from the same call instead, so the tools work either way. `workspace_lint` applies no fixes, but it is **not** in the never-touch-the-tree group: it executes those tools against the live worktree, and their own side effects — a refreshed lock file, a populated build or type-checker cache — are not poly's to control. ## Components In a core build (every release binary except Linux musl) the engines are downloadable components; the bundled Linux musl build links them in and nothing is ever missing. The result's `components` block (`used`, `installed_now`, `missing`) is present only when a run needed one. A missing component that fails the run sets `isError`; one skipped under `install: "never"` shows in `skipped` and `components.missing` without failing it. Check `components.missing` before reading an empty `results` as clean. `lint`, `format_check`, `lint_fix` and `format_write` are open-world: with `install: "config"` (default, follows `[components] install`) or `"auto"` they download what the run needs before running. `"never"` downloads nothing and skips the files a missing component would have handled. A server started `--offline` never downloads whatever `install` says. `install` governs engine components only; an opt-in recipe tool with `[tools.<name>] install = "auto"` follows its own setting. When the client declared the tasks capability and the run (or `components_install`) would download, the call returns a Task: poll `tasks/get`. Its status message names the components; there is no byte-level progress, and no `notifications/progress`. Otherwise the call blocks and returns the result. There is no `hooks` tool: `poly hooks` is CLI-only. ## Parameters - `lint` / `format_check` / `lint_fix` / `format_write`: `paths` (files or directories; empty means the current directory), `exclude` (gitignore-style globs merged with `[discovery] exclude` — unanchored globs match at any depth), `config` (path to a `poly.toml`), `install` (`"config"` default, `"auto"` or `"never"`), `format` (`"json"` default, or `"toon"`). - `components`: `paths`, `config`, `install` (the policy `would_download` is judged under), `format`. - `components_install`: `names`, `languages`, `paths`, `config`, `dry_run`, `format`. - `components_uninstall`: `names`, `stale`, `format`. - `rules`: `dirs` (empty means `rule_dirs` from the config), `config`, `test` (bool), `format`. - `config_show`: `config`, `format`. - `cache_stats` / `cache_clean` / `version`: `format` only. - `workspace_lint` / `workspace_lint_fix`: `config`, `format`, `jobs`, `no_cache` — no `paths`. `format` selects only the paired **text** block; `structured_content` is always JSON. Treat the read-only tools as safe to call freely; gate the mutating tools behind explicit intent since they change files. ## Every result identifies the binary that answered Each result carries a `poly` block (version, build id, channel, executable, pid, `flavor` — `bundled`, `core` or `partial` — `components_lock` — a digest of the embedded component lock, or null — and an `engines` digest — a blake3 hash over the sorted compiled-in engine name + version pairs, excluding native-toolchain and catalog engines since those depend on the host and on config) in `structured_content` and in `_meta`, because an MCP caller has no `poly --version` to fall back on. The digest is what distinguishes two builds sharing one version number (a `dev` build, or two builds of one tag) when their wrapped crates differ; the full engine map is on the `version` tool. The server fingerprints its own executable at startup and re-checks it per request: if the binary is replaced or deleted underneath a long-lived server, every tool but `version` fails rather than answering with superseded behaviour. ## Per-file outcomes: checked, skipped, error The result object is `{results, errors, skipped, summary, configs}`, not a bare array. `summary` is `{checked, skipped, errored}` — the run's own count of what it did, and the field to gate on. It cannot be derived from `results`: `results` holds only files with something to report, so a file that was checked and found clean produces **no** `results` entry at all — a present entry does not mean checked, either, since `results` also carries a synthetic entry (empty `diagnostics`, `skipped` or `error` set) for every file the run declined or failed on. The skipped/error sets and `results` overlap on purpose: - **Checked** — counted in `summary.checked`. Not derivable from `results`. - **Skipped** (`skipped` field, and the top-level `skipped` array) — poly correctly declined the file (e.g. a template dialect no backend handles). Not a failure. - **Errored** (`error` field, and the top-level `errors` array) — poly failed to process the file (unreadable file, backend crash, bad engine config). Distinct from `skipped` on purpose: a skip is a deliberate decision, an error is poly failing on a file it accepted. The top-level `errors` array duplicates the `error`-carrying records in `results` so a caller can gate on "did the run fail on anything" without scanning every record. When `errors` is non-empty, the tool result's `CallToolResult.is_error` (`isError` over the wire) is set `true`. **An MCP-driving agent must check `isError` (or `summary.errored`) before trusting any other part of the result.** Before this shape existed, a file poly failed to process was absent from the output entirely — indistinguishable from a file that was checked and found clean. An agent that gated on "no findings in `results`" was reading a run that had silently failed to check some files as a clean pass. Check `isError` first; only then read `summary` for coverage and `results` for diagnostics.
GitHub에서 보기