@danwahl/gemini-cli-mcp 0.1.4 → 0.1.6

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/README.md CHANGED
@@ -34,16 +34,16 @@ npm run build
34
34
  **User install** (available across all projects):
35
35
 
36
36
  ```sh
37
- claude mcp add --scope user gemini npx -- -y @danwahl/gemini-cli-mcp
37
+ claude mcp add gemini-cli -s user -- npx -y @danwahl/gemini-cli-mcp
38
38
  ```
39
39
 
40
40
  **Project install** (shared with your team via `.mcp.json`):
41
41
 
42
42
  ```sh
43
- claude mcp add --scope project gemini npx -- -y @danwahl/gemini-cli-mcp
43
+ claude mcp add gemini-cli -s project -- npx -y @danwahl/gemini-cli-mcp
44
44
  ```
45
45
 
46
- Or from source, replace `npx @danwahl/gemini-cli-mcp` with `node /absolute/path/to/gemini-cli-mcp/cli.js`.
46
+ Or from source, replace `npx -y @danwahl/gemini-cli-mcp` with `node /absolute/path/to/gemini-cli-mcp/dist/index.js`.
47
47
 
48
48
  Verify with `claude mcp list`.
49
49
 
@@ -96,14 +96,14 @@ Gemini runs with `--approval-mode yolo`, giving it full tool access: read/write
96
96
  ## Development
97
97
 
98
98
  ```sh
99
- npm run build # compile with tsdown
99
+ npm run build # compile with tsc
100
100
  npm test # run unit tests
101
101
  ```
102
102
 
103
103
  ### Smoke test
104
104
 
105
105
  ```sh
106
- echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node cli.js
106
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/index.js
107
107
  ```
108
108
 
109
109
  ## Design
package/dist/index.js CHANGED
@@ -1,221 +1,79 @@
1
+ #!/usr/bin/env node
1
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
4
  import { createRequire } from "node:module";
4
5
  import { z } from "zod";
