Problem
MCP tools in Onyx pass LLM-generated arguments directly to the MCP server with zero filtering or modification. Built-in tools use override_kwargs but MCP tools don't (mcp_tool.py has override_kwargs: None).
This means admins cannot guarantee specific argument values for MCP tool calls — they must rely on the LLM obeying the system prompt, which is unreliable. The LLM frequently "forgets" to include required arguments.
Use Cases
- Presentation service (Alai MCP) — force
theme_id so presentations always use the correct corporate theme
- Slack MCP — force
channel_id to restrict posts to a specific channel
- CRM MCP — force
organization_id for tenant isolation
- Any MCP with fixed API keys or IDs in arguments
Proposed Solution
Add a forced_args field (JSONB, nullable) to the Tool model. When an MCP tool is called, forced args are merged over the LLM-provided arguments, ensuring admin-configured values always take precedence.
Changes
- DB: New
forced_args column on tool table (Alembic migration)
- Backend:
MCPTool.run() merges {**llm_kwargs, **self._forced_args} before calling the MCP server
- API: New
PATCH /api/admin/tool/{tool_id}/forced-args endpoint (admin-only)
- Frontend: Settings button per MCP tool to configure forced args via key-value editor
Key Design Decisions
forced_args works on any tool type (MCP, custom, built-in), not just custom tools
- Admin-only access enforced via
admin_router + current_curator_or_admin_user
- Backward compatible — nullable field, tools without forced_args work unchanged
PR
Implementation: #10496
Problem
MCP tools in Onyx pass LLM-generated arguments directly to the MCP server with zero filtering or modification. Built-in tools use
override_kwargsbut MCP tools don't (mcp_tool.pyhasoverride_kwargs: None).This means admins cannot guarantee specific argument values for MCP tool calls — they must rely on the LLM obeying the system prompt, which is unreliable. The LLM frequently "forgets" to include required arguments.
Use Cases
theme_idso presentations always use the correct corporate themechannel_idto restrict posts to a specific channelorganization_idfor tenant isolationProposed Solution
Add a
forced_argsfield (JSONB, nullable) to theToolmodel. When an MCP tool is called, forced args are merged over the LLM-provided arguments, ensuring admin-configured values always take precedence.Changes
forced_argscolumn ontooltable (Alembic migration)MCPTool.run()merges{**llm_kwargs, **self._forced_args}before calling the MCP serverPATCH /api/admin/tool/{tool_id}/forced-argsendpoint (admin-only)Key Design Decisions
forced_argsworks on any tool type (MCP, custom, built-in), not just custom toolsadmin_router+current_curator_or_admin_userPR
Implementation: #10496