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

はじめに
こんにちは
株式会社BTMでエンジニアをしている島谷です。
現在、他社様と副業契約を結んでおり、毎月月初に請求書を作成して送付しています。
その作業が毎回手間に感じられ、「もっとスマートに作成できないか」と考えるようになりました。
そこで、話題の Model Context Protocol(以下、MCP)を使って、請求書作成から送付までの自動化に試みました。
https://modelcontextprotocol.io/introduction
背景
これまで、月初になると手作業で次のような手順を踏んでいました。
- Toggl Trackで前月分の合計作業時間を控える
- Googleスプレッドシートの「請求書テンプレート」シートを複製
- 複製したシートに合計作業時間および請求日、支払い期限等の日付を入力
- PDFとしてエクスポート
- 担当者宛てに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