5
- import { spawn } from "node:child_process";
6
- import { existsSync } from "node:fs";
7
-
8
- //#region src/lib.ts
9
- function buildGeminiArgs(prompt, model, sessionId, outputFormat = "json") {
10
- const args = [
11
- "-p",
12
- prompt,
13
- "--output-format",
14
- outputFormat,
15
- "--approval-mode",
16
- "yolo"
17
- ];
18
- if (model) args.push("--model", model);
19
- if (sessionId) args.push("--resume", sessionId);
20
- return args;
21
- }
22
- function parseGeminiOutput(stdout) {
23
- const trimmed = stdout.trim();
24
- if (!trimmed) return {
25
- sessionId: null,
26
- response: ""
27
- };
28
- try {
29
- const parsed = JSON.parse(trimmed);
30
- if (parsed !== null && typeof parsed === "object" && "response" in parsed && typeof parsed.response === "string") {
31
- const obj = parsed;
32
- return {
33
- sessionId: typeof obj.session_id === "string" ? obj.session_id : null,
34
- response: obj.response,
35
- stats: typeof obj.stats === "object" && obj.stats !== null ? obj.stats : void 0
36
- };
37
- }
38
- return {
39
- sessionId: null,
40
- response: trimmed
41
- };
42
- } catch {
43
- return {
44
- sessionId: null,
45
- response: trimmed
46
- };
47
- }
48
- }
49
- function extractStructuredOutput(output) {
50
- const models = {};
51
- const tools = {};
52
- const stats = output.stats;
53
- if (stats) {
54
- if (stats.models && typeof stats.models === "object") {
55
- for (const [name, modelStats] of Object.entries(stats.models)) if (modelStats && typeof modelStats === "object") {
56
- const t = modelStats.tokens;
57
- if (t && typeof t === "object" && typeof t.total === "number") models[name] = t.total;
58
- }
59
- }
60
- if (stats.tools && typeof stats.tools === "object") {
61
- const byName = stats.tools.byName;
62
- if (byName && typeof byName === "object") {
63
- for (const [name, toolStats] of Object.entries(byName)) if (toolStats && typeof toolStats === "object") {
64
- const count = toolStats.count;
65
- if (typeof count === "number") tools[name] = count;
66
- }
67
- }
68
- }
69
- }
70
- return {
71
- sessionId: output.sessionId,
72
- response: output.response,
73
- models,
74
- tools
75
- };
76
- }
77
- function runGemini(prompt, cwd, model, timeoutMs, sessionId) {
78
- if (!existsSync(cwd)) return Promise.resolve({
79
- output: {
80
- sessionId: null,
81
- response: ""
82
- },
83
- isError: true,
84
- errorMessage: `Working directory does not exist: ${cwd}`
85
- });
86
- return new Promise((resolve) => {
87
- const args = buildGeminiArgs(prompt, model, sessionId);
88
- let child;
89
- try {
90
- child = spawn("gemini", args, {
91
- cwd,
92
- env: process.env
93
- });
94
- } catch (err) {
95
- resolve({
96
- output: {
97
- sessionId: null,
98
- response: ""
99
- },
100
- isError: true,
101
- errorMessage: `Failed to spawn gemini: ${String(err)}. Is gemini-cli installed? Try: npm install -g @google/gemini-cli`
102
- });
103
- return;
104
- }
105
- let stdout = "";
106
- let stderr = "";
107
- let timedOut = false;
108
- const timer = setTimeout(() => {
109
- timedOut = true;
110
- child.kill("SIGTERM");
111
- setTimeout(() => {
112
- try {
113
- child.kill("SIGKILL");
114
- } catch {}
115
- }, 5e3);
116
- }, timeoutMs);
117
- child.stdout?.on("data", (chunk) => {
118
- stdout += chunk.toString();
119
- });
120
- child.stderr?.on("data", (chunk) => {
121
- stderr += chunk.toString();
122
- });
123
- child.on("error", (err) => {
124
- clearTimeout(timer);
125
- const isNotFound = err.code === "ENOENT" || err.message.includes("ENOENT");
126
- resolve({
127
- output: {
128
- sessionId: null,
129
- response: ""
130
- },
131
- isError: true,
132
- errorMessage: isNotFound ? `gemini binary not found. Install with: npm install -g @google/gemini-cli` : `Failed to spawn gemini: ${err.message}`
133
- });
134
- });
135
- child.on("close", (code) => {
136
- clearTimeout(timer);
137
- if (timedOut) {
138
- resolve({
139
- output: {
140
- sessionId: null,
141
- response: ""
142
- },
143
- isError: true,
144
- errorMessage: `gemini timed out after ${timeoutMs / 1e3}s`
145
- });
146
- return;
147
- }
148
- if (code !== 0) {
149
- const detail = stderr.trim() || stdout.trim() || `exit code ${code}`;
150
- resolve({
151
- output: {
152
- sessionId: null,
153
- response: ""
154
- },
155
- isError: true,
156
- errorMessage: `gemini exited with code ${code}: ${detail}`
157
- });
158
- return;
159
- }
160
- resolve({
161
- output: parseGeminiOutput(stdout),
162
- isError: false
163
- });
164
- });
165
- });
166
- }
167
-
168
- //#endregion
169
- //#region src/index.ts
6
+ import { runGemini, extractStructuredOutput } from "./lib.js";
170
7
  const { version } = createRequire(import.meta.url)("../package.json");
171
8
  const server = new McpServer({
172
- name: "gemini-cli-mcp",
173
- version
9
+ name: "gemini-cli-mcp",
10
+ version,
174
11
  });
