grok-cli-mcp 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Howard Peng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,221 @@
1
+ # grok-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/grok-cli-mcp.svg)](https://www.npmjs.com/package/grok-cli-mcp)
4
+ [![MCP Registry](https://img.shields.io/badge/MCP%20Registry-published-success)](https://registry.modelcontextprotocol.io/)
5
+
6
+ > Use Grok (via the official xAI [Grok CLI](https://x.ai/news/grok-build-cli)) as a **peer code reviewer, adversary, and consultant** inside Claude Code, Cursor, Cline, OpenClaw, and any other MCP host.
7
+
8
+ `grok-mcp` (npm: [`grok-cli-mcp`](https://www.npmjs.com/package/grok-cli-mcp)) is a [Model Context Protocol](https://modelcontextprotocol.io) server that wraps the `grok` CLI. It gives your primary agent (Claude, Cursor, etc.) four tools so it can delegate to Grok for second opinions without leaving the session:
9
+
10
+ - `grok_review` — structured diff review with per-dimension scores
11
+ - `grok_challenge` — adversarial bug/race/security hunting
12
+ - `grok_consult` — multi-turn consultation (caller owns history)
13
+ - `grok_chat` — one-shot questions
14
+
15
+ English | [繁體中文](./README.zh-TW.md)
16
+
17
+ ## Why grok-mcp?
18
+
19
+ Most "Grok MCP" packages expose Grok's chat/search/image capabilities so Claude can *use* Grok. `grok-mcp` does the opposite: it lets your main coding agent (Claude/Cursor/…) **ask Grok to review and attack its own work**. A different model challenging your primary catches bugs single-model loops miss.
20
+
21
+ ## What you get
22
+
23
+ Four tools, all stateless, all stdout-only:
24
+
25
+ | Tool | Use it for |
26
+ |------|------------|
27
+ | `grok_chat` | One-shot prompt → Grok's reply |
28
+ | `grok_review` | Pass a unified diff (or auto-grab `git diff main...HEAD`) and get a per-dimension code review |
29
+ | `grok_consult` | Replay a message history for multi-turn — caller owns the thread |
30
+ | `grok_challenge` | Adversarial: ask Grok to find every bug, race, edge case, and security hole |
31
+
32
+ ## Prerequisites
33
+
34
+ - Node.js ≥ 18
35
+ - The Grok CLI installed:
36
+ ```bash
37
+ curl -fsSL https://x.ai/cli/install.sh | bash
38
+ ```
39
+ - An auth method — either browser OAuth (`grok` once interactively) **or** an `XAI_API_KEY` from [console.x.ai](https://console.x.ai). See [Authentication](#authentication) below.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ npm install -g grok-cli-mcp
45
+ # or use npx — no install needed
46
+ npx grok-cli-mcp
47
+ ```
48
+
49
+ ## Authentication
50
+
51
+ The wrapped Grok CLI supports two auth methods; `grok-mcp` inherits whichever is active.
52
+
53
+ | Method | Best for | Rate limits |
54
+ |--------|----------|-------------|
55
+ | **API key** (`XAI_API_KEY` env var) | MCP / CI / automation | Pay-per-call, no subscription cap |
56
+ | **Browser OAuth** (`grok` interactive login) | Local interactive use | Subject to your grok.com plan tier |
57
+
58
+ Per [xAI's auth precedence](https://docs.x.ai/docs/api-reference#authentication), `XAI_API_KEY` always wins over `~/.grok/auth.json`. So you can keep your browser login for interactive `grok` use and override it *just for this MCP server* by setting `XAI_API_KEY` in the server's env block:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "grok": {
64
+ "command": "npx",
65
+ "args": ["-y", "grok-cli-mcp"],
66
+ "env": {
67
+ "XAI_API_KEY": "xai-...",
68
+ "GROK_MCP_TIMEOUT": "600000"
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ Treat the key file as a secret — it ends up in your MCP host's config (e.g. `~/.claude.json`), which is plain JSON on disk.
76
+
77
+ ## Wire it into your MCP host
78
+
79
+ ### Claude Code
80
+
81
+ Recommended — use `add-json` so the env block parses cleanly:
82
+
83
+ ```bash
84
+ claude mcp add-json -s user grok '{
85
+ "command": "npx",
86
+ "args": ["-y", "grok-cli-mcp"],
87
+ "env": { "XAI_API_KEY": "xai-...", "GROK_MCP_TIMEOUT": "600000" }
88
+ }'
89
+ ```
90
+
91
+ > **Why `add-json` not `claude mcp add -e ...`?** The `-e KEY=val` flag is variadic and will greedily consume the server name as another env value if you pass more than one. `add-json` sidesteps that footgun entirely.
92
+
93
+ Or edit `~/.claude.json` directly. Minimal (OAuth fallback):
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "grok": {
99
+ "command": "npx",
100
+ "args": ["-y", "grok-cli-mcp"]
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### Cursor
107
+
108
+ Create `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "grok": {
114
+ "command": "npx",
115
+ "args": ["-y", "grok-cli-mcp"]
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### Cline (VS Code)
122
+
123
+ Settings → Cline → MCP Servers:
124
+
125
+ ```json
126
+ {
127
+ "grok": {
128
+ "command": "npx",
129
+ "args": ["-y", "grok-cli-mcp"]
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### Any other MCP host
135
+
136
+ `grok-mcp` speaks plain stdio MCP. Point any client at `npx -y grok-cli-mcp` and it works.
137
+
138
+ ## Tool reference
139
+
140
+ ### `grok_chat`
141
+
142
+ ```json
143
+ { "prompt": "Explain consistent hashing in two sentences." }
144
+ ```
145
+
146
+ Optional: `model` to override the default Grok model; `timeout` (seconds) to extend the per-call limit for long grok-4 reasoning. All four tools accept `timeout`.
147
+
148
+ ### `grok_review`
149
+
150
+ ```json
151
+ { "base_ref": "main", "focus": "security" }
152
+ ```
153
+
154
+ If `diff` is omitted, runs `git diff <base_ref>...HEAD` in `cwd` (defaults to your host's working directory). Returns a markdown review with verdict, per-dimension scores (correctness / readability / architecture / security / performance), and concrete fix-it items.
155
+
156
+ ### `grok_consult`
157
+
158
+ ```json
159
+ {
160
+ "messages": [
161
+ { "role": "system", "content": "You are a senior backend engineer." },
162
+ { "role": "user", "content": "How would you cache this query?" },
163
+ { "role": "assistant", "content": "Two options..." },
164
+ { "role": "user", "content": "What's the failure mode of option 2?" }
165
+ ]
166
+ }
167
+ ```
168
+
169
+ The server is stateless — the caller passes the full thread each time. Most MCP hosts handle this naturally.
170
+
171
+ ### `grok_challenge`
172
+
173
+ ```json
174
+ {
175
+ "code": "function transfer(from, to, amount) { from.balance -= amount; to.balance += amount; }",
176
+ "context": "Node.js, called concurrently from HTTP handlers"
177
+ }
178
+ ```
179
+
180
+ Returns severity-ranked issues (Critical / High / Medium / Low) with concrete reproductions and patches.
181
+
182
+ ## Configuration
183
+
184
+ | Env var | Default | Purpose |
185
+ |---------|---------|---------|
186
+ | `XAI_API_KEY` | *(unset — falls back to OAuth)* | API key from [console.x.ai](https://console.x.ai). When set, overrides `~/.grok/auth.json` and switches the server to pay-per-call billing with no subscription rate cap. See [Authentication](#authentication). |
187
+ | `GROK_MCP_BIN` | `grok` | Path to the `grok` binary |
188
+ | `GROK_MCP_TIMEOUT` | `300000` | Default per-call timeout in milliseconds |
189
+
190
+ Model defaults live in the Grok CLI itself (`~/.grok/config.toml`).
191
+
192
+ ### Timeouts
193
+
194
+ grok-4 is a reasoning model and long prompts routinely take longer than two minutes. The server's default per-call limit is **300s (5 min)**. You can change it three ways:
195
+
196
+ - **Per call** — pass `timeout` (seconds) to any tool: `{ "prompt": "...", "timeout": 600 }`.
197
+ - **Per server** — set `GROK_MCP_TIMEOUT` (milliseconds) in the MCP server's env.
198
+ - **Host side** — the MCP host has its *own* request timeout that can fire before the server's. If calls still time out after raising the above, raise the host limit too. In Claude Code that's `MCP_TIMEOUT` (server startup) and `MCP_TOOL_TIMEOUT` (per tool call), both in milliseconds.
199
+
200
+ On timeout the error includes any partial output Grok produced before the deadline, so you don't lose a near-complete answer.
201
+
202
+ ## Roadmap
203
+
204
+ - **v0.1** — four stateless tools, stdio transport (current)
205
+ - **Discoverability push (v0.1.3)** — naming unification, MCP Registry, Smithery, glama.ai, stronger positioning
206
+ - **v0.2** — server-side session persistence so `grok_consult` can take a `conversation_id`
207
+ - **v0.3** — streaming responses through MCP `progress` notifications
208
+
209
+ ## Development
210
+
211
+ ```bash
212
+ git clone https://github.com/howardpen9/grok-mcp.git
213
+ cd grok-mcp
214
+ npm install
215
+ npm test
216
+ npm run build
217
+ ```
218
+
219
+ ## License
220
+
221
+ MIT
@@ -0,0 +1,221 @@
1
+ # grok-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/grok-cli-mcp.svg)](https://www.npmjs.com/package/grok-cli-mcp)
4
+ [![MCP Registry](https://img.shields.io/badge/MCP%20Registry-published-success)](https://registry.modelcontextprotocol.io/)
5
+
6
+ > 讓 Claude Code、Cursor、Cline、OpenClaw 等 MCP host 透過官方 xAI [Grok CLI](https://x.ai/news/grok-build-cli),把 **Grok 當成 code reviewer、adversary 與第二意見顧問** 使用。
7
+
8
+ `grok-mcp`(npm 套件名 [`grok-cli-mcp`](https://www.npmjs.com/package/grok-cli-mcp))是 [Model Context Protocol](https://modelcontextprotocol.io) server,將 `grok` CLI 包裝成工具,讓你的主要 agent(Claude、Cursor…)可以隨時叫 Grok 幫忙 review、挑戰、諮詢,而不用切換 session:
9
+
10
+ - `grok_review` — 結構化 diff review,附五維度評分
11
+ - `grok_challenge` — 對抗式找 bug / race / security hole
12
+ - `grok_consult` — 多輪諮詢(caller 自己重送 history)
13
+ - `grok_chat` — 一次性問答
14
+
15
+ English: [README.md](./README.md)
16
+
17
+ ## 為什麼用 grok-mcp?
18
+
19
+ 市面上其他 "Grok MCP" 套件大多讓 Claude 可以「使用」Grok 的 chat / search / image 能力。`grok-mcp` 反過來:讓你的主要 coding agent(Claude / Cursor)**請 Grok 來 review、挑戰自己的產出**。換一個 model 攻擊主 agent 的盲點,能抓到單模型 loop 找不到的 bug。
20
+
21
+ ## 提供什麼
22
+
23
+ 四個 tool,全部 stateless:
24
+
25
+ | Tool | 用途 |
26
+ |------|------|
27
+ | `grok_chat` | 一次性問答 |
28
+ | `grok_review` | 給 diff(或自動 `git diff main...HEAD`),回結構化 code review |
29
+ | `grok_consult` | 多輪對話,caller 自己重送 history |
30
+ | `grok_challenge` | 對抗模式:請 Grok 找 bug、race condition、security hole |
31
+
32
+ ## 前置需求
33
+
34
+ - Node.js ≥ 18
35
+ - 已安裝 Grok CLI:
36
+ ```bash
37
+ curl -fsSL https://x.ai/cli/install.sh | bash
38
+ ```
39
+ - 一種認證方式 — 瀏覽器 OAuth(互動跑一次 `grok`)**或**到 [console.x.ai](https://console.x.ai) 拿一把 `XAI_API_KEY`。詳見下方 [認證](#認證)。
40
+
41
+ ## 安裝
42
+
43
+ ```bash
44
+ npm install -g grok-cli-mcp
45
+ # 或直接 npx 不裝
46
+ npx grok-cli-mcp
47
+ ```
48
+
49
+ ## 認證
50
+
51
+ 包裝的 Grok CLI 支援兩種認證方式,`grok-mcp` 繼承當前啟用的那一種。
52
+
53
+ | 方式 | 適合場景 | Rate limit |
54
+ |------|---------|-----------|
55
+ | **API key**(`XAI_API_KEY` 環境變數)| MCP / CI / 自動化 | 按次計費,無訂閱配額上限 |
56
+ | **瀏覽器 OAuth**(互動跑 `grok` 登入)| 本機互動使用 | 依你的 grok.com 訂閱方案 |
57
+
58
+ 依照 [xAI 認證優先順序](https://docs.x.ai/docs/api-reference#authentication),`XAI_API_KEY` 永遠勝過 `~/.grok/auth.json`。所以可以保留瀏覽器登入給互動式 `grok` 用,**只在這個 MCP server 的 env block 加 `XAI_API_KEY`** 來覆蓋:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "grok": {
64
+ "command": "npx",
65
+ "args": ["-y", "grok-cli-mcp"],
66
+ "env": {
67
+ "XAI_API_KEY": "xai-...",
68
+ "GROK_MCP_TIMEOUT": "600000"
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ 注意 API key 等同密鑰 — 會寫進 MCP host 的設定檔(例如 `~/.claude.json`),磁碟上是明文 JSON。
76
+
77
+ ## 串到 MCP host
78
+
79
+ ### Claude Code
80
+
81
+ 推薦用 `add-json`,env block 才會正確 parse:
82
+
83
+ ```bash
84
+ claude mcp add-json -s user grok '{
85
+ "command": "npx",
86
+ "args": ["-y", "grok-cli-mcp"],
87
+ "env": { "XAI_API_KEY": "xai-...", "GROK_MCP_TIMEOUT": "600000" }
88
+ }'
89
+ ```
90
+
91
+ > **為什麼不用 `claude mcp add -e ...`?** `-e KEY=val` 是 variadic flag,傳超過一個 `-e` 時,server 名字會被當成下一個 env value 吃掉。`add-json` 一次到位避開這個坑。
92
+
93
+ 或直接編輯 `~/.claude.json`,最簡寫法(fallback 到 OAuth):
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "grok": {
99
+ "command": "npx",
100
+ "args": ["-y", "grok-cli-mcp"]
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### Cursor
107
+
108
+ `.cursor/mcp.json`(專案)或 `~/.cursor/mcp.json`(全域):
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "grok": {
114
+ "command": "npx",
115
+ "args": ["-y", "grok-cli-mcp"]
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### Cline (VS Code)
122
+
123
+ Settings → Cline → MCP Servers:
124
+
125
+ ```json
126
+ {
127
+ "grok": {
128
+ "command": "npx",
129
+ "args": ["-y", "grok-cli-mcp"]
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### 其他 MCP host
135
+
136
+ `grok-mcp` 跑標準 stdio MCP。任何 client 指向 `npx -y grok-cli-mcp` 即可。
137
+
138
+ ## Tool 用法
139
+
140
+ ### `grok_chat`
141
+
142
+ ```json
143
+ { "prompt": "兩句話解釋 consistent hashing。" }
144
+ ```
145
+
146
+ 可選 `model` 覆寫預設 Grok model;`timeout`(秒)拉長單次 call 的時限,給 grok-4 長推理用。四個 tool 都接受 `timeout`。
147
+
148
+ ### `grok_review`
149
+
150
+ ```json
151
+ { "base_ref": "main", "focus": "security" }
152
+ ```
153
+
154
+ 沒給 `diff` 就跑 `git diff <base_ref>...HEAD`。回傳 markdown 評審,含整體判決、五維度評分(correctness / readability / architecture / security / performance)、具體修正建議。
155
+
156
+ ### `grok_consult`
157
+
158
+ ```json
159
+ {
160
+ "messages": [
161
+ { "role": "system", "content": "你是資深後端工程師。" },
162
+ { "role": "user", "content": "這個 query 怎麼 cache?" },
163
+ { "role": "assistant", "content": "兩個方案..." },
164
+ { "role": "user", "content": "方案 2 的 failure mode 是什麼?" }
165
+ ]
166
+ }
167
+ ```
168
+
169
+ Server 不存 state,caller 每次帶完整 history。一般 MCP host 會自動處理。
170
+
171
+ ### `grok_challenge`
172
+
173
+ ```json
174
+ {
175
+ "code": "function transfer(from, to, amount) { from.balance -= amount; to.balance += amount; }",
176
+ "context": "Node.js,HTTP handler 並發呼叫"
177
+ }
178
+ ```
179
+
180
+ 回傳 severity 分級的問題(Critical / High / Medium / Low),含重現步驟與修補建議。
181
+
182
+ ## 設定
183
+
184
+ | 環境變數 | 預設值 | 用途 |
185
+ |---------|--------|------|
186
+ | `XAI_API_KEY` | *(未設,fallback 到 OAuth)* | 到 [console.x.ai](https://console.x.ai) 拿。設定後會覆蓋 `~/.grok/auth.json`,切到按次計費、無訂閱配額上限。詳見 [認證](#認證)。 |
187
+ | `GROK_MCP_BIN` | `grok` | grok binary 路徑 |
188
+ | `GROK_MCP_TIMEOUT` | `300000` | 預設單次 call timeout(毫秒) |
189
+
190
+ 預設 model 設定在 Grok CLI 自己的 `~/.grok/config.toml`。
191
+
192
+ ### Timeout
193
+
194
+ grok-4 是 reasoning model,長 prompt 動輒超過兩分鐘。Server 預設單次時限為 **300 秒(5 分鐘)**,有三種調整方式:
195
+
196
+ - **單次 call** — 對任一 tool 傳 `timeout`(秒):`{ "prompt": "...", "timeout": 600 }`。
197
+ - **整個 server** — 在 MCP server 的環境變數設 `GROK_MCP_TIMEOUT`(毫秒)。
198
+ - **Host 端** — MCP host 自己也有 request timeout,可能比 server 更早觸發。若上面兩項都調高仍超時,請一併拉高 host 的時限。在 Claude Code 是 `MCP_TIMEOUT`(server 啟動)與 `MCP_TOOL_TIMEOUT`(單次 tool call),單位皆為毫秒。
199
+
200
+ 超時時,錯誤訊息會附上 Grok 在截止前已產生的 partial 輸出,避免快完成的答案整個丟失。
201
+
202
+ ## Roadmap
203
+
204
+ - **v0.1** — 四個 stateless tool、stdio transport(目前)
205
+ - **Discoverability push(v0.1.3)** — 統一命名、MCP Registry、Smithery、glama.ai 上架、加強定位
206
+ - **v0.2** — server 端 session 持久化,`grok_consult` 可帶 `conversation_id`
207
+ - **v0.3** — 透過 MCP `progress` notification 做 streaming
208
+
209
+ ## 開發
210
+
211
+ ```bash
212
+ git clone https://github.com/howardpen9/grok-mcp.git
213
+ cd grok-mcp
214
+ npm install
215
+ npm test
216
+ npm run build
217
+ ```
218
+
219
+ ## License
220
+
221
+ MIT
package/dist/grok.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ export interface RunGrokOptions {
2
+ model?: string;
3
+ timeoutMs?: number;
4
+ cwd?: string;
5
+ extraArgs?: string[];
6
+ }
7
+ export interface RunGrokResult {
8
+ stdout: string;
9
+ stderr: string;
10
+ exitCode: number;
11
+ }
12
+ export declare class GrokCliError extends Error {
13
+ readonly exitCode: number;
14
+ readonly stderr: string;
15
+ constructor(message: string, exitCode: number, stderr: string);
16
+ }
17
+ export declare class GrokTimeoutError extends Error {
18
+ readonly timeoutMs: number;
19
+ readonly partialStdout: string;
20
+ constructor(timeoutMs: number, partialStdout?: string);
21
+ }
22
+ export declare function runGrok(prompt: string, opts?: RunGrokOptions): Promise<RunGrokResult>;
23
+ export declare function checkGrokAvailable(): Promise<{
24
+ ok: true;
25
+ version: string;
26
+ } | {
27
+ ok: false;
28
+ reason: string;
29
+ }>;
package/dist/grok.js ADDED
@@ -0,0 +1,120 @@
1
+ import { spawn } from "node:child_process";
2
+ import stripAnsi from "strip-ansi";
3
+ export class GrokCliError extends Error {
4
+ exitCode;
5
+ stderr;
6
+ constructor(message, exitCode, stderr) {
7
+ super(message);
8
+ this.exitCode = exitCode;
9
+ this.stderr = stderr;
10
+ this.name = "GrokCliError";
11
+ }
12
+ }
13
+ export class GrokTimeoutError extends Error {
14
+ timeoutMs;
15
+ partialStdout;
16
+ constructor(timeoutMs, partialStdout = "") {
17
+ const seconds = Math.round(timeoutMs / 1000);
18
+ const hint = `grok CLI timed out after ${seconds}s. grok-4 reasoning on long prompts can exceed this. ` +
19
+ `Raise it per-call with the "timeout" parameter (seconds), or globally via the GROK_MCP_TIMEOUT env var (ms). ` +
20
+ `If the MCP host itself times out first, raise its limit too (e.g. Claude Code: MCP_TIMEOUT / MCP_TOOL_TIMEOUT).`;
21
+ const partial = partialStdout.trim()
22
+ ? `\n\n--- Partial output received before timeout ---\n${partialStdout.trim()}`
23
+ : "";
24
+ super(`${hint}${partial}`);
25
+ this.timeoutMs = timeoutMs;
26
+ this.partialStdout = partialStdout;
27
+ this.name = "GrokTimeoutError";
28
+ }
29
+ }
30
+ const DEFAULT_TIMEOUT_MS = Number(process.env.GROK_MCP_TIMEOUT ?? 300_000);
31
+ const GROK_BIN = process.env.GROK_MCP_BIN ?? "grok";
32
+ export async function runGrok(prompt, opts = {}) {
33
+ // Disable agentic behaviour by default: this is a text-completion wrapper,
34
+ // not an interactive coding session. Permission prompts would hang the
35
+ // headless subprocess (stdin is closed).
36
+ const args = ["-p", prompt];
37
+ if (opts.model)
38
+ args.push("--model", opts.model);
39
+ if (opts.extraArgs)
40
+ args.push(...opts.extraArgs);
41
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
42
+ return new Promise((resolve, reject) => {
43
+ const child = spawn(GROK_BIN, args, {
44
+ cwd: opts.cwd,
45
+ env: process.env,
46
+ stdio: ["ignore", "pipe", "pipe"],
47
+ });
48
+ let stdout = "";
49
+ let stderr = "";
50
+ let timedOut = false;
51
+ const timer = setTimeout(() => {
52
+ timedOut = true;
53
+ child.kill("SIGTERM");
54
+ setTimeout(() => child.kill("SIGKILL"), 2_000).unref();
55
+ }, timeoutMs);
56
+ child.stdout.on("data", (chunk) => {
57
+ stdout += chunk.toString("utf8");
58
+ });
59
+ child.stderr.on("data", (chunk) => {
60
+ stderr += chunk.toString("utf8");
61
+ });
62
+ child.on("error", (err) => {
63
+ clearTimeout(timer);
64
+ if (err.code === "ENOENT") {
65
+ reject(new GrokCliError(`grok CLI not found in PATH (looked for "${GROK_BIN}"). Install with: curl -fsSL https://x.ai/cli/install.sh | bash`, 127, ""));
66
+ return;
67
+ }
68
+ reject(err);
69
+ });
70
+ child.on("close", (code) => {
71
+ clearTimeout(timer);
72
+ const cleanStdout = stripAnsi(stdout).trim();
73
+ const cleanStderr = stripAnsi(stderr).trim();
74
+ if (timedOut) {
75
+ reject(new GrokTimeoutError(timeoutMs, cleanStdout));
76
+ return;
77
+ }
78
+ if (code !== 0) {
79
+ const tail = cleanStderr.slice(-2000);
80
+ reject(new GrokCliError(`grok CLI exited with code ${code}${tail ? `: ${tail}` : ""}`, code ?? -1, cleanStderr));
81
+ return;
82
+ }
83
+ resolve({
84
+ stdout: cleanStdout,
85
+ stderr: cleanStderr,
86
+ exitCode: code ?? 0,
87
+ });
88
+ });
89
+ });
90
+ }
91
+ export async function checkGrokAvailable() {
92
+ return new Promise((resolve) => {
93
+ const child = spawn(GROK_BIN, ["--version"], {
94
+ stdio: ["ignore", "pipe", "pipe"],
95
+ });
96
+ let out = "";
97
+ child.stdout.on("data", (c) => (out += c.toString("utf8")));
98
+ child.stderr.on("data", (c) => (out += c.toString("utf8")));
99
+ child.on("error", (err) => {
100
+ if (err.code === "ENOENT") {
101
+ resolve({
102
+ ok: false,
103
+ reason: `grok CLI not found in PATH (looked for "${GROK_BIN}"). Install with: curl -fsSL https://x.ai/cli/install.sh | bash`,
104
+ });
105
+ }
106
+ else {
107
+ resolve({ ok: false, reason: err.message });
108
+ }
109
+ });
110
+ child.on("close", (code) => {
111
+ if (code === 0) {
112
+ resolve({ ok: true, version: stripAnsi(out).trim() });
113
+ }
114
+ else {
115
+ resolve({ ok: false, reason: `grok --version exited with code ${code}` });
116
+ }
117
+ });
118
+ });
119
+ }
120
+ //# sourceMappingURL=grok.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grok.js","sourceRoot":"","sources":["../src/grok.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
8
+ import { zodToJsonSchema } from "zod-to-json-schema";
9
+ import { checkGrokAvailable } from "./grok.js";
10
+ import { grokChat } from "./tools/chat.js";
11
+ import { grokReview } from "./tools/review.js";
12
+ import { grokConsult } from "./tools/consult.js";
13
+ import { grokChallenge } from "./tools/challenge.js";
14
+ const TOOLS = [grokChat, grokReview, grokConsult, grokChallenge];
15
+ const here = dirname(fileURLToPath(import.meta.url));
16
+ const pkg = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
17
+ async function main() {
18
+ const server = new Server({
19
+ name: "grok-mcp",
20
+ version: pkg.version,
21
+ }, {
22
+ capabilities: {
23
+ tools: {},
24
+ },
25
+ });
26
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
27
+ tools: TOOLS.map((t) => ({
28
+ name: t.name,
29
+ description: t.description,
30
+ inputSchema: zodToJsonSchema(t.inputSchema, { target: "openApi3" }),
31
+ })),
32
+ }));
33
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
34
+ const tool = TOOLS.find((t) => t.name === req.params.name);
35
+ if (!tool) {
36
+ return {
37
+ isError: true,
38
+ content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }],
39
+ };
40
+ }
41
+ const parsed = tool.inputSchema.safeParse(req.params.arguments ?? {});
42
+ if (!parsed.success) {
43
+ return {
44
+ isError: true,
45
+ content: [
46
+ {
47
+ type: "text",
48
+ text: `Invalid arguments for ${tool.name}:\n${JSON.stringify(parsed.error.format(), null, 2)}`,
49
+ },
50
+ ],
51
+ };
52
+ }
53
+ try {
54
+ const result = await tool.handler(parsed.data);
55
+ return {
56
+ content: [{ type: "text", text: result }],
57
+ };
58
+ }
59
+ catch (err) {
60
+ const msg = err instanceof Error ? err.message : String(err);
61
+ return {
62
+ isError: true,
63
+ content: [{ type: "text", text: msg }],
64
+ };
65
+ }
66
+ });
67
+ // Startup check: warn (to stderr, never stdout) if grok CLI missing.
68
+ const probe = await checkGrokAvailable();
69
+ if (!probe.ok) {
70
+ process.stderr.write(`[grok-mcp] WARN: ${probe.reason}\n`);
71
+ }
72
+ else {
73
+ process.stderr.write(`[grok-mcp] grok CLI detected: ${probe.version}\n`);
74
+ }
75
+ const transport = new StdioServerTransport();
76
+ await server.connect(transport);
77
+ process.stderr.write("[grok-mcp] ready (stdio)\n");
78
+ }
79
+ main().catch((err) => {
80
+ process.stderr.write(`[grok-mcp] fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
81
+ process.exit(1);
82
+ });
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const grokChallenge: import("./types.js").ErasedTool;
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ import { runGrok } from "../grok.js";
3
+ import { defineTool, timeoutField, timeoutOpts } from "./types.js";
4
+ const inputSchema = z.object({
5
+ code: z.string().min(1).describe("The code or design to attack."),
6
+ context: z
7
+ .string()
8
+ .optional()
9
+ .describe("Optional context: language, framework, intended behaviour, constraints."),
10
+ model: z.string().optional(),
11
+ timeout: timeoutField,
12
+ });
13
+ const CHALLENGE_TEMPLATE = (code, context) => `You are a hostile senior engineer tasked with breaking this code. Be specific and ruthless — vague concerns are useless.
14
+
15
+ ${context ? `Context: ${context}\n` : ""}For each issue you find, output:
16
+ - Severity (Critical / High / Medium / Low)
17
+ - Concrete reproduction (input, sequence of events, environment)
18
+ - Why the current code fails
19
+ - Smallest patch that would fix it
20
+
21
+ Cover at minimum:
22
+ - Edge cases (empty, null, very large, very small, unicode, malformed)
23
+ - Concurrency / race conditions / re-entrancy
24
+ - Error paths and partial failure
25
+ - Security: injection, auth bypass, information leak, resource exhaustion
26
+ - Backward / forward compatibility
27
+ - Adversarial inputs designed to break invariants
28
+
29
+ If you genuinely find nothing to break, say so explicitly and list the invariants you verified.
30
+
31
+ --- CODE START ---
32
+ ${code}
33
+ --- CODE END ---`;
34
+ export const grokChallenge = defineTool({
35
+ name: "grok_challenge",
36
+ description: "Ask Grok to adversarially break a piece of code: edge cases, race conditions, security holes, adversarial inputs. Returns severity-ranked issues with reproductions.",
37
+ inputSchema,
38
+ async handler({ code, context, model, timeout }) {
39
+ const { stdout } = await runGrok(CHALLENGE_TEMPLATE(code, context), {
40
+ model,
41
+ ...timeoutOpts(timeout),
42
+ });
43
+ return stdout;
44
+ },
45
+ });
46
+ //# sourceMappingURL=challenge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge.js","sourceRoot":"","sources":["../../src/tools/challenge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IACjE,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,yEAAyE,CAAC;IACtF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,YAAY;CACtB,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAE,OAAgB,EAAE,EAAE,CAAC;;EAE7D,OAAO,CAAC,CAAC,CAAC,YAAY,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;EAiBtC,IAAI;iBACW,CAAC;AAElB,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;IACtC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,sKAAsK;IACxK,WAAW;IACX,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;QAC7C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;YAClE,KAAK;YACL,GAAG,WAAW,CAAC,OAAO,CAAC;SACxB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const grokChat: import("./types.js").ErasedTool;
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import { runGrok } from "../grok.js";
3
+ import { defineTool, timeoutField, timeoutOpts } from "./types.js";
4
+ const inputSchema = z.object({
5
+ prompt: z.string().min(1).describe("The prompt to send to Grok."),
6
+ model: z.string().optional().describe("Override default Grok model (e.g. 'grok-4')."),
7
+ timeout: timeoutField,
8
+ });
9
+ export const grokChat = defineTool({
10
+ name: "grok_chat",
11
+ description: "Send a one-shot prompt to xAI Grok and return its reply. Stateless — for multi-turn use grok_consult.",
12
+ inputSchema,
13
+ async handler({ prompt, model, timeout }) {
14
+ const { stdout } = await runGrok(prompt, { model, ...timeoutOpts(timeout) });
15
+ return stdout;
16
+ },
17
+ });
18
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/tools/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IACjE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;IACrF,OAAO,EAAE,YAAY;CACtB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAC;IACjC,IAAI,EAAE,WAAW;IACjB,WAAW,EACT,uGAAuG;IACzG,WAAW;IACX,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE;QACtC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7E,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const grokConsult: import("./types.js").ErasedTool;
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ import { runGrok } from "../grok.js";
3
+ import { defineTool, timeoutField, timeoutOpts } from "./types.js";
4
+ const messageSchema = z.object({
5
+ role: z.enum(["user", "assistant", "system"]),
6
+ content: z.string(),
7
+ });
8
+ const inputSchema = z.object({
9
+ messages: z
10
+ .array(messageSchema)
11
+ .min(1)
12
+ .describe("Conversation history. Caller maintains state across turns."),
13
+ model: z.string().optional(),
14
+ timeout: timeoutField,
15
+ });
16
+ function flattenMessages(messages) {
17
+ const parts = [];
18
+ for (const m of messages) {
19
+ if (m.role === "system") {
20
+ parts.push(`[SYSTEM]\n${m.content}\n`);
21
+ }
22
+ else if (m.role === "user") {
23
+ parts.push(`[USER]\n${m.content}\n`);
24
+ }
25
+ else {
26
+ parts.push(`[ASSISTANT]\n${m.content}\n`);
27
+ }
28
+ }
29
+ parts.push("[ASSISTANT]\n");
30
+ return parts.join("\n");
31
+ }
32
+ export const grokConsult = defineTool({
33
+ name: "grok_consult",
34
+ description: "Continue a conversation with Grok by replaying the full message history each call. Stateless on the server side — the caller owns the thread.",
35
+ inputSchema,
36
+ async handler({ messages, model, timeout }) {
37
+ const prompt = flattenMessages(messages);
38
+ const { stdout } = await runGrok(prompt, { model, ...timeoutOpts(timeout) });
39
+ return stdout;
40
+ },
41
+ });
42
+ //# sourceMappingURL=consult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consult.js","sourceRoot":"","sources":["../../src/tools/consult.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC7C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;CACpB,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC;SACR,KAAK,CAAC,aAAa,CAAC;SACpB,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,4DAA4D,CAAC;IACzE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,YAAY;CACtB,CAAC,CAAC;AAEH,SAAS,eAAe,CAAC,QAA8C;IACrE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;IACpC,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,+IAA+I;IACjJ,WAAW;IACX,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE;QACxC,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7E,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const grokReview: import("./types.js").ErasedTool;
@@ -0,0 +1,71 @@
1
+ import { spawn } from "node:child_process";
2
+ import { z } from "zod";
3
+ import { runGrok } from "../grok.js";
4
+ import { defineTool, timeoutField, timeoutOpts } from "./types.js";
5
+ const inputSchema = z.object({
6
+ diff: z.string().optional().describe("Unified diff to review. If omitted, runs `git diff <base_ref>`."),
7
+ base_ref: z
8
+ .string()
9
+ .optional()
10
+ .describe("Git ref to diff against when diff is not provided. Defaults to 'main'."),
11
+ focus: z
12
+ .string()
13
+ .optional()
14
+ .describe("Optional focus area (e.g. 'security', 'performance', 'API design')."),
15
+ model: z.string().optional(),
16
+ cwd: z.string().optional().describe("Working directory for git diff. Defaults to process cwd."),
17
+ timeout: timeoutField,
18
+ });
19
+ function gitDiff(baseRef, cwd) {
20
+ return new Promise((resolve, reject) => {
21
+ const child = spawn("git", ["diff", `${baseRef}...HEAD`], {
22
+ cwd,
23
+ stdio: ["ignore", "pipe", "pipe"],
24
+ });
25
+ let out = "";
26
+ let err = "";
27
+ child.stdout.on("data", (c) => (out += c.toString("utf8")));
28
+ child.stderr.on("data", (c) => (err += c.toString("utf8")));
29
+ child.on("error", reject);
30
+ child.on("close", (code) => {
31
+ if (code !== 0)
32
+ reject(new Error(`git diff failed: ${err.trim()}`));
33
+ else
34
+ resolve(out);
35
+ });
36
+ });
37
+ }
38
+ const REVIEW_TEMPLATE = (diff, focus) => `Review the unified diff below as a senior staff engineer. Reason only from the diff text — do not attempt to read files, run commands, or browse the web.
39
+
40
+ ${focus ? `Focus area: ${focus}\n\n` : ""}Score each dimension 1-10:
41
+ 1. Correctness
42
+ 2. Readability
43
+ 3. Architecture
44
+ 4. Security
45
+ 5. Performance
46
+
47
+ Respond in markdown with:
48
+ - One-line verdict (LGTM / Approve with comments / Request changes / Block)
49
+ - Per-dimension score with a one-line justification
50
+ - A short list of the most important concerns visible in the diff
51
+
52
+ --- DIFF START ---
53
+ ${diff}
54
+ --- DIFF END ---`;
55
+ export const grokReview = defineTool({
56
+ name: "grok_review",
57
+ description: "Have Grok review a git diff. If no diff is provided, runs `git diff <base_ref>...HEAD` (default base: main). Returns a structured review with per-dimension scores.",
58
+ inputSchema,
59
+ async handler({ diff, base_ref, focus, model, cwd, timeout }) {
60
+ const actualDiff = diff ?? (await gitDiff(base_ref ?? "main", cwd));
61
+ if (!actualDiff.trim()) {
62
+ return "No diff to review (empty result from git diff).";
63
+ }
64
+ const { stdout } = await runGrok(REVIEW_TEMPLATE(actualDiff, focus), {
65
+ model,
66
+ ...timeoutOpts(timeout),
67
+ });
68
+ return stdout;
69
+ },
70
+ });
71
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/tools/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ export interface ToolDefinition<S extends z.ZodTypeAny> {
3
+ name: string;
4
+ description: string;
5
+ inputSchema: S;
6
+ handler: (input: z.infer<S>) => Promise<string>;
7
+ }
8
+ export interface ErasedTool {
9
+ name: string;
10
+ description: string;
11
+ inputSchema: z.ZodTypeAny;
12
+ handler: (input: unknown) => Promise<string>;
13
+ }
14
+ export declare function defineTool<S extends z.ZodTypeAny>(def: ToolDefinition<S>): ErasedTool;
15
+ /** Shared per-call timeout field (seconds). All tools expose this. */
16
+ export declare const timeoutField: z.ZodOptional<z.ZodNumber>;
17
+ /** Convert an optional seconds value into the { timeoutMs } shape runGrok expects. */
18
+ export declare function timeoutOpts(timeout?: number): {
19
+ timeoutMs?: number;
20
+ };
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ export function defineTool(def) {
3
+ return def;
4
+ }
5
+ /** Shared per-call timeout field (seconds). All tools expose this. */
6
+ export const timeoutField = z
7
+ .number()
8
+ .positive()
9
+ .optional()
10
+ .describe("Per-call timeout in seconds. Defaults to 300. Raise for long grok-4 reasoning.");
11
+ /** Convert an optional seconds value into the { timeoutMs } shape runGrok expects. */
12
+ export function timeoutOpts(timeout) {
13
+ return timeout === undefined ? {} : { timeoutMs: Math.round(timeout * 1000) };
14
+ }
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgBxB,MAAM,UAAU,UAAU,CAAyB,GAAsB;IACvE,OAAO,GAA4B,CAAC;AACtC,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,MAAM,EAAE;KACR,QAAQ,EAAE;KACV,QAAQ,EAAE;KACV,QAAQ,CAAC,gFAAgF,CAAC,CAAC;AAE9F,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;AAChF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "grok-cli-mcp",
3
+ "version": "0.1.3",
4
+ "description": "MCP server that wraps the xAI Grok CLI. Exposes grok_chat, grok_review, grok_consult, and grok_challenge so Claude Code, Cursor, Cline, and other MCP hosts can use Grok as a peer reviewer, adversary, and second-opinion consultant.",
5
+ "type": "module",
6
+ "bin": {
7
+ "grok-cli-mcp": "dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "mcpName": "io.github.howardpen9/grok-mcp",
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "README.zh-TW.md",
15
+ "LICENSE"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsc --watch",
20
+ "start": "node dist/index.js",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "prepublishOnly": "npm run build && npm test"
24
+ },
25
+ "keywords": [
26
+ "mcp",
27
+ "model-context-protocol",
28
+ "grok",
29
+ "xai",
30
+ "ai",
31
+ "claude-code",
32
+ "cursor",
33
+ "cline",
34
+ "code-review",
35
+ "adversarial-testing",
36
+ "second-opinion"
37
+ ],
38
+ "author": "Howard Peng <howard.peng.tw@gmail.com>",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/howardpen9/grok-mcp.git"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/howardpen9/grok-mcp/issues"
46
+ },
47
+ "homepage": "https://github.com/howardpen9/grok-mcp#readme",
48
+ "engines": {
49
+ "node": ">=18"
50
+ },
51
+ "dependencies": {
52
+ "@modelcontextprotocol/sdk": "^1.0.4",
53
+ "strip-ansi": "^7.1.0",
54
+ "zod": "^3.23.8",
55
+ "zod-to-json-schema": "^3.23.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^20.14.0",
59
+ "typescript": "^5.5.0",
60
+ "vitest": "^2.0.0"
61
+ }
62
+ }