FlowCentral MCP服务器
在以下网址创建帐户 flowcentral.ai 机器人会引导你完成设置。
基本上,我们有一个分布式linux风格的系统,为机器人提供工具基础设施。工具排列在文件夹中,便于跨职能和团队进行管理。团队可以直接调用彼此的功能,当然机器人也可以自己做事情。下面是一个符合MCP标准的系统,但我们支持热加载等,而不需要不断更新MCP工具的一些繁琐开销。
首先,克隆repo,执行Python env操作,将API键设置为环境变量(OPENROUTER_API_KEY、ANTHROPIC_API_KEY等),并将本地Python服务器连接到主服务器(请参见runServer)。我们给你所有的源代码来构建你自己的工具调用聊天机器人,就像克劳德一样。看 Games/FlowCentral/Bots/Atlas/ 对于bot角色配置和 Home/chat.py 对于共享聊天循环,机器人通过搜索/dir动态发现工具,而不是预先加载它们。
\*请注意 game_set("FlowCentral") 将服务器锁定到游戏,然后 character_bot() 为机器人分配角色, move_bot()/move_human() 处理位置之间的移动,以及 bot_spawn() 进行完整的一次性设置(角色+位置)
FlowCentral网络
每个MCP服务器都是人工智能代理和开发人员协作网络的一部分。使用模型上下文协议,该平台创建了一个生态系统,在这个生态系统中,代理可以在网络中发现和使用彼此的能力。工具和功能可以在代理之间共享、发现和协调,无论是用于企业自动化、工作流编排还是任何其他应用程序。网络架构使代理能够找到并利用其他用户的工具,从而创建一个共享功能的去中心化生态系统。
该项目的核心是一个Python MCP主机(称为“远程”),它允许您动态安装函数和第三方MCP工具
快速开始
- 先决条件-需要为服务器安装Python,为Lobster(MCP客户端)安装Node;您还应该安装uv/uvx和node/npx,因为MCP似乎需要两者
- 由于异步支持,Python 3.13现在似乎是最稳定的
- 设置Python虚拟环境并安装依赖项:
cd python-server
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt- 设置API密钥。在中创建脚本
python-server/导出您的密钥(这些密钥是gitignored的,因此您的密钥不会被提交)。例如,创建set_OPENROUTER.bat:
#!/bin/bash
# Usage: source set_OPENROUTER.bat
export OPENROUTER_API_KEY="sk-or-v1-your-key-here"
echo "OPENROUTER_API_KEY has been set"为您需要的每个提供商创建一个(set_ANTHROPIC.bat, set_GOOGLE.bat等等)遵循相同的模式。激活venv后获取它们:
source venv/bin/activate
source set_OPENROUTER.bat
source set_ANTHROPIC.bat # if using Anthropic models
source set_GOOGLE.bat # if using Google APIs您只需要计划使用的提供商的密钥。至少, OPENROUTER_API_KEY 默认bot(Atlas)需要。
- 在中编辑runServer脚本
python-server文件夹并设置电子邮件和服务名称(实际上,最佳做法是创建一个副本“runServerFoo”,您可以在我们进行更新时用它替换runServer文件):
python server.py \
--email=youremail@gmail.com \ # email you use for flowcentral
--api-key=foobar \ # should change online
--host=localhost \ # npx MCP will be looking here to connect to remote (assumes there is at least one running locally)
--port=8000 \
--cloud-host=wss://flowcentral.ai \ # points to cloud
--cloud-port=443 \
--service-name=home # remote name, can be anything but must be unique across all machines- MCP客户端现在被调用 龙虾。要将其用作常规的独立MCP服务器,请将以下配置添加到Windsurf或Cursor或其他任何服务器中:
"mcpServers": {
"atlantis": {
"command": "npx",
"args": [
"atlantis-mcp",
"--port",
"8000"
]
}
}要将亚特兰蒂斯添加到克劳德代码:
claude mcp add atlantis -- npx atlantis-mcp --port 8000
要连接到Codex:
codex mcp add atlantis -- npx atlantis-mcp --port 8000
要添加亚特兰蒂斯开放天气进行测试:
claude mcp add --transport stdio weather_forecast --env OPENWEATHER_API_KEY=mykey123 -- uvx --from atlantis-open-weather-mcp start-weather-server
- 要连接到FlowCentral,请登录https://www.flowcentral.ai在同一封电子邮件下
- 您的远程设备应使用电子邮件和默认api key='foobar'自动连接(请参阅稍后生成新密钥的'api'命令)。除非您稍后手动更改,否则将为要连接的第一台服务器分配“默认”服务器
- 最初,除了一些示例外,函数和服务器文件夹将为空
- 您可以运行这个独立的MCP,也可以从云端访问,或者两者兼而有之
建筑
警告:MCP术语已经很糟糕了,称之为“服务器”或“主机”只会让人更加困惑,因为MCP本质上就是p2p
系统部件:
- 云:FlowCentral云服务器;一个分享工具并让用户使用它们的地方
- 远程:此仓库中的Python服务器进程,正式称为MCP“主机”(您可以在同一台机器或不同的机器上运行>1,只需指定不同的服务名称)
- 动态函数:你编写的一个简单的Python函数,充当一个工具
- 动态MCP服务器:任何第三方MCP,存储为JSON配置文件
请注意,MCP身份验证和安全性仍在研究中,因此现在使用云进行身份验证更容易
目录
- Python远程(MCP P2P服务器) (
python-server/)
- 我们的“远程”位置。在本地运行,但可以远程控制
- 龙虾(MCP客户端) (
client/)
- 允许Claude Code或Codex运行Atlantis命令或通过MCP聊天 - 使用npx(易于安装到Claude Code或Codex中) - 不需要云连接-尽管它可能会抱怨 - 仅支持规范的一个子集 - 只能看到本地框上的工具(至少现在)或共享的工具 工具设置为“公共”
Python服务器布局
如果你想了解Python源代码,请从 python-server/server.py 然后从那里分支出来:
server.py-主要入口点和协议主机。它启动Starlette应用程序,拥有DynamicAdditionServer类,管理WebSocket和云Socket。IO连接和将功能/服务器管理器连接在一起。如果您正在跟踪工具调用,则整合的MCPtools/call处理者住在这里DynamicAdditionServer._handle_tools_call(),然后委托给_execute_tool().DynamicFunctionManager.py-拥有动态Python工具系统dynamic_functions/这就是定义函数装饰器的地方(@visible,@public,@protected,@exclude等),扫描和验证文件,加载/重新加载Python模块,并将工具调用分派到用户代码中。DynamicServerManager.py-管理第三方MCP服务器配置dynamic_servers/。它保存/加载JSON配置,启动stdio MCP服务器,保持会话活动,并获取其工具列表。atlantis.py-注入到动态函数中的动态函数利用/运行时API。这是工具代码使用的桥梁client_log、流媒体、HTML/图像/视频响应、点击/上传回调、请求上下文和持久共享状态。看 动态函数文档 用于此API的功能授权端。lobster.py-本地Atlantis MCP客户端的兼容层。它定义了readme/command/chat工具,并将这些本地调用转换为云支持的命令流。state.py-中央配置和全流程状态。它设置日志记录,定义FUNCTIONS_DIR和SERVERS_DIR,并存储主机/端口和请求超时等基本服务器常数。utils.py-跨服务器和动态函数共享的低级助手。它包含搜索词解析、JSON/log格式化、全局服务器实例桥和客户端命令/日志管道atlantis.py.PIDManager.py-通过PID文件为Python服务器进程提供单实例保护。ColoredFormatter.py-日志格式化程序和请求上下文过滤器state.py.
运行时分割基本上是:
server.py接收MCP流量。server.py路由MCPtools/call通过DynamicAdditionServer._handle_tools_call()._handle_tools_call()将Python工具的执行委托给DynamicFunctionManager.py并代理MCP工具的执行DynamicServerManager.py.- 动态函数通过以下方式回调到主机
atlantis.py和utils.py.
有关动态函数编写的详细信息,请参见 动态函数文档.
特性
动态函数
动态函数使用户能够创建和维护作为工具的自定义函数,这些函数保存在 dynamic_functions/ 文件夹。函数在启动时加载,修改后自动重新加载。
有关创建和使用动态函数的详细信息,请参阅 动态函数文档.
动态MCP服务器
- 使用户能够安装和管理第三方MCP服务器工具;JSON配置文件保存在
dynamic_servers/文件夹
- 每个MCP服务器都需要先“启动”才能获取工具列表
- 每个服务器配置都遵循通常的JSON结构,其中包含一个“mcpServers”元素;例如,这将安装一个openweather MCP服务器:
{
"mcpServers": {
"openweather": {
"command": "uvx",
"args": [
"--from",
"atlantis-open-weather-mcp",
"start-weather-server",
"--api-key",
""
]
}
}
}气象MCP服务只是移植到uvx的现有服务。看 这里
云
云服务在https://www.flowcentral.ai提供了一个集中式中心,用于管理远程服务器和跨机器共享工具。
应用程序组织
动态功能通过以下方式组织到应用程序中 文件夹结构。只需放置您的 .py 子目录中的文件:
dynamic_functions/
├── Home/ # App: "Home"
│ └── atlas.py
├── Accounting/ # App: "Accounting"
│ ├── accounting.py
│ └── foo.py
└── FilmFromImage/ # App: "FilmFromImage"
└── qwen_image_edit_local.py文件夹名称就是应用程序名称。 功能在 Home 相应地分配文件夹。
嵌套应用程序(子文件夹)
使用子文件夹创建嵌套应用程序结构:
dynamic_functions/
└── MyApp/
└── SubModule/
└── Feature/
└── my_function.py这将创建应用程序名称: MyApp/SubModule/Feature
最佳实践:
- 保持简单——一级文件夹通常就足够了
- 使用描述性文件夹名称(例如。,
Chat,Admin,Tools) - 将相关功能组合在同一文件夹中
- 文件夹结构使您的代码保持有序和清晰
使用搜索词调用工具
调用工具时,您可以使用 复合工具名称 以消除功能歧义。 仅包含唯一标识函数所需的路径。
格式: remote_owner*remote_name*app*location*function
关键原则:使用唯一解析的最简单形式
# If you have these functions:
# - dynamic_functions/Chat/send_message.py
# - dynamic_functions/Email/send_message.py
# - dynamic_functions/SMS/send_message.py
send_message ❌ Ambiguous! Which one?
**Chat**send_message ✅ Clear! The one in Chat
**Email**send_message ✅ Clear! The one in Email示例:
update_image → Simple call (only works if unique)
**MyApp**update_image → Specify app to disambiguate
**MyApp/SubModule**process_data → Nested app path
alice*prod*Admin**restart → Full routing: owner + remote + app + function
***office*print → Just location context它是如何工作的:
- 领域:
remote_owner*remote_name*app*location*function - 用以下内容分隔字段
*(星号) - 省略不需要的字段 (使用空字符串:
**App**func) - 应用程序字段支持嵌套应用程序的斜线表示法(
MyApp/SubModule) - 最后一个字段始终是函数名
- 无星号=将整个名称视为函数名称
何时使用化合物名称:
- 名称冲突:多个应用程序具有同名功能
- 远程定位:从云端调用特定遥控器上的功能
- 位置路线:特定物理位置的目标功能
- 多用户设置:在共享环境中指定所有者和远程
最佳实践: 简单开始(update_image)仅在需要解决歧义时添加上下文(**ImageTools**update_image).
例子:
# File: dynamic_functions/ImageTools/process.py
@visible
async def update_image(image_path: str):
"""Update an image."""
return "updated"
# If this is the ONLY update_image:
update_image ✅ Works fine!
# If Chat app ALSO has update_image:
**ImageTools**update_image ✅ Now we need to specify the app机器人:阿特拉斯
Atlas是FlowCentral的前台聊天机器人。机器人角色现在位于每个游戏文件夹中,共享运行时位于 Home/:
Games/FlowCentral/ # Game definition
├── Bots/ # Bot personas for this game
│ ├── Atlas/
│ │ ├── config.json # Model, provider, greeting, handler references
│ │ ├── system_prompt.md # Base system prompt (markdown)
│ │ ├── prompt.py # System prompt builder with context injection
│ │ ├── main.py # Index placeholder
│ │ └── atlas_face.jpg # Bot avatar
│ └── Celeste/ # Executive concierge
│ ├── config.json
│ ├── system_prompt.md
│ ├── prompt.py
│ ├── main.py
│ └── celeste_face.jpg
├── Locations/ # Rooms players can move between
│ ├── Lobby.json # Location metadata + adjacency
│ ├── Lobby.jpg # Background image
│ ├── Lounge.json
│ └── Lounge.jpg
└── Roles/ # NPC role definitions
├── Greeter/ # Atlas's role
│ ├── system_prompt.md # Role-specific system prompt
│ └── prompt.py
└── Concierge/ # Celeste's role
├── system_prompt.md
└── prompt.py
Home/ # Shared bot + game runtime
├── main.py # Entry point: index(), show_tools()
├── game.py # Game state: game_set(), game_show(), game_list()
├── bot.py # Bot listing with thumbnails, bot_spawn()
├── character.py # Character CRUD, roles, role_list()
├── location.py # Locations, positions, movement: move_bot(), move_human(), go(), look()
├── camera.py # Per-game camera location tracking
├── map.py # Interactive visual map of locations
├── common.py # Shared helpers: bot config, thumbnails, game data I/O
├── chat.py # Bot chat runtime: BotChatContext, dispatch_chat, system prompt builder
├── chat_callback.py # Routes room chat to correct bot, interaction tracking
├── chat_common.py # Transcript fetch, tool discovery, pseudo-tools (search, dir, todo)
├── turn.py # Multi-turn LLM conversation loop with tool calls
├── todo.py # Per-session todo pseudo-tool for bot task tracking
├── GAME.md # ER diagram of the game data model
├── MULTIX.md # User-facing CLI documentation
└── README.py # Serves MULTIX.md and GAME.md via MCP游戏系统
游戏管理机器人任务、角色、位置和移动。每个游戏的范围都是:
game_set(name)--将服务器锁定到游戏(例如。"FlowCentral")character_bot(sid, role)--为机器人分配角色(例如。character_bot("atlas", "Greeter"))character_human(sid, role, name)--为人类玩家分配角色character_self(role, name)--将呼叫者指定为人类角色move_bot(sid, location)/move_human(sid, location)--在位置之间移动字符go(location)--移动呼叫者的角色并更新背景game_show()--呈现游戏状态的实时ER图map(location)--显示当前位置和相邻区域的视觉地图
位置定义为JSON文件 Games//Locations/ 带有邻接图(connects_to).只允许沿着连接的边缘移动。新玩家从默认位置开始(标记为 "default": true).
玩家数据
所有游戏状态都在以下范围内 Data/{game_id}/.数据I/O助手(game_dir, _read_json, _write_json等)住在 Home/common.py.
Data/
├── main.py # Index placeholder, imports list_games from Home/common
└── {game_id}/ # Per-game data (created at runtime)
├── characters.json # Bot and human role assignments
├── positions.json # Current location of each character
├── camera.json # Current camera location
├── bot_interactions.json # Per-bot interaction history (timestamps, counts)
└── api_payload.json # Debug: last LLM API payload关键文件
python-server/dynamic_functions/Home/MULTIX.md--FlowCentral MCP工具的面向用户的文档(命令、搜索词、工具前缀等)。这是由readmeMCP工具。Games/FlowCentral/Bots/Atlas/config.json--机器人配置:模型(minimax-m2.7)、提供者(OpenRouter)、问候消息以及聊天处理程序和系统提示的参考。Home/main.py--入口点:index(),show_tools().Home/game.py--游戏生命周期:game_set(),game_show(),game_list(),game_entry()欢迎模式。Home/bot.py--机器人列表与缩略图生成,bot_spawn().Home/character.py--字符系统:character_bot(),character_human(),character_self(),character_list(),role_list().Home/location.py--位置、方位和移动:move_bot(),move_human(),go(),look(),position_get().Home/camera.py--每场比赛的摄像机位置跟踪:camera_get(),camera_set().Home/map.py--ELK.js布局的交互式可视化位置地图。Home/common.py--共享助手:机器人配置加载、缩略图生成、游戏数据I/O(game_dir,_read_json,_write_json).Home/chat.py--机器人聊天运行时:BotChatContext,dispatch_chat(),系统提示生成器,OpenAI客户端。Home/chat_callback.py--聊天路由:检测哪个机器人在房间里,构建上下文,分派给聊天处理程序,跟踪交互。Home/chat_common.py--转录获取、工具转换、参与者分析、伪工具(搜索、目录、待办事项)。Home/turn.py--具有工具调用执行功能的多回合LLM流式对话循环。Home/todo.py--每会话todo伪工具:机器人在对话中内部使用此工具来跟踪任务。与search/dir.Storage一起注入LLM工具列表:Data/{game_id}/todos/{sid}/.Data/main.py--游戏数据文件夹的索引占位符。
故障排除
如果MCP工具不工作(例如返回 Unknown tool 错误), 请先检查服务器日志Python服务器将详细日志写入 python-server/runServer.log --此文件准确显示了工具调用、云身份验证和客户端连接的情况。它可能会变大,所以把最后约1000行尾:
tail -1000 python-server/runServer.log日志中可见的常见问题:
⚠️ Unexpected tool call from local client--服务器收到一个工具调用,但没有识别出来;检查您的工具是否已注册❌ Authentication failed--云凭据错误或帐户不存在;检查您的电子邮件/api密钥🏠 Local MCP tool call intercepted--确认服务器正在接收来自MCP客户端的工具调用
与访客相关的日志行包括 "Visitor:", "New conversation for",以及 "Injected time-gap message".
如何构建一个新的机器人
要创建新的机器人,您需要: Games//Bots/,在 Games//Roles/,以及可选的新位置。
步骤1:创建角色文件夹 (Games/FlowCentral/Bots/YourBot/)
您需要4-5个文件:
config.json --型号和标识:
{
"sid": "yourbot",
"displayName": "YourBot",
"image": "yourbot_face.jpg",
"provider": "openrouter",
"model": "minimax/minimax-m2.7",
"baseUrl": "https://openrouter.ai/api/v1",
"apiKeyEnv": "OPENROUTER_API_KEY",
"chatHandler": "dynamic_functions.Home.chat.handle_chat_completions",
"systemPrompt": "system_prompt.md",
"greeting": "Hi, I'm YourBot."
}sid--唯一的机器人标识符,用于成绩单和字符系统chatHandler--总是dynamic_functions.Home.chat.handle_chat_completions(共享运行时)systemPrompt--bot文件夹中包含基本系统提示的markdown文件image--机器人文件夹中的头像图像文件名apiKeyEnv-保存API密钥的环境变量greeting--机器人首次出现时会说什么
system_prompt.md --机器人的个性以简单的标记显示:
You are YourBot, a [description of role and personality].
[Instructions for behavior, tone, tools, etc.]prompt.py --构建交互上下文(时间感知、回访检测)。复制自 Games/FlowCentral/Bots/Atlas/prompt.py 并根据需要进行调整。
main.py --索引占位符,以便机器人在工具发现中显示:
import atlantis
import logging
logger = logging.getLogger("mcp_server")
@visible
async def index():
"""YourBot — [role description]."""
passyourbot_face.jpg --头像。当机器人生成时显示。
第二步:创建角色 (Games/FlowCentral/Roles/YourRole/)
system_prompt.md --特定角色系统提示添加:
You are stationed at [location]. Your job is to [role description].prompt.py --可选的特定角色提示生成器。如果需要,从现有角色复制。
main.py --索引占位符:
import atlantis
import logging
logger = logging.getLogger("mcp_server")
@visible
async def index():
"""YourRole — [description]."""
pass步骤3:添加位置 (可选)
如果你的机器人需要自己的房间,请在以下位置创建一个JSON文件 Games/FlowCentral/Locations/:
YourLocation.json:
{
"name": "YourLocation",
"description": "A brief description of this location.",
"image": "YourLocation.jpg",
"connects_to": ["Lobby"]
}添加背景图像(YourLocation.jpg)相同 Locations/ 文件夹。然后更新大堂的 connects_to 数组包含 "YourLocation" 所以玩家可以在两者之间旅行。
步骤4:将您的机器人分配给其角色
一旦游戏被锁定到FlowCentral(通过 game_set),将您的机器人注册为角色,并将其分配给您创建的角色:
character_bot("yourbot", "YourRole")这链接了机器人的 sid 到角色文件夹,这样系统就知道要使用哪个系统提示和行为。如果一个角色有这个 sid 已存在,它会更新角色而不是创建副本。
步骤5:将您的机器人移动到其位置
将你的机器人放在它应该迎接访客的房间里:
await game_move_bot("yourbot", "YourLocation")新机器人必须先进入默认位置(大厅),然后才能移动到其他地方——这反映了玩家进入游戏的方式。如果你的机器人的位置是大厅本身,你可以省略位置参数。
第六步:生成机器人
展示机器人的头像,并让它通过配置的问候语进行自我介绍:
await spawn_bot("yourbot")这将向客户端显示机器人的面部图像,并将问候语作为聊天消息发送,以便机器人出现在对话记录中。在此之后,聊天回调将根据房间里的人自动将传入消息路由到您的机器人。
把它们放在一起:
以下是您在会话中使新机器人上线的完整序列:
await game_set("FlowCentral") # Lock server to the game (once per server)
character_bot("yourbot", "YourRole") # Assign bot to role
await game_move_bot("yourbot") # Enter the default lobby
await spawn_bot("yourbot") # Show face + greeting