Claude Google Apps Script MCP Guide

Integra Claude AI con Google Apps Script para automatizar tareas en Google Sheets y Gmail.

Documentación

Guía Completa de Integración de Claude MCP con Google Apps Script

Conecta Claude y Google Apps Script mediante MCP (Model Context Protocol) para construir un potente sistema de automatización de tareas

Google Apps Script Node.js Claude

📋 Tabla de Contenidos

Descripción General

Esta guía proporciona un método completo para conectar Claude AI y Google Apps Script mediante el protocolo MCP. Después de la conexión, podrás utilizar las siguientes funciones potentes:

🚀 Características Principales

  • 📊 Automatización de Google Sheets: Lectura/escritura de datos en tiempo real, análisis y generación de informes
  • 📧 Integración con Gmail: Clasificación inteligente de correos, respuestas automáticas y envíos masivos
  • 🤖 Automatización de Tareas: Gestión de calendarios, análisis de datos y sistemas de notificación
  • 📈 Panel de Control en Tiempo Real: Monitoreo integrado de múltiples fuentes de datos

Requisitos del Sistema

Requisitos Previos

  • Cuenta de Google (Gmail)
  • Node.js (v18 o superior) - Descargar
  • Aplicación Claude Desktop - Descargar

Verificación de Instalación

node -v    # v18.0.0 이상
npm -v     # 9.0.0 이상

Paso 1: Crear un Proyecto de Google Apps Script

1.1 Crear un Nuevo Proyecto

  1. Accede a Google Apps Script
  2. Haz clic en "Nuevo proyecto"
  3. Cambia el nombre del proyecto a "Claude MCP Server"
  4. Elimina todo el código myFunction() predeterminado

1.2 Verificación

  • ✅ El nombre del proyecto debe mostrar "Claude MCP Server"
  • ✅ El editor de código debe estar completamente vacío

Paso 2: Escribir el Código del Servidor MCP

2.1 Copiar y Pegar el Código

Copia y pega el siguiente código en el editor de Google Apps Script:

/**
 * Claude MCP Server for Google Apps Script
 * 클로드와 구글 워크스페이스를 연결하는 MCP 서버
 */

// MCP 서버 설정
const MCP_CONFIG = {
  name: "google-workspace-mcp",
  version: "1.0.0",
  description: "Google Workspace integration for Claude via MCP",
};

// 도구 목록 정의
const TOOLS = {
  READ_SHEET: {
    name: "read_google_sheet",
    description: "Google Sheets에서 데이터를 읽어옵니다",
    inputSchema: {
      type: "object",
      properties: {
        spreadsheetId: {
          type: "string",
          description: "스프레드시트 ID",
        },
        range: {
          type: "string",
          description: "읽을 범위 (예: A1:C10)",
          default: "A:Z",
        },
      },
      required: ["spreadsheetId"],
    },
  },

  WRITE_SHEET: {
    name: "write_google_sheet",
    description: "Google Sheets에 데이터를 씁니다",
    inputSchema: {
      type: "object",
      properties: {
        spreadsheetId: {
          type: "string",
          description: "스프레드시트 ID",
        },
        range: {
          type: "string",
          description: "쓸 범위 (예: A1:C10)",
        },
        values: {
          type: "array",
          description: "쓸 데이터 (2차원 배열)",
        },
      },
      required: ["spreadsheetId", "range", "values"],
    },
  },

  SEND_EMAIL: {
    name: "send_gmail",
    description: "Gmail을 통해 이메일을 발송합니다",
    inputSchema: {
      type: "object",
      properties: {
        to: {
          type: "string",
          description: "받는 사람 이메일",
        },
        subject: {
          type: "string",
          description: "이메일 제목",
        },
        body: {
          type: "string",
          description: "이메일 내용",
        },
      },
      required: ["to", "subject", "body"],
    },
  },
};

/**
 * MCP 서버 메인 핸들러
 */
function doPost(e) {
  try {
    const request = JSON.parse(e.postData.contents);
    console.log("MCP Request:", request);

    // 요청 타입에 따른 처리
    switch (request.method) {
      case "tools/list":
        return createResponse(handleToolsList());

      case "tools/call":
        return createResponse(handleToolCall(request.params));

      default:
        return createErrorResponse("Unknown method: " + request.method);
    }
  } catch (error) {
    console.error("MCP Error:", error);
    return createErrorResponse("Server error: " + error.message);
  }
}