175
12
  server.registerTool("cli", {
176
- description: "Send a task or question to Gemini CLI and return the response. Gemini runs headlessly with full tool access (file read/write, web search, shell commands). Use this to delegate tasks that benefit from Gemini's capabilities or to get a second opinion.",
177
- inputSchema: {
178
- prompt: z.string().describe("The task or question to send to Gemini CLI"),
179
- cwd: z.string().describe("Absolute path to the working directory for Gemini to operate in"),
180
- model: z.string().optional().describe("Model to use. Omit to use Gemini CLI's default (auto). Official aliases: \"auto\" (default routing), \"pro\" (complex reasoning), \"flash\" (fast, balanced), \"flash-lite\" (fastest). Or pass a concrete model name like \"gemini-2.5-pro\"."),
181
- sessionId: z.string().optional().describe("Resume a previous Gemini session by ID. The session ID is returned in the structured output of each call.")
182
- },
183
- outputSchema: {
184
- sessionId: z.string().nullable().describe("Gemini CLI session ID"),
185
- response: z.string().describe("Gemini's text response"),
186
- models: z.record(z.string(), z.number()).describe("Model name total tokens used"),
187
- tools: z.record(z.string(), z.number()).describe("Tool name call count")
188
- },
189
- annotations: {
190
- readOnlyHint: false,
191
- openWorldHint: true
192
- }
13
+ description: "Send a task to Gemini CLI and return the response. " +
14
+ "Gemini runs headlessly with full tool access (file read/write, web search, shell commands) " +
15
+ "and operates in the working directory you specify via `cwd`.\n\n" +
16
+ "When to use this tool:\n" +
17
+ "- Delegating rote coding tasks: boilerplate generation, repetitive refactors, bulk edits across many files\n" +
18
+ "- Getting a second opinion: code review, architecture feedback, sanity-checking an approach\n" +
19
+ "- Research and brainstorming: Gemini has web search and a large context window, useful for exploring options or summarizing docs\n" +
20
+ "- Large file analysis: processing files that would be expensive to handle directly\n" +
21
+ "- Parallel workstreams: offloading independent subtasks while you continue other work\n\n" +
22
+ "Session resumption: each response includes a `sessionId`. " +
23
+ "Pass it back via the `sessionId` parameter to continue a conversation " +
24
+ "without re-sending context useful for multi-step tasks or follow-up questions.\n\n" +
25
+ "Keep prompts self-contained: include all necessary context in the `prompt` since " +
26
+ "Gemini has no access to your conversation history or MCP state.",
27
+ inputSchema: {
28
+ prompt: z
29
+ .string()
30
+ .describe("The task or question to send to Gemini CLI"),
31
+ cwd: z
32
+ .string()
33
+ .describe("Absolute path to the working directory for Gemini to operate in"),
34
+ model: z
35
+ .string()
36
+ .optional()
37
+ .describe("Model to use. Omit to use Gemini CLI's default (auto). " +
38
+ "Official aliases: \"auto\" (default routing), \"pro\" (complex reasoning), " +
39
+ "\"flash\" (fast, balanced), \"flash-lite\" (fastest). " +
40
+ "Or pass a concrete model name like \"gemini-2.5-pro\"."),
41
+ sessionId: z
42
+ .string()
43
+ .optional()
44
+ .describe("Resume a previous Gemini session by ID. The session ID is returned in the structured output of each call."),
45
+ },
46
+ outputSchema: {
47
+ sessionId: z.string().nullable().describe("Gemini CLI session ID"),
48
+ response: z.string().describe("Gemini's text response"),
49
+ models: z.record(z.string(), z.number()).describe("Model name → total tokens used"),
50
+ tools: z.record(z.string(), z.number()).describe("Tool name → call count"),
51
+ },
52
+ annotations: {
53
+ readOnlyHint: false,
54
+ openWorldHint: true,
55
+ },
193
56
  }, async ({ prompt, cwd, model, sessionId }) => {
194
- const timeoutMs = 12e4;
195
- const result = await runGemini(prompt, cwd, model, timeoutMs, sessionId);
196
- if (result.isError) return {
197
- isError: true,
198
- content: [{
199
- type: "text",
200
- text: result.errorMessage ?? "Unknown error"
201
- }],
202
- structuredContent: {
203
- sessionId: null,
204
- response: "",
205
- models: {},
206
- tools: {}
207
- }
208
- };
209
- const structured = extractStructuredOutput(result.output);
210
- return {
211
- content: [{
212
- type: "text",
213
- text: structured.response
214
- }],
215
- structuredContent: structured
216
- };
57
+ const timeoutMs = 120_000;
58
+ const result = await runGemini(prompt, cwd, model, timeoutMs, sessionId);
59
+ if (result.isError) {
60
+ return {
61
+ isError: true,
62
+ content: [{ type: "text", text: result.errorMessage ?? "Unknown error" }],
63
+ structuredContent: { sessionId: null, response: "", models: {}, tools: {} },
64
+ };
65
+ }
66
+ const structured = extractStructuredOutput(result.output);
67
+ return {
68
+ content: [{ type: "text", text: structured.response }],
69
+ structuredContent: structured,
70
+ };
71
+ });
72
+ async function runServer() {
73
+ const transport = new StdioServerTransport();
74
+ await server.connect(transport);
75
+ }
76
+ runServer().catch((error) => {
77
+ console.error("Fatal error:", error);
78
+ process.exit(1);
217
79
  });
