{
  "markdown": "# grok-build-mcp-server\n\n[![npm](https://img.shields.io/npm/v/grok-build-mcp-server?style=flat-square)](https://www.npmjs.com/package/grok-build-mcp-server)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.Nuruvala%2Fgrok--build--mcp--server-6E56CF?style=flat-square)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.Nuruvala/grok-build-mcp-server)\n[![CI](https://img.shields.io/github/actions/workflow/status/Nuruvala/grok-build-to-claude/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/Nuruvala/grok-build-to-claude/actions/workflows/ci.yml)\n[![Node](https://img.shields.io/node/v/grok-build-mcp-server?style=flat-square)](https://nodejs.org)\n[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE)\n\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=grok-build&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22grok-build-mcp-server%22%5D%7D)\n[![Install in Cursor](https://img.shields.io/badge/Cursor-Install_server-1c1c1c?style=flat-square)](https://cursor.com/install-mcp?name=grok-build&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImdyb2stYnVpbGQtbWNwLXNlcnZlciJdfQ%3D%3D)\n\nAn [MCP](https://modelcontextprotocol.io) stdio server that exposes the [Grok Build](https://x.ai)\nCLI (`grok`) as tools you can call from Claude Code, Cursor, VS Code, or any other MCP client.\n\n```\nClaude Code  ──stdio/MCP──▶  grok-build-mcp-server  ──spawn──▶  grok CLI  ──▶  xAI API\n```\n\nIt is a thin process wrapper. It does not reimplement agent logic and does not talk to the xAI API\ndirectly — all the intelligence stays in the `grok` CLI. What this server adds is faithful argument\nconstruction, robust process supervision, and clean MCP-shaped output.\n\n> **Status: 0.2.2.** The tool surface is complete. The server runs real headless Grok agents in the\n> foreground or detached in the background, streams progress while they run, stops a run on request,\n> reviews git diffs, researches questions on the web, lists the sessions those runs created, and\n> reports session, usage, and cost. See [CHANGELOG.md](CHANGELOG.md) for what shipped and\n> [ROADMAP.md](ROADMAP.md) for what was considered and rejected.\n\n## Progress\n\nA long agent run is visible while it happens, rather than a silent wait ending in a wall of text.\nWhen your client sends a `progressToken`, the server runs Grok with `--output-format streaming-json`\nand forwards a notification per event:\n\n```\n#5  list_dir .\n#6  read_file README.md\n#7  read_file — completed\n#8  thinking: the user asked me to list files, read README.md, then …\n#10 writing: DONE\n#11 finished: end_turn (2 turns)\n```\n\nProgress tracks what the agent is doing, not what phase it is in. Reasoning and response text are\ncoalesced so a token stream does not flood your client, while tool calls are reported as they\nhappen. Clients that support `resetTimeoutOnProgress` will not time out mid-run.\n\nA client that sends no `progressToken` gets the cheaper non-streaming path and pays nothing for\nthis.\n\n## Requirements\n\n- [Grok Build CLI](https://x.ai) 1.0.0 or newer, authenticated (`grok models` should succeed)\n- Node.js 22 or newer\n\nIf `grok` is not on your `PATH`, set `GROK_BINARY` to its full path when you register the server.\n\n## Install\n\n### Claude Code\n\n```bash\nclaude mcp add grok-build -s user -- npx -y grok-build-mcp-server\n```\n\n`-s user` registers the server for your whole account rather than for the directory you happen to be\nin. Without it the scope is that one project, which is rarely what you want for a general coding\nassistant, and the symptom is a server that is missing the next time you start Claude Code somewhere\nelse.\n\nThen, in Claude Code:\n\n```\n> use the grok-build check tool\n```\n\n`check` reports the resolved binary, the CLI version, whether you are authenticated, and the active\npermission ceiling. If it is happy, the rest will work.\n\n### Any other MCP client\n\nThe server speaks MCP over stdio and takes no arguments of its own:\n\n```json\n{\n  \"mcpServers\": {\n    \"grok-build\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"grok-build-mcp-server\"]\n    }\n  }\n}\n```\n\nVS Code and Cursor accept the install badges at the top of this page, which carry exactly that\nconfiguration.\n\nClients that install from the [MCP Registry](https://registry.modelcontextprotocol.io) know this\nserver as `io.github.Nuruvala/grok-build-mcp-server`. The registry entry is published from the same\ntag as the npm release and points at the same package.\n\n### If `npx` cannot find the server\n\n`npx` resolves a bare package name against the _local_ project first. If your MCP client's working\ndirectory is a checkout of this repository — or of anything else whose `package.json` is named\n`grok-build-mcp-server` — `npx -y grok-build-mcp-server` runs the local entry point, does not find\none, and fails with `command not found`. Install it somewhere of its own and register that path:\n\n```bash\nnpm install --prefix ~/.local/share/grok-build-mcp grok-build-mcp-server\nclaude mcp add grok-build -s user -- ~/.local/share/grok-build-mcp/node_modules/.bin/grok-build-mcp-server\n```\n\n## Permissions\n\nGrok runs launched through this server are **read-only by default**: `--permission-mode plan` with\n`--sandbox read-only`. Nothing can modify your files until you say so.\n\nPermission is a **ceiling**, set once when you register the server, rather than a prompt on every\ncall. Three levels:\n\n| Level                 | `--permission-mode` | `--sandbox` | What it allows                     |\n| --------------------- | ------------------- | ----------- | ---------------------------------- |\n| `read-only` (default) | `plan`              | `read-only` | Reading and reasoning. No edits    |\n| `write`               | `auto`              | `workspace` | Edits inside the working directory |\n| `full`                | `bypassPermissions` | `off`       | Unattended full approval           |\n\nThe sandbox is not advisory, and a refusal is not a warning. Under `write` the run **cannot write\noutside `cwd`**, and a refused tool call ends the **whole run**: the CLI reports\n`stopReason: cancelled`, exits 0, and returns only whatever the model had said before the refusal.\nThe server names the refused call and its path in that case, so a refused tool is not mistaken for a\nmodel that gave up. The server can see which call failed, not why the CLI refused it. If a run must\nwrite somewhere else, say a report outside the repository, either point it at a path inside `cwd` or\nuse `full`.\n\n`write` uses `--permission-mode auto` rather than `acceptEdits`, which is measured rather than\ninherited from the flag's name. Headless grok has no human to accept an edit, so under\n`acceptEdits`, `dontAsk` and `default` every file mutation is refused and the run dies, on both\nsandbox profiles. `auto` and `bypassPermissions` both work; `auto` is the narrower one, and it still\nrefuses a write outside the workspace, so `full` remains a real step up rather than a synonym.\n\nTo let Grok make edits:\n\n```bash\nclaude mcp add grok-build -s user \\\n  -e GROK_MCP_PERMISSION_CEILING=write \\\n  -e GROK_MCP_DEFAULT_PERMISSION=write \\\n  -- npx -y grok-build-mcp-server\n```\n\nUse `full` only if you already run your MCP client with full approval and want the delegated Grok\nrun to be equally unattended. It grants the spawned `grok` process the same authority you have.\n\nA call that requests more than the ceiling is **rejected, not silently downgraded** — a clamped run\nwould report success while changing nothing, which is worse than a clear error.\n\n## Environment variables\n\n| Variable                       | Default                    | Purpose                                                          |\n| ------------------------------ | -------------------------- | ---------------------------------------------------------------- |\n| `GROK_BINARY`                  | `grok`                     | Path to the `grok` executable                                    |\n| `GROK_MCP_PERMISSION_CEILING`  | `read-only`                | Highest level any call may request                               |\n| `GROK_MCP_DEFAULT_PERMISSION`  | `read-only`                | Level used when a call requests none                             |\n| `GROK_MCP_DEFAULT_MODEL`       | `grok-4.6`                 | Model when a call omits one. `none` defers to the CLI            |\n| `GROK_MCP_DEFAULT_EFFORT`      | `high`                     | Reasoning effort when a call omits one. `none` defers to the CLI |\n| `GROK_MCP_TIMEOUT_MS`          | `1800000`                  | Wall clock for a single run                                      |\n| `GROK_MCP_STATE_DIR`           | `$XDG_STATE_HOME/grok-mcp` | Background job records                                           |\n| `GROK_MCP_MAX_CONCURRENT_RUNS` | `4`                        | Background runs alive at once. `off` for no cap                  |\n| `GROK_MCP_LOG_LEVEL`           | `info`                     | `debug`, `info`, `warn`, `error`. Logs go to stderr              |\n| `STRUCTURED_CONTENT_ENABLED`   | off                        | Also emit `structuredContent` alongside `_meta`                  |\n\nGrok's own variables (`XAI_API_KEY`, `GROK_HOME`, `GROK_DISABLE_AUTOUPDATER`) pass through to the\nchild process untouched.\n\n## Tools\n\n| Tool        | Read-only  | Purpose                                                                                         |\n| ----------- | ---------- | ----------------------------------------------------------------------------------------------- |\n| `grok`      | by ceiling | Run a headless Grok agent. Prompt, session resume/continue/fork, model, effort, tool allow/deny |\n| `review`    | always     | Review a git diff: working tree, a merge-base diff against a ref, or a single commit            |\n| `websearch` | always     | Research a question on the web, and report which searches and sources it actually used          |\n| `status`    | always     | Poll a background run, or list recent ones                                                      |\n| `stop`      | no         | Terminate a background run's process tree                                                       |\n| `sessions`  | always     | List, search, and look up the Grok sessions on this machine                                     |\n| `check`     | yes        | Server version, resolved binary, `grok version`, auth, permission ceiling, run defaults         |\n| `help`      | yes        | `grok --help` passthrough                                                                       |\n\n### `review`\n\nThe diff is collected in-process and embedded in the prompt, so the model does not spend turns\nrediscovering what it is meant to review.\n\n```\n> review my working tree with grok-build\n> review the diff against origin/main\n```\n\nTargets are `uncommitted`, `base: \"<ref>\"` (a merge-base diff, so commits that landed on the base\nafter you branched are not attributed to you), or `commit: \"<sha>\"`. With none given it\nauto-detects: the upstream diff when your branch is ahead, otherwise the working tree — and it says\nwhich it chose rather than guessing silently.\n\n`review` is **always read-only**, whatever `GROK_MCP_PERMISSION_CEILING` allows. It takes no\n`permission`, `write`, or `yolo` argument, because a review that edits the code under review is\nnever what was wanted.\n\nPass `structured: true` for machine-readable findings (`severity`, `file`, `line`, `summary`,\n`rationale`) on `_meta.findings`, validated before you see them.\n\nTwo different things can go wrong, and they are reported differently rather than blurred together:\n\n- **The run never finished** — it was cut off, or ended without producing its findings. There is no\n  review, so the call is `isError: true` and `_meta.findingsComplete` is `false`. The body leads\n  with why, quoting the CLI's own reason, and names the fix that fits the actual cause.\n- **The run finished but its output will not validate.** The call still succeeds, returning the raw\n  text plus a `_meta.parseError` — a degraded review beats a failed one.\n\nWhat you will never get is a plausible-looking finding that the model made up. `--json-schema`\nconstrains every message the model emits, so while it is still reading it has no way to say \"I am\nworking\" except in the shape of a finding — and left unchecked it does exactly that. The schema\ncarries a required `status` field to keep that narration out of your results, and nothing is ever\nsalvaged from a partial response by pattern-matching.\n\nStructured reviews of large targets do fail this way with some regularity. The failure is loud by\ndesign.\n\nA review that reaches for a shell is refused, not killed. In headless mode an unapprovable tool\nrequest cancels the entire run while the CLI still exits 0, so `review` denies the shell and edit\ntools outright — the model is told no and finishes its review instead of dying mid-sentence.\n\n### `websearch`\n\n```\n> websearch: what changed in the latest Bun release?\n> search the web for how Postgres handles advisory lock contention, in depth\n```\n\n`numResults` (1–50) and `searchDepth` (`basic` or `full`) shape the prompt — the `grok` CLI has no\nflags for either, and neither parameter pretends otherwise. They do work: the same question asked at\n`basic` made one search across two pages, and at `full` made six searches across three, for two and\na half times the cost.\n\n**The result tells you what was actually looked up**, not just what the model wrote:\n\n```\n[1 web search, 9 sources]\n```\n\nwith `_meta` carrying `webSearches`, `webToolCalls`, `searchQueries`, `sources`, `sourceCount`,\n`pagesOpened`, and `searchPerformed`. That matters more than it sounds. Grok can research through\nweb search or through X, and when the web is unavailable it will quietly do the second — answering\nconfidently, citing `x.com`, exiting successfully. The prose gives you no way to tell. So a run that\nsearched X and not the web says so in its first line and reports `xSearches` separately, and a run\nwhere nothing came back at all is an error rather than a confident-looking answer from the model's\nown memory:\n\n```\nNo search ran. The answer below is the model's own prior knowledge, not current sources.\n```\n\n`searchPerformed` means sources came back — not that a search was attempted. A search that started\nand never returned, or returned an empty result set, is reported as what it was.\n\nLike `review`, `websearch` is **always read-only** and takes no `permission`, `write`, or `yolo`\nargument. It never passes `--disable-web-search`.\n\n### Background runs, `status`, and `stop`\n\nA long agent run does not have to occupy your client. Pass `background: true` to `grok`, `review`,\nor `websearch` and the call returns a `runId` immediately, while a detached worker process runs the\njob to completion:\n\n```\n> have grok refactor the parser in the background\n> status\n> status the run from a minute ago and wait 30s for it\n> stop that run\n```\n\nThe run belongs to the machine, not to this server: it keeps going if your MCP client disconnects,\nif the server restarts, or if you close your editor. Records live under `GROK_MCP_STATE_DIR`, one\ndirectory per run.\n\n**`status` on a finished run returns what the synchronous call would have returned** — same text,\nsame metadata, same error flag. Background is a transport for a tool call, not a second\nimplementation of one. While a run is live you get its state, elapsed time, both process ids, and\nthe tail of its progress log; `waitMs` blocks for up to two minutes and forwards progress\nnotifications as they arrive. A timed-out wait is not an error.\n\nTwo kinds of dishonesty are ruled out by construction. A run whose worker process no longer exists\nis reported as `abandoned` rather than as still running — the machine rebooted, or something killed\nit. And a run that finished early is labelled as such:\n\n```\nmfk2p1x9-3ac71f0b  completed (cut off: cancelled)  grok  4m 12s  refactor the parser\n```\n\nValidation still happens before you get a `runId`: a request above `GROK_MCP_PERMISSION_CEILING`, or\na contradictory pair of session flags, is rejected as a failed call rather than accepted and then\nfailed in a process nobody is watching.\n\n`stop` ends a run early. It signals the worker's whole process group — the worker and the `grok`\nprocess it spawned — with SIGTERM, then SIGKILL if that is not enough. Stopping an already-finished\nrun is not an error, and neither is stopping one that finished a moment before your call landed.\n\n**A stop that could not kill the process tree is reported as a failure, not as a stopped run.** If\nthere is nothing to signal, or the kill is refused, or the tree survives SIGKILL, the run is left\nreading `running` and the call returns an error naming the pid. A `cancelled` record sitting next to\na live process would be the tidier answer and the useless one.\n\nA run you stop mid-flight has usually already produced something worth keeping, and both the partial\nresult and the session id are preserved:\n\n```\nStopped run msxji60o-8f5e27c4 (grok, ran 20s).\nSignalled SIGTERM to process group 1703005; the tree exited.\n\nThe run was cancelled mid-flight, but it recorded a session before it ended:\n  grok -r 01a010e2-478c-73d2-bce9-23552245c64d\n```\n\nGrok only reports a session id when a run reaches its end, which a stopped one never does — so that\nid is read back from the CLI's own session store rather than reconstructed. `_meta.sessionIdSource`\ntells you which you have. If two runs in the same directory could both match, you get the candidate\nids and no resume command: resuming the wrong session continues somebody else's work.\n\n### `sessions`\n\nEvery Grok run leaves a session on disk, and every session id this server reports can be resumed\nlater — from any directory, by you in a terminal or by another tool call.\n\n```\n> list my recent grok sessions\n> what grok sessions did I run in this repo?\n> find the grok session about the rate limiter\n```\n\nSessions are read from `$GROK_HOME/sessions` (default `~/.grok/sessions`), which is the CLI's own\nstore, so they survive restarts of this server, of your MCP client, and of your machine. Pass `id`\nfor one session, `query` for a case-insensitive search over titles, first prompts, and ids, `cwd` to\nscope to one project, and `limit` to bound the list.\n\nA run that has just finished has no title yet — Grok fills those in later, if at all — so rows fall\nback to the first prompt of the session, and `titleSource` tells you which you are looking at. Every\nrow carries `resumeCommand`, and so does every `grok` and `review` result:\n\n```\ngrok -r 01a00c8d-970c-7531-8a12-31dac582c22b\n```\n\nSearch is local-only. `grok sessions search` also consults a remote index; this tool does not, so a\nsession that exists only server-side will not appear.\n\n## Development\n\n```bash\nnpm install\nnpm run build          # tsc -> dist/\nnpm run dev            # tsx src/index.ts\nnpm test               # node --test via tsx\nnpm run test:coverage  # same, with enforced coverage floors\nnpm run lint\nnpm run typecheck\nnpm run format\n```\n\n- [docs/api-reference.md](docs/api-reference.md) — every tool's parameters, result text, `_meta`\n  keys, and the exact conditions under which each is set.\n- [docs/security.md](docs/security.md) — what registering this server authorises, what each\n  permission level actually grants, and what leaves your machine.\n- [docs/engineering.md](docs/engineering.md) — how code is written here: architecture, functional\n  TypeScript rules, error and effect discipline, testing and coverage policy, commit workflow.\n- [CLAUDE.md](CLAUDE.md) — project background and the verified `grok` CLI behaviour this server\n  depends on.\n- [ROADMAP.md](ROADMAP.md) — milestones, acceptance criteria, and the ideas that were measured and\n  rejected.\n\n### Releasing\n\nBump `version` in `package.json`, move the `Unreleased` section of [CHANGELOG.md](CHANGELOG.md)\nunder the new version heading, commit, then:\n\n```bash\ngit tag -a v0.2.0 -m v0.2.0 && git push origin v0.2.0\n```\n\n[.github/workflows/release.yml](.github/workflows/release.yml) runs the full gate, refuses to\npublish if the tag and `package.json` disagree, installs the packed tarball into a scratch directory\nand drives a real `initialize` against the installed binary, then publishes **that same file** and\ncuts a GitHub release.\n\nThere is no publish credential to manage. Authentication is\n[npm trusted publishing](https://docs.npmjs.com/trusted-publishers): the workflow exchanges a\nshort-lived OIDC token, and npm generates the provenance attestation on its own. The trust is\nregistered against this repository and this workflow's **filename**, so renaming `release.yml`\nbreaks publishing — and npm does not check the configuration until a publish is attempted, where the\nsymptom is `ENEEDAUTH` rather than anything that names the cause.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n",
  "bytes": 21002,
  "sha": "343b7e375a42cb8c3d15cc026a327a3827a694375d5d0b033031337689709893",
  "repo_slug": "nuruvala/grok-build-to-claude",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_nuruvala_grok_build_mcp_server_fcac6da6/readme"
}