Search

Discussion – 

0

Discussion – 

0

ClaudeMCP(ModelContextProtocol)とGoogleDriveを接続する方法について解説!Windows編

はじめに

Claudeからリリースされた、「MCP(ModelContextProtcol」。早速、外部サービスとの接続を試して、自動化を試している人も多いかと思います。そこで本記事では、Claude DesktopアプリとGoogle Driveを連携させる具体的な手順を詳しく解説します。この設定により、Google Drive内のファイル操作をClaudeの環境下で簡単に行うことが可能になります。


必要な準備

必須インストール項目

ClaudeとGoogle Driveを連携するには、以下のソフトウェアが必要です。事前にインストールしておきましょう。

  • Claude Desktopアプリ
  • Node.js
  • winget
  • Git(未インストールの場合)

Wingetのインストール方法

コマンドプロンプトを開いて、以下のコマンドを実行してください。

winget install --id=astral-sh.uv -e

Gitのインストール方法


MCPサーバーのインストール

ClaudeとGoogle DriveをつなぐMCPサーバーをインストールします。

MCPサーバーの取得と配置

  1. コマンドプロンプトやターミナルで、目的のディレクトリに移動します。bashコードをコピーするcd C:\Projects
  2. Google Drive MCPサーバーのリポジトリをクローンします。

git clone https://github.com/modelcontextprotocol/servers.git cd servers

そして、インストールされたserversフォルダに移動します。

cd servers

そうすると、serversフォルダの中にファイルやフォルダがインストールされていることがわかります。これで、MCPサーバはインストールできています。

Google Cloud Consoleの設定

Google Drive APIを有効にするために、Google Cloud Consoleでプロジェクトを設定します。

Google Drive APIの有効化

  1. Google Cloud Consoleにログイン。
  2. 新しいプロジェクトを作成します。
  3. 「APIとサービス」 > 「ライブラリ」からGoogle Drive APIを検索して有効化します。

OAuth 2.0 クライアントIDの作成

  1. 「APIとサービス」 > 「認証情報」を開き、「認証情報を作成」 > **「OAuthクライアントID」**を選択します。
  2. アプリケーションタイプを「デスクトップアプリ」に設定し、JSONファイルをダウンロード。
  3. ダウンロードしたJSONファイルをgcp-oauth.keys.jsonにファイル名変更を行い、serversフォルダに配置します。
  4. OAuth同意画面へ移動すると、アプリが 「テスト」モード に設定されていることが確認されます。
  5. 「アプリを公開」ボタンをクリックして、「公開」モード に変更してください。

JSONファイルの配置

  1. ファイルパス検索で「C:\Users\USERNAME\AppData\Roaming\Claude」を検索
  2. ファイルをserversフォルダのルートに、先ほどファイル名変更したJSONファイルを配置します:
    servers/gcp-oauth.keys.json

MCPサーバーのビルドと設定

MCPサーバーをビルドして、Claudeとの連携を可能にします。

サーバーのビルド

  1. MCPサーバーのフォルダに移動します。 コマンド:cd C:\Users\ユーザー名\servers
  2. 必要なパッケージをインストールします。コマンド:npm install
  3. ビルドを実行します。コマンド:npm run build
  4. ビルド後、distフォルダが作成されていることを確認します。コマンド:dir

ts.config.jsonファイルの編集

上記手順の中でdirコマンドを実行して、distというフォルダが表示されない場合、serversフォルダ内のtsconfig.jjsoファイルを開いて、outDir(コンパイル後の出力先)を指定します。

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "outDir": "./dist",  // コンパイル後の出力先ディレクトリ
    "rootDir": "./src"   // ソースコードのルートディレクトリ
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

tsconfig.json を保存したら_修正を反映させるために、以下のコマンドを実行してください:

npx tsc

その後、もう一度確認のために、フォルダの中身を確認するコマンドを実行します。

dir

無事に、distが表示されていることがわかります。

gdriveフォルダ内のindex.jsファイルのコードを編集

index.jsという名前のJavaScriptファイルが表示されるはずです。

ファイル名が確認できたら、以下の通り、ファイルのコードを修正します。

#!/usr/bin/env node
import { authenticate } from "@google-cloud/local-auth";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
    CallToolRequestSchema,
    ListResourcesRequestSchema,
    ListToolsRequestSchema,
    ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fs from "fs";
import { google } from "googleapis";
import path from "path";
import { fileURLToPath } from "url";

// __dirname の代替
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 認証情報保存ファイルのパス
const credentialsPath = path.join(__dirname, "../../../.gdrive-server-credentials.json");

// ユーザーが準備するファイルのパス
const keyFilePath = path.join(__dirname, "../../gcp-oauth.keys.json"); // <変更が必要>

// Google Drive API クライアント
const drive = google.drive("v3");

// MCP サーバーの設定
const server = new Server(
    {
        name: "example-servers/gdrive",
        version: "0.1.0",
    },
    {
        capabilities: {
            resources: {},
            tools: {},
        },
    }
);

// リソース一覧のハンドラ
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
    const pageSize = 10; // 取得するファイル数
    const params = {
        pageSize,
        fields: "nextPageToken, files(id, name, mimeType)",
    };

    if (request.params?.cursor) {
        params.pageToken = request.params.cursor;
    }

    const res = await drive.files.list(params);
    const files = res.data.files;

    return {
        resources: files.map((file) => ({
            uri: `gdrive:///${file.id}`,
            mimeType: file.mimeType,
            name: file.name,
        })),
        nextCursor: res.data.nextPageToken,
    };
});