/**
 * 도구 목록 반환
 */
function handleToolsList() {
  return {
    tools: Object.values(TOOLS),
  };
}

/**
 * 도구 실행
 */
function handleToolCall(params) {
  const { name, arguments: args } = params;

  try {
    switch (name) {
      case "read_google_sheet":
        return readGoogleSheet(args);

      case "write_google_sheet":
        return writeGoogleSheet(args);

      case "send_gmail":
        return sendGmail(args);

      default:
        throw new Error("Unknown tool: " + name);
    }
  } catch (error) {
    return {
      isError: true,
      content: [
        {
          type: "text",
          text: `도구 실행 오류: ${error.message}`,
        },
      ],
    };
  }
}

/**
 * Google Sheets 데이터 읽기
 */
function readGoogleSheet(args) {
  const { spreadsheetId, range = "A:Z" } = args;

  try {
    const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
    const sheet = spreadsheet.getActiveSheet();
    const data = sheet.getRange(range).getValues();

    // 빈 행 제거
    const filteredData = data.filter((row) => row.some((cell) => cell !== ""));

    return {
      content: [
        {
          type: "text",
          text: `스프레드시트 데이터 (${
            filteredData.length
          }행):\n${JSON.stringify(filteredData, null, 2)}`,
        },
      ],
    };
  } catch (error) {
    throw new Error(`Sheets 읽기 실패: ${error.message}`);
  }
}

/**
 * Google Sheets 데이터 쓰기
 */
function writeGoogleSheet(args) {
  const { spreadsheetId, range, values } = args;

  try {
    const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
    const sheet = spreadsheet.getActiveSheet();

    if (values.length > 0) {
      sheet.getRange(range).setValues(values);
    }

    return {
      content: [
        {
          type: "text",
          text: `성공적으로 ${values.length}행의 데이터를 ${range} 범위에 저장했습니다.`,
        },
      ],
    };
  } catch (error) {
    throw new Error(`Sheets 쓰기 실패: ${error.message}`);
  }
}

/**
 * Gmail 이메일 발송
 */
function sendGmail(args) {
  const { to, subject, body } = args;

  try {
    GmailApp.sendEmail(to, subject, body);

    return {
      content: [
        {
          type: "text",
          text: `이메일이 성공적으로 ${to}에게 발송되었습니다.`,
        },
      ],
    };
  } catch (error) {
    throw new Error(`이메일 발송 실패: ${error.message}`);
  }
}

/**
 * 응답 생성 헬퍼
 */
function createResponse(data) {
  return ContentService.createTextOutput(JSON.stringify(data)).setMimeType(
    ContentService.MimeType.JSON
  );
}

function createErrorResponse(message) {
  return ContentService.createTextOutput(
    JSON.stringify({
      error: {
        code: -1,
        message: message,
      },
    })
  ).setMimeType(ContentService.MimeType.JSON);
}

/**
 * 테스트 함수
 */
function testMCPServer() {
  console.log("MCP 서버 테스트 시작");

  // 도구 목록 테스트
  const toolsList = handleToolsList();
  console.log("도구 목록:", toolsList);

  console.log("MCP 서버가 정상적으로 설정되었습니다!");
}

2.2 Guardar

  • Haz clic en Ctrl + S o en el botón 💾 Guardar
  • Verifica que no haya errores de sintaxis (no debe haber subrayados rojos)

Paso 3: Implementar la Aplicación Web

3.1 Configuración de la Implementación

  1. Haz clic en el botón "Implementar" en la esquina superior derecha
  2. Selecciona "Nueva implementación"
  3. Haz clic en el icono de engranaje ⚙️ → Selecciona "Aplicación web"
  4. Ingresa los valores de configuración:
    • Descripción: "Claude MCP Server v1.0"
    • Ejecutar como: "Yo"
    • Acceso: "Cualquier usuario"

3.2 Aprobación de Permisos

  1. Haz clic en el botón "Implementar"
  2. Haz clic en la ventana emergente "Aprobar acceso"
  3. Selecciona tu cuenta de Google
  4. Haz clic en "Avanzado""Ir a no seguro (no seguro)""Ir"
  5. Haz clic en el botón "Permitir"

