Claude Google Apps Script MCP Guide

Integre o Claude AI com o Google Apps Script para automatizar tarefas no Google Sheets e Gmail.

Documentação

Guia Completo de Integração Claude MCP Google Apps Script

Construindo um poderoso sistema de automação conectando Claude e Google Apps Script via MCP (Model Context Protocol)

Google Apps Script Node.js Claude

📋 Sumário

Visão Geral

Este guia fornece um método completo para conectar o Claude AI e o Google Apps Script por meio do protocolo MCP. Após a conexão, você poderá usar os seguintes recursos poderosos:

🚀 Principais recursos

  • 📊 Automação do Google Sheets: leitura/gravação de dados em tempo real, análise, geração de relatórios
  • 📧 Integração com Gmail: classificação inteligente de e-mails, respostas automáticas, envio em massa
  • 🤖 Automação de trabalho: gerenciamento de agenda, análise de dados, sistema de notificações
  • 📈 Dashboard em tempo real: monitoramento integrado de múltiplas fontes de dados

Requisitos do Sistema

Pré-requisitos

  • Conta do Google (Gmail)
  • Node.js (v18 ou superior) - Download
  • Aplicativo Claude Desktop - Download

Verificação da instalação

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

Etapa 1: Criar projeto do Google Apps Script

1.1 Criar novo projeto

  1. Acesse o Google Apps Script
  2. Clique em "Novo projeto"
  3. Altere o nome do projeto para "Claude MCP Server"
  4. Exclua todo o código myFunction() padrão

1.2 Verificações

  • ✅ O nome do projeto aparece como "Claude MCP Server"
  • ✅ O editor de código está completamente vazio

Etapa 2: Escrever o código do servidor MCP

2.1 Copiar e colar o código

Copie e cole o seguinte código no editor do 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 Salvar

  • Clique em Ctrl + S ou no botão 💾 Salvar
  • Verifique se não há erros de sintaxe (não deve haver sublinhados vermelhos)

Etapa 3: Implantar o aplicativo web

3.1 Configuração da implantação

  1. Clique no botão "Implantar" no canto superior direito
  2. Selecione "Nova implantação"
  3. Clique no ícone de engrenagem ⚙️ → Selecione "Aplicativo web"
  4. Insira os valores de configuração:
    • Descrição: "Claude MCP Server v1.0"
    • Executar como: "Eu"
    • Permissão de acesso: "Todos os usuários"

3.2 Aprovação de permissões

  1. Clique no botão "Implantar"
  2. Clique no pop-up "Aprovar acesso"
  3. Selecione a conta do Google
  4. Clique em "Avançado""Não seguro (unsafe)""Ir"
  5. Clique no botão "Permitir"

3.3 Copiar a URL do aplicativo web

  • Copie e salve a URL do aplicativo web exibida após a conclusão da implantação
  • Formato: https://script.google.com/macros/s/ABC...XYZ/exec

Etapa 4: Criar planilha de teste

4.1 Criar nova planilha

  1. Acesse o Google Sheets
  2. Clique em "Novo""Planilha em branco"
  3. Altere o nome da planilha para "Claude MCP Test Sheet"

4.2 Inserir dados de teste

Copie e cole os seguintes dados a partir da célula A1:

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

4.3 Configuração da planilha

  1. Copiar o ID da planilha

    • Copie a parte do ID na barra de endereço do navegador
    • https://docs.google.com/spreadsheets/d/[이부분이ID]/edit
  2. Configuração de compartilhamento

    • Clique no botão "Compartilhar" no canto superior direito
    • Altere para "Todos que têm o link" com permissão de "Editor"
    • Clique em "Concluído"

Etapa 5: Testar o servidor MCP

5.1 Teste básico

  1. Volte ao Google Apps Script
  2. Selecione testMCPServer no menu suspenso de seleção de função
  3. Clique no botão ▶️ "Executar"
  4. Aprove as permissões (na primeira execução)

5.2 Teste de leitura da planilha

Adicione a seguinte função no final do 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 Executar o teste

  1. Selecione e execute a função testReadSheet
  2. Verifique se os dados de teste são exibidos no log de execução

Etapa 6: Configurar o cliente MCP local

6.1 Criar pasta do projeto

Crie uma pasta com a seguinte estrutura no local desejado:

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

6.2 Criar package.json

Crie o arquivo package.json na raiz do projeto:

{
  "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 dependências

npm install

6.4 Criar arquivo de configuração

Crie o arquivo 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 Criar código do servidor MCP

Crie o arquivo 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 Criar script de teste

Crie o arquivo 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 Teste de conexão

node src/test.js

Etapa 7: Conectar ao Claude Desktop

7.1 Modificar o arquivo de configuração do Claude Desktop

Localização do arquivo de configuração no Windows:

%APPDATA%\Claude\claude_desktop_config.json

7.2 Conteúdo do arquivo de configuração

Adicione o seguinte conteúdo à configuração 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 o Claude Desktop

  1. Feche completamente o aplicativo Claude Desktop
  2. Reinicie o aplicativo
  3. Inicie uma nova conversa

7.4 Teste de conexão

Teste no Claude Desktop da seguinte forma:

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

Exemplos de uso

📊 Manipulação básica de dados

Ler planilha

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

Adicionar dados

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

Enviar e-mail

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

🤖 Solicitações de automação avançada

Criar função de automação de trabalho

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

Sistema de e-mail inteligente

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

Resultado: o Claude cria um sistema completo de automação de e-mail com algoritmo de classificação baseado em palavras-chave, sistema de resposta automática e funcionalidade de etiquetagem.

Dashboard em tempo real

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

Resultado: integra múltiplas fontes de dados para construir um dashboard HTML com atualização em tempo real e sistema de renovação automática.

Automação de análise de dados

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

Resultado: constrói um sistema de BI com análise estatística, modelagem preditiva, gráficos de visualização e geração automática de relatórios.