PyBullet MCP服务器
模型上下文协议(MCP)服务器,使AI助手能够与PyBullet物理模拟进行交互。通过与AI代理的自然语言交互构建基于物理的项目。
特性
- 37 MCP工具:用于物理模拟控制(包括机器人关节控制)的全面API
- 仿真管理:使用可配置的重力创建和管理多个独立的物理模拟
- 对象操纵:添加具有完整属性控制的基本体形状(长方体、球体、圆柱体、胶囊)和URDF模型
- 机器人控制:查询关节信息,控制电机(位置/速度/扭矩),并计算反向运动学
- 物理控制:使用可配置的时间步长施加力、扭矩和逐步模拟
- 状态持久性:在JSON文件中保存和加载完整的模拟状态
- 约束条件:在对象之间创建关节(固定、棱柱、球形)
- 碰撞检测:查询具有详细碰撞信息的联系点
- 可视化:可选的GUI模式,带有调试可视化和摄像头控制
- 错误处理:带有描述性错误消息的全面验证
重要说明
- 坐标要求:所有矢量必须作为完整的3D坐标\[x,y,z\]提供
- 重力: [0, 0, -9.81] (不是 [-9.81]) - 位置: [x, y, z] (不是 [x, y] 或 [x]) - 力/扭矩: [fx, fy, fz] (不是 [fx]) - 方向: [x, y, z, w] 四元数(不是 [w])
- 质量约束:对象质量必须为正(质量>0)。对静态对象使用大质量(例如1000)
- GUI限制:一次只能激活一个GUI模拟(PyBullet限制)
- URDF路径:使用绝对路径或相对于服务器工作目录的路径
- 转动关节:
create_constraint不支持"revolute"--使用generate_revolute_joint+load_urdf相反。始终传递一个明确的output_path在工作空间内generate_revolute_joint否则,生成的URDF将着陆/tmp/和load_urdf将拒绝它。
安装
先决条件
- Python 3.9或更高版本
- pip包管理器
- 虚拟环境(推荐)
安装依赖项
- 创建并激活虚拟环境:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate- 安装FastMCP和PyBullet:
pip install fastmcp pybullet- 对于开发(包括测试工具):
pip install fastmcp pybullet pytest hypothesis pytest-cov验证安装
检查是否安装了所需的软件包:
python -c "import pybullet; import mcp; print('Installation successful!')"快速开始
运行服务器
看 QUICKSTART.md 有关以下内容的详细说明:
- 启动服务器
- 配置Claude桌面
- 探索所有功能的示例提示
- 常见工作流程和用例
快速命令:
source venv/bin/activate # On Windows: venv\Scripts\activate
python -m src.server服务器将启动并监听来自AI助手的MCP协议连接。
MCP客户端使用示例
一旦连接到MCP客户端(如Claude Desktop),您就可以通过自然语言进行交互:
1.创建模拟:
Create a new physics simulation with Earth gravity这叫 create_simulation 有重力 [0, 0, -9.81].
重要:重力必须是三维矢量。服务器接受以下简写 [-9.81] 并将其扩展为 [0, 0, -9.81].
2.添加对象:
Add a red box at position (0, 0, 1) with dimensions 0.5x0.5x0.5 and mass 1.0这叫 add_box 创建一个长方体对象。位置会自动扩展为 [0, 0, 1].
Add a sphere at (2, 0, 1) with radius 0.3这叫 add_sphere 创建一个球体。
备注:质量必须为正。对于静态对象(如地平面),使用较大的质量值(例如1000)。
3.运行模拟:
Step the simulation forward 100 times这叫 step_simulation 步数=100。
4.查询对象状态:
What is the position and velocity of object 0?这叫 get_object_state 检索位置、方向和速度。
5.施加力:
Apply a force of [10, 0, 0] to object 0这叫 apply_force 推动物体。
6.保存模拟:
Save the current simulation state to simulation.json这叫 save_simulation 坚持国家。
7.加载模拟:
Load the simulation from simulation.json这叫 load_simulation 以恢复保存的状态。
MCP配置
要将此服务器与Cursor或任何其他MCP兼容客户端一起使用,请将以下内容添加到MCP配置文件中:
{
"mcpServers": {
"pybullet": {
"url": "http://localhost:8000/mcp",
"disabled": false
}
}
}默认情况下,服务器运行HTTP传输。您可以通过在中编辑入口点来更改传输方法 server.py:
if __name__ == "__main__":
mcp.run(transport="http", port=8000)更新配置后重新启动MCP客户端。
可用工具
服务器通过MCP协议公开了37个工具:
仿真管理(5个工具)
create_simulation:使用可配置的重力和可选的GUI初始化新的物理模拟
- 参数: gravity (列表\[float\],默认值:\[0,0,-9.81\]), gui (bool,默认值:false) - 返回:simulation_id、重力、gui_enabled
list_simulations:获取所有活动的模拟ID
- 返回:模拟ID列表
destroy_simulation:清理并删除模拟
- 参数: sim_id (str) - 返回:确认消息
step_simulation:通过一个或多个时间步推进模拟
- 参数: sim_id (str), steps (int,默认值:1) - 返回:simulation_id、steps_taked、current_time
set_timestep:配置模拟的时间步长持续时间
- 参数: sim_id (str), timestep (浮动) - 返回:确认消息
对象操作(9个工具)
add_box:将长方体形状添加到模拟中
- 参数: sim_id, dimensions (列表\[浮动\]), position (列表\[浮动\]), mass (浮点数,默认值:1.0), color (列表\[float\],可选) - 返回:object_id、shape、position
add_sphere:将球体形状添加到模拟中
- 参数: sim_id, radius (浮动), position (列表\[浮动\]), mass (浮点数,默认值:1.0), color (列表\[float\],可选) - 返回:object_id、shape、position
add_cylinder:将圆柱体形状添加到模拟中
- 参数: sim_id, radius (浮动), height (浮动), position (列表\[浮动\]), mass (浮点数,默认值:1.0), color (列表\[float\],可选) - 返回:object_id、shape、position
add_capsule:将胶囊形状添加到模拟中
- 参数: sim_id, radius (浮动), height (浮动), position (列表\[浮动\]), mass (浮点数,默认值:1.0), color (列表\[float\],可选) - 返回:object_id、shape、position
load_urdf:从URDF文件加载机器人模型
- 参数: sim_id, file_path (str), position (列表\[浮动\]), orientation (列表\[float\],可选) - 返回:object_id、file_path、position
set_object_pose:更新对象位置和方向
- 参数: sim_id, object_id (int), position (列表\[浮动\]), orientation (列表\[浮动\]) - 返回:确认消息
get_object_state:查询完整对象状态
- 参数: sim_id, object_id (int) - 返回:位置、方向、线速度、角速度
apply_force:将力矢量应用于对象
- 参数: sim_id, object_id (int), force (列表\[浮动\]), position (列表\[float\],可选) - 返回:确认消息
apply_torque:对物体施加旋转力
- 参数: sim_id, object_id (int), torque (列表\[浮动\]) - 返回:确认消息
set_object_velocity:直接设置对象的线速度和/或角速度
- 参数: sim_id, object_id (int), linear_velocity (列表\[float\],可选), angular_velocity (列表\[float\],可选) - 返回:确认消息
change_dynamics:在运行时修改对象物理属性
- 参数: sim_id, object_id (int), link_index (int,默认值:-1), mass (浮动,可选), lateral_friction (浮动,可选), spinning_friction (浮动,可选), rolling_friction (浮动,可选), restitution (浮动,可选), linear_damping (浮动,可选), angular_damping (浮动,可选), contact_stiffness (浮动,可选), contact_damping (浮动,可选) - 返回:确认消息
get_dynamics_info:查询对象的当前动态属性
- 参数: sim_id, object_id (int), link_index (int,默认值:-1) - 返回:质量、侧向摩擦力、局部惯性对角线、恢复力、滚动摩擦力、旋转摩擦力、接触阻尼、接触刚度、身体类型、碰撞刚度
光线投射(2个工具)
ray_test:投射一条光线来探测障碍物并测量距离
- 参数: sim_id, ray_from (列表\[浮动\]), ray_to (列表\[浮动\]) - 返回:hit(bool)、object_id、link_index、hit_fract、hit_position、hit_normal
ray_test_batch:为激光雷达/传感器模拟高效地投射多条光线
- 参数: sim_id, rays_from (列表\[list\[float\]\]), rays_to (列表\[list\[float\]\]) - 返回:命中结果列表(与每条射线的ray_test字段相同)
摄影机渲染(4个工具)
compute_view_matrix:根据摄像机眼睛/目标/向上矢量计算视图矩阵
- 参数: camera_eye_position (列表\[浮动\]), camera_target_position (列表\[浮动\]), camera_up_vector (列表\[浮动\]) - 返回:将矩阵视为16个浮点数的列表
compute_view_matrix_from_yaw_pitch:根据球坐标计算视图矩阵(轨道相机)
- 参数: distance (浮动), yaw (浮动), pitch (浮动), target_position (列表\[浮动\]), up_axis_index (int,默认值:2) - 返回:将矩阵视为16个浮点数的列表
compute_projection_matrix:根据相机参数计算投影矩阵
- 参数: fov (浮动), aspect (浮动), near_plane (浮动), far_plane (浮动) - 返回:投影矩阵为16个浮点数的列表
get_camera_image:渲染来自虚拟相机的RGB、深度和分割图像
- 参数: sim_id, width (int), height (int), view_matrix (列表\[浮动\]), projection_matrix (列表\[浮动\]), renderer (str,默认值:“ER_BULLET_HARDWARE_OPENGL”) - 返回:宽度、高度、rgb(base64 PNG)、深度(list\[float\])、分段(list\[int\])
约束管理(2个工具)
create_constraint:在两个对象之间创建关节
- 参数: sim_id, parent_id (int), child_id (int), joint_type (str), joint_axis (列表\[float\],可选), parent_frame_position (列表\[float\],可选), child_frame_position (列表\[float\],可选) - 接头类型:“固定”、“棱柱”、“球形” - 返回:constraint_id、joint_type - 注: "revolute" 此处不支持--请使用 generate_revolute_joint + load_urdf 相反。
remove_constraint:从模拟中删除约束
- 参数: sim_id, constraint_id (int) - 返回:确认消息
旋转(铰链)接头——解决方法
PyBullet的运行时约束API不支持旋转关节。解决方法是使用这两个工具分两步进行:
步骤1——使用旋转关节生成URDF:
generate_revolute_joint:生成包含由旋转关节连接的两个形状的URDF文件
- 参数: parent_shape (str:“盒子”/“球体”/“圆柱体”), child_shape (str), parent_dimensions (列表\[浮动\]), child_dimensions (列表\[浮动\]), parent_mass (浮动), child_mass (浮动), joint_axis (列表\[浮动\]), joint_origin (列表\[float\],可选), joint_lower_limit (浮点数,默认值:-π), joint_upper_limit (浮点数,默认值:π), max_effort (浮动), max_velocity (浮动), output_path (str) - 返回:urdf_path、parent_shape、child_shape,joint_type、joint_axis、joint_limits - output_path 必须设置为服务器工作目录内的路径。 如果省略,则将文件写入系统临时目录(/tmp/)这超出了允许的路径,将导致 load_urdf 由于访问被拒绝错误而失败。
步骤2——加载生成的URDF:
- 呼叫
load_urdf随着urdf_path从...返回generate_revolute_joint - 然后使用
set_joint_motor_control驱动关节
碰撞检测(2个工具)
get_all_collisions:查询模拟中的所有接触点
- 参数: sim_id - 返回:具有位置、法线、力的接触点列表
get_collisions_for_pair:查询特定对象之间的联系点
- 参数: sim_id, obj_a (int), obj_b (int) - 返回:该对的接触点列表
可视化(2个工具)
enable_debug_visualization:启用触点和框架的调试渲染
- 参数: sim_id, show_contacts (bool,默认值:true), show_frames (bool,默认值:false) - 返回:确认消息
set_camera:为GUI模式配置相机位置和目标
- 参数: sim_id, distance (浮动), yaw (浮动), pitch (浮动), target (列表\[浮动\]) - 返回:确认消息
持久性(2个工具)
save_simulation:将模拟状态保存到JSON文件
- 参数: sim_id, file_path (str) - 返回:确认文件路径
load_simulation:从JSON文件加载模拟状态
- 参数: file_path (str), gui (bool,默认值:false) - 返回:new simulation_id,file_path
机器人控制(5个工具)
get_num_joints:查询URDF模型中的关节数
- 参数: sim_id (str), object_id (int) - 返回值:关节数(int)
get_joint_info:获取详细的关节属性
- 参数: sim_id (str), object_id (int), joint_index (int) - 返回:joint_name、joint_type、lower_limit、upper_limit
get_joint_state:获取当前关节状态
- 参数: sim_id (str), object_id (int), joint_index (int) - 返回值:joint_position、joint_speed、反作用力、电机扭矩
set_joint_motor_control:控制机器人关节
- 参数: sim_id (str), object_id (int), joint_index (int), control_mode (str), target_position (浮动,可选), target_velocity (浮动,可选), force (浮动,可选), position_gain (浮动,可选), velocity_gain (浮动,可选) - 控制模式:“位置控制”、“速度控制”和“扭矩控制” - 返回:确认消息
calculate_inverse_kinematics:计算目标末端执行器姿势的关节角度
- 参数: sim_id (str), object_id (int), end_effector_link_index (int), target_position (列表\[浮动\]), target_orientation (列表\[float\],可选), lower_limits (列表\[float\],可选), upper_limits (列表\[float\],可选), joint_ranges (列表\[float\],可选), rest_poses (列表\[float\],可选) - 返回:关节位置列表
示例工作流
基本落箱
创建一个简单的模拟,其中一个盒子在重力作用下下落:
# Through MCP client (natural language):
"Create a simulation with Earth gravity"
"Add a box at position (0, 0, 5) with dimensions 1x1x1"
"Step the simulation 200 times"
"What is the position of object 0?"堆叠物体
创建一堆对象:
"Create a simulation"
"Add a box at (0, 0, 0.5) with dimensions 10x10x1 and mass 1000" # Ground
"Add a box at (0, 0, 1.5) with dimensions 1x1x1"
"Add a sphere at (0, 0, 3) with radius 0.5"
"Step the simulation 300 times"
"Get all collisions"受约束对象
创建由关节连接的对象:
"Create a simulation"
"Add a box at (0, 0, 2) with dimensions 1x1x1" # Object 0
"Add a sphere at (2, 0, 2) with radius 0.5" # Object 1
"Create a fixed constraint between object 0 and object 1"
"Apply a torque of [0, 0, 10] to object 1"
"Step the simulation 200 times"保存和加载
坚持模拟:
"Create a simulation"
"Add a box at (0, 0, 1)"
"Add a sphere at (1, 0, 1)"
"Step the simulation 50 times"
"Save the simulation to my_sim.json"
# Later...
"Load the simulation from my_sim.json"
"Step the simulation 50 more times"机器人仿真
加载并控制URDF机器人模型:
"Create a simulation with GUI enabled"
"Load URDF from /path/to/robot.urdf at position (0, 0, 1)"
"How many joints does object 0 have?"
"Get information about joint 0 of object 0"
"Get the current state of joint 0"
"Set joint 0 to position 1.57 with position control and force 100"
"Step the simulation 100 times"
"Get the state of joint 0 again to see it moved"
"Calculate inverse kinematics for object 0 end-effector link 6 at position [0.5, 0, 0.5]"机器人控制功能:
- 查询关节数量和关节属性(类型、限制、轴)
- 读取关节状态(位置、速度、力、扭矩)
- 控制接头有三种模式:
- 位置控制:将关节移动到目标角度/位置 - 速度控制:以目标速度旋转关节 - 扭矩控制:对接头施加直接扭矩
- 计算末端执行器定位的反向运动学
持久性文件格式
模拟状态保存为具有以下结构的JSON文件:
{
"gravity": [0.0, 0.0, -9.81],
"timestep": 0.01,
"objects": [
{
"object_id": 0,
"type": "primitive",
"shape": "box",
"dimensions": [0.5, 0.5, 0.5],
"position": [0.0, 0.0, 1.0],
"orientation": [0.0, 0.0, 0.0, 1.0],
"linear_velocity": [0.0, 0.0, -0.98],
"angular_velocity": [0.0, 0.0, 0.0],
"mass": 1.0,
"color": [1.0, 0.0, 0.0, 1.0]
},
{
"object_id": 1,
"type": "urdf",
"urdf_path": "/path/to/model.urdf",
"position": [2.0, 0.0, 0.5],
"orientation": [0.0, 0.0, 0.0, 1.0],
"linear_velocity": [0.0, 0.0, 0.0],
"angular_velocity": [0.0, 0.0, 0.0]
}
],
"constraints": [
{
"constraint_id": 0,
"parent_id": 0,
"child_id": 1,
"joint_type": "fixed"
}
]
}兼容性说明
- 对象标识:加载时重新分配对象ID(可能与保存的ID不同)
- URDF文件:加载时URDF文件路径必须有效。使用绝对路径保证可靠性
- 模拟ID:加载时生成新的模拟ID
- 格式版本:当前格式与PyBullet 3.2.5兼容+
- 约束条件:约束已完全序列化并恢复
常见问题及解决方法
坐标误差
问题: "force needs a 3 coordinates [x,y,z]" 或类似错误
解决方案:始终提供完整的3D矢量:
# Wrong
gravity = [-9.81]
position = [1, 2]
force = [10]
# Correct
gravity = [0, 0, -9.81]
position = [1, 2, 0]
force = [10, 0, 0]批量验证错误
问题: "Mass must be positive, got 0.0"
解决方案:PyBullet需要正质量。对于静态对象,请使用大质量:
# Wrong
add_box(mass=0) # Error!
# Correct
add_box(mass=1000) # Heavy static objectGUI窗口未出现
问题:GUI窗口在以下情况下不显示 gui=true
解决方案:
- 每个服务器实例只允许一个GUI模拟
- 在创建新的GUI模拟之前,先销毁现有的GUI模拟
- 某些环境(Docker、没有X11的SSH)不支持GUI
- 在Linux上,确保X11可用:
echo $DISPLAY
URDF加载失败
问题: "Failed to load URDF: File not found"
解决方案:
- 使用绝对路径:
/full/path/to/robot.urdf - 或者使用相对于服务器工作目录的路径
- 验证文件是否存在:
ls -la /path/to/robot.urdf - 检查URDF中引用的网格文件是否也可访问
物体从地面坠落
问题:物体穿过地平面
解决方案:
- 确保您正在逐步进行模拟:
step_simulation(steps=100) - 使用适当的时间步长(默认0.01通常很好)
- 为接地平面提供大尺寸和高质量(例如1000)
- 验证对象是否具有正质量
故障排除
常见问题
1.启动服务器时导入错误
ModuleNotFoundError: No module named 'mcp' or 'pybullet'解决方案:确保您的虚拟环境已激活并安装了依赖项:
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install fastmcp pybullet2.Python版本错误
SyntaxError or version compatibility issues解决方案:检查Python版本(必须是3.9+):
python --version如果需要,使用特定的Python版本创建一个venv:
python3.9 -m venv venv3.PyBullet GUI未显示
GUI window doesn't appear when gui=true解决方案:
- 必须明确启用GUI模式:
create_simulation(gui=true) - 某些系统(服务器、Docker)不支持GUI模式,请改用无头模式
- 在Linux上,确保X11可用:
echo $DISPLAY
4.文件权限错误
PermissionError when saving/loading simulations解决方案:
- 确保目标目录中的写入权限
- 使用绝对路径:
/full/path/to/simulation.json - 检查磁盘空间:
df -h
5.MCP客户端无法连接到服务器
Server not responding解决方案:
- 验证服务器是否正在运行:
python -m src.server - 检查MCP配置中的URL是否与服务器端口匹配(默认值:
http://localhost:8000/mcp) - 配置更改后重新启动MCP客户端
- 检查服务器终端输出是否有错误消息
6.模拟行为异常
Objects fall through the ground or constraints don't work解决方案:
- 确保您正在逐步进行模拟:
step_simulation(sim_id, steps=100) - 检查时间步长值(默认值0.01通常很好)
- 验证物体质量是否为正
- 对于接地平面,使用尺寸较大、质量=1000的长方体
7.URDF加载失败
ToolError: Failed to load URDF解决方案:
- 验证URDF文件路径是否正确且可访问
- 对URDF文件使用绝对路径
- 检查URDF中引用的网格文件是否也可访问
- 直接使用PyBullet验证URDF语法
调试模式
要查看详细的错误消息,请检查终端中的服务器输出。服务器记录所有操作和错误。
获取帮助
如果您遇到此处未涵盖的问题:
- 检查服务器日志以获取详细的错误消息
- 验证您的MCP客户端配置
- 直接用Python测试服务器,以隔离MCP和PyBullet问题
- 查阅PyBullet文档,了解物理方面的具体问题
建筑
服务器遵循分层架构:
MCP Client (Claude Desktop)
↓
MCP Protocol
↓
FastMCP Server (37 tools)
↓
Manager Classes (helpers)
↓
PyBullet Physics Engine关键部件:
- FastMCP服务器 (
src/server.py):使用以下工具暴露37个MCP工具@mcp.tool装饰器 - 模拟管理器:管理PyBullet物理客户端和仿真生命周期
- 对象管理器:处理对象创建、操作和状态查询
- 约束管理器:创建和管理对象之间的关节
- 持久化处理程序:将模拟状态序列化/反序列化为JSON
- 冲突查询处理程序:查询联系点和碰撞信息
每个MCP工具都会验证输入,调用相应的管理器,并直接返回Python对象(dict/list/str/int)——FastMCP会自动处理MCP协议转换。
贡献
欢迎投稿!请确保:
- 所有测试均通过:
pytest - 代码的格式为:
black src tests - 代码传递linting:
ruff check src tests - 类型提示正确:
mypy src - 新功能包括测试(基于单元+属性)
- 文档已更新
致谢
支持
对于问题、疑问或贡献:
- 查看此README和故障排除部分
- 查看PyBullet文档以了解物理特定问题