3.3 Copiar la URL de la Aplicación Web

  • Después de la implementación, copia y guarda la URL de la aplicación web que aparece
  • Formato: https://script.google.com/macros/s/ABC...XYZ/exec

Paso 4: Crear una Hoja de Cálculo de Prueba

4.1 Crear una Nueva Hoja de Cálculo

  1. Accede a Google Sheets
  2. Haz clic en "Nuevo""Hoja de cálculo vacía"
  3. Cambia el nombre de la hoja de cálculo a "Claude MCP Test Sheet"

4.2 Ingresar Datos de Prueba

Copia y pega los siguientes datos comenzando desde la celda A1:

이름	부서	직급	급여
김철수	개발팀	과장	5000
이영희	마케팅팀	대리	4000
박민수	인사팀	차장	6000
최은정	재무팀	사원	3500

4.3 Configuración de la Hoja de Cálculo

  1. Copiar el ID de la hoja de cálculo

    • Copia la parte del ID desde la barra de direcciones del navegador
    • https://docs.google.com/spreadsheets/d/[이부분이ID]/edit
  2. Configuración de uso compartido

    • Haz clic en el botón "Compartir" en la esquina superior derecha
    • Cambia "Cualquier persona con el enlace" al permiso de "Editor"
    • Haz clic en "Listo"

Paso 5: Probar el Servidor MCP

5.1 Prueba Básica

  1. Vuelve a Google Apps Script
  2. En el menú desplegable de selección de funciones, elige testMCPServer
  3. Haz clic en el botón ▶️ "Ejecutar"
  4. Aprueba los permisos (solo la primera vez)

5.2 Prueba de Lectura de Hoja de Cálculo

Agrega la siguiente función al final del código existente:

/**
 * 실제 스프레드시트 읽기 테스트
 */
function testReadSheet() {
  const spreadsheetId = "YOUR_SHEET_ID"; // 실제 스프레드시트 ID로 변경

  try {
    const result = readGoogleSheet({
      spreadsheetId: spreadsheetId,
      range: "A1:D10",
    });

    console.log("스프레드시트 읽기 성공!");
    console.log("결과:", result);
  } catch (error) {
    console.error("스프레드시트 읽기 실패:", error);
  }
}

5.3 Ejecutar la Prueba

  1. Selecciona la función testReadSheet y ejecútala
  2. Verifica que los datos de prueba aparezcan en el registro de ejecución

Paso 6: Configurar el Cliente MCP Local

6.1 Crear la Estructura de Carpetas del Proyecto

Crea una carpeta con la siguiente estructura en la ubicación deseada:

mkdir claude-gas-mcp
cd claude-gas-mcp
mkdir src
mkdir config

6.2 Crear package.json

Crea el archivo package.json en la raíz del proyecto:

{
  "name": "claude-gas-mcp",
  "version": "1.0.0",
  "description": "Claude와 Google Apps Script 연결을 위한 MCP 클라이언트",
  "main": "src/server.js",
  "type": "module",
  "scripts": {
    "start": "node src/server.js",
    "dev": "node --watch src/server.js"
  },
  "keywords": ["claude", "mcp", "google-apps-script"],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.4.0",
    "axios": "^1.6.0"
  }
}

6.3 Instalar Dependencias

npm install

6.4 Crear el Archivo de Configuración

Crea el archivo config/mcp-config.json:

{
  "name": "Google Apps Script MCP Server",
  "version": "1.0.0",
  "description": "Google Workspace와 Claude 연결",
  "config": {
    "webAppUrl": "YOUR_WEB_APP_URL_HERE",
    "testSpreadsheetId": "YOUR_SPREADSHEET_ID_HERE"
  },
  "tools": ["read_google_sheet", "write_google_sheet", "send_gmail"]
}

6.5 Crear el Código del Servidor MCP

Crea el archivo src/server.js:

#!/usr/bin/env node

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 설정 파일 로드
const configPath = path.join(__dirname, "../config/mcp-config.json");
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));

