0
# MCP Integration (Experimental)
1
2
The MCP (Model Context Protocol) integration allows you to convert MCP clients and tools into Gemini-compatible tools for extended functionality and interoperability.
3
4
## Capabilities
5
6
### mcpToTool
7
8
Convert MCP clients or tools to Gemini CallableTool interface.
9
10
```typescript { .api }
11
/**
12
* Convert MCP clients/tools to Gemini tools
13
* @param mcpClientOrTools - MCP client or tools array
14
* @param config - Tool configuration
15
* @returns Promise resolving to callable tool
16
*/
17
function mcpToTool(
18
mcpClientOrTools: McpClient | McpTool[],
19
config?: CallableToolConfig
20
): Promise<CallableTool>;
21
22
interface CallableToolConfig {
23
/** Tool display name */
24
displayName?: string;
25
/** Tool description */
26
description?: string;
27
/** Additional configuration */
28
[key: string]: unknown;
29
}
30
```
31
32
**Usage Examples:**
33
34
```typescript
35
import { GoogleGenAI, mcpToTool } from '@google/genai';
36
import { McpClient } from '@modelcontextprotocol/sdk';
37
38
const client = new GoogleGenAI({ apiKey: 'YOUR_API_KEY' });
39
40
// Connect to MCP server
41
const mcpClient = new McpClient({
42
serverUrl: 'http://localhost:3000'
43
});
44
45
await mcpClient.connect();
46
47
// Convert MCP client to Gemini tool
48
const mcpTool = await mcpToTool(mcpClient, {
49
displayName: 'External MCP Tools',
50
description: 'Tools provided by MCP server'
51
});
52
53
// Use in generation with automatic function calling
54
const response = await client.models.generateContent({
55
model: 'gemini-2.0-flash',
56
contents: 'Use the available tools to complete this task',
57
config: {
58
tools: [mcpTool],
59
automaticFunctionCalling: {
60
maximumRemoteCalls: 10
61
}
62
}
63
});
64
65
console.log('Response:', response.text);
66
67
// Close MCP connection
68
await mcpClient.disconnect();
69
```
70
71
## Types
72
73
### McpClient
74
75
MCP client interface (from @modelcontextprotocol/sdk).
76
77
```typescript { .api }
78
interface McpClient {
79
/** Connect to MCP server */
80
connect(): Promise<void>;
81
/** Disconnect from MCP server */
82
disconnect(): Promise<void>;
83
/** List available tools */
84
listTools(): Promise<McpTool[]>;
85
/** Call a tool */
86
callTool(name: string, args: Record<string, unknown>): Promise<unknown>;
87
}
88
```
89
90
### McpTool
91
92
MCP tool definition.
93
94
```typescript { .api }
95
interface McpTool {
96
/** Tool name */
97
name: string;
98
/** Tool description */
99
description?: string;
100
/** Input schema */
101
inputSchema?: {
102
type: string;
103
properties?: Record<string, unknown>;
104
required?: string[];
105
};
106
}
107
```
108
109
### CallableTool
110
111
Gemini callable tool interface.
112
113
```typescript { .api }
114
interface CallableTool {
115
/** Get tool declaration */
116
tool(): Promise<Tool>;
117
/** Execute function calls */
118
callTool(functionCalls: FunctionCall[]): Promise<Part[]>;
119
}
120
```
121
122
## Complete Examples
123
124
### Connect to MCP Server
125
126
```typescript
127
import { GoogleGenAI, mcpToTool } from '@google/genai';
128
import { McpClient } from '@modelcontextprotocol/sdk';
129
130
const client = new GoogleGenAI({ apiKey: 'YOUR_API_KEY' });
131
132
// Create and connect MCP client
133
const mcpClient = new McpClient({
134
serverUrl: 'http://localhost:3000',
135
apiKey: 'MCP_SERVER_KEY'
136
});
137
138
await mcpClient.connect();
139
console.log('Connected to MCP server');
140
141
// List available tools
142
const tools = await mcpClient.listTools();
143
console.log('Available MCP tools:');
144
tools.forEach(tool => {
145
console.log(` - ${tool.name}: ${tool.description}`);
146
});
147
148
// Convert to Gemini tool
149
const geminiTool = await mcpToTool(mcpClient);
150
151
// Use in generation
152
const response = await client.models.generateContent({
153
model: 'gemini-2.0-flash',
154
contents: 'Search for information about AI',
155
config: {
156
tools: [geminiTool]
157
}
158
});
159
160
// Handle function calls manually
161
if (response.functionCalls) {
162
console.log('MCP tools were called:', response.functionCalls);
163
}
164
165
// Cleanup
166
await mcpClient.disconnect();
167
```
168
169
### Use Specific MCP Tools
170
171
```typescript
172
import { McpTool } from '@modelcontextprotocol/sdk';
173
174
// Define specific MCP tools
175
const mcpTools: McpTool[] = [
176
{
177
name: 'search_database',
178
description: 'Search the database',
179
inputSchema: {
180
type: 'object',
181
properties: {
182
query: { type: 'string' },
183
limit: { type: 'number' }
184
},
185
required: ['query']
186
}
187
},
188
{
189
name: 'get_weather',
190
description: 'Get weather information',
191
inputSchema: {
192
type: 'object',
193
properties: {
194
location: { type: 'string' }
195
},
196
required: ['location']
197
}
198
}
199
];
200
201
// Convert tools (not client)
202
const geminiTool = await mcpToTool(mcpTools, {
203
displayName: 'Database and Weather Tools'
204
});
205
206
// Use in generation
207
const response = await client.models.generateContent({
208
model: 'gemini-2.0-flash',
209
contents: 'Search the database for AI papers and check weather in San Francisco',
210
config: {
211
tools: [geminiTool],
212
automaticFunctionCalling: {
213
maximumRemoteCalls: 5
214
}
215
}
216
});
217
218
console.log('Response:', response.text);
219
```
220
221
### MCP with Streaming
222
223
```typescript
224
// Connect MCP client
225
const mcpClient = new McpClient({
226
serverUrl: 'http://localhost:3000'
227
});
228
229
await mcpClient.connect();
230
231
// Convert to tool
232
const mcpTool = await mcpToTool(mcpClient);
233
234
// Stream with MCP tools
235
const stream = await client.models.generateContentStream({
236
model: 'gemini-2.0-flash',
237
contents: 'Use the tools to gather information',
238
config: {
239
tools: [mcpTool]
240
}
241
});
242
243
for await (const chunk of stream) {
244
if (chunk.text) {
245
process.stdout.write(chunk.text);
246
}
247
248
// Check for function calls
249
if (chunk.functionCalls) {
250
console.log('\nMCP tools invoked:', chunk.functionCalls);
251
}
252
}
253
254
await mcpClient.disconnect();
255
```
256
257
### MCP in Chat Session
258
259
```typescript
260
// Setup MCP
261
const mcpClient = new McpClient({
262
serverUrl: 'http://localhost:3000'
263
});
264
265
await mcpClient.connect();
266
const mcpTool = await mcpToTool(mcpClient);
267
268
// Create chat with MCP tools
269
const chat = client.chats.create({
270
model: 'gemini-2.0-flash',
271
config: {
272
tools: [mcpTool],
273
systemInstruction: 'You are a helpful assistant with access to external tools.'
274
}
275
});
276
277
// Multi-turn conversation with MCP
278
const r1 = await chat.sendMessage({
279
message: 'Search for recent AI developments'
280
});
281
console.log('Assistant:', r1.text);
282
283
const r2 = await chat.sendMessage({
284
message: 'Get more details about the first result'
285
});
286
console.log('Assistant:', r2.text);
287
288
// Cleanup
289
await mcpClient.disconnect();
290
```
291
292
### Multiple MCP Servers
293
294
```typescript
295
// Connect to multiple MCP servers
296
const mcpClient1 = new McpClient({
297
serverUrl: 'http://localhost:3000'
298
});
299
300
const mcpClient2 = new McpClient({
301
serverUrl: 'http://localhost:4000'
302
});
303
304
await Promise.all([
305
mcpClient1.connect(),
306
mcpClient2.connect()
307
]);
308
309
// Convert each to tool
310
const [tool1, tool2] = await Promise.all([
311
mcpToTool(mcpClient1, { displayName: 'Database Tools' }),
312
mcpToTool(mcpClient2, { displayName: 'API Tools' })
313
]);
314
315
// Use both in generation
316
const response = await client.models.generateContent({
317
model: 'gemini-2.0-flash',
318
contents: 'Use both database and API tools to gather information',
319
config: {
320
tools: [tool1, tool2],
321
automaticFunctionCalling: {
322
maximumRemoteCalls: 10
323
}
324
}
325
});
326
327
console.log('Response:', response.text);
328
329
// Cleanup
330
await Promise.all([
331
mcpClient1.disconnect(),
332
mcpClient2.disconnect()
333
]);
334
```
335
336
### MCP with Custom Tool Implementation
337
338
```typescript
339
import { CallableTool, Tool, FunctionCall, Part } from '@google/genai';
340
import { McpClient } from '@modelcontextprotocol/sdk';
341
342
// Custom wrapper for MCP client
343
class CustomMcpTool implements CallableTool {
344
constructor(private mcpClient: McpClient) {}
345
346
async tool(): Promise<Tool> {
347
// Get tools from MCP server
348
const mcpTools = await this.mcpClient.listTools();
349
350
// Convert to Gemini format
351
const functionDeclarations = mcpTools.map(mcpTool => ({
352
name: mcpTool.name,
353
description: mcpTool.description,
354
parametersJsonSchema: mcpTool.inputSchema
355
}));
356
357
return {
358
functionDeclarations
359
};
360
}
361
362
async callTool(functionCalls: FunctionCall[]): Promise<Part[]> {
363
const results: Part[] = [];
364
365
for (const fc of functionCalls) {
366
try {
367
console.log(`Calling MCP tool: ${fc.name}`);
368
369
// Call MCP server
370
const result = await this.mcpClient.callTool(fc.name!, fc.args || {});
371
372
results.push({
373
functionResponse: {
374
name: fc.name,
375
response: { result },
376
id: fc.id
377
}
378
});
379
} catch (error) {
380
console.error(`MCP tool error: ${fc.name}`, error);
381
382
results.push({
383
functionResponse: {
384
name: fc.name,
385
response: {
386
error: error.message
387
},
388
id: fc.id
389
}
390
});
391
}
392
}
393
394
return results;
395
}
396
}
397
398
// Use custom wrapper
399
const mcpClient = new McpClient({ serverUrl: 'http://localhost:3000' });
400
await mcpClient.connect();
401
402
const customTool = new CustomMcpTool(mcpClient);
403
404
const response = await client.models.generateContent({
405
model: 'gemini-2.0-flash',
406
contents: 'Use the tools',
407
config: {
408
tools: [customTool],
409
automaticFunctionCalling: {
410
maximumRemoteCalls: 5
411
}
412
}
413
});
414
```
415
416
### Error Handling with MCP
417
418
```typescript
419
// MCP connection with error handling
420
async function connectMcpWithRetry(
421
config: { serverUrl: string },
422
maxRetries: number = 3
423
): Promise<McpClient> {
424
const mcpClient = new McpClient(config);
425
426
for (let attempt = 1; attempt <= maxRetries; attempt++) {
427
try {
428
await mcpClient.connect();
429
console.log('Connected to MCP server');
430
return mcpClient;
431
} catch (error) {
432
console.error(`Connection attempt ${attempt} failed:`, error);
433
434
if (attempt === maxRetries) {
435
throw new Error('Failed to connect to MCP server after retries');
436
}
437
438
await new Promise(resolve => setTimeout(resolve, 2000));
439
}
440
}
441
442
throw new Error('Unexpected error');
443
}
444
445
// Use with error handling
446
try {
447
const mcpClient = await connectMcpWithRetry({
448
serverUrl: 'http://localhost:3000'
449
});
450
451
const mcpTool = await mcpToTool(mcpClient);
452
453
const response = await client.models.generateContent({
454
model: 'gemini-2.0-flash',
455
contents: 'Use the MCP tools',
456
config: {
457
tools: [mcpTool]
458
}
459
});
460
461
console.log('Response:', response.text);
462
463
await mcpClient.disconnect();
464
} catch (error) {
465
console.error('MCP error:', error);
466
}
467
```
468
469
### MCP Tool Discovery
470
471
```typescript
472
// Discover and document MCP tools
473
async function discoverMcpTools(mcpClient: McpClient): Promise<void> {
474
await mcpClient.connect();
475
476
const tools = await mcpClient.listTools();
477
478
console.log(`Discovered ${tools.length} MCP tools:\n`);
479
480
tools.forEach((tool, index) => {
481
console.log(`${index + 1}. ${tool.name}`);
482
console.log(` Description: ${tool.description || 'N/A'}`);
483
484
if (tool.inputSchema?.properties) {
485
console.log(' Parameters:');
486
Object.entries(tool.inputSchema.properties).forEach(([name, schema]: [string, any]) => {
487
const required = tool.inputSchema?.required?.includes(name) ? '(required)' : '(optional)';
488
console.log(` - ${name}: ${schema.type} ${required}`);
489
if (schema.description) {
490
console.log(` ${schema.description}`);
491
}
492
});
493
}
494
495
console.log('');
496
});
497
498
await mcpClient.disconnect();
499
}
500
501
// Discover tools
502
const mcpClient = new McpClient({
503
serverUrl: 'http://localhost:3000'
504
});
505
506
await discoverMcpTools(mcpClient);
507
```
508
509
### MCP with Function Calling Mode
510
511
```typescript
512
import { FunctionCallingConfigMode } from '@google/genai';
513
514
// Connect MCP
515
const mcpClient = new McpClient({
516
serverUrl: 'http://localhost:3000'
517
});
518
519
await mcpClient.connect();
520
const mcpTool = await mcpToTool(mcpClient);
521
522
// Force model to use MCP tools
523
const response = await client.models.generateContent({
524
model: 'gemini-2.0-flash',
525
contents: 'Get information',
526
config: {
527
tools: [mcpTool],
528
toolConfig: {
529
functionCallingConfig: {
530
mode: FunctionCallingConfigMode.ANY // Must call at least one tool
531
}
532
}
533
}
534
});
535
536
console.log('Response:', response.text);
537
538
await mcpClient.disconnect();
539
```
540
541
### MCP Health Check
542
543
```typescript
544
// Monitor MCP server health
545
class McpHealthMonitor {
546
private mcpClient: McpClient;
547
private isHealthy: boolean = false;
548
549
constructor(serverUrl: string) {
550
this.mcpClient = new McpClient({ serverUrl });
551
}
552
553
async check(): Promise<boolean> {
554
try {
555
await this.mcpClient.connect();
556
557
// Try to list tools as health check
558
const tools = await this.mcpClient.listTools();
559
560
this.isHealthy = tools.length >= 0;
561
562
await this.mcpClient.disconnect();
563
564
return this.isHealthy;
565
} catch (error) {
566
console.error('MCP health check failed:', error);
567
this.isHealthy = false;
568
return false;
569
}
570
}
571
572
async waitUntilHealthy(timeoutMs: number = 30000): Promise<void> {
573
const startTime = Date.now();
574
575
while (Date.now() - startTime < timeoutMs) {
576
const healthy = await this.check();
577
578
if (healthy) {
579
console.log('MCP server is healthy');
580
return;
581
}
582
583
await new Promise(resolve => setTimeout(resolve, 1000));
584
}
585
586
throw new Error('MCP server health check timeout');
587
}
588
589
isServerHealthy(): boolean {
590
return this.isHealthy;
591
}
592
}
593
594
// Use health monitor
595
const monitor = new McpHealthMonitor('http://localhost:3000');
596
597
await monitor.waitUntilHealthy();
598
599
if (monitor.isServerHealthy()) {
600
// Proceed with MCP integration
601
const mcpClient = new McpClient({
602
serverUrl: 'http://localhost:3000'
603
});
604
605
await mcpClient.connect();
606
const mcpTool = await mcpToTool(mcpClient);
607
608
// Use tool...
609
610
await mcpClient.disconnect();
611
}
612
```
613
614
### Combined Native and MCP Tools
615
616
```typescript
617
import { Type } from '@google/genai';
618
619
// Define native Gemini tool
620
const nativeTool = {
621
functionDeclarations: [{
622
name: 'calculate',
623
description: 'Perform calculation',
624
parameters: {
625
type: Type.OBJECT,
626
properties: {
627
expression: { type: Type.STRING }
628
}
629
}
630
}]
631
};
632
633
// Setup MCP tool
634
const mcpClient = new McpClient({
635
serverUrl: 'http://localhost:3000'
636
});
637
638
await mcpClient.connect();
639
const mcpTool = await mcpToTool(mcpClient);
640
641
// Use both together
642
const response = await client.models.generateContent({
643
model: 'gemini-2.0-flash',
644
contents: 'Calculate 2+2 and search for information',
645
config: {
646
tools: [nativeTool, mcpTool],
647
automaticFunctionCalling: {
648
maximumRemoteCalls: 10
649
}
650
}
651
});
652
653
console.log('Response:', response.text);
654
655
await mcpClient.disconnect();
656
```
657
658
## Notes
659
660
- MCP integration is experimental and requires the @modelcontextprotocol/sdk package
661
- MCP servers must implement the Model Context Protocol specification
662
- Connection management and error handling are critical for reliable MCP integration
663
- MCP tools are automatically converted to Gemini's function calling format
664
- Supports both automatic and manual function calling modes
665
- Can combine MCP tools with native Gemini tools in the same request
666