robot-twin-mcp
Exposes a robot twin HTTP API to LLM agents, enabling robot manipulation tasks such as pick-and-place, stacking, and peg-in-hole operations via the twin's HTTP interface without requiring a ROS installation.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@robot-twin-mcpbegin a task, run pick and place on the one_cube scene, then end the task"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
robot-twin-client
로봇 트윈 HTTP API 클라이언트, pick-and-place 시퀀스 예제, 그리고 로봇을 LLM 에이전트에게 노출하는 MCP 서버.
rdfp 워크스페이스 문서 docs/robot_twin/robot_twin_user_guide.md 의 5.9 절 예제를
독립 실행 가능한 프로젝트로 옮긴 것이다. 트윈은 HTTP 로만 접근하므로 ROS 설치도
source install/setup.bash 도 필요 없다. 클라이언트와 예제는 표준 라이브러리만
쓰고, MCP 서버만 mcp extra 를 요구한다.
패키지 이름이
robot_twin_client인 이유 —rdfp_ws에robot_twin이라는 같은 이름의 ROS 파이썬 패키지(트윈 서버 본체)가 있다. ROS 를 source 한 셸에서는PYTHONPATH가 editable 설치의.pth보다 먼저 검색되므로 그쪽이 이 패키지를 가려버린다 (증상:No module named robot_twin.mcp_server). 이름을 겹치지 않게 두는 것으로 해결한다. 저장소·배포 이름도 같은 이유로robot-twin-client이고, 클래스도RobotTwinClient다 (2026-09-11 개명) — 이 저장소는 트윈이 아니라 트윈을 호출하는 쪽이라는 것이 세 이름에 일관되게 드러난다.명령 이름 넷과 MCP 등록 이름은
robot-twin접두사 그대로다 (robot-twin-mcp,robot-twin-pick,robot-twin-stack,robot-twin-peg). 충돌하지 않고, 등록 이름을 바꾸면 이미 등록된claude mcp get robot-twin이 끊긴다.
구성
모듈 | 설명서 절 | 내용 |
| 5.2 |
|
| 5.6 / 5.7 / 4.2 |
|
| 5.9 / 5.10 |
|
| — | 쌓기. 물체를 집어 다른 물체 위에 얹는다 — |
| — | peg-in-hole. |
| — | MCP 서버. 트윈 카탈로그를 LLM 도구로 노출한다 (아래 참고) |
ops.py 가 따로 있는 이유는 트윈의 COMPLETED 가 "도달했다" 는 뜻이 아니기
때문이다. 직선 이동은 경로 일부만 실행돼도 성공으로 끝나고, 그리퍼는 물체를 물면
목표 폭에 못 미친 채(reached_goal=False, stalled=True) 끝난다. 판정을 한군데
모아 두고 pick / place 는 그 결과만 본다.
연산마다 판정 근거가 다르다는 점에 주의한다.
연산 |
| 판정 근거 |
| 계획의 60~100% 만 실행돼도 성공으로 끝난다 ( |
|
| 관절 공간 계획이라 부분 실행은 없지만, JGPC 스택은 open loop 라 도달 보장이 없다 |
|
그리퍼 결과의 이름이 바뀌었다. 트윈은 이제 at_goal / width 를 보낸다
(rdfp_msgs/GripperState). 옛 이름 reached_goal / position 만 읽으면
KeyError 로 죽는데, 증상이 원인을 안 가리킨다 — 실제로 Isaac 트윈에서 pick 이
"대상이 잘못되었다" 로 끝났다. set_gripper 가 at_goal 에서 reached_goal 을
채워 주므로 기존 호출자는 그대로 동작하지만, 새 코드는 at_goal 을 본다 —
그것이 목표별 판정식을 이미 적용한 유일한 성공 신호다.
mock 백엔드에서는 파지 판정이 성립하지 않는다. 물리가 없어 물체를 물어도
stalled 가 서지 않으므로, 판정을 그대로 적용하면 파지에서 멈춰 그 이후 단계를
전혀 검증할 수 없다. --allow-empty-grasp (라이브러리에서는 pick(..., require_grasp=False)) 로 건너뛴다 — 경고를 찍고 진행한다. 실제 로봇에서는 쓰지
않는다; 빈손인 채로 이송하게 된다.
이 우회는 한시적이다. 붙일 수 있는 스택이 mock 뿐이라 둔 것이고, 물리가 있는 스택(gazebo / isaac-sim)을 쓸 수 있게 되면
--allow-empty-grasp와require_grasp인자를 함께 제거한다. 그때부터 파지 실패는 원칙대로 오류다.
move_to_named_target 의 목표 관절값은 SRDF 안에 있어 클라이언트가 모른다. 그래서
closed_loop: false 일 때는 좌표로 검증할 방법이 없어 reached=False 와 why 를
돌려주고 판단을 호출자에게 넘긴다. 쓸 수 있는 이름은 twin.read('named_targets')
로 먼저 확인한다 — 오타는 400 이 아니라 계획 단계의 FAILED 로 온다.
좌표는 손끝(TCP) 기준이다
트윈의 move_linear 는 panda_link8(planning group 의 tip link)을 움직이는데,
손끝은 거기서 약 10.3 cm 더 뻗어 있다. 물체 중심을 그대로 명령하면 그리퍼가 그만큼
아래로 내려가 바닥을 파고든다 — 5 cm 큐브(중심 z=0.025)라면 손끝이 z=-0.078 이다.
그래서 이 스크립트는 좌표를 손끝 기준으로 다루고, 팔에 보내기 직전에만
to_arm_command() 로 바꾼다. 두 가지를 되돌린다.
보정 | 이유 |
위치 — 목표 자세로 회전시킨 오프셋만큼 뒤로 | 손끝이 목표에 오게 한다. DOWN 자세면 z 가 10.3 cm 올라간다 |
자세 — z축 +45° | URDF 의 |
두 프레임의 위치는 같으므로(panda_hand_joint 의 이동이 0) move_linear_verified
가 outputs.final_pose(= panda_hand)와 비교하는 것은 이 변환 뒤에도 유효하다.
정석은 URDF 에
panda_hand_tcp프레임을 두고link_name으로 지정하는 것이다. 그러면 이미 녹화된/ee_pose기준이 달라져 데이터셋 호환을 따져야 하므로, 우선은 클라이언트 쪽 보정으로 둔다.
Related MCP server: docfy-mcp
설치
cd ~/development/mdtpy/robot-twin-client
uv sync실행
먼저 로봇 스택과 트윈이 떠 있어야 한다 (사용 설명서 1.2 / 1.3).
uv run robot-twin-pick --help
uv run robot-twin-pick --scene one_cube --seed 7 --angle 30물체를 먼저 배치한다. --scene 레시피대로 reset_scene 을 호출하고, 그 결과로
나온 실제 배치 좌표를 집는다 — 랜덤하게 놓고 고정 좌표를 집으면 그 자리에 아무것도
없기 때문이다. --seed 가 같으면 배치도 같다. 축을 고정하고 싶으면 -x/-y/-z 로
덮어쓴다.
reset_scene ─ pick → place ─ return_home이 스크립트는 로봇 조작만 한다 — 세션/에피소드 경계를 다루지 않는다. 조작과 수집을
한 함수에 묶으면 조작만 하고 싶을 때 쓸 수가 없어서다. 그래서 수집 계층(rdfp)이 떠
있지 않아도 되고, 제어 스택(robot_control panda_mock)만으로 동작한다.
같은 실행을 학습 데이터로 남기려면 경계를 찍는 쪽이 이 흐름을 감싼다 — MCP 서버의
begin_task / end_task 가 그 역할을 한다(아래 "작업 경계는 서버가 소유한다").
집은 다음 베이스 z축(panda_link0) 둘레로 --angle 만큼 반시계로 돈 자리에
놓는다. 기본값은 30° 이고, 음수를 주면 시계 방향이다. 놓을 자리는 파지 지점과 같은
반경·같은 높이의 원호 위이며, 그리퍼 자세도 같은 각만큼 함께 돌아 쥔 물체와의 상대
자세가 유지된다. 놓고 상승한 뒤에는 SRDF named target ready 로 복귀한다
(--home 으로 바꾼다).
인자를 주지 않으면 설명서의 예시 좌표를 쓴다. 좌표는 position(m) + 고정 자세
DOWN(그리퍼가 아래를 봄)이며 좌표계는 panda_link0 고정이다.
트윈이 다른 호스트/포트에 있으면 --host / --port / --twin-id 로 지정한다.
이 프로그램은 실제로 로봇을 움직인다. 파지 판정(
stalled)은 그 자리에 실제로 물체가 있어야 성립하고, 회전한 자리가 작업 공간 안이어야 한다.필요한 것: 트윈과 백엔드 씬 노드(mock 은
mock_scene_state_node). 씬 노드는 mock 계열 launch 가 기본으로 띄운다.
라이브러리로 쓸 때는 다음과 같다.
from robot_twin_client import (
RobotTwinClient, above_of, grasp_pose_of, pick, place, return_home, rotated_about_base_z
)
twin = RobotTwinClient(host='127.0.0.1', port=8801, twin_id='panda01')
placement = twin.run('reset_scene', {'scene': 'one_cube', 'seed': 7})['outputs']
grasp = grasp_pose_of(placement['objects'][0]) # 배치된 물체를 집는다
target = rotated_about_base_z(grasp, 30.0) # 반시계 30°
if pick(twin, above_of(grasp), grasp):
place(twin, above_of(target), target)
return_home(twin) # 복귀는 place 밖이다 — 다음 물체를 이어 집을 수도 있다경계까지 포함한 전체 흐름은 reset_and_pick_and_place(twin, args) 하나로 돈다.
peg-in-hole — robot-twin-peg
peg 을 한 고정물에서 다른 고정물로 옮겨 꽂는다. 펑션베이 백엔드 전용이다 (포트·트윈 이름 기본값이 그쪽이다).
uv run robot-twin-peg # 반대쪽으로 (지금 위치에서 자동 판단)
uv run robot-twin-peg peg_tray # 목적지를 명시
uv run robot-twin-peg --dry-run # 판단만 하고 움직이지 않는다실측(2026-09-11): 왕복 5회 연속, 물체 이탈 0건, 삽입 오차 0.05~0.40 mm.
세 판정이 이 모듈의 실체다. 셋 다 "집어서 옮긴다" 만으로는 나오지 않고, 틀렸을 때 증상이 에러가 아니라 물체가 날아가는 것이다.
판정 | 없으면 |
파지 오프셋 보정 — peg 바닥 끝을 겨냥한다 (중심이 아니다) | 0.74° 기울기가 바닥을 0.32 mm 옮겨 입구에 걸린다 (여유 0.50 mm) |
기하 사전 확인 — 손끝이 고정물 상면 위에 남는가 | 밀려 올라간 파지로 밀어 넣다 물체가 튕겨 나간다. 움직이기 전에 막는다 |
앉음 확인 — 놓기 전에 실제로 앉았는가 | 안 앉은 채 놓으면 물체를 영구히 잃는다 |
⚠️ 실패하면 peg 을 쥔 채로 멈춘다 (PegInHoleError.holding). 그리퍼를 열면 안 되고,
같은 호출을 재시도해도 안 된다 — 원인이 그대로면 결과도 같다.
⚠️ 고정물 밖에는 내려놓을 수 없다. 시뮬레이터 씬에 peg ↔ 탁자 접촉이 정의돼 있지
않아, 고정물이 잡아 주지 않으면 물체가 탁자를 통과해 떨어진다(3회 확인, 낙하 가속도
−11.25 m/s² = 중력). 절차의 한계가 아니라 씬의 한계다 — 벤더 요청 B-14.
⚠️ 다루는 것은 서 있는 peg 뿐이다. 쓰러진 것은 범위 밖이며 거부한다.
쌓기 — robot-twin-stack
물체를 집어 다른 물체 위에 얹는다.
uv run robot-twin-stack --help
uv run robot-twin-stack # block_a 를 cylinder_a 위에 (기본)
uv run robot-twin-stack --source cylinder_a --base block_a # 반대로
uv run robot-twin-stack --repeat 10 # 10 회 반복 (매 회 ready 복귀 + 씬 무작위)
uv run robot-twin-stack --repeat 10 --seed 100 # 재현 가능한 10 회
uv run robot-twin-stack --no-reset # 이미 놓인 것 위에 이어서 쌓는다reset_scene ─ pick(source) ─ 물린 위치 실측 ─ place(base 위) ─ return_home ─ verify시작할 때 씬을 먼저 배치한다. 리셋 없이 두 번 돌리면 이미 얹혀 있는 물체를 다시
집어 제자리에 놓는 꼴이 된다. --scene / --seed 로 레시피와 배치를 고르고, 같은
시드는 같은 배치를 준다.
리셋은 stack 밖에 있다. 쌓기는 겹쳐 쓸 수 있어야 하기 때문이다 — A 위에 B 를
올린 뒤 그 위에 C 를 올리는 식이다. stack 이 스스로 리셋하면 두 번째 호출이 첫
번째 결과를 무너뜨린다. 그래서 조작은 stack, 배치까지 묶은 것은
reset_and_stack 이고, CLI 는 --no-reset 으로 앞의 것만 쓴다.
리셋 뒤에는 씬 변수가 따라올 때까지 기다린다. /scene/reset 이 끝나도
scene_objects 는 주기 발행이라 직전 배치를 한동안 더 말한다. 그대로 읽으면
리셋 전 자리를 집으러 가고 거기엔 아무것도 없는데, 시퀀스는 끝까지 정상으로 보이고
파지만 조용히 빗나간다. await_fresh_scene 이 새 표본 둘을 기다린다 — 하나로는
리셋 직전에 떠난 발행이 바로 도착할 수 있어 부족하다.
쥔 뒤에 물린 위치를 실측하는 것이 핵심이다. 손끝을 물체 중심에 맞춰 닫아도 물체는
손가락 사이에서 미끄러진다 — Isaac 실측에서 실린더가 12 mm 내려간 채 물린 적이
있다(같은 동작을 다시 하면 1 mm 였다; 재현되지 않는다). 상수 TCP_OFFSET_M 만 믿고
내려놓으면 그만큼 띄워 떨어뜨리게 되고, 원통은 굴러떨어진다. 그래서 들어올린 뒤
ee_pose 와 scene_objects 를 함께 읽어 손끝과 물체 중심의 실제 차이를 구하고,
놓을 좌표를 x·y·z 모두 그만큼 보정한다.
치수는 타입마다 순서가 다르다 (shape_msgs/SolidPrimitive 규약).
타입 |
| 반높이 |
|
|
|
|
|
|
|
|
|
뒤집어 읽어도 값이 나오고 크래시하지 않는다 — 물체가 엉뚱한 높이에 놓일 뿐이라
실행해 봐서는 안 갈린다. 그래서 half_height_of 에 모아 두고 테스트로 고정했다.
scene_objects 변수와 reset_scene 의 출력은 모양이 다르다. 쌓기에는 type 과
dimensions 가 필요해 변수 쪽을 읽는다 — reset_scene 출력에는 치수가 없다.
reset_scene outputs.objects 리스트 [{'name': ..., 'position': {...}}, ...]
scene_objects 변수 딕셔너리 {'objects': {이름: {'type', 'dimensions',
'pose': {'position', ...}}}}놓았다는 것이 얹혔다는 뜻은 아니다. place 의 성공은 팔이 움직였다는 것까지이므로,
끝나고 verify_stacked 로 두 물체의 높이차와 가로 어긋남을 확인한다.
물리가 있는 백엔드가 필요하다. mock 은 물체가 서로 얹히지 않아 확인할 수 없다. 그래서 기본 접속 대상이
robot-twin-pick(8801 /panda01) 과 달리 8802 /panda_isaac이다.
라이브러리로 쓸 때는 다음과 같다.
from robot_twin_client import RobotTwinClient, reset_and_stack, stack, verify_stacked
twin = RobotTwinClient(host='127.0.0.1', port=8802, twin_id='panda_isaac')
# 배치부터 하고 쌓는다.
if reset_and_stack(twin, 'block_a', 'cylinder_a', scene='two_objects', seed=7):
print(verify_stacked(twin, 'block_a', 'cylinder_a'))
# 이미 놓인 것 위에 이어서 쌓을 때는 stack 을 직접 쓴다 — 리셋이 없어야 한다.
stack(twin, 'block_b', 'cylinder_a')MCP 서버
LLM 에이전트가 프로그램을 짜지 않고 대화만으로 로봇 상태를 확인하고 연산을 조합할 수 있게 한다. "박스를 반시계 50도로 옮겨줘" 같은 요청을 에이전트가 도구 조합으로 푼다.
등록은 한 번, 기동은 매번이다.
[한 번만] ./sbin/register_mcp_server.sh
[매번] 로봇 스택 → 트윈 → Claude Code 에서 /mcp 확인# 터미널 A — 로봇 스택 (rdfp_ws)
rdfp_env # ROS 환경 + overlay + 워크스페이스로 cd
ros2 launch robot_control panda_mock.launch.py
# 터미널 B — 트윈 (rdfp_ws)
rdfp_env
./scripts/run_robot_twin.shrdfp_env 는 rdfp_ws 머신의 옵트인 셸 함수다(~/.bashrc 가 정의만 한다). 켜지 않고
install/setup.bash 만 하면 ros2 는 돌지만 ROS_DOMAIN_ID 가 0 / RMW 가 fastrtps
로 떠서, 트윈과 스택이 서로를 보지 못한다.
MCP 서버는 띄우지 않는다 — Claude Code 가 세션마다 알아서 spawn 한다. 도구
목록을 트윈 카탈로그에서 가져오므로 트윈이 먼저 떠 있어야 하고, 순서가 뒤바뀌면
tools fetch failed 로 잡힌다(그 상태면 /mcp 에서 재연결).
uv sync --extra mcp
./sbin/check_mcp_server.sh # 배선 점검 — 서버 기동 + 도구 목록인자 없이 실행하면 initialize → tools/list 를 한 번 주고받아 서버·트윈·도구 목록까지
한 번에 확인한다. 트윈이 꺼져 있으면 도구 조회 단계에서 Connection refused 로
멈추므로 어디가 끊겼는지 바로 보인다.
stdio 트랜스포트이므로 보통 직접 실행하지 않고 MCP 클라이언트에 등록한다. 등록 스크립트를 쓴다.
./sbin/register_mcp_server.sh # 기본 (user scope — 모든 프로젝트)
./sbin/register_mcp_server.sh --scope local # 이 프로젝트에서만
# 두 번째 트윈. **`--twin-id` 를 빠뜨리지 않는다** — 포트만 바꾸면 트윈 id 가 기본값
# `panda01` 로 남아 URL 이 /api/v1/robot_twins/panda01 이 되고, 도구 목록을 가져올 때
# `HTTP 404` 로 실패한다. 등록 자체는 성공하므로 증상이 그 404 뿐이다.
./sbin/register_mcp_server.sh --name robot-twin-isaac \
--port 8802 --twin-id panda_isaac기본이 user scope 인 이유 — local 은 등록할 때의 프로젝트 디렉터리에서만
잡힌다. 로봇 작업은 보통 rdfp_ws 쪽에서 하므로, local 로 등록하면 정작 거기서
도구가 보이지 않는다.
등록 해제
--remove 는 --name 이 가리키는 것 하나만 지운다. 이름을 안 주면 기본값인
robot-twin 이 대상이므로, 다른 이름으로 등록해 둔 것은 그대로 남는다.
./sbin/register_mcp_server.sh --remove # robot-twin (기본 이름)
./sbin/register_mcp_server.sh --name robot-twin-isaac --remove # 이름을 지정해서--port / --twin-id 는 해제에 아무 영향이 없다. 등록할 때 쓰는 인자라
--port 8802 --remove 로 써도 지워지는 것은 여전히 robot-twin 이다. 대상은
이름뿐이다.
없는 이름을 주면 조용히 아무것도 하지 않는다 — removed existing registration: <이름>
이 안 찍혔다면 그 이름이 없었던 것이다. 무엇이 지워질지 미리 보려면 등록 내용을
확인한다 (커맨드 인자에 포트와 트윈 id 가 박혀 있다).
claude mcp list # 등록된 이름 목록
claude mcp get robot-twin # 그 이름이 어느 포트·트윈에 붙어 있는지스크립트는 덮어쓰기다 — 같은 이름이 있으면 지우고 다시 넣으므로 인자를 바꿔
재실행하면 그대로 반영된다. uv sync --extra mcp 도 함께 수행하고, uv 를 절대
경로로 박는다 (Claude Code 가 서버를 spawn 할 때의 PATH 가 이 셸과 다를 수 있고,
GUI 클라이언트는 로그인 셸 PATH 를 보지 못한다).
손으로 등록한다면 다음과 같다.
claude mcp add robot-twin -- "$(command -v uv)" --directory ~/development/mdtpy/robot-twin-client \
run --extra mcp robot-twin-mcp등록 직후
claude mcp list가tools fetch failed로 보이면 트윈이 안 떠 있는 것이다 — 도구 목록을 트윈 카탈로그에서 가져오기 때문이며, 등록 자체는 정상이다../sbin/check_mcp_server.sh로 같은 것을 더 자세히 볼 수 있다.
sbin/
스크립트 | 하는 일 |
| Claude Code 에 등록/해제. 덮어쓰기라 재실행해도 된다 |
| 배선 점검 — 서버·트윈·도구 목록을 한 번에 확인 |
|
|
check_mcp_server.sh --serve 는 클라이언트가 하는 spawn 을 손으로 흉내내는 모드다.
표준입력에서 JSON-RPC 를 기다리며 멈춘 것처럼 보이는데 고장이 아니라 stdio 서버의
정상 동작이며, 사람이 쓸 일은 거의 없다.
도구는 트윈 카탈로그에서 자동 생성된다
GET /operations 의 inputs_schema 가 이미 JSON Schema 이고 description 도 트윈
설정에 있으므로, 트윈 YAML 에 연산을 추가하면 MCP 도구가 저절로 늘어난다. 손으로
유지하는 중복 목록이 없다. 다만 그대로 내보내면 안 되는 것이 있어 예외를 둔다.
분류 | 대상 | 이유 |
검증 래퍼로 교체 |
| 트윈의 |
감춤 |
| 미구현 — 호출하면 실패한다 |
감춤 |
| 여는 경로를 |
추가 | 상태 읽기 · 기하 계산 · 작업 경계 | 카탈로그에 없는 것들 |
추가 도구
도구 | 하는 일 |
| 상태 변수 조회. |
|
|
| 좌표 계산. 로봇을 움직이지 않는다 |
| 씬 리셋 + 세션/에피소드 경계 |
| 비상 정지 |
| peg-in-hole 절차. 좌표를 만들지 않는다 — 보정·판정이 도구 안에서 일어난다 |
기하 계산을 도구로 여는 이유는 쿼터니언을 에이전트에게 맡기면 조용히 틀리기
때문이다. xyzw/wxyz 순서 하나만 어긋나도 예외 없이 엉뚱한 자세로 간다. "50도
회전한 자리"는 pose_rotated_about_base_z 가 계산한다.
작업 경계는 서버가 소유한다
에이전트는 호출 사이에 상태를 잃어버리므로, 에피소드를 열고 닫는 것을 잊으면 다음
작업이 막힌다. 그래서 여는 경로를 begin_task 로 좁히고 서버가 짝을 보장한다.
begin_task ─ reset_scene ─ start_session ─ start_episode
(에이전트가 작업)
end_task ─ stop_episode ─ stop_session ← 한쪽이 실패해도 나머지를 시도begin_task가 돌려준objects가 실제 배치다. 집을 좌표는 여기서 가져온다.그 배치를 서버가 기억했다가
end_task의metadata에 자동으로 합친다 — 에이전트가 되돌려 주기를 기대하면 잊는 순간 재현 불가능한 에피소드가 남는다.닫지 않은 채 새 작업을 시작하면 이전 것을
failure로 닫고 경고한다. 연결이 끊겨도 종료 경로에서 닫는다.
오류는 복구 방법과 함께 돌아온다
오류 메시지가 에이전트의 유일한 피드백 채널이라, 코드만 던지면 같은 호출을 그대로
재시도한다. RESOURCE_BUSY → "get_resource_status 로 확인하라",
PRECONDITION_FAILED → "session_state 를 확인하라" 처럼 다음 행동을 붙인다.
도구 실패는 예외가 아니라 is_error 결과로 돌아가므로 세션이 끊기지 않는다.
팔 이동은 수십 초가 걸린다. 블로킹 HTTP 호출을 스레드로 내리므로 이동 중에도 상태 조회가 응답한다. 다만 MCP 클라이언트 쪽 타임아웃은 별개이니, 긴 연산이 잦으면 클라이언트 타임아웃을 늘린다.
테스트
uv run pytestROS 를 source 한 쉘에서는 PYTHONPATH 를 타고 ROS 의 pytest 플러그인이 venv 안까지
자동 로드되어 충돌한다. 그럴 때는 다음으로 실행한다.
uv run --env-file .env pytest # 또는 쉘에 export UV_ENV_FILE=.env알려진 한계 (설명서와 동일)
자원 경합 재시도가 없다.
409 RESOURCE_BUSY가 그대로TwinError로 올라와 시퀀스가 중단된다. 경합이 잦다면 설명서 5.3 의run_with_retry로 감싼다.중단 시 복구 책임이 클라이언트에 있다. 중간에 실패하면 로봇이 어떤 자세로 남는지 트윈은 모른다. 단계가 늘어나면 클라이언트 조합이 아니라 트윈의 복합 연산(설명서 8.3)으로 옮기는 것이 맞다.
move_to_pose가 미구현이라 접근 지점까지도 직선(move_linear)으로 간다.
This server cannot be deployed
Maintenance
Related MCP Connectors
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
Runtime permission, approval, and audit layer for AI agent tool execution.
The governed runtime for agent skills. Search the catalog and inspect a skill before running it.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceExposes task management (add, list, complete tasks) and document search (RAG) as MCP tools for AI agents.-
- AlicenseNot gradedqualityAmaintenanceExposes an OpenAPI catalog as tools for AI agents (e.g., Claude Code, Cursor) to query API endpoints via list_endpoints and get_endpoint tools, enabling interactive API exploration without a browser.15 npmMIT
- FlicenseNot gradedqualityDmaintenanceProvides 19 tools for discovery, data analysis, configuration, and simulation, enabling an agent to drive digital twin workflows with session persistence and knowledge graph capabilities.1-
- FlicenseNot gradedqualityCmaintenanceEnables agents to securely discover and invoke a centrally governed catalog of tools from distributed internal and external providers, with policy enforcement, quotas, inspection, and audit controls.-