ブログ

Blog

MCPサーバーを使って請求書作成から送付まで自動化してみた話

MCPサーバーを使って請求書作成から送付まで自動化してみた話

はじめに

こんにちは
株式会社BTMでエンジニアをしている島谷です。

現在、他社様と副業契約を結んでおり、毎月月初に請求書を作成して送付しています。
その作業が毎回手間に感じられ、「もっとスマートに作成できないか」と考えるようになりました。

そこで、話題の Model Context Protocol(以下、MCP)を使って、請求書作成から送付までの自動化に試みました。
https://modelcontextprotocol.io/introduction

背景

これまで、月初になると手作業で次のような手順を踏んでいました。

  1. Toggl Trackで前月分の合計作業時間を控える
  2. Googleスプレッドシートの「請求書テンプレート」シートを複製
  3. 複製したシートに合計作業時間および請求日、支払い期限等の日付を入力
  4. PDFとしてエクスポート
  5. 担当者宛てにGmailで送信

流れ自体は単純ですが、シートへの入力ミスを防ぐために何度も確認していることから、10〜15分ほど取られていました。

そこで、「MCPサーバーを使って各サービスを連携させれば、AIチャットに『先月分の請求書を作って送って』とひと言指示するだけで、一連の処理を完結できるのではないか」と考えました。

結果として、請求書作成から送付までを自動化できたので、成果物と自動化までの過程を紹介します。

出来上がったもの

わかりにくいですが、プロンプトを投げた後、以下の処理を自動で行ってます。

  • Toggl Trackから作業時間を取得
  • templateシートを複製
  • 複製したシートの名称を変更
  • 作業時間および請求日等を入力
  • PDFエクスポート
  • Gmail作成

請求書の内容は全てサンプルとなっています。

デモ用のためメール送信は行わず、宛先を空欄にし下書き保存しています。

投げたプロンプト

toggle-toolsのMCPサーバーを使って以下のことをしてほしい。
・togglApiTokenはmcp.jsonに記載している値を対象とする
・2025年4月の合計作業時間を取得して

Google SheetsのMCPサーバーを使って以下のことをしてほしい。
・spreadsheetIdはmcp.jsonに記載している値を対象とする
・「template」シートを複製して

GAS ToolboxのMCPサーバーを使って以下のことをしてほしい。
・spreadsheetIdやrenameSheetBaseUrlはmcp.jsonに記載している値を対象とする
・上記で複製したシートの名前を「25.05」に変更して

再度、Google SheetsのMCPサーバーを使って以下のことをしてほしい。
・「25.05」シートのシートIDを取得して
・上記のシートIDを使用して、K10セルに合計作業時間をhh:mm:ss形式でセットして
・上記のシートIDを使用して、K17セルに「'2025年4月」をセットして
・上記のシートIDを使用して、K18セルに「2025年5月1日」をセットして
・上記のシートIDを使用して、K19セルに「2025年5月31日」をセットして

GAS ToolboxのMCPサーバーを使って以下のことをしてほしい。
・createSheetPdfBaseUrlはmcp.jsonに記載している値を対象とする
・上記で複製したシートをPDFにしてほしい。ファイル名は「請求書(25.04)」として

GmailのMCPサーバーを用いて、以下のことをしてほしい。
・宛先は空欄とする
・上記のダウンロードリンクを添付ファイルとしてメールを下書き保存で作成して
・添付ファイル名は「請求書(25.04)」として

アーキテクチャは以下の通りです。

自動化までの過程

まず、自動化する上で関わってくる、MCPホストとMCPクライアント、MCPサーバーの役割について簡単に説明しておきます。

名称 説明
MCPホスト “LLMを動かすアプリ本体”で、ユーザーからの入力を受け取り、内部でMCPクライアントを起動します。
MCPクライアント ホストとサーバーの間に立つプロキシで、ホスト側からのリクエストをサーバーへ送り、返ってきたレスポンスをホストに中継する役目を担います。
MCPサーバー クライアントに対して特定のデータソースやツールへのアクセスを提供します。

