Claude Runner-带作业调度的MCP服务器
一个单文件MCP服务器,通过cron表达式调度和执行Claude Code CLI任务。具有web仪表板、webhook支持、动态MCP服务器创建和令牌/成本跟踪功能。
先决条件
- Python 3.11+ (需要
asyncio.timeout()) - Claude代理SDK (
pip install claude-agent-sdk) - SQLite3 (通常预装在macOS/Linux上)
- 无烟煤API键 -作业通过Claude Agent SDK执行,这需要
ANTHROPIC_API_KEY. 不要依赖个人Max/Pro订阅 -SDK需要来自的API密钥 console.anthropic.com。将其设置在您的环境中或.env文件:
export ANTHROPIC_API_KEY=sk-ant-...快速开始
# Clone the repository
git clone https://github.com/floriansmeyers/SFLOW-AIRunner-MCP-PRD.git
cd SFLOW-AIRunner-MCP-PRD
# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Run the server (stdio transport for Claude Desktop)
python server.py首次运行时,服务器将:
- 创建
jobs.db带所有表的SQLite数据库 - 自动生成OAuth凭据(打印到stderr-保存这些!)
- 启动调度程序循环(每60秒检查一次)
跑步
本地(stdio传输-适用于Claude Desktop)
python server.py添加到Claude桌面配置(~/Library/Application Support/Claude/claude_desktop_config.json 在macOS上):
{
"mcpServers": {
"claude-runner": {
"command": "/path/to/SFLOW-AIagents-MCP-Spinner/.venv/bin/python",
"args": ["/path/to/SFLOW-AIagents-MCP-Spinner/server.py"]
}
}
}重要提示: 使用Python解释器的完整路径 .venv 以确保依赖关系可用。
远程(SSE传输-用于web仪表板)
MCP_TRANSPORT=sse python server.py
# Server accessible at http://localhost:8080
# Web dashboard at http://localhost:8080/两种运输方式
MCP_TRANSPORT=both python server.py
# stdio for Claude Desktop + SSE for web dashboard环境变量
| 变量 | 必填 | 默认 | 描述 |
|---|---|---|---|
ANTHROPIC_API_KEY | 是 | - | 来自的API密钥 console.anthropic.com --通过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 # Main MCP server
├── requirements.txt # Python dependencies
├── jobs.db # SQLite database (auto-created)
├── .env # Environment variables (optional)
├── fixed-servers/ # Built-in MCP servers
│ └── email/
│ ├── server.py
│ └── metadata.json
├── dynamic_servers/ # User-created MCP servers (auto-created)
│ ├── cat-facts/
│ └── r2-images/
├── deploy/ # Deployment configs (systemd, nginx, deploy script)
│ ├── deploy.sh
│ ├── mcpserver.service
│ ├── nginx.conf
│ └── README-HETZNER.md
└── claude_playground/ # Working directory for job execution (auto-created)数据库
SQLite数据库位于 ./jobs.db 如下表所示:
表格
| 表 | 说明 |
|---|---|
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 # Creates fresh databaseMCP工具可用
作业管理
| 工具 | 说明 |
|---|---|
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) | 创建webhook端点 |
list_webhooks | 列出所有Webhook |
get_webhook(webhook_id) | 获取webhook详细信息 |
update_webhook(webhook_id, ...) | 更新webhook |
delete_webhook(webhook_id) | 删除webhook |
动态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执行,该SDK在后台运行本地Claude Code CLI。你需要 克劳德代码 已安装并验证(claude 必须在系统PATH上可用并已登录)。
以下是主要工作流程。
创建自定义工具
您可以要求Claude动态构建新的MCP工具服务器。服务器代码保存到 dynamic_servers// 每个服务器都会得到一个 DATA_DIR 本地文件存储的路径变量。通过引用的环境变量 os.environ.get() 或 os.getenv() 在代码中,会自动检测并标记为所需的凭据。
You: Create a tool that fetches the current weather for a given city using the
OpenWeatherMap API.
Claude: [calls create_mcp_server — saves server to dynamic_servers/weather/,
detects OPENWEATHERMAP_API_KEY from code]
Done! I created the "weather" server with a get_weather(city) tool.
It needs an API key — want me to store yours now?
You: Yes, the key is abc123
Claude: [calls set_server_credential("weather", "OPENWEATHERMAP_API_KEY", "abc123")]
Credential saved. The weather server is ready to use.安排重复作业
作业使用Claude Agent SDK按cron计划运行。您可以指定作业允许使用的工具(空数组 [] 指所有工具)。
You: Create a job that runs every weekday at 9am to summarize our Azure DevOps sprint
Claude: [calls create_job with:]
name: "Daily Sprint Summary"
cron: "0 9 * * 1-5"
prompt: "Connect to Azure DevOps and summarize the current sprint..."
tools: ["mcp__azure-devops__wit_my_work_items", "mcp__email__send_email"]
Job created (id: a1b2c3d4). Next run: tomorrow at 9:00 AM.
You: Show me the last 5 runs
Claude: [calls list_runs with limit=5]
Here are the recent runs — 4 completed successfully, 1 errored out...设置Webhooks
Webhooks允许外部服务通过HTTP POST触发提示。这 prompt_template 支持 {{payload}} 全身或 {{payload.field.subfield}} 对于嵌套值。
You: Create a webhook that sends a Slack summary whenever a new Azure DevOps
work item is created. The POST body will have the item title at
resource.fields.System.Title.
Claude: [calls create_webhook with:]
name: "New Work Item Notifier"
prompt_template: "A new work item was created: {{payload.resource.fields.System.Title}}.
Summarize it and post to Slack."
Webhook created! POST to this URL to trigger it:
https://your-server.com/webhook/abc123def456...
You: Test it — trigger the webhook manually
Claude: I can't trigger webhooks via MCP, but you can test with 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服务器上的工具,而无需创建作业。
You: Use the weather tool to check the forecast in Berlin
Claude: [calls invoke_internal_mcp_tool with:]
tool: "mcp__weather__get_weather"
payload: {"city": "Berlin"}
Currently 12°C and cloudy in Berlin, with rain expected this afternoon.管理服务器和凭据
您可以启用、禁用和更新内置(固定)和用户创建(动态)服务器,并管理它们的凭据。
You: What servers are available?
Claude: [calls list_fixed_mcp_servers and list_dynamic_mcp_servers]
Fixed servers: email (enabled), playwright (disabled)
Dynamic servers: weather (enabled), url-shortener (disabled)
You: Enable playwright and disable the weather server
Claude: [calls enable_fixed_server("playwright") and disable_mcp_server("weather")]
Done — playwright is now enabled and weather is disabled.
You: Which servers are missing credentials?
Claude: [calls get_unconfigured_servers]
The email server needs SENDGRID_API_KEY and SENDER_EMAIL.特别提示
对于一次性任务,请使用 快速运行 web仪表板(SSE模式)中的功能,无需创建作业即可立即执行提示。从claude.ai,您还可以手动触发任何现有作业:
You: Run the "Daily Sprint Summary" job right now
Claude: [calls trigger_job("a1b2c3d4")]
Run queued (run_id: e5f6g7h8). I'll check back for results.Cron示例
| 表达式 | 描述 |
|---|---|
0 9 * * 1-5 | 工作日上午9:00 |
0 */2 * * * | 每2小时 |
0 9 * * 1 | 周一上午9:00 |
*/30 * * * * | 每30分钟 |
0 0 1 * * | 每月的第一天午夜 |
故障排除
ModuleNotFoundation错误:没有名为“dotenv”的模块
Claude Desktop正在使用Python系统,而不是您的venv。更新配置以使用完整的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 # New credentials printed to stderr作业未运行
- 检查调度程序是否正在运行(在日志中查找“调度程序循环已启动”)
- 验证作业是否已启用:
sqlite3 jobs.db "SELECT enabled FROM jobs" - 检查cron表达式是否有效
- 查找运行中的错误:
sqlite3 jobs.db "SELECT error FROM runs ORDER BY started_at DESC LIMIT 1"
MCP工具在作业中不可用
如果作业报告“我无法访问\[MCP服务器\]工具”,请检查工具名称格式:
正确格式: mcp____ (双下划线)
- 例子:
mcp__email__send_email - 例子:
mcp__playwright__navigate
自动标准化格式: 这些将自动转换:
email:send_email→mcp__email__send_emailemail.send_email→mcp__email__send_email
提示: 使用空的工具数组 [] 允许所有可用工具,或检查响应 tool_warnings 查看是否有任何工具被规范化。
服务器立即断开连接
检查stderr输出是否有错误。常见原因:
- 缺少依赖项(运行
pip install -r requirements.txt) - Python版本\<3.11
- 数据库被其他进程锁定
Git“所有权可疑”错误
如果自动部署失败,并显示“致命:在存储库中检测到可疑的所有权”:
git config --system --add safe.directory /opt/mcpserver/app当存储库由与运行部署脚本的用户不同的用户拥有时,就会发生这种情况。
找不到Playwright浏览器
如果Playwright因浏览器未找到错误而失败,请手动安装Chromium:
# Install system dependencies first (as root) - Ubuntu 24.04
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
# Then install browser (as application user)
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 │ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘服务器运行三个并发异步组件:
- MCP服务器 -通过FastMCP显示25+个工具
- 调度器循环 -每60秒检查一次根据cron到期的作业
- 运行处理器循环 -拾取挂起的运行并执行它们
关键依赖
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-浏览器自动化
