This content originally appeared on Level Up Coding – Medium and was authored by hideya
Drop-in replacement that unblocks MCP tool schemas in Gemini

TL;DR
If you see 400 Bad Request errors when using LangChain.js with Gemini and MCP servers, install this drop-in replacement:
npm i @h1deya/langchain-google-genai-ex
Then swap the import and the classname:
// Before
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
...
const model = new ChatGoogleGenerativeAI({...});
// After (drop-in)
import { ChatGoogleGenerativeAIEx } from "@h1deya/langchain-google-genai-ex";
...
const model = new ChatGoogleGenerativeAIEx({...});
That’s it!
This prevents Gemini from rejecting MCP tool schemas containing complex and unsupported constructs.
The Problem You’re Probably Having
These days, I am totally fascinated by the potential of MCPs and the value that Gemini offers.
If you’re like me and have tried using Google Gemini together with LangChain.js and feature-rich MCP servers with complex schemas, you may have run into this frustrating error:
[GoogleGenerativeAI Error]: Error fetching from
https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent:
[400 Bad Request] Invalid JSON payload received.
Unknown name "anyOf" at 'tools[0].function_declarations[8]...
This typically occurs when you configure multiple MCP servers using MultiServerMCPClient, especially if some of the servers are feature-rich.
The annoying and confusing part is that this happens even with MCP servers that work fine with LLMs from OpenAI, Anthropic, etc.
I was also caught up by this issue so many times that I came up with a solution. I would like to share it with you here in this article.
If you searched for GoogleGenerativeAIFetchError: [GoogleGenerativeAI Error] 400 Bad Request, this document explains the cause and how to work around it when using LangChain.js.
Why This Happens
Because Gemini’s schema validation for function calling is very strict (docs), compared with the validation imposed by OpenAI, Anthropic, etc. So, when MCP tools are executed via the LLM’s function calling mechanism, the Gemini API can return a 400 error for tools containing complex schemas exposed by MCP servers.
For many developers, including myself, this can make Gemini difficult to use with LangChain.js and MCP servers. Even if only one incompatible MCP server is included in the MCP definitions passed to MultiServerMCPClient , all subsequent MCP usage starts failing with the error above.
The MCP servers I have encountered so far that have failed are:
・@notionhq/notion-mcp-server@1.9.0 (run with npx)
・airtable-mcp-server@1.6.1 (run with npx)
・mcp-server-fetch==2025.4.7 (run with uvx)
The official @langchain/google-genai package doesn’t automatically fix this. Google provides a fix in its new Gemini SDK (@google/genai, docs), but LangChain.js users cannot leverage it due to architectural incompatibility. Google’s Vertex API’s schema handling is more relaxed, but it requires GCP setup.
The Solution
So, I wrote @h1deya/langchain-google-genai-ex (link). It transparently converts unsupported schema constructs to Gemini-friendly JSON before making requests.
You can keep your MCP tools as-is — no patching any MCP schema definitions — and Gemini won’t choke.
Simple Repro Example
Follow the following steps to see how it works.
You can also try a simple usage example on GitHub (link) that is ready to clone and run.
- Install dependencies:
npm i @langchain/core @langchain/mcp-adapters @langchain/langgraph @langchain/google-genai @h1deya/langchain-google-genai-ex - Set your API key:
export GOOGLE_API_KEY=… - Run this program:
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
// import { ChatGoogleGenerativeAIEx } from "@h1deya/langchain-google-genai-ex";
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { HumanMessage } from "@langchain/core/messages";
const client = new MultiServerMCPClient({
mcpServers: {
fetch: { // This MCP server causes "400 Bad Request"
command: "uvx",
args: ["mcp-server-fetch==2025.4.7"]
}
}
});
(async () => { // workaround for top-level await
const mcpTools = await client.getTools();
const llm = new ChatGoogleGenerativeAI({ model: "gemini-2.5-flash" });
// const llm = new ChatGoogleGenerativeAIEx({ model: "gemini-2.5-flash"} );
const agent = createReactAgent({ llm, tools: mcpTools });
const result = await agent.invoke({
messages: [new HumanMessage("Read https://en.wikipedia.org/wiki/LangChain and summarize")]
});
console.log(result.messages[result.messages.length - 1].content);
await client.close();
})();
Before vs After
Before — run the above code as is:
GoogleGenerativeAIFetchError: [GoogleGenerativeAI Error]: Error fetching from https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent:
[400 Bad Request] Invalid JSON payload received. Unknown name "exclusiveMaximum" at 'tools[0].function_declarations[0].parameters.properties[1].value': Cannot find field.
Invalid JSON payload received. Unknown name "exclusiveMinimum" at 'tools[0].function_declarations[0].parameters.properties[1].value': Cannot find field. [{"@type":"type.googleapis.com/google.rpc.BadRequest","fieldViolations":[{"field":"tools[0].function_declarations[0].parameters.properties[1].value","description":"Invalid JSON payload received. Unknown name \"exclusiveMaximum\" at 'tools[0].function_declarations[0].parameters.properties[1].value': Cannot find field."},{"field":"tools[0].function_declarations[0].parameters.properties[1].value","description":"Invalid JSON payload received. Unknown name \"exclusiveMinimum\" at 'tools[0].function_declarations[0].parameters.properties[1].value': Cannot find field."}]}]
at handleResponseNotOk (file:///.../node_modules/@google/generative-ai/dist/index.mjs:432:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async makeRequest (file:///.../node_modules/@google/generative-ai/dist/index.mjs:401:9)
at async generateContent (file:///.../node_modules/@google/generative-ai/dist/index.mjs:865:22)
at async file:///.../node_modules/@langchain/google-genai/dist/chat_models.js:737:24
at async RetryOperation._fn (/.../node_modules/p-retry/index.js:50:12) {
status: 400,
statusText: 'Bad Request',
errorDetails: [
...
After switching toChatGoogleGenerativeAIEx (revive the two commented lines) :
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
// import { ChatGoogleGenerativeAIEx } from "@h1deya/langchain-google-genai-ex";
︙
︙
// const llm = new ChatGoogleGenerativeAI({ model: "gemini-2.5-flash" });
const llm = new ChatGoogleGenerativeAIEx({ model: "gemini-2.5-flash"} );
︙
Then you will get:
LangChain is an open-source software framework launched in October 2022
by Harrison Chase. It facilitates the integration of large language models
(LLMs) into applications, with use cases including document analysis,
summarization, chatbots, and code analysis.
...
It just works!
Key Benefits:
- Simple to use — Just replace the import and the classname
- Preserves all functionality — Streaming, system instructions, etc.
- No breaking changes — Full LangChain.js integration
- Tested with Gemini 1.5 and 2.5 models
You can easily switch back to the original ChatGoogleGenerativeAI when its schema handling improves, or when the MCP server's schema improves to meet Gemini's strict requirements.
Checking the Transformations: Verbose Logging
Want to see exactly what schema transformations are happening?
Set the environment variable to get detailed logs:
LANGCHAIN_GOOGLE_GENAI_EX_VERBOSE=true
Example output:
🔧 Transforming 3 MCP tool(s) for Gemini compatibility...
✅ get-alerts: No transformation needed (simple schema)
✅ get-forecast: No transformation needed (simple schema)
🔄 fetch: 2 exclusive bound(s) converted, 1 unsupported format(s) removed (uri)
📊 Summary: 1/3 tool(s) required schema transformation
How It Works
The library intercepts the MCP tool schemas and rewrites problematic constructs. For example:
// Before (from MCP)
{
"type": ["string", "null"]
}
// After (sent to Gemini)
// Gemini only accepts single types plus nullable,
// not JSON Schema's "union types"
{
"type": "string",
"nullable": true
}
As above, it performs a comprehensive schema transformation for Gemini consumption.
Known Limitations
A bit detailed, but here is a list of known issues with the transformation:
- Unresolved references: If a schema points to $ref definitions that aren’t available, they’re simplified to a generic object.
- Tuple-style arrays: For schemas that define arrays with position-specific types, only the first item is used.
- Enums and formats: Only string enums and a small set of formats are kept; others are dropped.
- Complex combinations: oneOf/allOf are simplified, which may loosen or slightly change validation rules.
These adjustments keep most MCP tools working, but rare edge cases could behave differently from the original schema. If you encounter any issue, please report it using GitHub Issues.
Compatibility
This library addresses the schema issue present with (as of September 5, 2025):
- @langchain/core v0.3.72
- @langchain/google-genai v0.2.16
References
- Gemini schema strictness
- This library’s npm.js package page
- This library’s GitHub repository
- A simple usage example on GitHub that is ready to clone and run
I built this library after encountering repeated 400 errors while trying to connect Gemini to MCP tools using LangChain.js…
I really hope this is helpful to you!
Please feel free to leave feedback — issues and PRs welcome on GitHub.
I’ve wasted far too much time on this schema issue. You don’t have to.
Fix Gemini “400 Error” with LangChain.js + MCP (Drop-in Patch) was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding – Medium and was authored by hideya