Fix proxy plugin config, logging and agent passthrough; port MCP to mcp 2.x (0.4.0) - #331
Merged
Merged
Conversation
Fixes #330. - Logging: --log / OPTILLM_LOG now sets the root logger (case-insensitive), so proxy and plugin DEBUG logs show; drop forced levels in the proxy modules; monitoring.log_level is an optional proxy-only override. - Config: stop falling back to the bundled example_config.yaml (its sample providers received traffic); add OPTILLM_PROXY_CONFIG. - Failover: 4xx responses no longer mark a provider unhealthy, and when all providers are unhealthy they are retried before the default client. - /v1/models lists the proxy providers' models with --approach proxy. - Agent clients (e.g. Crush): forward original messages (tool_calls, tool results) for the proxy and none approaches, stream full completions with tool_calls/finish_reason/usage, drop stream_options upstream, and handle null message content in parse_conversation. - Docs for the proxy plugin updated; tests added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Frame SAST flagged the new OPTILLM_PROXY_CONFIG env var as a HIGH path-traversal source (even with path validation). It isn't needed for #330, so remove it; ~/.optillm/proxy_config.yaml stays the config path. - mcp 2.x removed mcp.client.websocket and McpError, breaking the MCP plugin import in fresh installs. Pin mcp[ws]>=1.6,<2 (the lower bound stops pip backtracking to 1.3.0, which has no websocket client). - Run tests/test_proxy_plugin.py in the CI unit-test job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mcp 2.x removed the WebSocket client and renamed or reshaped several APIs,
which broke the MCP plugin import on fresh installs.
- McpError -> MCPError; tool/result fields are snake_case
(input_schema, mime_type, is_error).
- Add the Streamable HTTP transport ("streamable_http", also
"streamable-http"/"http") with headers and timeouts via
create_mcp_http_client. "websocket" now fails with a clear error
pointing to streamable_http or sse.
- LoggingClientSession logs the method/params of 2.x request and
notification objects.
- Detect server capabilities by value; hasattr was always true.
- Handle non-CallToolResult results (e.g. InputRequiredResult).
- Share header env expansion between SSE and Streamable HTTP.
- Require mcp>=2,<3 (replaces the earlier <2 pin); update README and tests.
Verified against real mcp 2.2.0 servers over stdio, SSE and Streamable
HTTP (connect, discover, call tool).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This release has breaking changes (mcp 2.x requirement, removed MCP websocket transport, proxy no longer loads the bundled example config, OPTILLM_LOG_LEVEL removed), so bump the minor version instead of 0.3.23. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #330
Summary
Each problem reported in #330 was reproduced against a mock llama.cpp server before fixing.
DEBUG logging didn't work
--log/OPTILLM_LOGonly changed theoptillm.serverlogger, so proxy/plugin DEBUG logs were dropped. It now sets the root logger and is case-insensitive (OPTILLM_LOG=DEBUGwas silently ignored before).proxy/routing.pyandproxy_plugin.py.monitoring.log_levelis now an optional proxy-only override.Server target in the proxy config was ignored
~/.optillm/proxy_config.yaml, the bundledexample_config.yamlwas loaded, sending traffic to OpenAI/Azure/Together and usinglocalhost:8080only asfallback_only. It is no longer on the search path; a blank template is created instead.--base-urlclient. 4xx responses (other than 408/429) no longer mark providers unhealthy, and unhealthy providers are retried before the default client./v1/modelsnow lists the providers' models (plusmodel_mapaliases) with--approach proxy.Crush / agent clients failing
"User: ...\nAssistant: None"), droppingtool_callsand tool results. The proxy andnoneapproaches now forward the original messages (with<optillm_approach>tags stripped).content, so a tool-call response became justdata: [DONE]. Full completions are now streamed withtool_calls,finish_reasonand usage.stream_optionswas forwarded upstream withoutstream, which providers reject. It is no longer forwarded.parse_conversationno longer crashes oncontent: null.Docs: updated the proxy README (logging, config location, models, failover, local servers/agents).
MCP plugin ported to mcp 2.x (CI was failing on fresh installs:
No module named 'mcp.client.websocket')McpError→MCPError; tool/result fields are snake_case in 2.x (input_schema,mime_type,is_error).streamable_httptransport (headers/timeouts supported). Thewebsockettransport was removed from the SDK, so it now returns a clear error pointing tostreamable_httporsse.CallToolResultresults are handled.mcp>=2,<3. README MCP section updated.CI:
tests/test_proxy_plugin.pynow runs in the unit-test job.Release: bumps version to 0.4.0 (breaking changes below).
Breaking changes
websockettransport removed (dropped from the MCP Python SDK in 2.x). Configs using"transport": "websocket"must switch tostreamable_httporsse.mcp>=2,<3. Environments that also needmcp<2won't install.example_config.yamlwhen~/.optillm/proxy_config.yamlis missing. It creates an empty template and uses the server's default client (--base-url) until providers are added.OPTILLM_LOG_LEVELremoved. Use--log/OPTILLM_LOG(now case-insensitive);monitoring.log_levelin the proxy config is an optional proxy-only override.Behavior changes (not breaking): the
noneand proxy approaches now forward the full conversation (including tool calls) instead of one flattened message, and streamed responses carry tool calls, finish reason and usage in OpenAI chunk format.Testing
--fail-on high, same pinned commit as CI) passes on all changed Python files.tests/test_mcp_plugin.py,tests/test_plugins.py,tests/test_proxy_plugin.py: 63 passed, 1 skipped with mcp 2.2.0.tests/test_proxy_plugin.py(10 tests) covers passthrough, streaming tool calls, config loading, failover and/v1/models.test_proxy_plugin_token_countsnow patches the config load. It previously read the developer's real~/.optillm/proxy_config.yamland made live calls.--approach proxyand the default passthrough.test_basic_none_approach_loggingfails onmainas well (local-model tokenizer error); unchanged.🤖 Generated with Claude Code