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

Function connectOne

coderd/x/chatd/mcpclient/mcpclient.go:172–280  ·  view source on GitHub ↗

connectOne establishes a connection to a single MCP server, discovers its tools, and wraps each one as an AgentTool with the server slug prefix applied.

(
	ctx context.Context,
	logger slog.Logger,
	cfg database.MCPServerConfig,
	tokensByConfigID map[uuid.UUID]database.MCPServerUserToken,
	userID uuid.UUID,
	oidcSrc UserOIDCTokenSource,
	coderHeaders map[string]string,
)

Source from the content-addressed store, hash-verified

170// discovers its tools, and wraps each one as an AgentTool with
171// the server slug prefix applied.
172func connectOne(
173 ctx context.Context,
174 logger slog.Logger,
175 cfg database.MCPServerConfig,
176 tokensByConfigID map[uuid.UUID]database.MCPServerUserToken,
177 userID uuid.UUID,
178 oidcSrc UserOIDCTokenSource,
179 coderHeaders map[string]string,
180) ([]fantasy.AgentTool, *client.Client, error) {
181 headers := buildAuthHeaders(ctx, logger, cfg, tokensByConfigID, userID, oidcSrc)
182
183 // When opted-in, merge Coder identity headers BEFORE the
184 // transport is created so any auth header already set above
185 // wins on a conflict. Conflict detection uses
186 // http.CanonicalHeaderKey because the upstream transport applies
187 // http.Header.Set, which canonicalizes keys; without that, an
188 // admin-configured header that differs only in case from a Coder
189 // identity header would land in the request map twice and the
190 // surviving value would be non-deterministic.
191 if cfg.ForwardCoderHeaders {
192 canonicalAuth := make(map[string]struct{}, len(headers))
193 for k := range headers {
194 canonicalAuth[http.CanonicalHeaderKey(k)] = struct{}{}
195 }
196 for k, v := range coderHeaders {
197 if _, exists := canonicalAuth[http.CanonicalHeaderKey(k)]; exists {
198 continue
199 }
200 headers[k] = v
201 }
202 }
203
204 tr, err := createTransport(cfg, headers)
205 if err != nil {
206 return nil, nil, xerrors.Errorf(
207 "create transport: %w", err,
208 )
209 }
210
211 mcpClient := client.NewClient(tr)
212
213 // The timeout covers the entire connect+init+list sequence,
214 // not each phase individually.
215 connectCtx, cancel := context.WithTimeout(
216 ctx, connectTimeout,
217 )
218 defer cancel()
219
220 if err := mcpClient.Start(connectCtx); err != nil {
221 _ = mcpClient.Close()
222 return nil, nil, xerrors.Errorf(
223 "start transport: %w", err,
224 )
225 }
226
227 _, err = mcpClient.Initialize(
228 connectCtx,
229 mcp.InitializeRequest{

Callers 1

ConnectAllFunction · 0.85

Calls 10

CloseMethod · 0.95
VersionFunction · 0.92
buildAuthHeadersFunction · 0.85
createTransportFunction · 0.85
isToolAllowedFunction · 0.85
newMCPToolFunction · 0.85
InitializeMethod · 0.80
StartMethod · 0.65
ListToolsMethod · 0.65
ErrorfMethod · 0.45

Tested by

no test coverage detected