Skip to main content
Glama

Spreadsheet MCP Server

by HosakaKeigo
/** * スプレッドシートAPI * Google Apps ScriptのWeb Appを呼び出す実装 */ import { SpreadsheetInfo, SheetData } from './types.js'; import { config } from '../config.js'; /** * スプレッドシートのURLからIDを抽出する関数 * @param url スプレッドシートのURL * @returns スプレッドシートID */ export function extractSpreadsheetId(url: string): string | null { try { // URL自体がnullまたはundefinedの場合 if (!url) { return null; } // 実際のGoogle SpreadsheetのURLからIDを抽出 // 例: https://docs.google.com/spreadsheets/d/1a2b3c4d5e6f7g8h9i0j/edit#gid=0 const regex = /\/d\/([a-zA-Z0-9_-]+)/; const match = url.match(regex); if (match && match[1]) { return match[1]; } // モック用に特殊なURLも処理 if (config.isMockMode && (url.includes("budget") || url.includes("project"))) { return url.includes("budget") ? "mock_budget" : "mock_project"; } return null; } catch (error) { console.error("URL解析エラー:", error); return null; } } /** * スプレッドシートの基本情報を取得するAPIクライアント関数 * @param spreadsheetId スプレッドシートID * @returns スプレッドシート情報 */ export async function getSpreadsheetInfo(spreadsheetId: string): Promise<SpreadsheetInfo> { // モックモードの場合はモックデータを返す if (config.isMockMode) { return getMockSpreadsheetInfo(spreadsheetId); } // API呼び出し用のURLを生成 const apiUrl = new URL(config.gas.webAppUrl); apiUrl.searchParams.append('action', 'getSpreadsheet'); apiUrl.searchParams.append('id', spreadsheetId); apiUrl.searchParams.append('apiKey', config.gas.apiKey); // APIリクエスト const response = await fetch(apiUrl); // ステータスコードのチェック if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || `API Error: ${response.status}`); } // レスポンスをJSONとしてパース return await response.json() as SpreadsheetInfo; } /** * シートのデータを取得するAPIクライアント関数 * @param spreadsheetId スプレッドシートID * @param sheetName シート名 * @returns シートデータ(二次元配列) */ export async function getSheetData( spreadsheetId: string, sheetName: string ): Promise<SheetData> { // モックモードの場合はモックデータを返す if (config.isMockMode) { return getMockSheetData(spreadsheetId, sheetName); } // API呼び出し用のURLを生成 const apiUrl = new URL(config.gas.webAppUrl); apiUrl.searchParams.append('action', 'getSheetData'); apiUrl.searchParams.append('id', spreadsheetId); apiUrl.searchParams.append('sheetName', sheetName); apiUrl.searchParams.append('apiKey', config.gas.apiKey); // 任意のパラメータ(必要に応じて) // apiUrl.searchParams.append('maxRows', '1000'); // APIリクエスト const response = await fetch(apiUrl); // ステータスコードのチェック if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || `API Error: ${response.status}`); } // レスポンスをJSONとしてパース const result = await response.json(); // APIのレスポンス形式を SheetData 形式(二次元配列)に変換 return result.data as SheetData; } /** * モック用のスプレッドシート情報データ */ function getMockSpreadsheetInfo(spreadsheetId: string): SpreadsheetInfo { // 異なるスプレッドシートIDで異なるモックを返す if (spreadsheetId === "mock_budget") { return { id: "mock_budget", name: "家計簿 2024", url: `https://docs.google.com/spreadsheets/d/${spreadsheetId}`, lastModified: "2024-04-01T10:30:00Z", sheets: [ { id: 1, name: "4月", index: 0, rowCount: 100, columnCount: 10 }, { id: 2, name: "5月", index: 1, rowCount: 100, columnCount: 10 }, { id: 3, name: "集計", index: 2, rowCount: 50, columnCount: 8 } ] }; } else if (spreadsheetId === "mock_project") { return { id: "mock_project", name: "プロジェクト管理", url: `https://docs.google.com/spreadsheets/d/${spreadsheetId}`, lastModified: "2024-03-28T15:45:00Z", sheets: [ { id: 1, name: "タスク一覧", index: 0, rowCount: 200, columnCount: 12 }, { id: 2, name: "予算", index: 1, rowCount: 50, columnCount: 8 }, { id: 3, name: "メンバー", index: 2, rowCount: 20, columnCount: 6 } ] }; } else { // 存在しないスプレッドシートIDの場合はエラーを投げる throw new Error(`スプレッドシート「${spreadsheetId}」は存在しないか、アクセスできません。`); } } /** * モック用のシートデータ */ function getMockSheetData(spreadsheetId: string, sheetName: string): SheetData { // 家計簿のモックデータ if (spreadsheetId === "mock_budget") { if (sheetName === "4月") { return [ ["日付", "カテゴリ", "内容", "金額", "備考"], ["2024/4/1", "食費", "スーパー", 3500, null], ["2024/4/2", "交通費", "電車", 500, "通勤"], ["2024/4/3", "日用品", "ドラッグストア", 2800, null], ["2024/4/5", "食費", "外食", 4200, "ランチミーティング"], ["2024/4/7", "娯楽", "映画", 1800, null] ]; } else if (sheetName === "5月") { return [ ["日付", "カテゴリ", "内容", "金額", "備考"], ["2024/5/1", "食費", "スーパー", 3800, null], ["2024/5/3", "交通費", "電車", 500, "通勤"], ["2024/5/5", "日用品", "ホームセンター", 5600, "掃除用品"], ["2024/5/8", "食費", "外食", 3500, null] ]; } else if (sheetName === "集計") { return [ ["月", "食費", "交通費", "日用品", "娯楽", "その他", "合計"], ["4月", 7700, 500, 2800, 1800, 0, 12800], ["5月", 7300, 500, 5600, 0, 0, 13400] ]; } // シートが見つからない場合はエラーを投げる throw new Error(`シート「${sheetName}」は「家計簿 2024」に存在しません。`); } // プロジェクト管理のモックデータ else if (spreadsheetId === "mock_project") { if (sheetName === "タスク一覧") { return [ ["ID", "タスク名", "担当者", "開始日", "期限", "状態", "進捗率"], [1, "要件定義", "佐藤", "2024/3/1", "2024/3/15", "完了", 100], [2, "設計", "田中", "2024/3/16", "2024/3/31", "完了", 100], [3, "実装", "鈴木", "2024/4/1", "2024/4/30", "進行中", 60], [4, "テスト", "高橋", "2024/5/1", "2024/5/15", "未着手", 0], [5, "リリース", "伊藤", "2024/5/16", "2024/5/20", "未着手", 0] ]; } else if (sheetName === "予算") { return [ ["項目", "予算", "実績", "差異"], ["人件費", 5000000, 4800000, 200000], ["ハードウェア", 1000000, 950000, 50000], ["ソフトウェア", 800000, 820000, -20000], ["外注費", 1500000, 1400000, 100000], ["その他", 500000, 300000, 200000], ["合計", 8800000, 8270000, 530000] ]; } else if (sheetName === "メンバー") { return [ ["名前", "役割", "部署", "参画率"], ["佐藤", "PM", "システム開発部", 100], ["田中", "設計", "システム開発部", 80], ["鈴木", "開発", "システム開発部", 100], ["高橋", "テスト", "品質保証部", 50], ["伊藤", "インフラ", "運用部", 30] ]; } // シートが見つからない場合はエラーを投げる throw new Error(`シート「${sheetName}」は「プロジェクト管理」に存在しません。`); } // 存在しないスプレッドシートIDの場合はエラーを投げる throw new Error(`スプレッドシート「${spreadsheetId}」は存在しないか、アクセスできません。`); }

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/HosakaKeigo/spreadsheet-mcp-server'

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