218
- const transport = new StdioServerTransport();
219
- await server.connect(transport);
220
-
221
- //#endregion
package/dist/lib.js ADDED
@@ -0,0 +1,149 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ export function buildGeminiArgs(prompt, model, sessionId, outputFormat = "json") {
4
+ const args = ["-p", prompt, "--output-format", outputFormat, "--approval-mode", "yolo"];
5
+ if (model) {
6
+ args.push("--model", model);
7
+ }
8
+ if (sessionId) {
9
+ args.push("--resume", sessionId);
10
+ }
11
+ return args;
12
+ }
13
+ export function parseGeminiOutput(stdout) {
14
+ const trimmed = stdout.trim();
15
+ if (!trimmed) {
16
+ return { sessionId: null, response: "" };
17
+ }
18
+ try {
19
+ const parsed = JSON.parse(trimmed);
20
+ if (parsed !== null &&
21
+ typeof parsed === "object" &&
22
+ "response" in parsed &&
23
+ typeof parsed.response === "string") {
24
+ const obj = parsed;
25
+ return {
26
+ sessionId: typeof obj.session_id === "string" ? obj.session_id : null,
27
+ response: obj.response,
28
+ stats: typeof obj.stats === "object" && obj.stats !== null
29
+ ? obj.stats
30
+ : undefined,
31
+ };
32
+ }
33
+ return { sessionId: null, response: trimmed };
34
+ }
35
+ catch {
36
+ return { sessionId: null, response: trimmed };
37
+ }
38
+ }
39
+ export function extractStructuredOutput(output) {
40
+ const models = {};
41
+ const tools = {};
42
+ const stats = output.stats;
43
+ if (stats) {
44
+ if (stats.models && typeof stats.models === "object") {
45
+ for (const [name, modelStats] of Object.entries(stats.models)) {
46
+ if (modelStats && typeof modelStats === "object") {
47
+ const t = modelStats.tokens;
48
+ if (t && typeof t === "object" && typeof t.total === "number") {
49
+ models[name] = t.total;
50
+ }
51
+ }
52
+ }
53
+ }
54
+ if (stats.tools && typeof stats.tools === "object") {
55
+ const byName = stats.tools.byName;
56
+ if (byName && typeof byName === "object") {
57
+ for (const [name, toolStats] of Object.entries(byName)) {
58
+ if (toolStats && typeof toolStats === "object") {
59
+ const count = toolStats.count;
60
+ if (typeof count === "number")
61
+ tools[name] = count;
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ return { sessionId: output.sessionId, response: output.response, models, tools };
68
+ }
69
+ export function runGemini(prompt, cwd, model, timeoutMs, sessionId) {
70
+ if (!existsSync(cwd)) {
71
+ return Promise.resolve({
72
+ output: { sessionId: null, response: "" },
73
+ isError: true,
74
+ errorMessage: `Working directory does not exist: ${cwd}`,
75
+ });
76
+ }
77
+ return new Promise((resolve) => {
78
+ const args = buildGeminiArgs(prompt, model, sessionId);
79
+ let child;
80
+ try {
81
+ child = spawn("gemini", args, { cwd, env: process.env });
82
+ }
83
+ catch (err) {
84
+ resolve({
85
+ output: { sessionId: null, response: "" },
86
+ isError: true,
87
+ errorMessage: `Failed to spawn gemini: ${String(err)}. Is gemini-cli installed? Try: npm install -g @google/gemini-cli`,
88
+ });
89
+ return;
90
+ }
91
+ let stdout = "";
92
+ let stderr = "";
93
+ let timedOut = false;
94
+ const timer = setTimeout(() => {
95
+ timedOut = true;
96
+ child.kill("SIGTERM");
97
+ setTimeout(() => {
98
+ try {
99
+ child.kill("SIGKILL");
100
+ }
101
+ catch {
102
+ // already dead
103
+ }
104
+ }, 5000);
105
+ }, timeoutMs);
106
+ child.stdout?.on("data", (chunk) => {
107
+ stdout += chunk.toString();
108
+ });
109
+ child.stderr?.on("data", (chunk) => {
110
+ stderr += chunk.toString();
111
+ });
112
+ child.on("error", (err) => {
113
+ clearTimeout(timer);
114
+ const isNotFound = err.code === "ENOENT" ||
115
+ err.message.includes("ENOENT");
116
+ resolve({
117
+ output: { sessionId: null, response: "" },
118
+ isError: true,
119
+ errorMessage: isNotFound
120
+ ? `gemini binary not found. Install with: npm install -g @google/gemini-cli`
121
+ : `Failed to spawn gemini: ${err.message}`,
122
+ });
123
+ });
124
+ child.on("close", (code) => {
125
+ clearTimeout(timer);
126
+ if (timedOut) {
127
+ resolve({
128
+ output: { sessionId: null, response: "" },
129
+ isError: true,
130
+ errorMessage: `gemini timed out after ${timeoutMs / 1000}s`,
131
+ });
132
+ return;
133
+ }
134
+ if (code !== 0) {
135
+ const detail = stderr.trim() || stdout.trim() || `exit code ${code}`;
136
+ resolve({
137
+ output: { sessionId: null, response: "" },
138
+ isError: true,
139
+ errorMessage: `gemini exited with code ${code}: ${detail}`,
140
+ });
141
+ return;
142
+ }
143
+ resolve({
144
+ output: parseGeminiOutput(stdout),
145
+ isError: false,
146
+ });
147
+ });
148
+ });
149
+ }
@@ -0,0 +1,145 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { buildGeminiArgs, parseGeminiOutput, extractStructuredOutput, } from "./lib.ts";
4
+ describe("buildGeminiArgs", () => {
5
+ it("omits --model when not provided", () => {
6
+ const args = buildGeminiArgs("hello", undefined);
7
+ assert.ok(!args.includes("--model"));
8
+ });
9
+ it("includes --model when provided", () => {
10
+ const args = buildGeminiArgs("hello", "gemini-2.5-pro");
11
+ const idx = args.indexOf("--model");
12
+ assert.ok(idx !== -1);
13
+ assert.equal(args[idx + 1], "gemini-2.5-pro");
14
+ });
15
+ it("passes model string through unchanged", () => {
16
+ const args = buildGeminiArgs("hello", "gemini-1.5-flash-001");
17
+ assert.equal(args[args.indexOf("--model") + 1], "gemini-1.5-flash-001");
18
+ });
19
+ it("includes --resume when sessionId provided", () => {
20
+ const args = buildGeminiArgs("x", undefined, "my-session-id");
21
+ const idx = args.indexOf("--resume");
22
+ assert.ok(idx !== -1);
23
+ assert.equal(args[idx + 1], "my-session-id");
24
+ });
25
+ it("omits --resume when sessionId not provided", () => {
26
+ const args = buildGeminiArgs("x", undefined);
27
+ assert.ok(!args.includes("--resume"));
28
+ });
29
+ it("includes --approval-mode yolo", () => {
30
+ const args = buildGeminiArgs("x", undefined);
31
+ const idx = args.indexOf("--approval-mode");
32
+ assert.ok(idx !== -1);
33
+ assert.equal(args[idx + 1], "yolo");
34
+ });
35
+ it("includes --output-format json", () => {
36
+ const args = buildGeminiArgs("x", undefined);
37
+ const idx = args.indexOf("--output-format");
38
+ assert.ok(idx !== -1);
39
+ assert.equal(args[idx + 1], "json");
40
+ });
41
+ });
42
+ describe("parseGeminiOutput", () => {
43
+ it("parses valid JSON response", () => {
44
+ const result = parseGeminiOutput(JSON.stringify({ response: "Hello, world!" }));
45
+ assert.equal(result.response, "Hello, world!");
46
+ assert.equal(result.sessionId, null);
47
+ assert.equal(result.stats, undefined);
48
+ });
49
+ it("extracts session_id", () => {
50
+ const result = parseGeminiOutput(JSON.stringify({ session_id: "abc-123", response: "ok" }));
51
+ assert.equal(result.sessionId, "abc-123");
52
+ });
53
+ it("extracts stats field", () => {
54
+ const stats = { models: {}, tools: {} };
55
+ const result = parseGeminiOutput(JSON.stringify({ response: "ok", stats }));
56
+ assert.deepEqual(result.stats, stats);
57
+ });
58
+ it("handles missing stats gracefully", () => {
59
+ const result = parseGeminiOutput(JSON.stringify({ response: "ok" }));
60
+ assert.equal(result.stats, undefined);
61
+ });
62
+ it("returns raw stdout when JSON parsing fails", () => {
63
+ const raw = "this is not json";
64
+ const result = parseGeminiOutput(raw);
65
+ assert.equal(result.response, raw);
66
+ assert.equal(result.sessionId, null);
67
+ });
68
+ it("returns raw stdout for JSON without response field", () => {
69
+ const raw = JSON.stringify({ message: "unexpected shape" });
70
+ const result = parseGeminiOutput(raw);
71
+ assert.equal(result.response, raw);
72
+ });
73
+ it("handles empty stdout", () => {
74
+ const result = parseGeminiOutput("");
75
+ assert.equal(result.response, "");
76
+ });
77
+ it("trims surrounding whitespace before parsing", () => {
78
+ const result = parseGeminiOutput(" " + JSON.stringify({ response: "trimmed" }) + "\n");
79
+ assert.equal(result.response, "trimmed");
80
+ });
81
+ });
82
+ describe("extractStructuredOutput", () => {
83
+ it("passes through sessionId and response", () => {
84
+ const output = { sessionId: "abc", response: "hello" };
85
+ const result = extractStructuredOutput(output);
86
+ assert.equal(result.sessionId, "abc");
87
+ assert.equal(result.response, "hello");
88
+ });
89
+ it("returns empty records when no stats", () => {
90
+ const output = { sessionId: null, response: "hi" };
91
+ const result = extractStructuredOutput(output);
92
+ assert.deepEqual(result.models, {});
93
+ assert.deepEqual(result.tools, {});
94
+ });
95
+ it("extracts model token totals", () => {
96
+ const output = {
97
+ sessionId: null,
98
+ response: "hi",
99
+ stats: {
100
+ models: {
101
+ "gemini-2.5-pro": { tokens: { total: 100 } },
102
+ "gemini-2.0-flash": { tokens: { total: 50 } },
103
+ },
104
+ },
105
+ };
106
+ assert.deepEqual(extractStructuredOutput(output).models, {
107
+ "gemini-2.5-pro": 100,
108
+ "gemini-2.0-flash": 50,
109
+ });
110
+ });
111
+ it("omits models with no token data", () => {
112
+ const output = {
113
+ sessionId: null,
114
+ response: "hi",
115
+ stats: { models: { "gemini-2.5-pro": {} } },
116
+ };
117
+ assert.deepEqual(extractStructuredOutput(output).models, {});
118
+ });
119
+ it("extracts tool call counts from byName", () => {
120
+ const output = {
121
+ sessionId: null,
122
+ response: "hi",
123
+ stats: {
124
+ tools: {
125
+ byName: {
126
+ list_directory: { count: 2 },
127
+ web_fetch: { count: 1 },
128
+ },
129
+ },
130
+ },
131
+ };
132
+ assert.deepEqual(extractStructuredOutput(output).tools, {
133
+ list_directory: 2,
134
+ web_fetch: 1,
135
+ });
136
+ });
137
+ it("returns empty tools when no tool calls", () => {
138
+ const output = {
139
+ sessionId: null,
140
+ response: "hi",
141
+ stats: { tools: { totalCalls: 0, byName: {} } },
142
+ };
143
+ assert.deepEqual(extractStructuredOutput(output).tools, {});
144
+ });
145
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@danwahl/gemini-cli-mcp",
3
3
  "type": "module",
4
- "version": "0.1.4",
4
+ "version": "0.1.6",
5
5
  "description": "MCP server that exposes Gemini CLI as a single tool for Claude Code",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -10,15 +10,14 @@
10
10
  },
11
11
  "keywords": ["mcp", "gemini", "claude", "llm", "ai"],
12
12
  "engines": { "node": ">=18" },
13
- "bin": { "gemini-cli-mcp": "./cli.js" },
13
+ "bin": { "gemini-cli-mcp": "dist/index.js" },
14
14
  "scripts": {
15
- "build": "tsdown src/index.ts",
16
- "test": "node --import tsx/esm --test src/index.test.ts",
15
+ "build": "tsc && shx chmod +x dist/*.js",
16
+ "test": "node --import tsx/esm --test src/lib.test.ts",
17
17
  "prepublishOnly": "npm run build"
18
18
  },
19
19
  "files": [
20
- "dist",
21
- "cli.js"
20
+ "dist"
22
21
  ],
23
22
  "dependencies": {
24
23
  "@modelcontextprotocol/sdk": "^1.21.0",
@@ -26,7 +25,7 @@
26
25
  },
27
26
  "devDependencies": {
28
27
  "@types/node": "^25.3.3",
29
- "tsdown": "^0.10.0",
28
+ "shx": "^0.3.4",
30
29
  "tsx": "^4.21.0",
31
30
  "typescript": "^5.8.0"
32
31
  }
package/cli.js DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./dist/index.js"