🚀 Claude Runner - MCPサーバー(ジョブスケジューリング付き)
単一ファイルのMCPサーバーで、cron式を使ってClaude Code CLIタスクをスケジュールし実行します。ウェブダッシュボード、ウェブフックサポート、動的MCPサーバー作成、トークン/コスト追跡機能を備えています。
🚀 クイックスタート
前提条件
クイックスタート手順
git clone https://github.com/floriansmeyers/SFLOW-AIRunner-MCP-PRD.git
cd SFLOW-AIRunner-MCP-PRD
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python server.py
初回起動時、サーバーは以下のことを行います。
- すべてのテーブルを持つ
jobs.db SQLiteデータベースを作成します。
- OAuth資格情報を自動生成し(stderrに出力されます - これを保存してください!)
- スケジューラーループを開始します(60秒ごとにチェックします)。
実行方法
ローカル(stdioトランスポート - Claude Desktop用)
python server.py
Claude Desktopの設定ファイル(macOSの場合は~/Library/Application Support/Claude/claude_desktop_config.json)に以下を追加します。
{
"mcpServers": {
"claude-runner": {
"command": "/path/to/SFLOW-AIagents-MCP-Spinner/.venv/bin/python",
"args": ["/path/to/SFLOW-AIagents-MCP-Spinner/server.py"]
}
}
}
重要: .venv内のPythonインタープリターの完全パスを使用して、依存関係が利用可能であることを確認してください。
リモート(SSEトランスポート - ウェブダッシュボード用)
MCP_TRANSPORT=sse python server.py
両方のトランスポート
MCP_TRANSPORT=both python server.py
✨ 主な機能
環境変数
| 変数 |
必須 |
デフォルト |
説明 |
ANTHROPIC_API_KEY |
はい |
- |
console.anthropic.comからのAPIキー — Claude Agent SDKを介したジョブ実行に必要です。個人のMax/Proサブスクリプションを使用しないでください。 |
MCP_TRANSPORT |
いいえ |
both |
トランスポートモード: stdio, sse, または both |
OAUTH_CLIENT_ID |
いいえ |
自動生成 |
OAuthクライアントID |
OAUTH_CLIENT_SECRET |
いいえ |
自動生成 |
OAuthクライアントシークレット |
OAUTH_SECRET_KEY |
いいえ |
自動生成 |
JWTトークンの署名用のシークレットキー |
DASHBOARD_USERNAME |
いいえ |
- |
ダッシュボードの基本認証ユーザー名 |
DASHBOARD_PASSWORD |
いいえ |
- |
ダッシュボードの基本認証パスワード |
NGROK_AUTHTOKEN |
いいえ |
- |
リモートトンネリング用のngrok認証トークン |
PUBLIC_URL |
いいえ |
- |
OAuthコールバックのベースURLを上書き(例: https://your-domain.com) |
これらを永続化するには、.envファイルを作成します。
ANTHROPIC_API_KEY=sk-ant-...
OAUTH_CLIENT_ID=your_client_id
OAUTH_CLIENT_SECRET=your_client_secret
OAUTH_SECRET_KEY=your_secret_key
DASHBOARD_USERNAME=admin
DASHBOARD_PASSWORD=secure_password
NGROK_AUTHTOKEN=your_ngrok_token
認証(OAuth 2.1)
SSEトランスポートにはOAuth 2.1認証が必要です。初回起動時、サーバーは資格情報を自動生成し、stderrに出力します。
============================================================
OAUTH CREDENTIALS FOR CLAUDE CONNECTOR
============================================================
Client ID: abc123...
Client Secret: xyz789...
Save these to your .env file:
OAUTH_CLIENT_ID=abc123...
OAUTH_CLIENT_SECRET=xyz789...
============================================================
重要: これらの資格情報をすぐに保存してください。シークレットは一度しか表示されず、回復することはできません。
OAuthエンドポイント
| エンドポイント |
説明 |
/.well-known/oauth-authorization-server |
サーバーメタデータ |
/.well-known/oauth-protected-resource |
保護されたリソースのメタデータ |
/oauth/authorize |
認証エンドポイント |
/oauth/token |
トークンエンドポイント |
資格情報の再生成
資格情報を失った場合は、データベースからクライアントを削除します。
sqlite3 jobs.db "DELETE FROM oauth_clients WHERE client_name = 'Claude (auto)'"
その後、サーバーを再起動して新しい資格情報を生成します。
ディレクトリ構造
SFLOW-AIRunner-MCP-PRD/
├── server.py # メインMCPサーバー
├── requirements.txt # Python依存関係
├── jobs.db # SQLiteデータベース(自動作成)
├── .env # 環境変数(オプション)
├── fixed-servers/ # 組み込みMCPサーバー
│ └── email/
│ ├── server.py
│ └── metadata.json
├── dynamic_servers/ # ユーザー作成のMCPサーバー(自動作成)
│ ├── cat-facts/
│ └── r2-images/
├── deploy/ # デプロイ設定(systemd, nginx, デプロイスクリプト)
│ ├── deploy.sh
│ ├── mcpserver.service
│ ├── nginx.conf
│ └── README-HETZNER.md
└── claude_playground/ # ジョブ実行用の作業ディレクトリ(自動作成)
データベース
./jobs.dbにあるSQLiteデータベースには、以下のテーブルがあります。
テーブル
| テーブル |
説明 |
jobs |
cron式でスケジュールされたタスク |
runs |
出力、トークン、コストを含む実行履歴 |
settings |
設定(許可されたツール、MCPサーバー、資格情報) |
webhooks |
プロンプトをトリガーするHTTPエンドポイント |
oauth_clients |
OAuthクライアント資格情報 |
oauth_codes |
OAuth認証コード |
oauth_refresh_tokens |
OAuthリフレッシュトークン |
デフォルト設定
初回実行時、以下のデフォルト設定が作成されます。
| キー |
デフォルト値 |
allowed_tools |
["WebSearch", "WebFetch", "Read", "Write", "Edit", "Bash"] |
mcp_servers |
[] |
mcp_env_vars |
{} |
webhook_base_url |
"http://localhost:8080" |
sandbox_mode |
true |
完全なリセット
データベースを完全にリセットするには、以下のコマンドを実行します。
rm jobs.db
python server.py
利用可能なMCPツール
ジョブ管理
| ツール |
説明 |
list_jobs |
すべてのスケジュールされたジョブをリストする |
get_job(job_id) |
特定のジョブを取得する |
create_job(name, cron, prompt, ...) |
新しいスケジュールされたジョブを作成する |
update_job(job_id, ...) |
既存のジョブを更新する |
delete_job(job_id) |
ジョブとその実行履歴を削除する |
trigger_job(job_id) |
ジョブを手動で即時実行する |
実行管理
| ツール |
説明 |
list_runs(job_id?, limit?) |
最近の実行履歴をリストする |
get_run(run_id) |
出力を含む完全な実行詳細を取得する |
kill_run(run_id) |
保留中/実行中の実行をキャンセルする |
ウェブフック
| ツール |
説明 |
create_webhook(name, prompt_template) |
ウェブフックエンドポイントを作成する |
list_webhooks |
すべてのウェブフックをリストする |
get_webhook(webhook_id) |
ウェブフックの詳細を取得する |
update_webhook(webhook_id, ...) |
ウェブフックを更新する |
delete_webhook(webhook_id) |
ウェブフックを削除する |
動的MCPサーバー
| ツール |
説明 |
create_mcp_server(name, code, ...) |
カスタムMCPサーバーを作成する |
list_dynamic_mcp_servers |
ユーザー作成のサーバーをリストする |
get_dynamic_mcp_server(name) |
サーバーの詳細を取得する |
update_mcp_server(name, code, ...) |
動的サーバーのコード/説明を更新する |
delete_mcp_server(name) |
動的サーバーを削除する |
enable_mcp_server(name) |
動的MCPサーバーを有効にする |
disable_mcp_server(name) |
動的MCPサーバーを無効にする |
固定MCPサーバー
| ツール |
説明 |
list_fixed_mcp_servers |
組み込みサーバーをリストする |
enable_fixed_server(name) |
固定サーバーを有効にする |
disable_fixed_server(name) |
固定サーバーを無効にする |
内部MCPツール
| ツール |
説明 |
invoke_internal_mcp_tool(tool, payload) |
内部MCPサーバー上のツールを呼び出す |
資格情報
| ツール |
説明 |
set_server_credential(server, key, value) |
資格情報を設定する |
get_server_credentials(server) |
資格情報を表示する(マスクされる) |
list_required_credentials(server) |
必要な資格情報を確認する |
get_unconfigured_servers |
資格情報が不足しているサーバーを見つける |
delete_server_credential(server, key) |
資格情報を削除する |
claude.aiを介した使用方法
接続後、サーバーとのやり取りはすべて自然言語で行います。Claudeがあなたのリクエストを適切なMCPツール呼び出しに変換します。
重要: ジョブはClaude Agent SDKを介して実行され、内部でローカルのClaude Code CLIが実行されます。サーバーを実行しているマシンにClaude Codeをインストールし、認証する必要があります(claudeがシステムのPATHにあり、ログインしている必要があります)。
以下は主なワークフローです。
カスタムツールの作成
Claudeにリアルタイムで新しいMCPツールサーバーを構築するように依頼することができます。サーバーコードはdynamic_servers/<name>/に保存され、各サーバーにはローカルファイルストレージ用のDATA_DIRパス変数が割り当てられます。コード内でos.environ.get()またはos.getenv()を介して参照される環境変数は自動的に検出され、必要な資格情報としてマークされます。
あなた: OpenWeatherMap APIを使って指定した都市の現在の天気を取得するツールを作成してください。
Claude: [create_mcp_serverを呼び出し — サーバーをdynamic_servers/weather/に保存し、コードからOPENWEATHERMAP_API_KEYを検出]
完了!"weather"サーバーとget_weather(city)ツールを作成しました。
APIキーが必要です — あなたのキーを保存しますか?
あなた: はい、キーはabc123です。
Claude: [set_server_credential("weather", "OPENWEATHERMAP_API_KEY", "abc123")を呼び出し]
資格情報を保存しました。天気サーバーは使用可能です。
定期ジョブのスケジューリング
ジョブはClaude Agent SDKを使ってcronスケジュールで実行されます。ジョブが使用できるツールを指定することができます(空の配列[]はすべてのツールを意味します)。
あなた: 平日の9時に毎日Azure DevOpsのスプリントを要約するジョブを作成してください。
Claude: [以下のパラメータでcreate_jobを呼び出し]
name: "Daily Sprint Summary"
cron: "0 9 * * 1-5"
prompt: "Azure DevOpsに接続し、現在のスプリントを要約して..."
tools: ["mcp__azure-devops__wit_my_work_items", "mcp__email__send_email"]
ジョブが作成されました(id: a1b2c3d4)。次回の実行は明日の9:00 AMです。
あなた: 最後の5回の実行を表示してください。
Claude: [limit=5でlist_runsを呼び出し]
最近の実行はこちら — 4回が正常に完了し、1回がエラーになりました...
ウェブフックの設定
ウェブフックを使うと、外部サービスがHTTP POSTを介してプロンプトをトリガーすることができます。prompt_templateは{{payload}}で全体のボディ、{{payload.field.subfield}}でネストされた値をサポートします。
あなた: 新しいAzure DevOpsのワークアイテムが作成されたときにSlackの要約を送信するウェブフックを作成してください。POSTボディには、アイテムのタイトルがresource.fields.System.Titleにあります。
Claude: [以下のパラメータでcreate_webhookを呼び出し]
name: "New Work Item Notifier"
prompt_template: "新しいワークアイテムが作成されました: {{payload.resource.fields.System.Title}}.
それを要約してSlackに投稿してください。"
ウェブフックが作成されました!このURLにPOSTするとトリガーできます:
https://your-server.com/webhook/abc123def456...
あなた: テストして — ウェブフックを手動でトリガーしてください。
Claude: MCPを介してウェブフックをトリガーすることはできませんが、curlでテストできます:
curl -X POST https://your-server.com/webhook/abc123def456... \
-H "Content-Type: application/json" \
-d '{"resource":{"fields":{"System":{"Title":"Bug: login broken"}}}}'
ツールの直接呼び出し
invoke_internal_mcp_toolを使って、ジョブを作成せずに有効なMCPサーバー上のツールをすぐに呼び出すことができます。
あなた: 天気ツールを使ってベルリンの天気予報を確認してください。
Claude: [以下のパラメータでinvoke_internal_mcp_toolを呼び出し]
tool: "mcp__weather__get_weather"
payload: {"city": "Berlin"}
現在、ベルリンは12°Cで曇りで、午後に雨が降る予定です。
サーバーと資格情報の管理
組み込み(固定)およびユーザー作成(動的)のサーバーを有効化、無効化、更新し、それらの資格情報を管理することができます。
あなた: 利用可能なサーバーはどれですか?
Claude: [list_fixed_mcp_serversとlist_dynamic_mcp_serversを呼び出し]
固定サーバー: email(有効), playwright(無効)
動的サーバー: weather(有効), url-shortener(無効)
あなた: playwrightを有効にし、天気サーバーを無効にしてください。
Claude: [enable_fixed_server("playwright")とdisable_mcp_server("weather")を呼び出し]
完了 — playwrightは現在有効で、天気サーバーは無効になりました。
あなた: 資格情報が不足しているサーバーはどれですか?
Claude: [get_unconfigured_serversを呼び出し]
メールサーバーにはSENDGRID_API_KEYとSENDER_EMAILが必要です。
即時プロンプト
一度限りのタスクには、ウェブダッシュボードのクイック実行機能(SSEモード)を使って、ジョブを作成せずにすぐにプロンプトを実行することができます。claude.aiからは、既存のジョブを手動でトリガーすることもできます。
あなた: 「Daily Sprint Summary」ジョブを今すぐ実行してください。
Claude: [trigger_job("a1b2c3d4")を呼び出し]
実行がキューに入れられました(run_id: e5f6g7h8)。結果を確認します。
Cronの例
| 式 |
説明 |
0 9 * * 1-5 |
平日の9:00 AM |
0 */2 * * * |
2時間ごと |
0 9 * * 1 |
月曜日の9:00 AM |
*/30 * * * * |
30分ごと |
0 0 1 * * |
月の初日の真夜中 |
🔧 技術詳細
トラブルシューティング
ModuleNotFoundError: No module named 'dotenv'
Claude DesktopがシステムのPythonを使用している代わりに、venvを使用するように設定を更新してください。
{
"command": "/full/path/to/.venv/bin/python",
"args": ["/full/path/to/server.py"]
}
OAuth資格情報を失った場合
自動生成されたクライアントを削除し、再起動します。
sqlite3 jobs.db "DELETE FROM oauth_clients WHERE client_name = 'Claude (auto)'"
python server.py
ジョブが実行されない場合
- スケジューラーが実行中であることを確認します(ログに「Scheduler loop started」が表示されていることを確認)
- ジョブが有効になっていることを確認します:
sqlite3 jobs.db "SELECT enabled FROM jobs"
- cron式が有効であることを確認します
- 実行履歴のエラーを確認します:
sqlite3 jobs.db "SELECT error FROM runs ORDER BY started_at DESC LIMIT 1"
ジョブでMCPツールが利用できない場合
ジョブが「I don't have access to [MCP server] tools」と報告する場合、ツール名の形式を確認してください。
正しい形式: mcp__<server>__<tool>(二重アンダースコア)
- 例:
mcp__email__send_email
- 例:
mcp__playwright__navigate
自動正規化される形式: これらは自動的に変換されます。
email:send_email → mcp__email__send_email
email.send_email → mcp__email__send_email
ヒント: 空のツール配列[]を使用して、すべての利用可能なツールを許可するか、応答のtool_warningsを確認して、ツールが正規化されたかどうかを確認してください。
サーバーがすぐに切断される場合
stderrの出力を確認してエラーを探します。一般的な原因は以下の通りです。
- 依存関係が不足している(
pip install -r requirements.txtを実行)
- Pythonバージョンが3.11未満
- データベースが別のプロセスによってロックされている
Gitの「dubious ownership」エラー
自動デプロイが「fatal: detected dubious ownership in repository」で失敗する場合、以下のコマンドを実行します。
git config --system --add safe.directory /opt/mcpserver/app
これは、リポジトリがデプロイスクリプトを実行しているユーザーと異なるユーザーによって所有されている場合に発生します。
Playwrightブラウザが見つからない場合
Playwrightがブラウザが見つからないエラーで失敗する場合、Chromiumを手動でインストールしてください。
apt install -y libnss3 libnspr4 libatk1.0-0t64 libatk-bridge2.0-0t64 libcups2t64 \
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 \
libpango-1.0-0 libcairo2 libasound2t64
su - mcpuser
cd /opt/mcpserver/app
source venv/bin/activate
playwright install chromium
動作を確認します。
python -c "from playwright.sync_api import sync_playwright; p = sync_playwright().start(); b = p.chromium.launch(); print('OK'); b.close(); p.stop()"
アーキテクチャ
┌─────────────────────────────────────────────────────────────┐
│ MCP Server │
│ ┌───────────┐ ┌───────────────┐ ┌───────────────────┐ │
│ │ Job CRUD │ │ Scheduler │ │ Run Processor │ │
│ │ Tools │ │ (60s loop) │ │ (async) │ │
│ └─────┬─────┘ └───────┬───────┘ └─────────┬─────────┘ │
│ │ │ │ │
│ └────────────────┼────────────────────┘ │
│ ▼ │
│ ┌────────────────┐ │
│ │ SQLite │ │
│ │ (jobs.db) │ │
│ └────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Claude Agent │ │
│ │ SDK │ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘
サーバーは3つの同時実行の非同期コンポーネントを実行します。
- MCPサーバー - FastMCPを介して25以上のツールを公開します。
- スケジューラーループ - cronに基づいて60秒ごとに実行するジョブをチェックします。
- 実行プロセッサーループ - 保留中の実行を取得して実行します。
主要な依存関係
fastmcp - MCPプロトコルの実装
claude-agent-sdk - ジョブを実行するためのコア実行エンジン
croniter - Cron式の解析
sendgrid, requests - メールプロバイダーの統合
uvicorn - SSEトランスポート用のASGIサーバー
pyngrok - claude.aiからのリモートアクセス用のngrokトンネル
python-dotenv - .envファイルの読み込み
PyJWT - OAuth用のJWTトークンの処理
beautifulsoup4 - ウェブスクレイピング
boto3 - AWSの統合
playwright - ブラウザー自動化