MCPcopy Index your code
hub / github.com/coder/coder / discoverWorkspaceMCPTools

Method discoverWorkspaceMCPTools

coderd/x/chatd/chatd.go:547–611  ·  view source on GitHub ↗

discoverWorkspaceMCPTools resolves the chat's workspace agent and lists the workspace MCP tools advertised by that agent. Results are cached per chat keyed on the agent ID so subsequent calls hit the cache. Returns nil (and never an error) on every failure mode so the caller can continue without MCP

(
	ctx context.Context,
	logger slog.Logger,
	chatID uuid.UUID,
	workspaceCtx *turnWorkspaceContext,
)

Source from the content-addressed store, hash-verified

545// mid-turn PrepareTools path triggered after create_workspace /
546// start_workspace bind a workspace to a chat that started without one.
547func (p *Server) discoverWorkspaceMCPTools(
548 ctx context.Context,
549 logger slog.Logger,
550 chatID uuid.UUID,
551 workspaceCtx *turnWorkspaceContext,
552) []fantasy.AgentTool {
553 // Fast path: check cache using the in-memory cached agent
554 // (ensureWorkspaceAgent is free when already loaded). This
555 // avoids a per-turn latest-build DB query on the common
556 // subsequent-turn path.
557 if agent, agentErr := workspaceCtx.getWorkspaceAgent(ctx); agentErr == nil {
558 if tools := p.loadCachedWorkspaceContext(
559 chatID, agent, workspaceCtx.getWorkspaceConn,
560 ); tools != nil {
561 return tools
562 }
563 } // Cache miss, agent changed, or no cache: validate
564 // that the workspace still has a live agent before
565 // attempting a dial.
566 _, _, agentErr := workspaceCtx.workspaceAgentIDForConn(ctx)
567 if agentErr != nil {
568 if xerrors.Is(agentErr, errChatHasNoWorkspaceAgent) {
569 p.workspaceMCPToolsCache.Delete(chatID)
570 return nil
571 }
572 logger.Warn(ctx, "failed to resolve workspace agent for MCP tools",
573 slog.Error(agentErr))
574 return nil
575 }
576
577 // List workspace MCP tools via the agent conn.
578 conn, connErr := workspaceCtx.getWorkspaceConn(ctx)
579 if connErr != nil {
580 logger.Warn(ctx, "failed to get workspace conn for MCP tools",
581 slog.Error(connErr))
582 return nil
583 }
584 listCtx, cancel := context.WithTimeout(ctx, workspaceMCPDiscoveryTimeout)
585 defer cancel()
586 toolsResp, listErr := conn.ListMCPTools(listCtx)
587 if listErr != nil {
588 logger.Warn(ctx, "failed to list workspace MCP tools",
589 slog.Error(listErr))
590 return nil
591 }
592 // Cache the result for subsequent turns. Skip caching when
593 // the list is empty because the agent's MCP Connect may not
594 // have finished yet; caching an empty list would hide tools
595 // permanently.
596 if len(toolsResp.Tools) > 0 {
597 if agent, agentErr := workspaceCtx.getWorkspaceAgent(ctx); agentErr == nil {
598 p.workspaceMCPToolsCache.Store(chatID, &cachedWorkspaceMCPTools{
599 agentID: agent.ID,
600 tools: toolsResp.Tools,
601 })
602 }
603 }
604

Callers 2

runChatMethod · 0.95

Calls 10

NewWorkspaceMCPToolFunction · 0.92
getWorkspaceAgentMethod · 0.80
getWorkspaceConnMethod · 0.80
DeleteMethod · 0.65
ListMCPToolsMethod · 0.65
IsMethod · 0.45
ErrorMethod · 0.45
StoreMethod · 0.45

Tested by

no test coverage detected