* Fix MCP API proxy support for streaming and headers
This commit fixes two issues with using the core API core/api/mcp through
the API proxy:
1. **Streaming support**: The proxy now detects text/event-stream responses
and properly streams them instead of buffering all data. This is required
for MCP's Server-Sent Events (SSE) transport.
2. **Header forwarding**: Added MCP-required headers to the forwarded headers:
- Accept: Required for content negotiation
- Last-Event-ID: Required for resuming broken SSE connections
- Mcp-Session-Id: Required for session management across requests
The proxy now also preserves MCP-related response headers (Mcp-Session-Id)
and sets X-Accel-Buffering to "no" for streaming responses to prevent
buffering by intermediate proxies.
Tests added to verify:
- MCP headers are properly forwarded to Home Assistant
- Streaming responses (text/event-stream) are handled correctly
- Response headers are preserved
* Refactor: reuse stream logic for SSE responses (#3)
* Fix ruff format + cover streaming payload error
* Fix merge error
* Address review comments (headers / streaming proxy) (#4)
* Address review: header handling for streaming/non-streaming
* Forward MCP-Protocol-Version and Origin headers
* Do not forward Origin header through API proxy (#5)
---------
Co-authored-by: Stefan Agner <stefan@agner.ch>
The Supervisor's /core/api proxy previously only supported GET and POST
methods, returning 405 Method Not Allowed for DELETE requests. This
prevented addons from calling Home Assistant Core REST API endpoints
that require DELETE methods, such as deleting automations, scripts,
or scenes.
The underlying proxy implementation already supported passing through
any HTTP method via request.method.lower(), so only the route
registration was needed.
Fixes#6509
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix root path requests
Since #5759 we've tried to access the path explicitly. However, this
raises KeyError exception when trying to access the proxied root path
(e.g. http://supervisor/core/api/). Before #5759 get was used, which
lead to no exception, but instead inserted a `None` into the path.
It seems aiohttp doesn't provide a path when the root is accessed. So
simply convert this to no path as well by setting path to an empty
string.
* Add rudimentary pytest for regular proxy requets
* Improve Home Assistant Core WebSocket proxy implementation
This change removes unnecessary task creation for every WebSocket
message and instead creates just two tasks, one for each direction.
This improves performance by about factor of 3 when measuring 1000
WebSocket requests to Core (from ~530ms to ~160ms).
While at it, also handle all WebSocket message related to closing the
WebSocket and report all other errors as warnings instead of just info.
* Improve logging and error handling
* Add WS client error test case
* Use asyncio.gather directly
* Use asyncio.wait to handle exceptions gracefully
* Drop cancellation handling and correctly wait for the other proxy task
* Handle unexpected WebSocket messages during auth
When an add-on does not respond or closes the WebSocket connection
during the authentication phase Supervisor does not handle errors
gracefully. Simply log such unexpected authentication to avoid
unnecessary stack traces in the log and make such cases no longer
appear on Sentry.
* Add pytest
* Introduce a timeout of 10s
* Bump Supervisor to Python 3.13
* Update ruff configuration to 0.9.1
Adjust pyproject.toml for ruff 0.9.1. Also make sure that latest version
of ruff is used in pre-commit.
* Set default configuration for pytest-asyncio
* Run ruff check
* Drop deprecated decorator no_type_check_decorator
The upstream PR (https://github.com/python/cpython/issues/106309) says
this never got really implemented by type checkers.
* Bump devcontainer to latest release
* Support proxy of binary messages from addons to HA
* Added tests for proxy
* Move instantiation into init
* Mock close method on server
* Add invalid auth test and remove auth mock