// リソース読み込みのハンドラ
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
    const fileId = request.params.uri.replace("gdrive:///", "");
    const file = await drive.files.get({
        fileId,
        fields: "mimeType",
    });

    // Google ドキュメントの場合
    if (file.data.mimeType?.startsWith("application/vnd.google-apps")) {
        let exportMimeType;
        switch (file.data.mimeType) {
            case "application/vnd.google-apps.document":
                exportMimeType = "text/markdown";
                break;
            case "application/vnd.google-apps.spreadsheet":
                exportMimeType = "text/csv";
                break;
            default:
                exportMimeType = "text/plain";
        }
        const res = await drive.files.export(
            { fileId, mimeType: exportMimeType },
            { responseType: "text" }
        );

        return {
            contents: [
                {
                    uri: request.params.uri,
                    mimeType: exportMimeType,
                    text: res.data,
                },
            ],
        };
    }

    // 通常のファイルの場合
    const res = await drive.files.get(
        { fileId, alt: "media" },
        { responseType: "arraybuffer" }
    );
    const mimeType = file.data.mimeType || "application/octet-stream";

    return {
        contents: [
            {
                uri: request.params.uri,
                mimeType,
                text: mimeType.startsWith("text/")
                    ? Buffer.from(res.data).toString("utf-8")
                    : Buffer.from(res.data).toString("base64"),
            },
        ],
    };
});

// ツールリストのハンドラ
server.setRequestHandler(ListToolsRequestSchema, async () => {
    return {
        tools: [
            {
                name: "search",
                description: "Search for files in Google Drive",
                inputSchema: {
                    type: "object",
                    properties: {
                        query: {
                            type: "string",
                            description: "Search query",
                        },
                    },
                    required: ["query"],
                },
            },
        ],
    };
});

// ツール実行のハンドラ
server.setRequestHandler(CallToolRequestSchema, async (request) => {
    if (request.params.name === "search") {
        const userQuery = request.params.arguments?.query;
        const res = await drive.files.list({
            q: `fullText contains '${userQuery}'`,
            pageSize: 10,
            fields: "files(id, name, mimeType)",
        });

        const fileList = res.data.files?.map(
            (file) => `${file.name} (${file.mimeType})`
        );

        return {
            content: [
                {
                    type: "text",
                    text: `Found ${res.data.files.length} files:\n${fileList.join(
                        "\n"
                    )}`,
                },
            ],
            isError: false,
        };
    }
    throw new Error("Tool not found");
});

