Skip to content

Adapt to the gateway 0.7.0 client surface - #30

Merged
bburda merged 1 commit into
mainfrom
fix/gateway-070-client-surface
Sep 2, 2026
Merged

Adapt to the gateway 0.7.0 client surface#30
bburda merged 1 commit into
mainfrom
fix/gateway-070-client-surface

Conversation

@bburda

@bburda bburda commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Pull Request

Summary

The gateway 0.7.0 spec renames and tightens parts of the surface this server calls. Adapting to it also fixed two calls the gateway had been rejecting all along.

Lifecycle. The operation ids lost their plural form, so the generated modules are now get_app_status, put_app_status_restart and the rest. The dispatch map named the old ones. Because client.py imports the API groups at module level, this was not only a lifecycle failure - nothing that imports ros2_medkit_mcp.client started at all.

Script execution. The body is ScriptExecutionRequest, where execution_type is required and the script inputs belong under parameters. The caller params went out as the whole body, so every execution this server started got:

400 {"error_code": "invalid-request", "message": "Missing required field: execution_type"}

They now travel under parameters, with execution_type set to now. That is the only value the shipped backend accepts, and the tool exposes no scheduling, so it is not something a caller has to supply.

Update registration. id is required and validated by the gateway, and becomes the path segment of the Location header on 201. The tool description showed an example without it, so an agent following the description built a request the gateway refused. The description now says id is required and the example uses it.

Data categories and data groups. These answer 501 not-implemented on every entity type, because the ROS 2 data provider neither groups nor categorises its topics. The 0.7.0 spec documents that; the 0.6.0 spec advertised a 200 the gateway never returned. Their tests mocked that 200, so they passed while the tools could not work. The tools stay in the set, since a provider plugin may implement the resources, and the error mapping already carries the gateway reason out intact:

[not-implemented] Data categories are not implemented for ROS 2

The tests now assert that. One more test pins the undocumented-200 path, so adding a 200 to the gateway schema shows up here instead of silently changing what the tool returns.

Execution type. The body's execution_type was going out as a hardcoded now. That is the only value the built-in script backend accepts, but the schema leaves it an open string and says a provider plugin defines its own vocabulary, so hardcoding it put a value the API treats as the caller's choice out of reach. It is an argument now, still defaulting to now, and the tool schema says what it means. The presence check on params was a truth test, so an explicitly empty object and an absent one produced the same request; parameters reaches the provider untouched, so those are two different requests.

This is a draft on purpose. The package version moves to 0.7.0 alongside the client pin, which is not published yet, so poetry.lock is stale and poetry check --lock fails. Run poetry lock once ros2_medkit_client 0.7.0 is released, then this is ready.


Issue


Type

  • Bug fix
  • New feature
  • Breaking change
  • Documentation only

Testing

Verified against a gateway built from the 0.7.0 release branch, with the client regenerated from that gateway's exported spec and installed locally.

  • poetry run python run_tests.py passes 221 tests. The three new ones assert the request body rather than the response status, since a 202 comes back either way: the script inputs travel under parameters, a caller-supplied execution type is forwarded, and an explicitly empty parameters object survives. Before the change the suite did not run at all: 6 test modules failed to import with ImportError: cannot import name 'get_apps_status'.
  • poetry run ruff check ., poetry run ruff format --check src/ tests/ and poetry run mypy src/ are clean.
  • Against the live gateway, not a mock:
    • get_status on an app and on a component both return {"status": "notReady"}, so the renamed modules resolve and the request reaches the gateway.
    • set_status reaches the gateway and gets its real answer for these entities ([not-implemented] Lifecycle control not available for this entity).
    • execute_script("talker", "hello", {"iterations": 3}) runs the script and the script reads back hello {"iterations":3} on stdin, so the parameters arrive where the provider looks for them.
    • Sending the old body shape by hand answers 400 Missing required field: execution_type, and the new shape answers 202.
    • list_data_categories and list_data_groups return [not-implemented] Data categories are not implemented for ROS 2 and the matching message for groups.

Checklist

  • Breaking changes are clearly described (and announced in docs / changelog if needed)
  • Linting passes (poetry run ruff check src/ tests/)
  • Formatting passes (poetry run ruff format --check src/ tests/)
  • Type checking passes (poetry run mypy src/)
  • Tests pass (poetry run python run_tests.py)
  • Docs were updated if behavior or public API changed

@bburda
bburda force-pushed the fix/gateway-070-client-surface branch 2 times, most recently from cfd0a33 to 75da163 Compare September 2, 2026 09:49
@bburda
bburda marked this pull request as ready for review September 2, 2026 09:57
@bburda bburda self-assigned this Sep 2, 2026
Lifecycle operation ids lost their plural form, so the generated modules
are get_app_status, put_app_status_restart and the rest. The dispatch map
named the old ones, and because client.py imports the API groups at module
level this was not only a lifecycle failure - nothing that imports
ros2_medkit_mcp.client started at all.

Two request bodies the gateway used to leave open are now described, and
both revealed calls the gateway had been rejecting:

- Script execution sends ScriptExecutionRequest. The caller's params went
  out as the whole body, so the gateway answered 400 'Missing required
  field: execution_type' for every execution this server has ever started.
  They now travel under 'parameters'. execution_type is an argument that
  defaults to 'now': that is the only value the built-in backend accepts,
  but the schema leaves it an open string and says a provider plugin
  defines its own vocabulary, so hardcoding it put a value the API treats
  as the caller's choice out of reach. The presence check on params is
  'is not None', because parameters reaches the provider untouched and an
  explicitly empty object is a different request from an absent one.
- Update registration requires 'id'. The tool's example omitted it, so an
  agent following the description built a request the gateway refused.

Data categories and data groups answer 501 on every entity type; the ROS 2
data provider neither groups nor categorises its topics. Their tests mocked
a 200 no gateway returns, so they passed while the tools could not work.
They now assert what the gateway sends, and a pinning test keeps the
undocumented-200 path visible if the schema ever gains one.

The client pin moves to the 0.7.0 wheel, and the package version follows it.
@bburda
bburda force-pushed the fix/gateway-070-client-surface branch from 75da163 to 3e94f44 Compare September 2, 2026 11:23
@bburda
bburda merged commit cbac09b into main Sep 2, 2026
3 checks passed
@bburda
bburda deleted the fix/gateway-070-client-surface branch September 2, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adapt to the gateway 0.7.0 client surface

2 participants