@Summary List MCP server configs @x-apidocgen {"skip": true} EXPERIMENTAL: this endpoint is experimental and is subject to change. nolint:revive // HTTP handler writes to ResponseWriter.
(rw http.ResponseWriter, r *http.Request)
| 146 | // |
| 147 | //nolint:revive // HTTP handler writes to ResponseWriter. |
| 148 | func (api *API) listMCPServerConfigs(rw http.ResponseWriter, r *http.Request) { |
| 149 | ctx := r.Context() |
| 150 | apiKey := httpmw.APIKey(r) |
| 151 | |
| 152 | // Admin users can see all MCP server configs (including disabled |
| 153 | // ones) for management purposes. Non-admin users see only enabled |
| 154 | // configs, which is sufficient for using the chat feature. |
| 155 | isAdmin := api.Authorize(r, policy.ActionRead, rbac.ResourceDeploymentConfig) |
| 156 | |
| 157 | var configs []database.MCPServerConfig |
| 158 | var err error |
| 159 | if isAdmin { |
| 160 | configs, err = api.Database.GetMCPServerConfigs(ctx) |
| 161 | } else { |
| 162 | //nolint:gocritic // All authenticated users need to read enabled MCP server configs to use the chat feature. |
| 163 | configs, err = api.Database.GetEnabledMCPServerConfigs(dbauthz.AsSystemRestricted(ctx)) |
| 164 | } |
| 165 | if err != nil { |
| 166 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 167 | Message: "Failed to list MCP server configs.", |
| 168 | Detail: err.Error(), |
| 169 | }) |
| 170 | return |
| 171 | } |
| 172 | |
| 173 | // Look up the calling user's OAuth2 tokens so we can populate |
| 174 | // auth_connected per server. Attempt to refresh expired tokens |
| 175 | // so the status is accurate and the token is ready for use. |
| 176 | //nolint:gocritic // Need to check user tokens across all servers. |
| 177 | userTokens, err := api.Database.GetMCPServerUserTokensByUserID(dbauthz.AsSystemRestricted(ctx), apiKey.UserID) |
| 178 | if err != nil { |
| 179 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 180 | Message: "Failed to get user tokens.", |
| 181 | Detail: err.Error(), |
| 182 | }) |
| 183 | return |
| 184 | } |
| 185 | |
| 186 | // Build a config lookup for the refresh helper. |
| 187 | configByID := make(map[uuid.UUID]database.MCPServerConfig, len(configs)) |
| 188 | for _, c := range configs { |
| 189 | configByID[c.ID] = c |
| 190 | } |
| 191 | |
| 192 | tokenMap := make(map[uuid.UUID]bool, len(userTokens)) |
| 193 | for _, tok := range userTokens { |
| 194 | cfg, ok := configByID[tok.MCPServerConfigID] |
| 195 | if !ok { |
| 196 | continue |
| 197 | } |
| 198 | tokenMap[tok.MCPServerConfigID] = api.refreshMCPUserToken(ctx, cfg, tok, apiKey.UserID) |
| 199 | } |
| 200 | |
| 201 | resp := make([]codersdk.MCPServerConfig, 0, len(configs)) |
| 202 | for _, config := range configs { |
| 203 | var sdkConfig codersdk.MCPServerConfig |
| 204 | if isAdmin { |
| 205 | sdkConfig = convertMCPServerConfig(config) |
nothing calls this directly
no test coverage detected