Claude Codeのトークン消費を98%削減する方法【MCP活用+コンテキスト最適化】
Claude Codeの利用料が想像以上に高くなる理由
Claude Codeを使っていると、気づかないうちにトークン(文字数カウント)がどんどん消費されていることがあります。一度のやり取りで数千、数万文字が使われることもあり、月間の利用料が跳ね上がってしまう方も少なくありません。
プロジェクトのファイル一式をClaudeに読み込ませたり、長いエラーログを貼り付けたり、やり取りが増えるたびに文字数は積み重なっていきます。「あれ、こんなに高い?」という経験をしたことがある方は、この問題に直面している可能性があります。
従来のトークン削減手法では20〜45%の削減にとどまることが多かったのに対し、複数のツールや戦略を組み合わせることで60〜90%のトークン削減を実現できるようになりました。これは、ファイルサイズの最適化・コンテキスト管理・事前トークンカウント・キャッシング活用をプロジェクトレベルで自動化することで達成されます。
一方で、MCPワークフローを使い始めたことで「請求が3倍になった」という報告も上がっています。MCPは正しく使えばコスト削減の強力な手段になりますが、設定の不備や使用パターンの理解不足が思わぬ料金トラブルを招くこともあります。
コスト削減の主要戦略
トークン削減を実現する戦略は大きく5つに分類できます。
戦略1:事前トークンカウント リクエスト前にトークン数を正確に把握し、予算超過を防ぎます。
戦略2:プロンプト最適化 冗長なシステムプロンプトや不要な説明を削減し、無駄なトークン消費を抑えます。
戦略3:キャッシング活用 同じプロンプトへの重複リクエストを排除し、コストを大幅に削減します。
戦略4:ファイルサイズの最適化 プロジェクト内の不要なファイルやコメント、ホワイトスペースを削減し、Claude Codeに送信する前にコードを圧縮します。
戦略5:コンテキストマネージャー Claude Codeとのやり取りで、どのファイルを対象にするか、どの情報を優先するかを自動判別し、必要最小限の情報だけをAIに送信します。
これらが連携することで、従来は手動管理していたトークン削減を自動化できます。特に以下のような開発シーンで効果が顕著です:
- 大規模なコードベースを扱う開発
- 頻繁にファイルサーチと読み込みを繰り返す作業
- プロジェクト内のドキュメントが肥大化している場合
- CI/CDパイプラインの生成・検証タスク
戦略1:事前トークンカウントで予算超過を防ぐ
トークン数の事前計算が必須な理由
APIはリクエストを送信した後、実際に消費したトークン数がレスポンスに含まれます。しかし、その時点では既に課金されています。予算管理のためには送信前にトークン数を正確に把握する必要があります。
Pythonでトークン数をカウントする
OpenAIの公式ライブラリtiktokenを使うことで、APIリクエスト前にトークン数を計算できます。
pip install tiktoken openai
import tiktoken
# GPT-4o用のエンコーディングを指定
encoding = tiktoken.encoding_for_model("gpt-4o")
# カウント対象のテキスト
text = "こんにちは。今日の天気について教えてください。"
# トークン数を計算
token_count = len(encoding.encode(text))
print(f"トークン数: {token_count}")
複数のテキスト(システムプロンプト + ユーザー入力)をカウント
import tiktoken
encoding = tiktoken.encoding_for_model("gpt-4o")
system_prompt = "あなたは親切なアシスタントです。簡潔に日本語で回答してください。"
user_message = "Python で日本語を扱うときの注意点は?"
system_tokens = len(encoding.encode(system_prompt))
user_tokens = len(encoding.encode(user_message))
# APIオーバーヘッド(メッセージ形式の追加トークン)を加算
overhead_per_message = 4
total_input_tokens = system_tokens + user_tokens + (overhead_per_message * 2)
print(f"システムプロンプト: {system_tokens} トークン")
print(f"ユーザー入力: {user_tokens} トークン")
print(f"総入力トークン(予測値): {total_input_tokens} トークン")
料金計算コード(実装例)
# 2026年7月時点のOpenAI API料金(例)
# 最新の料金は公式ドキュメントで確認してください
GPT_4O_INPUT_PRICE = 2.5 / 1_000_000 # $2.50 per 1M tokens
GPT_4O_OUTPUT_PRICE = 10.0 / 1_000_000 # $10.00 per 1M tokens
def estimate_cost(input_tokens, output_tokens):
"""API呼び出しのコストを計算"""
input_cost = input_tokens * GPT_4O_INPUT_PRICE
output_cost = output_tokens * GPT_4O_OUTPUT_PRICE
total_cost = input_cost + output_cost
return {
"input_cost_usd": input_cost,
"output_cost_usd": output_cost,
"total_cost_usd": total_cost,
"total_cost_jpy": total_cost * 150 # 1 USD = 150 JPYと仮定
}
cost = estimate_cost(500, 200)
print(f"推定コスト: ${cost['total_cost_usd']:.6f} (約¥{cost['total_cost_jpy']:.1f})")
また、Claude Codeの組み込みコマンドでも利用状況を確認できます:
claude analytics --start-date 2026-06-01 --end-date 2026-06-16
出力例:
Total Tokens Used: 250,000
Average Tokens Per Request: 8,500
Requests Count: 29
After Optimization:
Estimated Tokens (without tools): 1,000,000
Current Tokens: 250,000
Reduction: 75%
自作スクリプトでAPIレスポンスに含まれるトークン数を直接ログに記録する方法も有効です:
const Anthropic = require("@anthropic-ai/sdk");
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
async function callWithLogging(userMessage) {
const startTime = Date.now();
const message = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1024,
messages: [{ role: "user", content: userMessage }],
});
const endTime = Date.now();
console.log(
`入力: ${message.usage.input_tokens}トークン、` +
`出力: ${message.usage.output_tokens}トークン、` +
`実行時間: ${endTime - startTime}ms`
);
return message;
}
戦略2:プロンプト最適化で不要なトークンを削減
冗長なプロンプトが生む費用
非効率な例(580トークン):
あなたは、大規模言語モデルを活用したAIアシスタントです。ユーザーの質問に対して、
正確で有益な情報を提供することがあなたの役割です。回答は常に敬意を持ち、
分かりやすく、論理的に構成されるべきです。また、不確実な情報については、
その旨を明確に述べてください。回答は日本語で提供されるべきであり、
必要に応じて専門用語の説明も含めるべきです。...
効率的な例(45トークン):
あなたは日本語のAIアシスタントです。簡潔かつ正確に回答してください。
不確実な場合は明記してください。
同じ役割を果たしながら、92%のトークンを削減できています。
実装レベルの最適化テクニック
テンプレート化と動的置換
import tiktoken
encoding = tiktoken.encoding_for_model("gpt-4o")
BASE_SYSTEM_PROMPT = "あなたは日本語のAIアシスタントです。"
OPTIONAL_INSTRUCTIONS = {
"concise": "簡潔に答えてください。",
"detailed": "詳しく説明してください。",
"code": "Pythonコードの例を含めてください。",
"security": "セキュリティとプライバシーに注意してください。",
}
def build_system_prompt(task_type="concise"):
"""タスク種別に応じてシステムプロンプトを構築"""
prompt = BASE_SYSTEM_PROMPT
if task_type in OPTIONAL_INSTRUCTIONS:
prompt += OPTIONAL_INSTRUCTIONS[task_type]
return prompt
for task in ["concise", "detailed", "code"]:
prompt = build_system_prompt(task)
tokens = len(encoding.encode(prompt))
print(f"{task}: {tokens} トークン")
複数プロンプト候補の自動比較
import tiktoken
encoding = tiktoken.encoding_for_model("gpt-4o")
prompts = {
"detailed": "あなたは親切で詳しいAIアシスタントです。ユーザーの質問に対して、背景知識を交えながら詳しく説明してください。",
"concise": "親切で簡潔なAIアシスタントです。要点を短く答えてください。",
"technical": "技術的なAIアシスタント。正確な情報を提供。",
}
for name, text in prompts.items():
tokens = len(encoding.encode(text))
print(f"{name}: {tokens} tokens")
best = min(prompts.items(), key=lambda x: len(encoding.encode(x[1])))
print(f"\n推奨: {best[0]} (最小:{len(encoding.encode(best[1]))} tokens)")
戦略3:キャッシング活用で重複リクエストを排除
キャッシングの仕組みと効果
同じプロンプトに対して複数のリクエストが発生する場合、キャッシングを活用することで大幅なコスト削減ができます。
データベースレベルのキャッシング
import json
import hashlib
import sqlite3
from datetime import datetime, timedelta
class APICache:
def __init__(self, db_path="api_cache.db"):
self.conn = sqlite3.connect(db_path)
self.setup_db()
def setup_db(self):
self.conn.execute("""
CREATE TABLE IF NOT EXISTS cache (
hash TEXT PRIMARY KEY,
prompt TEXT,
model TEXT,
response TEXT,
created_at TIMESTAMP,
expires_at TIMESTAMP
)
""")
self.conn.commit()
def _make_hash(self, prompt: str, model: str) -> str:
key = f"{prompt}:{model}"
return hashlib.md5(key.encode()).hexdigest()
def get(self, prompt: str, model: str = "gpt-4o"):
hash_val = self._make_hash(prompt, model)
cursor = self.conn.execute(
"SELECT response FROM cache WHERE hash = ? AND expires_at > ?",
(hash_val, datetime.now())
)
row = cursor.fetchone()
if row:
return json.loads(row[0])
return None
def set(self, prompt: str, model: str, response: dict, ttl_hours: int = 24):
hash_val = self._make_hash(prompt, model)
expires_at = datetime.now() + timedelta(hours=ttl_hours)
self.conn.execute("""
INSERT OR REPLACE INTO cache (hash, prompt, model, response, created_at, expires_at)
VALUES (?, ?, ?, ?, ?, ?)
""", (hash_val, prompt, model, json.dumps(response), datetime.now(), expires_at))
self.conn.commit()
キャッシュヒット率の監視
class CacheMetrics:
def __init__(self):
self.hits = 0
self.misses = 0
def record_hit(self):
self.hits += 1
def record_miss(self):
self.misses += 1
def hit_rate(self) -> float:
total = self.hits + self.misses
if total == 0:
return 0.0
return self.hits / total * 100
def estimated_savings(self, avg_tokens_per_request: int = 300,
cost_per_million_tokens: float = 2.5) -> float:
saved_tokens = self.hits * avg_tokens_per_request
cost_per_token = cost_per_million_tokens / 1_000_000
return saved_tokens * cost_per_token
また、複数の質問がある場合は1つずつAPIを呼び出すのではなく、まとめて処理することでトークン消費を約30%削減できる場合があります。
async function processBatchQuestions(questions) {
const batchPrompt = `
以下の${questions.length}個の質問に順番に答えてください:
${questions.map((q, i) => `${i + 1}. ${q}`).join("\n")}
`;
const message = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 2048,
messages: [{ role: "user", content: batchPrompt }],
});
return message.content[0].text;
}
設定手順:ファイル最適化ツールの導入
ステップ1:プロジェクト直下に設定ファイルを作成
対象ディレクトリ内に.claudeignoreという設定ファイルを作成してください。
# .claudeignore
node_modules/
dist/
build/
.git/
.env
.env.local
*.log
coverage/
.next/
.nuxt/
out/
このファイルは、Claude Codeがプロジェクトをスキャンするときに除外するディレクトリ・ファイルを指定します。大規模な依存パッケージフォルダ(node_modulesなど)をあらかじめ除外することで、コンテキストウィンドウの浪費を防げます。
ステップ2:コード圧縮のルール定義
プロジェクト直下にcompression-rules.jsonを作成して、圧縮の詳細ルールを設定します。
{
"removeComments": true,
"removeConsoleLogs": false,
"minifyVariableNames": false,
"preserveReadability": true,
"targetLanguages": ["javascript", "typescript", "python"],
"excludePatterns": ["*.test.js", "*.spec.ts", "*.md"],
"compressionLevel": "aggressive"
}
各項目の意味:
removeComments: コメント行を削除(ただし重要なドキュメンテーションコメントは保持)removeConsoleLogs: console.log()などのログ出力を削除(本番コード確認時)minifyVariableNames: 変数名を短縮するか(可読性を損なうため通常はfalse)preserveReadability: 可読性の最低限のレベルを保つtargetLanguages: 圧縮対象の言語を指定excludePatterns: 除外するファイル形式compressionLevel: 圧縮度合い(aggressive/moderate/light)
ステップ3:Claude Codeでファイル最適化を有効化
Claude Code内で以下のコマンドを実行:
claude install-plugin token-optimizer
このプラグインがプロジェクト内のファイルを自動スキャンし、.claudeignoreとcompression-rules.jsonに従って最適化を適用します。
設定手順:コンテキストマネージャーの導入
ステップ1:コンテキストマネージャーのインストール
Claude Codeで以下を実行:
claude install-plugin context-manager
このツールは、Claude Codeとの対話で自動的に関連ファイルを判別し、必要最小限のコンテキスト情報をAIに渡す役割を担います。
ステップ2:プロジェクトメタデータの設定
プロジェクト直下にclaude-context.yamlファイルを作成します:
projectName: "my-app"
description: "Next.js e-commerce platform"
fileGroups:
core:
- "src/pages/**"
- "src/components/common/**"
priority: high
features:
- "src/features/**"
priority: medium
utils:
- "src/utils/**"
- "src/helpers/**"
priority: low
dependencies:
critical:
- "package.json"
- ".env.example"
reference:
- "README.md"
- "docs/**"
ignoreDuring:
- "*.test.ts"
- "node_modules"
- ".next"
tokenBudget:
maxTokensPerRequest: 50000
warningThreshold: 40000
ここで重要なのはfileGroupsとpriorityです。Claude Codeが質問を受け取ると、まずhigh優先度のファイルを読み込み、それでも足りない場合にmedium→lowの順で追加していきます。これにより、関連性の低いファイルはコンテキストに含まれず、トークン消費が抑えられます。
ステップ3:コンテキスト最適化の実行
Claude Code内でコンテキストマネージャーの最適化を開始:
claude optimize-context --project ./
このコマンドでプロジェクト構造が分析され、最適なファイルグループが自動構成されます。
MCPを使って本当に必要な情報だけをClaude Codeに渡す
MCP(Model Context Protocol)とは、Claude Codeが外部のツールやデータベースと連携するための仕組みです。この仕組みを活用すると、全ファイルをテキストで読み込む代わりに、特定の情報だけを効率的に取得できます。
たとえば、大きなコードベースがあるとき:
- 従来のやり方: プロジェクト全体をテキストでClaudeに貼り付ける → 数万文字消費
- MCP活用: Claudeが「このファイルの関数一覧をください」と外部ツールに問い合わせる → 必要な部分だけを自動取得 → 数百文字で済む
MCPを使った専用のコード解析ツールを自分で作成・設定することで、「このプロジェクトに必要な情報だけをフィルタリングして提供する」という使い方が実現します。
ただし、MCPワークフローでは以下のような意図しないループが自動で起きることがある点に注意が必要です:
- ユーザーがプロンプトを送信
- Claudeが外部APIを呼び出す
- データが返ってくる
- Claudeが不完全だと判断して再度APIを呼び出す
- この繰り返しが数十回単位で続く
このループが料金増加の主因となるケースも多いため、後述する呼び出し回数の制限と監視の設定を合わせて行うことが重要です。
コンテキストを賢く整理して文字数を節約する
Claude Codeのやり取りでは、過去の会話履歴もカウント対象です。会話が長くなるほど、古い部分も含めて毎回Claudeに送信されるため、文字数がどんどん増えていきます。
コンテキスト最適化のポイント:
要点だけを先に伝える
質問するときは、背景説明を長くするのではなく「今この状態で、この問題を解決したい」という結論から入ります。背景は聞かれたときだけ補足する。
不要な部分を削除してから聞く
エラーメッセージなら、意味のある部分だけを抜き出して貼り付け。「スタックトレース全体」ではなく「エラーが発生した行」に絞る。
新しい会話(セッション)に切り替える
1つのプロジェクトで細かいやり取りが増えてきたら、「新しいチャットを始める」のも手です。コンテキストがリセットされ、以降のやり取りから文字数が計算され直します。
MCPで構造化データを使う
テキストの説明ではなく「このプロジェクトの構造はこういう階層」という構造データ(JSONやYAML)をMCPから取得させることで、Claudeの理解精度が上がり、追加質問を減らせます。
実践例:プロジェクトファイルの構造情報取得
あるプロジェクトでは、以下のように変わりました:
- 従来: package.json、tsconfig.json、全ソースファイル(合計5万文字)をテキストで貼り付け → 毎回5万文字消費
- MCP活用: MCPが「依存パッケージ一覧」「型定義一覧」「主要関数の署名」だけを抽出 → 毎回2千文字で済む
この工夫だけで、同じ回数のやり取りを続けても文字数は数十分の一になります。
Mac向けメニューバーアプリによるリアルタイム監視
より常時的な監視を求めるMac開発者には、Swift + AppKitを使ったメニューバーアプリの自作という選択肢もあります:
import AppKit
class AppDelegate: NSObject, NSApplicationDelegate {
var statusBar: NSStatusBar?
var statusItem: NSStatusItem?
var updateTimer: Timer?
var apiClient: ClaudeAPIClient?
func applicationDidFinishLaunching(_ aNotification: Notification) {
guard let apiKey = ProcessInfo.processInfo.environment["CLAUDE_API_KEY"] else {
fatalError("CLAUDE_API_KEY環境変数が設定されていません")
}
apiClient = ClaudeAPIClient(apiKey: apiKey)
statusBar = NSStatusBar.system
statusItem = statusBar?.statusItem(withLength: NSStatusItem.variableLength)
updateUsageDisplay()
updateTimer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { _ in
self.updateUsageDisplay()
}
}
func updateUsageDisplay() {
apiClient?.fetchUsage { [weak self] usagePercent in
DispatchQueue.main.async {
let displayText = usagePercent.map { "Claude: \(Int($0 * 100))%" } ?? "Claude: --"
self?.statusItem?.button?.title = displayText
}
}
}
}
消費量が一定のしきい値を超えたときの通知も追加できます:
import UserNotifications
func showNotification(title: String, body: String) {
let content = UNMutableNotificationContent()
content.title = title
content.body = body
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
}
// 使用例:80%を超えたら警告
if usagePercent > 0.8 {
showNotification(title: "Claude使用量警告", body: "トークン消費が80%を超えました")
}
注意点・落とし穴
MCPの設定に時間がかかる
最初はツール設定に手間が必要です。急ぎの案件では従来のやり方が早いこともあります。「これから何度も使うプロジェクト」「継続的にメンテナンスが必要な大規模コード」向けの工夫と考えましょう。
MCPの呼び出し回数を制限する
無限ループを防ぐため、APIコールの最大回数を明示的に設定することが重要です。
const MAX_RETRIES = 3;
let retryCount = 0;
async function callMCPWithLimit(toolName, parameters) {
if (retryCount >= MAX_RETRIES) {
console.error("最大リトライ回数に達しました");
return null;
}
retryCount++;
console.log(`ツール呼び出し: ${toolName} (${retryCount}/${MAX_RETRIES})`);
return await mcp.invoke(toolName, parameters);
}
キャッシュの有効期限管理
キャッシュが古い情報を含むと、ユーザーに不正確な回答を返してしまいます。データベースキャッシュの場合は、必ず有効期限(TTL)を設定してください。また、tiktokenなど事前カウントに使うライブラリが古いと最新モデルに対応していない可能性があるため、常に最新版を保つことも重要です。
圧縮レベルの段階的な調整
最初はcompression-level: lightから始め、トークン削減効果を測定してからmoderate→aggressiveに進めることをお勧めします。急激な圧縮はコード可読性を損なう可能性があります。
削減しすぎて文脈が不足する可能性
トークン削減を意識しすぎると、本来必要な情報まで削ってしまう場合があります。Claudeが「もう少し詳しく教えてください」と聞き返す場合は、むしろ情報が少なすぎるサイン。バランスが大切です。
MCPは手作り・カスタマイズが必須
汎用的なMCPもありますが、自分のプロジェクト特有のニーズに合わせるには、カスタマイズが必要なことがほとんど。JavaScript/Pythonの基礎スキルがあると導入しやすい。
外部サービスの課金も見落とさない
MCPでデータベースやクラウドストレージ、外部APIと連携する場合、それらのサービスでも別途課金が発生することがあります。事前に各サービスのコスト見積もりを立てておきましょう。
応用アイデア
予算上限と監視アラートを設定する
Anthropicダッシュボード(https://console.anthropic.com)の「Billing」セクションで月間利用上限を設定し
あわせて読みたい
- Claude Codeで複数ファイル編集時のContext制限エラーを解決する3つの方法
- Claude Codeのコンテキスト設定【3つのステップで効率化】
- Claude Codeで修正回数を減らす7つのプロンプトテクニック|精度を上げる質問構造
参考ソース
- Cut Claude Code Token Usage 98% with Purpose-Built MCPs
- I Kept Hitting Claude Token Limits Until I Tracked What Was Actually Burning Them
- The Token Tax Problem: How I Built a Super Memory Layer for AI Coding Assistants using LLM Wiki
- dotbabel `/handoff`: portable context across Claude Code, Codex, Copilot CLI, and Gemini CLI