class GoogleAppsScriptMCPServer {
  constructor() {
    this.server = new Server(
      {
        name: "google-apps-script-mcp",
        version: "1.0.0",
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    this.setupToolHandlers();
    this.setupErrorHandling();
  }

  setupErrorHandling() {
    this.server.onerror = (error) => {
      console.error("[MCP Error]", error);
    };

    process.on("SIGINT", async () => {
      await this.server.close();
      process.exit(0);
    });
  }

  setupToolHandlers() {
    // 도구 목록 제공
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "read_google_sheet",
            description: "Google Sheets에서 데이터를 읽어옵니다",
            inputSchema: {
              type: "object",
              properties: {
                spreadsheetId: {
                  type: "string",
                  description: "스프레드시트 ID",
                },
                range: {
                  type: "string",
                  description: "읽을 범위 (예: A1:C10)",
                  default: "A:Z",
                },
              },
              required: ["spreadsheetId"],
            },
          },
          {
            name: "write_google_sheet",
            description: "Google Sheets에 데이터를 씁니다",
            inputSchema: {
              type: "object",
              properties: {
                spreadsheetId: {
                  type: "string",
                  description: "스프레드시트 ID",
                },
                range: {
                  type: "string",
                  description: "쓸 범위 (예: A1:C10)",
                },
                values: {
                  type: "array",
                  description: "쓸 데이터 (2차원 배열)",
                },
              },
              required: ["spreadsheetId", "range", "values"],
            },
          },
          {
            name: "send_gmail",
            description: "Gmail을 통해 이메일을 발송합니다",
            inputSchema: {
              type: "object",
              properties: {
                to: {
                  type: "string",
                  description: "받는 사람 이메일",
                },
                subject: {
                  type: "string",
                  description: "이메일 제목",
                },
                body: {
                  type: "string",
                  description: "이메일 내용",
                },
              },
              required: ["to", "subject", "body"],
            },
          },
        ],
      };
    });

    // 도구 실행
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;

      try {
        switch (name) {
          case "read_google_sheet":
            return await this.readGoogleSheet(args);

          case "write_google_sheet":
            return await this.writeGoogleSheet(args);

          case "send_gmail":
            return await this.sendGmail(args);

          default:
            throw new Error(`알 수 없는 도구: ${name}`);
        }
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `오류 발생: ${error.message}`,
            },
          ],
          isError: true,
        };
      }
    });
  }

  async callGoogleAppsScript(toolName, params) {
    const payload = {
      method: "tools/call",
      params: {
        name: toolName,
        arguments: params,
      },
    };

    try {
      console.log(`[MCP] Google Apps Script 호출: ${toolName}`, params);

      const response = await axios.post(config.config.webAppUrl, payload, {
        headers: {
          "Content-Type": "application/json",
        },
        timeout: 30000,
      });

      console.log(`[MCP] 응답 받음:`, response.data);
      return response.data;
    } catch (error) {
      console.error(`[MCP] 요청 실패:`, error.message);
      throw new Error(`Google Apps Script 호출 실패: ${error.message}`);
    }
  }

  async readGoogleSheet(args) {
    const result = await this.callGoogleAppsScript("read_google_sheet", args);

    return {
      content: [
        {
          type: "text",
          text: result.content?.[0]?.text || "데이터를 읽어왔습니다.",
        },
      ],
    };
  }

  async writeGoogleSheet(args) {
    const result = await this.callGoogleAppsScript("write_google_sheet", args);

    return {
      content: [
        {
          type: "text",
          text: result.content?.[0]?.text || "데이터를 저장했습니다.",
        },
      ],
    };
  }

  async sendGmail(args) {
    const result = await this.callGoogleAppsScript("send_gmail", args);

    return {
      content: [
        {
          type: "text",
          text: result.content?.[0]?.text || "이메일을 발송했습니다.",
        },
      ],
    };
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);

    console.error("Google Apps Script MCP 서버가 시작되었습니다.");
    console.error(`웹 앱 URL: ${config.config.webAppUrl}`);
    console.error(
      "사용 가능한 도구: read_google_sheet, write_google_sheet, send_gmail"
    );
  }
}

// 서버 시작
const server = new GoogleAppsScriptMCPServer();
server.run().catch(console.error);

6.6 Crear el Script de Prueba

Crea el archivo src/test.js:

