44package llm
55
66import (
7+ stdcontext "context"
78 "fmt"
89 "strings"
910 "time"
@@ -36,6 +37,13 @@ type Context struct {
3637 // User that is making the request
3738 RequestingUser * model.User
3839
40+ // RequestContext carries the caller's request-scoped context for downstream
41+ // work such as MCP tool discovery. May be nil in tests.
42+ RequestContext stdcontext.Context
43+
44+ // ConversationID identifies the conversation whose context is being built.
45+ ConversationID string
46+
3947 // Bot Specific
4048 BotName string
4149 BotUsername string
@@ -47,6 +55,42 @@ type Context struct {
4755 Tools * ToolStore
4856 DisabledToolsInfo []ToolInfo // Info about tools that are unavailable in the current context (e.g., DM-only tools in a channel)
4957 Parameters map [string ]interface {}
58+
59+ // MCPDynamicToolLoading indicates this context uses strict MCP dynamic loading.
60+ MCPDynamicToolLoading bool
61+ // MCPDynamicToolTelemetry receives low-cardinality dynamic MCP tool events.
62+ MCPDynamicToolTelemetry MCPDynamicToolTelemetry
63+ MCPDynamicToolSearchUsed bool
64+ MCPDynamicLoadedToolNames map [string ]bool
65+ MCPDynamicSearchLoadCallSuccessRecorded map [string ]bool
66+
67+ // DisabledMCPServerOrigins contains per-user disabled MCP server origins that
68+ // must be removed before strict registry construction.
69+ DisabledMCPServerOrigins []string
70+
71+ // KeepMCPTool, when non-nil, is applied to MCP tools before strict registry
72+ // construction and before flag-off visible MCP insertion.
73+ KeepMCPTool func (Tool ) bool
74+
75+ // PreloadedMCPTools contains exact-or-bare MCP tool selectors for internal
76+ // predefined flows. They are selected only from the already-authorized MCP
77+ // catalog and are request scoped.
78+ PreloadedMCPTools []EnabledMCPTool
79+
80+ // MCPToolRegistry holds the strict MCP tool registry that was built
81+ // alongside Tools, when MCP dynamic tool loading is enabled. It is stashed
82+ // here so callers can replay loaded-tool restoration after the conversation
83+ // row exists without rebuilding the entire tool store.
84+ //
85+ // Stored as `any` to avoid an llm -> mcp import cycle: the mcp package
86+ // already imports llm, and the only consumer that needs the concrete type
87+ // is the llmcontext package, which can import both. Type-assert to
88+ // *mcp.ToolRegistry there.
89+ MCPToolRegistry any
90+ }
91+
92+ type MCPDynamicToolTelemetry interface {
93+ ObserveMCPDynamicToolEvent (botName , event , result string )
5094}
5195
5296// ContextOption defines a function that configures a Context
@@ -99,6 +143,53 @@ func (c *Context) CustomPromptVars() map[string]string {
99143 return vars
100144}
101145
146+ func (c * Context ) ObserveMCPDynamicToolEvent (event , result string ) {
147+ if c == nil || c .MCPDynamicToolTelemetry == nil {
148+ return
149+ }
150+
151+ botName := c .BotUsername
152+ if botName == "" {
153+ botName = c .BotName
154+ }
155+ if botName == "" {
156+ botName = "unknown"
157+ }
158+
159+ c .MCPDynamicToolTelemetry .ObserveMCPDynamicToolEvent (botName , event , result )
160+ }
161+
162+ func (c * Context ) MarkMCPDynamicToolSearch () {
163+ if c == nil {
164+ return
165+ }
166+ c .MCPDynamicToolSearchUsed = true
167+ }
168+
169+ func (c * Context ) MarkMCPDynamicToolLoaded (name string ) {
170+ if c == nil || name == "" {
171+ return
172+ }
173+ if c .MCPDynamicLoadedToolNames == nil {
174+ c .MCPDynamicLoadedToolNames = make (map [string ]bool )
175+ }
176+ c .MCPDynamicLoadedToolNames [name ] = true
177+ }
178+
179+ func (c * Context ) ShouldRecordMCPDynamicSearchLoadCallSuccess (name string ) bool {
180+ if c == nil || name == "" || ! c .MCPDynamicToolSearchUsed || ! c .MCPDynamicLoadedToolNames [name ] {
181+ return false
182+ }
183+ if c .MCPDynamicSearchLoadCallSuccessRecorded == nil {
184+ c .MCPDynamicSearchLoadCallSuccessRecorded = make (map [string ]bool )
185+ }
186+ if c .MCPDynamicSearchLoadCallSuccessRecorded [name ] {
187+ return false
188+ }
189+ c .MCPDynamicSearchLoadCallSuccessRecorded [name ] = true
190+ return true
191+ }
192+
102193func (c Context ) String () string {
103194 var result strings.Builder
104195 result .WriteString (fmt .Sprintf ("Time: %v\n ServerName: %v\n CompanyName: %v" , c .Time , c .ServerName , c .CompanyName ))
0 commit comments