// 認証処理
async function authenticateAndSaveCredentials() {
    console.log("Launching auth flow...");
    const auth = await authenticate({
        keyfilePath: keyFilePath, // ユーザー指定ファイル
        scopes: ["https://www.googleapis.com/auth/drive.readonly"],
    });
    fs.writeFileSync(credentialsPath, JSON.stringify(auth.credentials));
    console.log("Credentials saved. You can now run the server.");
}

// サーバー起動処理
async function loadCredentialsAndRunServer() {
    if (!fs.existsSync(credentialsPath)) {
        console.error("Credentials not found. Please run with 'auth' argument first.");
        process.exit(1);
    }

    const credentials = JSON.parse(fs.readFileSync(credentialsPath, "utf-8"));
    const auth = new google.auth.OAuth2();
    auth.setCredentials(credentials);
    google.options({ auth });

    console.log("Credentials loaded. Starting server...");
    const transport = new StdioServerTransport();
    await server.connect(transport);
}

// コマンドライン引数の処理
if (process.argv[2] === "auth") {
    authenticateAndSaveCredentials().catch(console.error);
} else {
    loadCredentialsAndRunServer().catch(console.error);
}

コードを記述したら、ファイルを上書き保存します。

GoogleAPIを認証する

次に、認証情報を保存するために、コマンドプロンプトで以下のプロンプトを実行します。

node ./dist/gdrive/index.js auth

そうすると、ブラウザが自動的に開き、Google認証画面が表示されます。そこで、今回MCPとの接続に使用するGoogleアカウントでログインし、アクセスを承認します。

このまま、「続行」ボタンをクリックします。

そうすると、以下のように「このアプリはGoogleで確認されていません」という警告画面が表示されます。

今回、自分で作成したGoogleアプリのサービスに、自分のアカウントを接続させることになるため、問題がなければ、この画面の中の「詳細」をクリック後に画面に表示される「”アプリ名”(安全ではないページ)に移動」をクリックします。

そうすると、以下のような画面に切り替わり、Googleとの認証に成功します。

一連の認証フロー が正しく進んだ後、.gdrive-server-credentials.json が gdrive フォルダ内 に生成されます。


Claude Desktopの設定

Claude Desktopアプリの設定ファイルを編集して、MCPサーバーが起動できるようにします。

設定ファイルの編集

Claudeデスクトップアプリを開いて、メニュー画面の「File」→「Settings」へと進みます。

そうすると、設定画面に移動できます。画面左側に表示される「Developer」というタブをクリックし、次に画面に表示される「Edit Config」ボタンをクリックします。

そうすると、ローカルPCのエクスプローラーで、Claudeデスクトップアプリがインストールされているフォルダに移動できます。

この中からclaude_desktop_config.jsonを開き、以下の設定を追加します:

{
  "mcpServers": {
    "googleDrive": {
      "command": "node",
      "args": [
        "./dist/gdrive/index.js"
      ]
    }
  }
}

コードを追加したら、ファイルを保存し、ファイルを閉じます。

サーバーの起動と確認

MCPサーバーの起動

以下のコマンドでサーバーを起動します:

コマンド:node ./dist/gdrive/index.js

動作確認

次に、Claude Desktopを再起動し、新しいチャットセッションを開始します。以下のプロンプトを試して、動作確認を行いましょう:

プロンプト:Google Drive内のファイル一覧を取得してください

正しく接続ができていれば、ご自身のGoogleドライブに保存されているファイル名について、回答してくれるはずです。

まとめ

本記事では、Claude DesktopアプリとGoogle Driveを連携する方法について、具体的な手順を詳細に解説しました。この設定を完了することで、Google Drive内のファイルをMCPサーバーを通じてスムーズに操作できるようになります。特に、MCPサーバーのインストールやGoogle Cloud ConsoleでのAPI設定は少し手間がかかる部分ですが、絶対に試したいという方は、一度チャレンジしてみてください。

今後は、Google Driveとの接続を通してどのような効率化が測れるのか、私も模索しながら、みなさんに情報をお届けできたらと思います。

Tags:

machiko

0コメント

コメントを提出

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

You May Also Like

X