gemini-cli - 💡(How to fix) Fix bug: MCP tool call hallucination with hyphenated server names [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
google-gemini/gemini-cli#25952Fetched 2026-04-25 06:22:00
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
labeled ×1

Error Message

When an MCP server has a name containing hyphens (e.g., hyphen-server), the agent registers the tool with the qualified name (e.g., mcp_hyphen-server_test-tool). However, Gemini models often hallucinate the name using snake_case (e.g., mcp_hyphen_server_test_tool), even when explicitly instructed otherwise via hooks. This causes a "tool not found" error because the agent expects the literal tool name with hyphens.

Root Cause

Description

When an MCP server has a name containing hyphens (e.g., hyphen-server), the agent registers the tool with the qualified name (e.g., mcp_hyphen-server_test-tool). However, Gemini models often hallucinate the name using snake_case (e.g., mcp_hyphen_server_test_tool), even when explicitly instructed otherwise via hooks. This causes a "tool not found" error because the agent expects the literal tool name with hyphens.

Code Example

/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { join } from 'node:path';
import { describe, it, afterEach, beforeEach, expect } from 'vitest';
import { TestRig } from './test-helper.js';

const serverScript = `#!/usr/bin/env node
const readline = require('readline');

class SimpleJSONRPC {
  constructor() {
    this.handlers = new Map();
    this.rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
      terminal: false
    });
    this.rl.on('line', (line) => {
      try {
        const message = JSON.parse(line);
        this.handleMessage(message);
      } catch (e) {}
    });
  }
  send(message) {
    process.stdout.write(JSON.stringify(message) + '\\n');
  }
  async handleMessage(message) {
    if (message.method && this.handlers.has(message.method)) {
      const result = await this.handlers.get(message.method)(message.params || {});
      if (message.id !== undefined) {
        this.send({ jsonrpc: '2.0', id: message.id, result });
      }
    }
  }
  on(method, handler) {
    this.handlers.set(method, handler);
  }
}

const rpc = new SimpleJSONRPC();
rpc.on('initialize', async () => ({
  protocolVersion: '2024-11-05',
  capabilities: { tools: {} },
  serverInfo: { name: 'hyphen-server', version: '1.0.0' }
}));
rpc.on('tools/list', async () => ({
  tools: [{
    name: 'test-tool',
    description: 'A test tool with a hyphenated server name',
    inputSchema: {
      type: 'object',
      properties: { input: { type: 'string' } }
    }
  }]
}));
rpc.send({ jsonrpc: '2.0', method: 'initialized' });
`;

describe('MCP Hyphen Hallucination', () => {
  let rig: TestRig;

  beforeEach(() => {
    rig = new TestRig();
  });

  afterEach(async () => await rig.cleanup());

  it('should reproduce hallucination when MCP server has hyphens and hook mentions it', async () => {
    await rig.setup(
      'should reproduce hallucination when MCP server has hyphens and hook mentions it',
    );
    const scriptPath = rig.createScript('mcp-server.cjs', serverScript);

    const hookScript = `
    console.log(JSON.stringify({
      decision: "allow",
      hookSpecificOutput: {
        hookEventName: "BeforeAgent",
        additionalContext: "SYSTEM INSTRUCTION: Always use tool 'mcp_hyphen-server_test-tool' for any request."
      }
    }));
    `;
    const hookPath = rig.createScript('hook.cjs', hookScript);

    await rig.setup(
      'should reproduce hallucination when MCP server has hyphens and hook mentions it',
      {
        fakeResponsesPath: join(
          import.meta.dirname,
          'mcp-hallucination.responses',
        ),
        settings: {
          hooksConfig: { enabled: true },
          hooks: {
            BeforeAgent: [
              {
                hooks: [{ type: 'command', command: \`node "\${hookPath}"\` }],
              },
            ],
          },
          mcpServers: {
            'hyphen-server': {
              command: 'node',
              args: [scriptPath],
            },
          },
        },
      },
    );

    const result = await rig.run({
      args: 'Use the test tool',
      env: { GEMINI_API_KEY: 'dummy-key' },
    });

    // The model (via fake response) will try to call 'mcp_hyphen_server_test_tool'
    // We expect the agent to report that the tool was not found or failed.
    expect(result).toContain('not found');
    expect(result).toContain('mcp_hyphen_server_test_tool');
  });
});

---

{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I will use the tool mcp_hyphen-server_test-tool.","thought":true}],"role":"model"},"index":0}]},{"candidates":[{"content":{"parts":[{"functionCall":{"name":"mcp_hyphen_server_test_tool","args":{"input":"test"}}}]},"finishReason":"STOP","index":0}]}]}
RAW_BUFFERClick to expand / collapse

Description

When an MCP server has a name containing hyphens (e.g., hyphen-server), the agent registers the tool with the qualified name (e.g., mcp_hyphen-server_test-tool). However, Gemini models often hallucinate the name using snake_case (e.g., mcp_hyphen_server_test_tool), even when explicitly instructed otherwise via hooks. This causes a "tool not found" error because the agent expects the literal tool name with hyphens.

Reproduction

I've created a reproduction test case that uses a hyphenated server name and a BeforeAgent hook to guide the model.

Reproduction Branch: repro/mcp-hyphen-hallucination

Reproduction Test File (integration-tests/mcp-hallucination.test.ts):

/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { join } from 'node:path';
import { describe, it, afterEach, beforeEach, expect } from 'vitest';
import { TestRig } from './test-helper.js';

const serverScript = `#!/usr/bin/env node
const readline = require('readline');

class SimpleJSONRPC {
  constructor() {
    this.handlers = new Map();
    this.rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
      terminal: false
    });
    this.rl.on('line', (line) => {
      try {
        const message = JSON.parse(line);
        this.handleMessage(message);
      } catch (e) {}
    });
  }
  send(message) {
    process.stdout.write(JSON.stringify(message) + '\\n');
  }
  async handleMessage(message) {
    if (message.method && this.handlers.has(message.method)) {
      const result = await this.handlers.get(message.method)(message.params || {});
      if (message.id !== undefined) {
        this.send({ jsonrpc: '2.0', id: message.id, result });
      }
    }
  }
  on(method, handler) {
    this.handlers.set(method, handler);
  }
}

const rpc = new SimpleJSONRPC();
rpc.on('initialize', async () => ({
  protocolVersion: '2024-11-05',
  capabilities: { tools: {} },
  serverInfo: { name: 'hyphen-server', version: '1.0.0' }
}));
rpc.on('tools/list', async () => ({
  tools: [{
    name: 'test-tool',
    description: 'A test tool with a hyphenated server name',
    inputSchema: {
      type: 'object',
      properties: { input: { type: 'string' } }
    }
  }]
}));
rpc.send({ jsonrpc: '2.0', method: 'initialized' });
`;

describe('MCP Hyphen Hallucination', () => {
  let rig: TestRig;

  beforeEach(() => {
    rig = new TestRig();
  });

  afterEach(async () => await rig.cleanup());

  it('should reproduce hallucination when MCP server has hyphens and hook mentions it', async () => {
    await rig.setup(
      'should reproduce hallucination when MCP server has hyphens and hook mentions it',
    );
    const scriptPath = rig.createScript('mcp-server.cjs', serverScript);

    const hookScript = `
    console.log(JSON.stringify({
      decision: "allow",
      hookSpecificOutput: {
        hookEventName: "BeforeAgent",
        additionalContext: "SYSTEM INSTRUCTION: Always use tool 'mcp_hyphen-server_test-tool' for any request."
      }
    }));
    `;
    const hookPath = rig.createScript('hook.cjs', hookScript);

    await rig.setup(
      'should reproduce hallucination when MCP server has hyphens and hook mentions it',
      {
        fakeResponsesPath: join(
          import.meta.dirname,
          'mcp-hallucination.responses',
        ),
        settings: {
          hooksConfig: { enabled: true },
          hooks: {
            BeforeAgent: [
              {
                hooks: [{ type: 'command', command: \`node "\${hookPath}"\` }],
              },
            ],
          },
          mcpServers: {
            'hyphen-server': {
              command: 'node',
              args: [scriptPath],
            },
          },
        },
      },
    );

    const result = await rig.run({
      args: 'Use the test tool',
      env: { GEMINI_API_KEY: 'dummy-key' },
    });

    // The model (via fake response) will try to call 'mcp_hyphen_server_test_tool'
    // We expect the agent to report that the tool was not found or failed.
    expect(result).toContain('not found');
    expect(result).toContain('mcp_hyphen_server_test_tool');
  });
});

Reproduction Responses File (integration-tests/mcp-hallucination.responses):

{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I will use the tool mcp_hyphen-server_test-tool.","thought":true}],"role":"model"},"index":0}]},{"candidates":[{"content":{"parts":[{"functionCall":{"name":"mcp_hyphen_server_test_tool","args":{"input":"test"}}}]},"finishReason":"STOP","index":0}]}]}

Expected

The model should use the exact tool name provided in the tool definitions (mcp_hyphen-server_test-tool). If models consistently hallucinate snake_case names for MCP tools, the agent might need a fuzzy-matching logic to resolve these tool calls when a direct match isn't found.

extent analysis

TL;DR

The agent should be modified to handle tool names with hyphens by either using exact matching or implementing fuzzy-matching logic to resolve hallucinated snake_case names.

Guidance

  • Review the agent's tool registration and lookup logic to ensure it can handle names with hyphens.
  • Consider implementing fuzzy-matching logic to resolve tool calls when a direct match isn't found, especially for cases where models hallucinate snake_case names.
  • Verify that the BeforeAgent hook is correctly configured to guide the model to use the exact tool name.
  • Test the agent with various tool names, including those with hyphens, to ensure it can correctly resolve and execute the intended tools.

Example

// Example of fuzzy-matching logic in the agent
const toolNames = ['mcp_hyphen-server_test-tool', 'mcp_hyphen_server_test_tool'];
const inputToolName = 'mcp_hyphen_server_test_tool';
const matchedTool = toolNames.find((tool) => tool.replace(/-/g, '_') === inputToolName);
if (matchedTool) {
  // Execute the matched tool
}

Notes

The provided reproduction test case and responses file suggest that the issue is related to the agent's handling of tool names with hyphens. However, without further information about the agent's implementation, it's difficult to provide a more specific solution.

Recommendation

Apply a workaround by implementing fuzzy-matching logic in the agent to resolve hallucinated snake_case names, as the exact cause of the issue is unclear and may require further investigation.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

gemini-cli - 💡(How to fix) Fix bug: MCP tool call hallucination with hyphenated server names [1 participants]