今回、CursorをMCPホストとして使用してみます。
https://www.cursor.com/ja

Toggl Trackとの連携

前月分の作業時間を取得できるようにするため、Toggl TrackのMCPサーバーが公開されているか調査しました。

調査の結果、Pipedreamにありました。

Pipedreamは、2,500を超える統合アプリすべてに専用のMCPサーバーを提供しています。…

MCPサーバーの公開URLとOAuthトークンをコピーして貼り付けるだけでホストと接続できるため、導入がとても手軽です。そこで今回の自動化においては、PipedreamのMCPサーバーを採用することにしました。
https://mcp.pipedream.com/

Toggl TrackのMCPサーバーの仕様は以下の通りです。

Available toolsに「Get Time Entries」アクションがあるので、こちらが使えそうです。

しかし、MCPサーバー側の「Get Time Entries」アクションはリクエストパラメータを受け付けないため期間を限定できない問題がありました。
GitHub Issue

2025年5月16日時点で上記IssueはClose済です。

そこで、MCPサーバーを一旦自作することにしました。

MCPサーバー自作

以下リポジトリを使って自作します。
mcp-on-vercel

ツール定義


import { z } from "zod";
import { initializeMcpApiHandler } from "../lib/mcp-api-handler";
import { TogglTrackClient } from "../lib/toggle-track";

const handler = initializeMcpApiHandler(
  (server) => {
    server.tool("getTimeEntries", {
      togglApiToken: z.string(),
      startDate: z.string(),
      endDate: z.string()
    }, async ({ togglApiToken, startDate, endDate }) => {
      if (!togglApiToken) {
        throw new Error("Unauthorized: Invalid Toggle API key");
      }
      const client = new TogglTrackClient(togglApiToken);
      const data = await client.getTotalMonthlyDuration(startDate, endDate);
      return { content: [{ type: "text", text: `Result: ${JSON.stringify(data)}` }] };
    });
  },
  {
    capabilities: {
      tools: {
        getTimeEntries: { description: "Get span time entries" }
      }
    }
  }
);

export default handler;

作業時間の取得


import axios from 'axios';
const TOGGL_TRACK_API_BASE_URL = 'https://api.track.toggl.com/api/v9';

export class TogglTrackClient {
  private apiToken: string;
  constructor(apiToken: string) {
    this.apiToken = apiToken;
  }
  private getAuthHeader() {
    return {
      'Content-Type': "application/json",
      Authorization: `Basic ${Buffer.from(`${this.apiToken}:api_token`).toString('base64')}`,
    };
  }
  async getTotalMonthlyDuration(inputStartDate?: string, inputEndDate?: string) {
    const now = new Date();
    const start = inputStartDate ?? `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}-01`;
    const end   = inputEndDate   ?? `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}-${new Date(now.getFullYear(), now.getMonth()+1,0).getDate()}`;
    const { startUTC } = toJSTDayRangeUTC(start);
    const { endUTC: endOfEndUTC } = toJSTDayRangeUTC(end);
    const response = await axios.get(`${TOGGL_TRACK_API_BASE_URL}/me/time_entries`, {
      headers: this.getAuthHeader(),
      params: { start_date: startUTC, end_date: endOfEndUTC },
    });
    const totalSeconds = this.getTotalDurationSeconds(response.data);
    return this.formatSecondsToHHMMSS(totalSeconds);
  }
}

以降、同様にVercelデプロイ、Cursor設定、Google Sheets連携、GAS Toolbox自作、Gmail連携を行い、最後に一連の流れをまとめて実行できるようにしました。

終わりに

MCPサーバーを活用し、請求書の作成から送付までを自動化する過程を紹介しました。

公開サーバーを組み合わせるだけで連携フローが簡単に構築でき、足りない機能は自前で実装可能です。今後もMCPの発展に期待しています。

以上です、最後までご覧いただきありがとうございました。

株式会社BTMではエンジニアの採用をしております。ご興味がある方はぜひコチラをご覧ください。

  • SNS
  • 投稿日
  • カテゴリー

    BTM Useful