Modernise MCP stack, improve stability, and preserve Gemini CLI OAuth#65
Modernise MCP stack, improve stability, and preserve Gemini CLI OAuth#65jacobcxdev wants to merge 19 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request transitions the project to a fork that routes Gemini calls through the local CLI to preserve OAuth, adding a hardened executor and improved error handling. However, the PR contains critical bugs including hallucinated dependency versions and calls to non-existent library functions. Additionally, the changes introduce cross-platform compatibility issues and a regression by disabling progress notifications globally.
There was a problem hiding this comment.
Pull request overview
This PR modernizes the MCP server’s dependency stack while preserving the “Gemini CLI OAuth via gemini -p ...” execution path, and adds local verification scripts aimed at improving stability—especially under Claude Code—by hardening CLI execution and instrumenting/debugging the stdio lifecycle.
Changes:
- Upgrades MCP SDK + broader dependency refresh (including Zod v4 compatibility changes).
- Replaces the previous command execution utility with a hardened
spawn-based CLI executor + adds smoke/stability scripts. - Adds extensive stdio/server tracing and disables progress notifications to avoid a Claude Code stdio disconnect.
Reviewed changes
Copilot reviewed 17 out of 19 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Adds Node types to align TS compilation with Node globals. |
| src/utils/logger.ts | Makes most logging debug-gated and routes logs to stderr. |
| src/utils/geminiExecutor.ts | Switches Gemini CLI invocation to the new CLI executor and trims stdout. |
| src/utils/fileTrace.ts | Adds file-based trace utility for runtime diagnostics. |
| src/utils/cliExecutor.ts | Introduces hardened CLI execution wrapper around child_process.spawn. |
| src/tools/simple-tools.ts | Migrates simple tools to the new CLI executor and returns trimmed stdout. |
| src/tools/registry.ts | Updates Zod → JSON Schema conversion and tweaks argument parsing flow. |
| src/index.ts | Adds extensive lifecycle tracing, removes notifications capability, and disables progress tokens. |
| scripts/test-mcp-stability.mjs | Adds repeated Gemini CLI OAuth smoke test script. |
| scripts/test-mcp-client-stability.mjs | Adds repeated MCP client request stability test script. |
| package.json | Renames fork package + adds verify/smoke scripts and major dependency upgrades. |
| package-lock.json | Locks updated dependency graph for the refreshed stack. |
| docs/superpowers/plans/2026-04-26-gemini-cli-oauth-stability.md | Adds implementation plan documenting the stability work. |
| docs/installation.md | Updates install docs toward local fork usage. |
| docs/index.md | Updates docs site links to point at the fork. |
| docs/getting-started.md | Updates getting started flow for local fork + OAuth guidance. |
| docs/api.md | Documents tool behavior and stability validation steps. |
| README.md | Updates project positioning, fork links, and setup steps. |
| CHANGELOG.md | Adds unreleased notes about the stability/OAuth preservation work. |
Comments suppressed due to low confidence (2)
docs/getting-started.md:126
- The Warp config example sets
command: "node"but still usesargs: ["-y", "gemini-mcp-tool"](an NPX pattern). This won’t work withnode; update the example to pass the builtdist/index.jspath (or switchcommandback tonpxif that’s intended).
```json
{
"gemini-cli": {
"command": "node",
"args": [
"-y",
"gemini-mcp-tool"
],
src/tools/registry.ts:73
executeToolis currently written as a single-lineif (...) { ... } try { ... } catch { ... }statement. This makes the control flow hard to read/review and is easy to break with future edits; please reformat into a normal multi-line block structure (and ensure consistent semicolons/ASI safety).
export async function executeTool(toolName: string, args: ToolArguments, onProgress?: (newOutput: string) => void): Promise<string> {
const tool = toolRegistry.find(t => t.name === toolName);
if (!tool) { throw new Error(`Unknown tool: ${toolName}`); } try { const validatedArgs = tool.zodSchema.parse(args) as ToolArguments;
return tool.execute(validatedArgs, onProgress);
} catch (error) { if (error instanceof ZodError) {
const issues = error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}`).join(', ');
throw new Error(`Invalid arguments for ${toolName}: ${issues}`);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Keep the upstream PR free of fork-only metadata while making diagnostics opt-in, progress notifications configurable, and child process exits report signalled termination correctly.
Make the API page client-agnostic and lower the declared Node.js floor to the truthful minimum supported by the current dependency set.
- Add vitest as devDependency
- Update test script to run vitest
- Add geminiExecutor.test.ts with four assertions:
1. noFallback=true propagates QUOTA_EXCEEDED unchanged
2. noFallback=false retains default fallback behaviour
3. GEMINI_MCP_NO_FALLBACK=1 env var triggers gate without flag
4. Normal success path unaffected with noFallback=true
- Tests 1 and 3 currently fail (gate not yet implemented)
Add opt-in --no-fallback CLI flag and GEMINI_MCP_NO_FALLBACK=1 env var to gate the automatic quota-exceeded fallback from gemini-2.5-pro to gemini-2.5-flash. When either is set, a 429/quota-exceeded error propagates unchanged to the caller instead of silently downgrading. Default behaviour is unchanged for callers that do not set the flag, preserving backwards compatibility. Changes: - geminiExecutor.ts: add noFallback? parameter; insert noFallbackEffective gate before the Logger.warn + fallback block in the QUOTA_EXCEEDED catch - index.ts: parse --no-fallback from process.argv; inject noFallback into tool args so the flag flows through the MCP dispatch layer - ask-gemini.tool.ts: extract noFallback from args and pass to executeGeminiCLI - constants.ts: add noFallback?: boolean to ToolArguments interface
- Rename package from gemini-mcp-tool to @jacobcxdev/gemini-mcp-tool - Bump version to 1.2.0 - Add CHANGELOG entry for --no-fallback addition - Update server version string in index.ts
…OG entry" This reverts commit d5fd762.
This reverts commit c9ca8c5.
This reverts commit 921e31f.
|
Thanks again for putting this together, and for the clearly serious effort behind it. I can see you set out to modernize and harden the tool, and I appreciate that. I want to be straight about where it actually lands rather than leave you guessing, so here is the honest read claim by claim. A fair amount of this comes down to context that lives in commits I merged after the On the security motivation: I checked what That focus matters, because this is not really an SDK bump. It also moves On the hardened CLI executor: the new On progress notifications: this is the one I want to flag most clearly. The change disables progress by default for every client and hides it behind The parts I do want to take from this: the Claude Code bug report itself, and the OAuth documentation clarifying that So the plan: I will do the |
Fixes #64.
Summary
What changed
General improvements
@modelcontextprotocol/sdkto the current release linegemini -p ...)Claude Code compatibility workaround
In testing, Claude Code disconnects this stdio server after a successful
tools/callresponse if the request includes_meta.progressTokenand the server emits progress notifications.As a pragmatic workaround, this change makes progress notifications opt-in for this server path:
GEMINI_MCP_ENABLE_PROGRESS=1to re-enable them for clients that handle them correctlyThis appears to be a Claude Code bug rather than a fundamental server problem:
Anthropic bug report:
Diagnostics and portability
GEMINI_MCP_TRACE=1fileURLToPath(...)for cross-platform path handlingOAuth MCP configuration
Verified against official Gemini CLI auth selection:
GOOGLE_GENAI_USE_GCA=trueforcesoauth-personalbefore API-key auth. The docs now recommend settingHOME,GEMINI_CLI_HOME, andGOOGLE_GENAI_USE_GCA=truefor Claude MCP registrations that should use Google/OAuth rather thanGEMINI_API_KEY.Verification
npm run verifynpm run docs:buildNotes
This keeps the core project behaviour intact:
The declared Node.js floor is now
>=20.12.0, matching the current dependency set rather than the earlier stricter temporary requirement.