MCPサーバーを使った複数のStripeアカウントデータの統合分析と可視化に挑戦してみた
SaaSビジネスを成長させる過程で、複数のStripeアカウントを管理する必要性は珍しくありません。事業部門ごと、製品ラインごと、あるいは地域ごとに別々のアカウントを持つことで、会計管理や収益の追跡は柔軟になりますが、ビジネス全体を俯瞰するデータ分析は複雑になってしまいます。
本記事では、Model Context Protocol(MCP)を活用した複数のStripeアカウントからのデータ統合、分析手法、そして意味のあるビジネスインサイトを導き出すための可視化テクニックについて解説します。すでに構築されたMCPサーバーを基盤として、データを統合し、AIアシスタントとの連携によってデータの価値を最大化する方法を紹介します。
エンジニアの皆さんが抱える「複数アカウントのデータをどう統合すべきか」「統合したデータからどのようなインサイトを導き出せるか」という課題に対する実践的なアプローチを提供できればと思います。
オフィシャルのStripe MCPは複数アカウントに対応していない
Stripeは公式でMCPサーバーを提供しています。これを使うことで、請求書データや決済履歴、残高に関するデータをClaude Desktopにて調査や分析させることができます。
しかしこのツールは、2025/4時点では、複数のアカウントを横断して使う用途には利用できません。これはMCPを設定する際に、APIキーを指定する仕組みとなっているためです。
{
"mcpServers": {
"stripe": {
"command": "npx",
"args": ["-y", "@stripe/mcp", "--tools=all"],
"env": {
"STRIPE_SECRET_KEY": "sk_test_xxxx"
}
}
}
}
このため、たとえば「A / B / Cのサービス全てを使っているユーザー・企業はどこ?」のような、アカウントを横断した調査・検索などについては、別途MCPサーバーを自作する必要があります。
複数のStripeアカウントを横断検索するMCPサーバーを作る
複数のSaaSを提供している場合、やはりこのアカウント横断検索機能が欲しくなってきました。そこで現在試しているのが、APIキーの名前でアカウントを区別する仕組みです。
MCPサーバー側でAPIキーを読み込む際、特定の命名規則に従っていれば、アカウント名: APIキー
のパターンにマッピングし直す処理を実装します。
/**
* 環境変数からStripeのAPIキーを抽出する関数
*
* 環境変数の形式:
* "STRIPE_1ST_ACCOUNT_APIKEY": "sk_test_xxx",
* "STRIPE_2ND_ACCOUNT_APIKEY": "sk_test_xxx",
* "STRIPE_3RD_ACCOUNT_APIKEY": "sk_test_xxx"
*
* 戻り値の形式:
* {
* '1st_account': 'sk_test_xxx',
* '2nd_account': 'sk_test_xxx',
* '3rd_account': 'sk_test_xxx',
* }
*
* @param env 環境変数オブジェクト
* @returns 抽出されたStripe APIキーのオブジェクト
*/
export function extractStripeApiKeys(env: Record<string, string | undefined>): Record<string, string> {
return Object.entries(env)
.filter(([key, value]) => key.startsWith('STRIPE_') && key.includes('_ACCOUNT_') && key.endsWith('_APIKEY'))
.filter(([_, value]) => {
if (!value) return false;
if (value.startsWith('sk_')) {
logger.error(`[extractStripeApiKeys] sk_から始まるAPIキーは使用できません。rk_から始まる制限つきAPIキーを使用してください。`);
throw new Error('sk_から始まるAPIキーは使用できません。rk_から始まる制限つきAPIキーを使用してください。');
}
return value.startsWith('rk_');
})
.reduce((acc, [key, value]) => {
// STRIPE_1ST_ACCOUNT_APIKEY から 1st_account を抽出
const accountName = key.replace('STRIPE_', '').replace('_APIKEY', '').toLowerCase();
return {
...acc,
[accountName]: value as string
};
}, {} as Record<string, string>);
}
このマッピングに従って、Stripe SDKを初期化する関数も用意しました。
getStripeInstance(accountName: string): Stripe {
if (!(accountName in apiKeys)) {
throw new Error(`Account ${accountName} not found`);
}
return new Stripe(this.apiKeys[accountName] );
}
あとはMCPサーバーのツールに組み込んでいくだけです。ここで引数にaccount
を追加し、ユーザーが指示したアカウントを引数として取れるようにしています。
server.tool(`search_stripe_customer_by_name`, {
name: z.string().min(1, "Name is required"),
account: z.string().optional().describe("アカウント名(例: 1st_account, 2nd_account)または「all」ですべてのアカウントを検索"),
}, async (args: { name: string, account?: string }) => {
const { name, account } = args;
const stripeService = new StripeService({
apiKeys: extractStripeApiKeys(process.env),
logger: logger,
apiVersion: STRIPE_API_VERSION
});
...
統合レスポンスの生成
取得したデータは、クライアントが扱いやすい統一フォーマットに変換されます:
public formatResponse(results: SearchResult[]): { content: MCPResponseContent[] } {
if (results.length === 0) {
return {
content: [{ type: "text", text: `登録されているStripeアカウントが見つかりません。` }]
};
}
const recursiveCallTargets = results.filter((result) => {
return result.data.has_more
});
return {
content: [{
type: "text" as const,
text: JSON.stringify({
data: results.reduce((acc, result) => {
return {
...acc,
[result.accountName]: {
data: result.data,
success: result.success,
message: result.message,
has_more: result.has_more || undefined,
next_page: result.next_page || undefined,
}
}
}, {} as Record<string, object>),
has_more: recursiveCallTargets.length > 0,
notice: recursiveCallTargets.length < 1 ? null :
`データが全件必要な場合、次のリソースはnext_pageを指定してもう一度呼び出してください。\n${
recursiveCallTargets.map((target) =>
`- ${target.accountName}: 'next_page' is ${target.data?.next_page}`
).join('\n')
}`
})
}]
};
}
このフォーマットにより、各アカウントのデータがアカウント名をキーとして整理され、一貫した形式でクライアントに提供されます。また、ページネーション情報も含まれているため、大量のデータも適切に取得できます。
実装時の注意点として、特に大量のデータを扱う場合は、生成AIのトークン量(コンテキストウィンドウ)に注意が必要です。あまりに多くのデータを取得しようとすると、コンテキストウィンドウを使い切って処理が完了しなくなるケースがありました。
MCPサーバーを活用したデータ分析と可視化
このMCPサーバーを登録すると、Claude DesktopアプリはMCPサーバーから返されるデータを処理し、以下のような役割を果たします:
- データの解釈: 複雑なJSON構造を理解し、意味のある形式に変換
- クロスアカウント分析: 複数アカウントのデータを比較して重要なパターンを発見
- 自然言語でのインサイト提供: 分析結果を人間が理解しやすい形で説明
- 可視化の提案: データを適切にビジュアル化する方法を提示
この手のツールを使うメリットは、技術的な知識がなくても複雑なデータ分析が可能になることです。例えば、マーケティングチームやセールスチームのメンバーでも、簡単な質問をするだけで、データに基づいたインサイトを得ることができます。
Claude Desktopでの可視化例
Claude Desktopの分析機能を使用してデータを可視化できます:
この例では、サブスクリプションデータが視覚的にグラフ化されており、アカウント間の比較が容易になっています。グラフ化することで、数値の羅列だけでは見えにくかったパターンや異常値を簡単に発見できるようになります。
特に経営層やマネージャーへのレポーティングでは、このような視覚的な表現が非常に効果的です。短時間で重要なインサイトを伝えることができ、データに基づいた意思決定を促進します。
実践的な分析シナリオ
シナリオ1: 顧客重複分析
複数のStripeアカウントを持つビジネスでは、同じ顧客が異なるアカウントに存在する可能性があります。この分析は以下のステップで実行できます:
-
すべてのアカウントから顧客データを取得:
「全アカウントの顧客データを取得して」
-
メールアドレスを基準に重複を特定:
「取得した顧客データからメールアドレスが重複している顧客を特定して」
-
重複している顧客の詳細情報を分析:
「重複している顧客のサブスクリプション状況を比較して」
この分析により、クロスセリングの機会や、アカウント統合が必要な顧客を特定できます。例えば、あるアカウントでエンタープライズプランを利用している顧客が、別のアカウントでは基本プランを利用している場合、アップセルの機会があることを示しています。
具体的な実装では、メールアドレスだけでなく、氏名や会社名、請求先住所などの複数の要素を組み合わせて顧客の一致を判定することも検討すべきです。特に、企業顧客の場合は、同じ組織内の異なる部門が別々にサービスを契約しているケースもあるため、慎重な分析が必要です。
シナリオ2: 収益トレンド分析
複数アカウントの収益トレンドを分析することで、ビジネス全体の健全性を評価できます:
-
全アカウントの請求書データを取得:
「過去6ヶ月の全アカウントの請求書データを取得して」
-
月次収益をアカウント別に集計:
「それぞれのアカウントの月次収益を集計して」
-
トレンドを可視化:
「月次収益のトレンドをグラフで表示して」
この分析により、各アカウントの成長率や季節性、全体的な収益傾向が明らかになります。例えば、特定のアカウントで収益が急減している場合は、その原因(価格変更、競合の参入、製品の問題など)を調査する必要があるかもしれません。
収益分析を行う際の実践的なポイントとして、単純な総収益だけでなく、MRR(月間経常収益)やARR(年間経常収益)、顧客単価(ARPU)などの指標も分析することをおすすめします。これらの指標は、サブスクリプションビジネスの健全性をより正確に反映します。
シナリオ3: 解約分析
顧客の解約パターンを分析することで、ビジネスの改善点を特定できます:
-
キャンセルされたサブスクリプションを取得:
「過去3ヶ月にキャンセルされたサブスクリプションを全アカウントから取得して」
-
アカウント別・プロダクト別の解約率を計算:
「アカウントごとおよびプロダクトごとの解約率を計算して」
-
解約理由や傾向を分析:
「解約率が高いアカウントやプロダクトの特徴を分析して」
この分析により、顧客維持に問題のあるアカウントやプロダクトを特定し、改善策を講じることができます。例えば、特定の価格帯や機能セットで解約率が高い場合、その製品の価値提案を見直す必要があるかもしれません。
解約分析を効果的に行うためには、解約タイミングや解約前の利用パターンも分析することをおすすめします。例えば、サブスクリプション開始から3ヶ月以内の解約が多い場合は、オンボーディングプロセスに問題がある可能性があります。また、利用頻度が低下した後に解約するパターンが見られる場合は、エンゲージメント施策の強化が必要かもしれません。
まとめとnext step
今回作成したMCPサーバーは、GitHubにて公開しています。
Issueにあるように、101件以上のデータを取得する際の挙動など、まだまだ完全な状態ではありませんが、アカウントを横断したデータ分析の可能性を体験してみるなどで、ぜひ試していただければと思います。
Discussion