Skip to main content
Glama

MCP Google Maps - stdio Edition

MCP_USAGE.md16.6 kB
# 🔌 Uso con Clientes MCP Esta guía muestra cómo integrar el servidor MCP Google Maps con cualquier cliente que soporte el protocolo MCP. ## 📋 Sobre el Protocolo MCP El **Model Context Protocol (MCP)** es un protocolo estandarizado basado en JSON-RPC 2.0 que permite a LLMs y aplicaciones conectarse con herramientas externas de forma uniforme. ## 🚀 Modos de Transporte Soportados Este servidor soporta dos modos de transporte: ### 1. STDIO (Standard Input/Output) Comunicación a través de stdin/stdout, ideal para: - Claude Desktop - Aplicaciones de terminal - Procesos spawn/exec ### 2. HTTP + SSE (Server-Sent Events) Comunicación HTTP con soporte para streaming, ideal para: - Desarrollo y testing - Aplicaciones web - Servicios distribuidos ## 📡 Uso con STDIO ### Iniciar el Servidor ```bash # Con API key como variable de entorno GOOGLE_MAPS_API_KEY="tu_api_key" mcp-google-map-stdio --stdio # O con archivo .env # Crear archivo .env con: GOOGLE_MAPS_API_KEY=tu_api_key mcp-google-map-stdio --stdio ``` ### Ejemplo de Cliente en Node.js ```javascript import { spawn } from 'child_process'; class StdioMCPClient { constructor(apiKey) { this.apiKey = apiKey; this.server = null; this.requestId = 0; } start() { this.server = spawn('mcp-google-map-stdio', ['--stdio'], { env: { ...process.env, GOOGLE_MAPS_API_KEY: this.apiKey }, stdio: ['pipe', 'pipe', 'pipe'] }); // Capturar respuestas this.server.stdout.on('data', (data) => { const response = JSON.parse(data.toString()); console.log('Respuesta:', response); }); // Capturar logs (stderr) this.server.stderr.on('data', (data) => { console.error('[Server Log]:', data.toString()); }); } send(method, params = {}) { const message = { jsonrpc: '2.0', id: ++this.requestId, method: method, params: params }; this.server.stdin.write(JSON.stringify(message) + '\n'); } async initialize() { this.send('initialize', { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'mi-cliente', version: '1.0.0' } }); } async listTools() { this.send('tools/list', {}); } async callTool(toolName, args) { this.send('tools/call', { name: toolName, arguments: args }); } close() { if (this.server) { this.server.kill(); } } } // Uso const client = new StdioMCPClient('tu_api_key'); client.start(); setTimeout(async () => { await client.initialize(); setTimeout(() => { client.callTool('maps_geocode', { address: 'Torre Eiffel, París' }); }, 1000); }, 1000); ``` ### Ejemplo con Python ```python import subprocess import json import os class StdioMCPClient: def __init__(self, api_key): self.api_key = api_key self.request_id = 0 self.server = None def start(self): env = os.environ.copy() env['GOOGLE_MAPS_API_KEY'] = self.api_key self.server = subprocess.Popen( ['mcp-google-map-stdio', '--stdio'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, text=True, bufsize=1 ) def send(self, method, params=None): self.request_id += 1 message = { 'jsonrpc': '2.0', 'id': self.request_id, 'method': method, 'params': params or {} } self.server.stdin.write(json.dumps(message) + '\n') self.server.stdin.flush() def read_response(self): line = self.server.stdout.readline() if line: return json.loads(line) return None def initialize(self): self.send('initialize', { 'protocolVersion': '2024-11-05', 'capabilities': {}, 'clientInfo': { 'name': 'mi-cliente-python', 'version': '1.0.0' } }) return self.read_response() def list_tools(self): self.send('tools/list', {}) return self.read_response() def call_tool(self, tool_name, args): self.send('tools/call', { 'name': tool_name, 'arguments': args }) return self.read_response() def close(self): if self.server: self.server.terminate() # Uso client = StdioMCPClient('tu_api_key') client.start() # Inicializar init_response = client.initialize() print('Inicializado:', init_response) # Listar herramientas tools = client.list_tools() print('Herramientas:', tools) # Usar una herramienta result = client.call_tool('maps_geocode', { 'address': 'Torre Eiffel, París' }) print('Resultado:', result) client.close() ``` ## 🌐 Uso con HTTP ### Iniciar el Servidor ```bash # Por defecto en puerto 3000 GOOGLE_MAPS_API_KEY="tu_api_key" MCP_SERVER_PORT=3000 mcp-google-map-stdio # O con puerto personalizado GOOGLE_MAPS_API_KEY="tu_api_key" MCP_SERVER_PORT=8080 mcp-google-map-stdio ``` ### Flujo de Comunicación HTTP 1. **Initialize**: Crear sesión 2. **Capturar session-id**: Del header de respuesta 3. **Usar herramientas**: Con session-id en requests subsecuentes 4. **Cerrar sesión**: DELETE request (opcional) ### Ejemplo de Cliente HTTP en Node.js ```javascript import fetch from 'node-fetch'; class HttpMCPClient { constructor(serverUrl, apiKey) { this.serverUrl = serverUrl; this.apiKey = apiKey; this.sessionId = null; this.requestId = 0; } async request(method, params = {}) { const payload = { jsonrpc: '2.0', method: method, params: params, id: ++this.requestId }; const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream', 'X-Google-Maps-API-Key': this.apiKey }; if (this.sessionId) { headers['mcp-session-id'] = this.sessionId; } const response = await fetch(this.serverUrl, { method: 'POST', headers: headers, body: JSON.stringify(payload) }); // Capturar session ID if (!this.sessionId) { this.sessionId = response.headers.get('mcp-session-id'); } // Parsear respuesta SSE const text = await response.text(); return this.parseSSE(text); } parseSSE(text) { const lines = text.split('\n'); let currentEvent = {}; for (const line of lines) { if (line.startsWith('event:')) { currentEvent.event = line.slice(6).trim(); } else if (line.startsWith('data:')) { try { currentEvent.data = JSON.parse(line.slice(5).trim()); } catch (e) { currentEvent.data = line.slice(5).trim(); } } else if (line === '' && currentEvent.event === 'message') { return currentEvent.data; } } return null; } async initialize() { return await this.request('initialize', { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'mi-cliente-http', version: '1.0.0' } }); } async listTools() { const response = await this.request('tools/list'); return response.result.tools; } async callTool(toolName, args) { const response = await this.request('tools/call', { name: toolName, arguments: args }); return response.result; } async close() { if (!this.sessionId) return; await fetch(this.serverUrl, { method: 'DELETE', headers: { 'mcp-session-id': this.sessionId } }); } } // Uso async function main() { const client = new HttpMCPClient( 'http://localhost:3000/mcp', 'tu_api_key' ); try { // Inicializar const init = await client.initialize(); console.log('Sesión:', init); // Listar herramientas const tools = await client.listTools(); console.log('Herramientas:', tools.map(t => t.name)); // Usar herramienta const result = await client.callTool('maps_geocode', { address: 'Torre Eiffel, París' }); console.log('Resultado:', result); // Cerrar sesión await client.close(); } catch (error) { console.error('Error:', error); } } main(); ``` ### Ejemplo con curl ```bash API_KEY="tu_api_key" URL="http://localhost:3000/mcp" # 1. Initialize y capturar session ID RESPONSE=$(curl -i -X POST "$URL" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "X-Google-Maps-API-Key: $API_KEY" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "curl", "version": "1.0.0"} } }') # Extraer session ID del header SESSION_ID=$(echo "$RESPONSE" | grep -i "mcp-session-id:" | cut -d' ' -f2 | tr -d '\r') echo "Session ID: $SESSION_ID" # 2. Listar herramientas curl -X POST "$URL" \ -H "Content-Type: application/json" \ -H "mcp-session-id: $SESSION_ID" \ -H "X-Google-Maps-API-Key: $API_KEY" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }' # 3. Llamar herramienta curl -X POST "$URL" \ -H "Content-Type: application/json" \ -H "mcp-session-id: $SESSION_ID" \ -H "X-Google-Maps-API-Key: $API_KEY" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "maps_geocode", "arguments": { "address": "Torre Eiffel, París" } } }' # 4. Cerrar sesión (opcional) curl -X DELETE "$URL" \ -H "mcp-session-id: $SESSION_ID" ``` ## 📝 Formato de Mensajes ### Request (Solicitud) ```json { "jsonrpc": "2.0", "method": "nombre_del_metodo", "params": { "parametro1": "valor1" }, "id": 1 } ``` ### Response (Respuesta Exitosa) ```json { "jsonrpc": "2.0", "result": { "data": "resultado" }, "id": 1 } ``` ### Error Response ```json { "jsonrpc": "2.0", "error": { "code": -32602, "message": "Invalid params", "data": { "details": "..." } }, "id": 1 } ``` ## 🛠️ Métodos Disponibles ### initialize Inicializa una nueva sesión MCP. **Request**: ```json { "jsonrpc": "2.0", "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "mi-cliente", "version": "1.0.0" } }, "id": 1 } ``` **Response**: ```json { "jsonrpc": "2.0", "result": { "protocolVersion": "2024-11-05", "capabilities": { "logging": {}, "tools": { "listChanged": true } }, "serverInfo": { "name": "google-maps", "version": "0.0.1" } }, "id": 1 } ``` ### tools/list Lista todas las herramientas disponibles. **Request**: ```json { "jsonrpc": "2.0", "method": "tools/list", "params": {}, "id": 2 } ``` **Response**: ```json { "jsonrpc": "2.0", "result": { "tools": [ { "name": "search_nearby", "description": "Search for places near a location", "inputSchema": { "type": "object", "properties": { "center": { "type": "object", "description": "Search center point" } }, "required": ["center"] } } ] }, "id": 2 } ``` ### tools/call Ejecuta una herramienta específica. **Request**: ```json { "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "maps_geocode", "arguments": { "address": "Torre Eiffel, París" } }, "id": 3 } ``` **Response**: ```json { "jsonrpc": "2.0", "result": { "content": [ { "type": "text", "text": "{\"lat\": 48.8584, \"lng\": 2.2945}" } ], "isError": false }, "id": 3 } ``` ## 🔧 Headers HTTP Importantes ### Request Headers - `Content-Type: application/json` - Requerido - `Accept: application/json, text/event-stream` - Requerido para SSE - `X-Google-Maps-API-Key: <api_key>` - API key de Google Maps - `mcp-session-id: <session_id>` - ID de sesión (después del initialize) ### Response Headers - `mcp-session-id: <session_id>` - ID de sesión (solo en initialize) - `Content-Type: text/event-stream` - Para respuestas SSE ## ⚠️ Manejo de Errores ### Códigos de Error JSON-RPC | Código | Nombre | Descripción | |--------|--------|-------------| | -32700 | Parse error | JSON inválido | | -32600 | Invalid Request | Request no válido | | -32601 | Method not found | Método no existe | | -32602 | Invalid params | Parámetros inválidos | | -32603 | Internal error | Error interno | | -32000 | Server error | Error del servidor | ### Ejemplo de Manejo de Errores ```javascript async callTool(toolName, args) { try { const response = await this.request('tools/call', { name: toolName, arguments: args }); if (response.error) { console.error('Error de herramienta:', response.error.message); if (response.error.data) { console.error('Detalles:', response.error.data); } throw new Error(response.error.message); } return response.result; } catch (error) { console.error('Error de comunicación:', error.message); throw error; } } ``` ## 💡 Mejores Prácticas ### 1. Reutilizar Sesiones ```javascript // ✅ Bueno: Una sesión para múltiples operaciones const client = new MCPClient(url, apiKey); await client.initialize(); await client.callTool('tool1', {}); await client.callTool('tool2', {}); await client.close(); // ❌ Malo: Nueva sesión para cada operación for (const tool of tools) { const client = new MCPClient(url, apiKey); await client.initialize(); await client.callTool(tool, {}); await client.close(); } ``` ### 2. Validar Parámetros ```javascript // Validar antes de enviar if (!args.center || !args.center.value) { throw new Error('center es requerido'); } await client.callTool('search_nearby', args); ``` ### 3. Timeouts ```javascript async requestWithTimeout(method, params, timeout = 30000) { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Timeout')), timeout); }); return Promise.race([ this.request(method, params), timeoutPromise ]); } ``` ### 4. Retry Logic ```javascript async requestWithRetry(method, params, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await this.request(method, params); } catch (error) { if (i === maxRetries - 1) throw error; await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } } ``` ## 🧪 Testing ### Test Script de Ejemplo ```javascript async function testClient() { const client = new HttpMCPClient( 'http://localhost:3000/mcp', process.env.GOOGLE_MAPS_API_KEY ); console.log('🧪 Testing MCP Client...\n'); try { // Test 1: Initialize console.log('Test 1: Initialize'); const init = await client.initialize(); console.log('✅ Session ID:', client.sessionId); // Test 2: List Tools console.log('\nTest 2: List Tools'); const tools = await client.listTools(); console.log('✅ Tools:', tools.length); // Test 3: Geocode console.log('\nTest 3: Geocode'); const geocode = await client.callTool('maps_geocode', { address: 'Torre Eiffel, París' }); console.log('✅ Result:', geocode.content[0].text); // Test 4: Search Nearby console.log('\nTest 4: Search Nearby'); const search = await client.callTool('search_nearby', { center: { value: 'Times Square, NY', isCoordinates: false }, radius: 1000, keyword: 'restaurant' }); console.log('✅ Found places'); // Close await client.close(); console.log('\n✅ All tests passed!'); } catch (error) { console.error('\n❌ Test failed:', error.message); } } testClient(); ``` ## 📚 Recursos - [Especificación MCP](https://spec.modelcontextprotocol.io/) - [README.md](./README.md) - Documentación general - [CLAUDE_DESKTOP.md](./CLAUDE_DESKTOP.md) - Configuración Claude Desktop - [Repositorio GitHub](https://github.com/vicente-alvarado/mcp-google-map-stdio) ## 💬 Soporte Si tienes problemas integrando este servidor con tu cliente: - 🐛 [Reportar un issue](https://github.com/vicente-alvarado/mcp-google-map-stdio/issues) - 💡 Revisa los ejemplos de código arriba - 📧 Contacto: contacto@example.com --- **¡Feliz integración!** 🚀

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vicente-alvarado/mcp-google-map-stdio'

If you have feedback or need assistance with the MCP directory API, please join our Discord server