import axios from "axios";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 설정 파일 로드
const configPath = path.join(__dirname, "../config/mcp-config.json");
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));

async function testGoogleAppsScript() {
  console.log("🧪 Google Apps Script MCP 연결 테스트 시작\n");

  // 테스트 1: 스프레드시트 읽기
  console.log("📊 테스트 1: 스프레드시트 데이터 읽기");
  try {
    const readPayload = {
      method: "tools/call",
      params: {
        name: "read_google_sheet",
        arguments: {
          spreadsheetId: config.config.testSpreadsheetId,
          range: "A1:D10",
        },
      },
    };

    const readResponse = await axios.post(
      config.config.webAppUrl,
      readPayload,
      {
        headers: { "Content-Type": "application/json" },
        timeout: 10000,
      }
    );

    console.log("✅ 스프레드시트 읽기 성공!");
    console.log("📋 응답:", readResponse.data);
  } catch (error) {
    console.log("❌ 스프레드시트 읽기 실패:", error.message);
  }

  console.log("\n🎉 테스트 완료!");
}

// 테스트 실행
testGoogleAppsScript().catch(console.error);

6.7 Probar la Conexión

node src/test.js

Paso 7: Conectar con Claude Desktop

7.1 Modificar el Archivo de Configuración de Claude Desktop

Ubicación del archivo de configuración en Windows:

%APPDATA%\Claude\claude_desktop_config.json

7.2 Contenido del Archivo de Configuración

Agrega el siguiente contenido a la configuración existente:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "@modelcontextprotocol/server-filesystem",
        "C:\\Users\\[사용자명]\\Desktop"
      ],
      "env": {}
    },
    "google-apps-script": {
      "command": "node",
      "args": ["C:\\[프로젝트경로]\\claude-gas-mcp\\src\\server.js"],
      "env": {
        "NODE_ENV": "production"
      }
    }
  },
  "darkMode": "dark",
  "scale": 0,
  "locale": "ko-KR"
}

7.3 Reiniciar Claude Desktop

  1. Cierra completamente la aplicación Claude Desktop
  2. Vuelve a iniciar la aplicación
  3. Comienza una nueva conversación

7.4 Probar la Conexión

Prueba lo siguiente en Claude Desktop:

Google Apps Script MCP 서버가 연결되었는지 확인하고,
스프레드시트 ID [YOUR_SHEET_ID]의 데이터를 읽어서 보여줘.

Ejemplos de Uso

📊 Manipulación Básica de Datos

Leer una Hoja de Cálculo

"스프레드시트 ID 13Qy45cJ6oDJsyS007bml2GAyklGAiY7EGd1GZ1vO7ro에서
직원 데이터를 읽어서 부서별 평균 급여를 계산해줘"

Agregar Datos

"새 직원 정보를 추가해줘:
이름-홍길동, 부서-IT팀, 직급-사원, 급여-3200"

Enviar un Correo Electrónico

"부서별 급여 현황을 요약해서 manager@company.com으로 보내줘"

🤖 Solicitudes de Automatización Avanzada

Crear una Función de Automatización de Tareas

"매일 아침 8시에 전날 매출 데이터를 분석해서
이메일로 보내주는 GAS 함수를 만들어줘"

Sistema de Correo Electrónico Inteligente

"Gmail에서 특정 키워드가 포함된 이메일을 자동으로 분류하고
적절한 템플릿으로 답변하는 함수를 만들어줘"

Resultado: Claude crea un sistema completo de automatización de correos electrónicos que incluye algoritmos de clasificación basados en palabras clave, un sistema de respuestas automáticas y funciones de etiquetado.

Panel de Control en Tiempo Real

"여러 시트의 데이터를 종합해서 실시간 대시보드를
만들어주는 함수를 작성해줘"

Resultado: Construye un panel de control HTML con actualizaciones en tiempo real y un sistema de renovación automática que integra múltiples fuentes de datos.

Automatización de Análisis de Datos

"매출 데이터를 분석해서 트렌드 예측하고
인사이트를 요약해서 경영진에게 보고하는 시스템을 만들어줘"

Resultado: Construye un sistema de BI que incluye análisis estadístico, modelado predictivo, gráficos de visualización y funciones de generación automática de informes.