Skip to content

Fix proxy plugin config, logging and agent passthrough; port MCP to mcp 2.x (0.4.0) - #331

Merged
codelion merged 4 commits into
mainfrom
fix/proxy-issue-330
Sep 28, 2026
Merged

codelion merged 4 commits into
mainfrom
fix/proxy-issue-330

Conversation

@codelion

@codelion codelion commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

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_LOG only changed the optillm.server logger, so proxy/plugin DEBUG logs were dropped. It now sets the root logger and is case-insensitive (OPTILLM_LOG=DEBUG was silently ignored before).
  • Removed forced log levels in proxy/routing.py and proxy_plugin.py. monitoring.log_level is now an optional proxy-only override.

Server target in the proxy config was ignored

  • Without ~/.optillm/proxy_config.yaml, the bundled example_config.yaml was loaded, sending traffic to OpenAI/Azure/Together and using localhost:8080 only as fallback_only. It is no longer on the search path; a blank template is created instead.
  • One failed request (e.g. a 400) marked the only provider unhealthy, so later requests silently went to the --base-url client. 4xx responses (other than 408/429) no longer mark providers unhealthy, and unhealthy providers are retried before the default client.
  • /v1/models now lists the providers' models (plus model_map aliases) with --approach proxy.

Crush / agent clients failing

  • The conversation was flattened into one user message ("User: ...\nAssistant: None"), dropping tool_calls and tool results. The proxy and none approaches now forward the original messages (with <optillm_approach> tags stripped).
  • Streaming responses only emitted content, so a tool-call response became just data: [DONE]. Full completions are now streamed with tool_calls, finish_reason and usage.
  • stream_options was forwarded upstream without stream, which providers reject. It is no longer forwarded.
  • parse_conversation no longer crashes on content: 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).
  • New streamable_http transport (headers/timeouts supported). The websocket transport was removed from the SDK, so it now returns a clear error pointing to streamable_http or sse.
  • The logging session handles 2.x request/notification objects; capabilities are detected by value; non-CallToolResult results are handled.
  • Requires mcp>=2,<3. README MCP section updated.
  • Verified against real mcp 2.2.0 servers over stdio, SSE and Streamable HTTP (connect, discover, call tool).

CI: tests/test_proxy_plugin.py now runs in the unit-test job.

Release: bumps version to 0.4.0 (breaking changes below).

Breaking changes

  • MCP websocket transport removed (dropped from the MCP Python SDK in 2.x). Configs using "transport": "websocket" must switch to streamable_http or sse.
  • Requires mcp>=2,<3. Environments that also need mcp<2 won't install.
  • Proxy no longer loads the bundled example_config.yaml when ~/.optillm/proxy_config.yaml is missing. It creates an empty template and uses the server's default client (--base-url) until providers are added.
  • OPTILLM_LOG_LEVEL removed. Use --log / OPTILLM_LOG (now case-insensitive); monitoring.log_level in the proxy config is an optional proxy-only override.

Behavior changes (not breaking): the none and 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

  • Frame SAST (--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.
  • New tests/test_proxy_plugin.py (10 tests) covers passthrough, streaming tool calls, config loading, failover and /v1/models.
  • test_proxy_plugin_token_counts now patches the config load. It previously read the developer's real ~/.optillm/proxy_config.yaml and made live calls.
  • End-to-end check with the OpenAI SDK streaming parser against a mock upstream, for both --approach proxy and the default passthrough.
  • test_basic_none_approach_logging fails on main as well (local-model tokenizer error); unchanged.

🤖 Generated with Claude Code

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>
@CLAassistant

CLAassistant commented Sep 28, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

- 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>
@codelion codelion changed the title Fix proxy plugin config, logging and agent passthrough (bump 0.3.23) Fix proxy plugin config, logging and agent passthrough; port MCP to mcp 2.x (0.4.0) Sep 28, 2026
@codelion
codelion merged commit e4ad199 into main Sep 28, 2026
5 checks passed
@codelion
codelion deleted the fix/proxy-issue-330 branch September 28, 2026 02: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.

proxy bugs

3 participants