You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A chat assistant can run an agentic mode, but its toolset is fixed at build time: the retrieval tools in internal/agentic_rag plus an optional web_search. It cannot call anything from an MCP server, while the agent canvas can. That gap matters more than "chat feels limited", because a chat is the only form that can be bound to an IM channel: ChatChannel stores a chat_id and nothing else, and incoming messages are answered through ChatSessionService.ChatCompletions. A user in Feishu, DingTalk, WeCom or WhatsApp therefore cannot reach a tenant MCP tool no matter how the agent canvas is built.
I'd like to discuss whether serving channel users with tenant MCP tools is in scope for chat, and if so, whether wiring the already-ported ToolCallSession path is the right way to do it. No PR yet.
What exists today
Chat, agentic mode. A chat with at least one attached knowledge base can run the smart-reasoning agent (internal/service/chat_pipeline.go, conf/agentic_rag.yaml). Its tools come from toolRegistry() in internal/agentic_rag/config.go: think, todo_write, run_javascript, grep_chunks, search_chunks, search_bm25_chunks, search_semantic_chunks, list_chunks, search_metadata, graph_explore, graph_doc_outline, navigate_tree, navigate_structure. web_search is added separately, per conversation, via agentic_rag.WithWebSearch, only when the chat has a search provider.
The tool-call loop is already in the chat model layer.internal/entity/models/types.go defines the ToolCallSession interface (ToolCall(name, arguments) (string, error)), ChatModel.BindTools, and a ToolConfig with max rounds and terminal tools; internal/entity/models/chat_tools.go runs the multi-round loop. None of this is reachable from chat right now:
internal/service/chat_pipeline.go binds a session only when the caller passes kwargs["toolcall_session"] together with kwargs["tools"].
internal/service/openai_chat.go sets "toolcall_session": nil with the comment no tool calls on OpenAI-compat path.
The native chat handler never constructs one.
No type in the Go tree implements ToolCallSession. The agent-side MCP adapter (internal/agent/component/agent_mcp.go) calls internal/mcp/client.CallTool directly instead.
MCP, agent-only.internal/entity/mcp.go declares MCPServer with TenantID and no dataset binding, so servers are tenant-scoped. The only consumer is the agent canvas MCP component, which resolves mcp_id + selected tools from the node config and performs a canvas → MCP server dependency check. URLs go through internal/mcp/client with the SSRF guard and the private-host allowlist.
Channels are chat-only.internal/entity/chat_channel.go has ChatID *string and no agent binding. internal/service/chat_channel.go answers incoming messages via chatSessionSvc.ChatCompletions. There is no channel entry point for an agent.
Why "just use the agent canvas" does not cover this
Channel users are not operators. They cannot build a canvas, and the deployment owner cannot route one into Feishu/DingTalk/WeCom/WhatsApp today. The only way to serve those users is a chat assistant, which has no external tools.
To set expectations: this is not a Go migration regression
Before the Python removal, api/apps/restful_apis/openai_api.py also passed toolcall_session=None, and MCPToolCallSession was bound only to agent MCP nodes (agent/component/agent_with_tools.py) and used by the MCP server test endpoint. Chat + MCP has never existed. I'm proposing a feature, not reporting a bug.
Minimal shape I'd propose
Keep toolRegistry() static; add dynamic entries at run time for the servers a chat mounts.
Implement ToolCallSession over internal/mcp/client.CallTool, so the existing loop in chat_tools.go works unchanged, including the round cap.
Reuse internal/mcp/client for URL, server type, headers and variables, keeping the SSRF guard and the private-host allowlist.
Authorization: an explicit per-chat selection resolved from tenant-owned servers the caller can read, mirroring the canvas → MCP dependency check.
Citations: external tool results carry no corpus chunk — the same property decision_filter.go uses to exclude web_search — so they must not become dataset citations; they need their own "external source" rendering.
Off by default, next to the existing Agentic settings. Also decide whether a chat with no knowledge base should be allowed to run tools only; agentic mode currently requires at least one KB.
Questions
Is serving IM channel users with tenant MCP tools in scope for chat, or is the agent canvas the only supported home for external tools?
If in scope, should the mounted server set be an explicit per-chat selection (my assumption), or every tenant-visible server?
Should external tool output be citable at all, or answer-only context like web_search?
Should this be wired through the chat model's ToolCallSession loop, or would you rather route chat through the agent runtime?
If the direction sounds right, I'm glad to split it into two PRs: settings and authorization first, tool registration and execution second.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
TL;DR
A chat assistant can run an agentic mode, but its toolset is fixed at build time: the retrieval tools in
internal/agentic_ragplus an optionalweb_search. It cannot call anything from an MCP server, while the agent canvas can. That gap matters more than "chat feels limited", because a chat is the only form that can be bound to an IM channel:ChatChannelstores achat_idand nothing else, and incoming messages are answered throughChatSessionService.ChatCompletions. A user in Feishu, DingTalk, WeCom or WhatsApp therefore cannot reach a tenant MCP tool no matter how the agent canvas is built.I'd like to discuss whether serving channel users with tenant MCP tools is in scope for chat, and if so, whether wiring the already-ported
ToolCallSessionpath is the right way to do it. No PR yet.What exists today
Chat, agentic mode. A chat with at least one attached knowledge base can run the
smart-reasoningagent (internal/service/chat_pipeline.go,conf/agentic_rag.yaml). Its tools come fromtoolRegistry()ininternal/agentic_rag/config.go:think,todo_write,run_javascript,grep_chunks,search_chunks,search_bm25_chunks,search_semantic_chunks,list_chunks,search_metadata,graph_explore,graph_doc_outline,navigate_tree,navigate_structure.web_searchis added separately, per conversation, viaagentic_rag.WithWebSearch, only when the chat has a search provider.The tool-call loop is already in the chat model layer.
internal/entity/models/types.godefines theToolCallSessioninterface (ToolCall(name, arguments) (string, error)),ChatModel.BindTools, and aToolConfigwith max rounds and terminal tools;internal/entity/models/chat_tools.goruns the multi-round loop. None of this is reachable from chat right now:internal/service/chat_pipeline.gobinds a session only when the caller passeskwargs["toolcall_session"]together withkwargs["tools"].internal/service/openai_chat.gosets"toolcall_session": nilwith the commentno tool calls on OpenAI-compat path.ToolCallSession. The agent-side MCP adapter (internal/agent/component/agent_mcp.go) callsinternal/mcp/client.CallTooldirectly instead.MCP, agent-only.
internal/entity/mcp.godeclaresMCPServerwithTenantIDand no dataset binding, so servers are tenant-scoped. The only consumer is the agent canvas MCP component, which resolvesmcp_id+ selected tools from the node config and performs a canvas → MCP server dependency check. URLs go throughinternal/mcp/clientwith the SSRF guard and the private-host allowlist.Channels are chat-only.
internal/entity/chat_channel.gohasChatID *stringand no agent binding.internal/service/chat_channel.goanswers incoming messages viachatSessionSvc.ChatCompletions. There is no channel entry point for an agent.Why "just use the agent canvas" does not cover this
Channel users are not operators. They cannot build a canvas, and the deployment owner cannot route one into Feishu/DingTalk/WeCom/WhatsApp today. The only way to serve those users is a chat assistant, which has no external tools.
To set expectations: this is not a Go migration regression
Before the Python removal,
api/apps/restful_apis/openai_api.pyalso passedtoolcall_session=None, andMCPToolCallSessionwas bound only to agent MCP nodes (agent/component/agent_with_tools.py) and used by the MCP server test endpoint. Chat + MCP has never existed. I'm proposing a feature, not reporting a bug.Minimal shape I'd propose
toolRegistry()static; add dynamic entries at run time for the servers a chat mounts.ToolCallSessionoverinternal/mcp/client.CallTool, so the existing loop inchat_tools.goworks unchanged, including the round cap.internal/mcp/clientfor URL, server type, headers and variables, keeping the SSRF guard and the private-host allowlist.decision_filter.gouses to excludeweb_search— so they must not become dataset citations; they need their own "external source" rendering.Questions
web_search?ToolCallSessionloop, or would you rather route chat through the agent runtime?If the direction sounds right, I'm glad to split it into two PRs: settings and authorization first, tool registration and execution second.
All reactions