Skip to content

Commit 2eac874

Browse files
authored
HTTP Server Implementation (#3)
* adding notes * checkpoint for laptop work * removed unwanted files * launching simple http node * update to docs * moving tests around * pre-commit
1 parent 9daca9b commit 2eac874

26 files changed

+1524
-37
lines changed

robot_mcp_bringup/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
cmake_minimum_required(VERSION 3.8)
15-
project(robot_mcp_examples)
15+
project(robot_mcp_bringup)
1616

1717
find_package(ament_cmake REQUIRED)
1818

robot_mcp_bringup/DEVELOPING.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# robot_mcp_bringup Development Guide
2+
3+
## Launch File
4+
5+
`launch/robot_mcp.launch.yaml`: YAML launch format for declarative configuration
6+
7+
- Launches `robot_mcp_server_node` with parameters from file
8+
- Launches `nav2_lifecycle_manager` to manage node lifecycle with bond monitoring
9+
- Arguments: `params_file`, `autostart`, `namespace`
10+
11+
## Configuration
12+
13+
Uses Nav2 nested parameter pattern (see `config/minimal.yaml` for example):
14+
15+
```yaml
16+
mcp_http_server:
17+
ros__parameters:
18+
topics: ["name1", "name2"] # List of names
19+
name1: # Nested params per name
20+
field: value
21+
```
22+
23+
ConfigParser in `robot_mcp_server` validates configuration at runtime.
24+
25+
## Testing
26+
27+
```bash
28+
# Test launch
29+
ros2 launch robot_mcp_bringup robot_mcp.launch.yaml
30+
ros2 lifecycle get /mcp_http_server # Should show "active"
31+
32+
# Test without autostart
33+
ros2 launch robot_mcp_bringup robot_mcp.launch.yaml autostart:=false
34+
ros2 lifecycle set /mcp_http_server configure
35+
ros2 lifecycle set /mcp_http_server activate
36+
37+
# Multi-robot (use namespaces and different ports in config)
38+
ros2 launch robot_mcp_bringup robot_mcp.launch.yaml \
39+
namespace:=/robot1 params_file:=/path/to/robot1.yaml
40+
```

robot_mcp_bringup/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# robot_mcp_bringup
2+
3+
Launch files and configurations for `robot_mcp_server` with lifecycle management.
4+
5+
## Usage
6+
7+
```bash
8+
# Launch with default config
9+
ros2 launch robot_mcp_bringup robot_mcp.launch.yaml
10+
11+
# Custom config
12+
ros2 launch robot_mcp_bringup robot_mcp.launch.yaml params_file:=/path/to/config.yaml
13+
14+
# Without autostart (manual lifecycle control)
15+
ros2 launch robot_mcp_bringup robot_mcp.launch.yaml autostart:=false
16+
```
17+
18+
## Configuration
19+
20+
See `config/minimal.yaml` for example. Configuration structure:
21+
22+
```yaml
23+
mcp_http_server:
24+
ros__parameters:
25+
server:
26+
host: "0.0.0.0"
27+
port: 8080
28+
api_key: "" # Optional, recommended for production
29+
enable_https: false # Requires cert/key paths
30+
31+
topics: ["topic_name"]
32+
topic_name:
33+
topic: "/ros/topic"
34+
msg_type: "package/msg/Type"
35+
plugin: "plugin_class_name"
36+
```
37+
38+
## Testing
39+
40+
```bash
41+
# Check status
42+
ros2 lifecycle get /mcp_http_server
43+
44+
# Test endpoint
45+
curl -X POST http://localhost:8080/mcp \
46+
-H "Content-Type: application/json" \
47+
-d '{"jsonrpc": "2.0", "method": "test", "id": 1}'
48+
```
49+
50+
## Launch Arguments
51+
52+
- `params_file`: Config YAML path (default: `config/minimal.yaml`)
53+
- `autostart`: Auto configure/activate (default: `true`)
54+
- `namespace`: Node namespace (default: `""`)
55+
56+
Uses `nav2_lifecycle_manager` for lifecycle management with bond monitoring.
Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
# Minimal robot_mcp configuration example
2-
# This will be populated in Phase 2 (Configuration System)
2+
# For local/LAN use (HTTP with optional API key)
33

44
mcp_http_server:
55
ros__parameters:
6+
# HTTP server configuration
67
server:
78
host: "0.0.0.0"
89
port: 8080
10+
enable_https: false # Use HTTP for local networks
11+
# api_key: "your-secret-key-here" # Uncomment to enable API key auth
12+
thread_pool_size: 10
13+
max_connections: 100
14+
timeout_ms: 30000
15+
enable_cors: true
916

10-
# Example actions, services, and topics will be added later
17+
# SSL/HTTPS configuration (optional, for production)
18+
# enable_https: true
19+
# ssl_cert_path: "/etc/letsencrypt/live/robot.example.com/fullchain.pem"
20+
# ssl_key_path: "/etc/letsencrypt/live/robot.example.com/privkey.pem"
21+
22+
# Topics, services, and actions will be configured in Phase 3+
23+
# Example structure (Phase 5+):
24+
# topics: []
25+
# services: []
26+
# actions: []
27+
# resource_groups: []

robot_mcp_bringup/launch/robot_mcp.launch.yaml

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,41 @@
1515
launch:
1616
# Launch arguments
1717
- arg:
18-
name: config
19-
default: ""
18+
name: params_file
19+
default: "$(find-pkg-share robot_mcp_bringup)/config/minimal.yaml"
2020
description: "Path to robot_mcp configuration file"
2121

22-
# Node will be added in Phase 5 (Lifecycle Integration)
23-
# - node:
24-
# pkg: robot_mcp_server
25-
# exec: robot_mcp_server_node
26-
# name: robot_mcp_server
27-
# param:
28-
# - from: $(var config)
29-
# output: screen
22+
- arg:
23+
name: autostart
24+
default: "true"
25+
description: "Automatically configure and activate the lifecycle node"
26+
27+
- arg:
28+
name: namespace
29+
default: ""
30+
description: "Top-level namespace"
31+
32+
# robot_mcp_server lifecycle node
33+
- node:
34+
pkg: robot_mcp_server
35+
exec: robot_mcp_server_node
36+
name: mcp_http_server
37+
namespace: $(var namespace)
38+
output: screen
39+
emulate_tty: true
40+
param:
41+
- from: $(var params_file)
42+
43+
# Nav2 lifecycle manager to manage robot_mcp_server lifecycle
44+
- node:
45+
pkg: nav2_lifecycle_manager
46+
exec: lifecycle_manager
47+
name: robot_mcp_lifecycle_manager
48+
namespace: $(var namespace)
49+
output: screen
50+
emulate_tty: true
51+
param:
52+
- name: autostart
53+
value: $(var autostart)
54+
- name: node_names
55+
value: ['mcp_http_server']

robot_mcp_bringup/package.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0"?>
22
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
33
<package format="3">
4-
<name>robot_mcp_examples</name>
4+
<name>robot_mcp_bringup</name>
55
<version>0.1.0</version>
66
<description>Example configurations, launch files, and custom plugins for robot_mcp</description>
77

@@ -12,7 +12,7 @@
1212
<buildtool_depend>ament_cmake</buildtool_depend>
1313

1414
<exec_depend>robot_mcp_server</exec_depend>
15-
<exec_depend>robot_mcp_common_msg_plugins</exec_depend>
15+
<exec_depend>nav2_lifecycle_manager</exec_depend>
1616

1717
<export>
1818
<build_type>ament_cmake</build_type>

robot_mcp_server/CMakeLists.txt

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,27 @@ find_package(rclcpp_components REQUIRED)
3131
find_package(std_msgs REQUIRED)
3232
find_package(pluginlib REQUIRED)
3333
find_package(robot_mcp_msg_pluginlib REQUIRED)
34+
find_package(bondcpp REQUIRED)
3435
find_package(nlohmann_json REQUIRED)
36+
find_package(OpenSSL REQUIRED)
3537

3638
set(include_dir ${CMAKE_CURRENT_SOURCE_DIR}/include)
3739

3840
# Server library
3941
add_library(${PROJECT_NAME} SHARED
4042
src/robot_mcp_server_node.cpp
4143
src/mcp_config/config_parser.cpp
44+
src/mcp_http_server/auth_middleware.cpp
45+
src/mcp_http_server/json_rpc_handler.cpp
46+
src/mcp_http_server/http_server.cpp
4247
)
4348
target_include_directories(${PROJECT_NAME} PUBLIC
4449
$<BUILD_INTERFACE:${include_dir}>
4550
$<INSTALL_INTERFACE:include>
4651
)
52+
target_compile_definitions(${PROJECT_NAME} PRIVATE
53+
CPPHTTPLIB_OPENSSL_SUPPORT
54+
)
4755
target_link_libraries(${PROJECT_NAME}
4856
PUBLIC
4957
robot_mcp_msg_pluginlib::robot_mcp_msg_pluginlib
@@ -54,7 +62,11 @@ target_link_libraries(${PROJECT_NAME}
5462
rclcpp_components::component
5563
${std_msgs_TARGETS}
5664
pluginlib::pluginlib
65+
bondcpp::bondcpp
5766
nlohmann_json::nlohmann_json
67+
OpenSSL::SSL
68+
OpenSSL::Crypto
69+
cpp-httplib
5870
)
5971

6072
# Register as a rclcpp_components component
@@ -80,8 +92,10 @@ install(DIRECTORY include/
8092
)
8193

8294
# Install test configuration files
83-
install(DIRECTORY test_mcp_config/
84-
DESTINATION share/${PROJECT_NAME}/test_mcp_config
95+
install(DIRECTORY test/launch_tests/
96+
DESTINATION share/${PROJECT_NAME}/test/launch_tests
97+
FILES_MATCHING
98+
PATTERN "*.yaml"
8599
)
86100

87101
if(BUILD_TESTING)
@@ -99,13 +113,24 @@ if(BUILD_TESTING)
99113
${PROJECT_NAME}
100114
)
101115

102-
# Add configuration parser launch tests
116+
# Add HTTP component tests (Catch2)
117+
add_robot_mcp_test(test_http_components
118+
test/test_http_components.cpp
119+
LIBRARIES
120+
${PROJECT_NAME}
121+
)
122+
123+
# Add launch tests
124+
add_launch_test(
125+
test/launch_tests/test_complete_config.py
126+
)
127+
103128
add_launch_test(
104-
test_mcp_config/test_complete_config.py
129+
test/launch_tests/test_minimal_config.py
105130
)
106131

107132
add_launch_test(
108-
test_mcp_config/test_minimal_config.py
133+
test/launch_tests/test_http_integration.py
109134
)
110135
endif()
111136

robot_mcp_server/DEVELOPING.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# robot_mcp_server Development Guide
2+
3+
## Classes
4+
5+
See header files for detailed API documentation.
6+
7+
### Main
8+
- **`MCPServerNode`**: Lifecycle node, orchestrates config/HTTP/bond
9+
10+
### Config (`mcp_config/`)
11+
- **`ConfigParser`**: Parse ROS2 params → structs (Nav2 pattern)
12+
- **`config_types.hpp`**: Plain C++ config structs (ServerConfig, TopicConfig, etc.)
13+
- **`ConfigParseException`**: Config error exception
14+
15+
### HTTP (`mcp_http_server/`)
16+
- **`HTTPServer`**: cpp-httplib wrapper, HTTP/HTTPS switching
17+
- **`JSONRPCHandler`**: JSON-RPC 2.0 protocol, static utility
18+
- **`AuthMiddleware`**: API key auth, static utility
19+
20+
### Plugin System (Phase 4 - planned)
21+
- **`MessagePlugin`**, **`ServicePlugin`**, **`ActionPlugin`**: Base classes for pluginlib
22+
23+
## Request Flow
24+
25+
```
26+
HTTP POST → AuthMiddleware → JSONRPCHandler → MCPServerNode.handleMCPRequest()
27+
→ (Phase 3: Router → Plugins) → JSON-RPC Response
28+
```
29+
30+
## Testing
31+
32+
```bash
33+
# Run tests
34+
colcon test --packages-select robot_mcp_server --event-handlers console_direct+
35+
36+
# Manual test
37+
ros2 launch robot_mcp_bringup robot_mcp.launch.yaml
38+
curl -X POST http://localhost:8080/mcp -H "Content-Type: application/json" \
39+
-d '{"jsonrpc": "2.0", "method": "test", "id": 1}'
40+
```
41+
42+
**Test files:**
43+
- `test/test_lifecycle.cpp`: Unit tests
44+
- `test_mcp_config/*.py`: Launch tests with config files
45+
46+
## Development Status
47+
48+
- Phase 1: Config ✅
49+
- Phase 2: HTTP ✅
50+
- Phase 3: Router (in progress)
51+
- Phase 4: Plugins (planned)

robot_mcp_server/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# robot_mcp_server
2+
3+
MCP (Model Context Protocol) server for ROS2 robots - enables AI assistants to control robots via HTTP.
4+
5+
## Quick Start
6+
7+
```bash
8+
# Install dependencies and build
9+
rosdep install --from-paths . --ignore-src -y
10+
colcon build --packages-select robot_mcp_server
11+
12+
# Run (use robot_mcp_bringup for production)
13+
ros2 run robot_mcp_server robot_mcp_server_node --ros-args --params-file config.yaml
14+
15+
# Test
16+
curl -X POST http://localhost:8080/mcp \
17+
-H "Content-Type: application/json" \
18+
-d '{"jsonrpc": "2.0", "method": "test", "id": 1}'
19+
```
20+
21+
## Configuration
22+
23+
See `robot_mcp_bringup/config/minimal.yaml` for example configuration. Configuration follows Nav2 pattern:
24+
25+
```yaml
26+
mcp_http_server:
27+
ros__parameters:
28+
server:
29+
host: "0.0.0.0"
30+
port: 8080
31+
api_key: "" # Optional
32+
enable_https: false # Requires ssl_cert_path and ssl_key_path
33+
34+
topics: ["topic_name"] # List of topic names to expose
35+
topic_name:
36+
topic: "/ros/topic"
37+
msg_type: "package/msg/Type"
38+
plugin: "plugin_class_name"
39+
```
40+
41+
## Architecture
42+
43+
- **Config System**: Parses ROS2 parameters
44+
- **HTTP Server**: HTTP/HTTPS with JSON-RPC 2.0
45+
- **Router** (Phase 3): Dispatch MCP requests
46+
- **Plugin System** (Phase 4): Dynamic message/service/action handlers
47+
48+
Lifecycle node compatible with `nav2_lifecycle_manager`. See `DEVELOPING.md` for class reference.

0 commit comments

Comments
 (0)