Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit610c661

Browse files
committed
feat(mcp): add experiment control for MCP server HTTP endpoints
- Add ExperimentMCPServerHTTP constant for controlled rollout- Refactor OAuth2 middleware into generic experiment middleware- Make experiment middleware variadic to support multiple experiments- Apply experiment gating to /api/experimental/mcp/http routes- Maintain development mode bypass for testing flexibility- Remove OAuth2-specific middleware in favor of reusable patternChange-Id: Ia5b3d0615f4a5a45e5a233b1ea92e8bdc0a5f17eSigned-off-by: Thomas Kosiewski <tk@coder.com>
1 parent51f84ce commit610c661

File tree

8 files changed

+87
-33
lines changed

8 files changed

+87
-33
lines changed

‎coderd/apidoc/docs.go‎

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json‎

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/coderd.go‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ func New(options *Options) *API {
922922
// logging into Coder with an external OAuth2 provider.
923923
r.Route("/oauth2",func(r chi.Router) {
924924
r.Use(
925-
api.oAuth2ProviderMiddleware,
925+
httpmw.RequireExperimentWithDevBypass(api.Experiments,codersdk.ExperimentOAuth2),
926926
)
927927
r.Route("/authorize",func(r chi.Router) {
928928
r.Use(
@@ -973,6 +973,9 @@ func New(options *Options) *API {
973973
r.Get("/prompts",api.aiTasksPrompts)
974974
})
975975
r.Route("/mcp",func(r chi.Router) {
976+
r.Use(
977+
httpmw.RequireExperimentWithDevBypass(api.Experiments,codersdk.ExperimentOAuth2,codersdk.ExperimentMCPServerHTTP),
978+
)
976979
// MCP HTTP transport endpoint with mandatory authentication
977980
r.Mount("/http",api.mcpHTTPHandler())
978981
})
@@ -1473,7 +1476,7 @@ func New(options *Options) *API {
14731476
r.Route("/oauth2-provider",func(r chi.Router) {
14741477
r.Use(
14751478
apiKeyMiddleware,
1476-
api.oAuth2ProviderMiddleware,
1479+
httpmw.RequireExperimentWithDevBypass(api.Experiments,codersdk.ExperimentOAuth2),
14771480
)
14781481
r.Route("/apps",func(r chi.Router) {
14791482
r.Get("/",api.oAuth2ProviderApps)

‎coderd/httpmw/experiments.go‎

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,59 @@ package httpmw
33
import (
44
"fmt"
55
"net/http"
6+
"strings"
67

8+
"github.com/coder/coder/v2/buildinfo"
79
"github.com/coder/coder/v2/coderd/httpapi"
810
"github.com/coder/coder/v2/codersdk"
911
)
1012

11-
funcRequireExperiment(experiments codersdk.Experiments,experiment codersdk.Experiment)func(next http.Handler) http.Handler {
13+
// RequireExperiment returns middleware that checks if all required experiments are enabled.
14+
// If any experiment is disabled, it returns a 403 Forbidden response with details about the missing experiments.
15+
funcRequireExperiment(experiments codersdk.Experiments,requiredExperiments...codersdk.Experiment)func(next http.Handler) http.Handler {
1216
returnfunc(next http.Handler) http.Handler {
1317
returnhttp.HandlerFunc(func(w http.ResponseWriter,r*http.Request) {
14-
if!experiments.Enabled(experiment) {
15-
httpapi.Write(r.Context(),w,http.StatusForbidden, codersdk.Response{
16-
Message:fmt.Sprintf("Experiment '%s' is required but not enabled",experiment),
17-
})
18-
return
18+
for_,experiment:=rangerequiredExperiments {
19+
if!experiments.Enabled(experiment) {
20+
varexperimentNames []string
21+
for_,exp:=rangerequiredExperiments {
22+
experimentNames=append(experimentNames,string(exp))
23+
}
24+
25+
// Print a message that includes the experiment names
26+
// even if some experiments are already enabled.
27+
varmessagestring
28+
iflen(requiredExperiments)==1 {
29+
message=fmt.Sprintf("%s functionality requires enabling the '%s' experiment.",
30+
requiredExperiments[0].DisplayName(),requiredExperiments[0])
31+
}else {
32+
message=fmt.Sprintf("This functionality requires enabling the following experiments: %s",
33+
strings.Join(experimentNames,", "))
34+
}
35+
36+
httpapi.Write(r.Context(),w,http.StatusForbidden, codersdk.Response{
37+
Message:message,
38+
})
39+
return
40+
}
1941
}
42+
2043
next.ServeHTTP(w,r)
2144
})
2245
}
2346
}
47+
48+
// RequireExperimentWithDevBypass checks if ALL the given experiments are enabled,
49+
// but bypasses the check in development mode (buildinfo.IsDev()).
50+
funcRequireExperimentWithDevBypass(experiments codersdk.Experiments,requiredExperiments...codersdk.Experiment)func(next http.Handler) http.Handler {
51+
returnfunc(next http.Handler) http.Handler {
52+
returnhttp.HandlerFunc(func(w http.ResponseWriter,r*http.Request) {
53+
ifbuildinfo.IsDev() {
54+
next.ServeHTTP(w,r)
55+
return
56+
}
57+
58+
RequireExperiment(experiments,requiredExperiments...)(next).ServeHTTP(w,r)
59+
})
60+
}
61+
}

‎coderd/oauth2.go‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616

1717
"github.com/sqlc-dev/pqtype"
1818

19-
"github.com/coder/coder/v2/buildinfo"
2019
"github.com/coder/coder/v2/coderd/audit"
2120
"github.com/coder/coder/v2/coderd/database"
2221
"github.com/coder/coder/v2/coderd/database/db2sdk"
@@ -37,19 +36,6 @@ const (
3736
displaySecretLength=6// Length of visible part in UI (last 6 characters)
3837
)
3938

40-
func (api*API)oAuth2ProviderMiddleware(next http.Handler) http.Handler {
41-
returnhttp.HandlerFunc(func(rw http.ResponseWriter,r*http.Request) {
42-
if!api.Experiments.Enabled(codersdk.ExperimentOAuth2)&&!buildinfo.IsDev() {
43-
httpapi.Write(r.Context(),rw,http.StatusForbidden, codersdk.Response{
44-
Message:"OAuth2 provider functionality requires enabling the 'oauth2' experiment.",
45-
})
46-
return
47-
}
48-
49-
next.ServeHTTP(rw,r)
50-
})
51-
}
52-
5339
// @Summary Get OAuth2 applications.
5440
// @ID get-oauth2-applications
5541
// @Security CoderSessionToken

‎codersdk/deployment.go‎

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,8 +3342,30 @@ const (
33423342
ExperimentWorkspaceUsageExperiment="workspace-usage"// Enables the new workspace usage tracking.
33433343
ExperimentWebPushExperiment="web-push"// Enables web push notifications through the browser.
33443344
ExperimentOAuth2Experiment="oauth2"// Enables OAuth2 provider functionality.
3345+
ExperimentMCPServerHTTPExperiment="mcp-server-http"// Enables the MCP HTTP server functionality.
33453346
)
33463347

3348+
func (eExperiment)DisplayName()string {
3349+
switche {
3350+
caseExperimentExample:
3351+
return"Example Experiment"
3352+
caseExperimentAutoFillParameters:
3353+
return"Auto-fill Template Parameters"
3354+
caseExperimentNotifications:
3355+
return"SMTP and Webhook Notifications"
3356+
caseExperimentWorkspaceUsage:
3357+
return"Workspace Usage Tracking"
3358+
caseExperimentWebPush:
3359+
return"Browser Push Notifications"
3360+
caseExperimentOAuth2:
3361+
return"OAuth2 Provider Functionality"
3362+
caseExperimentMCPServerHTTP:
3363+
return"MCP HTTP Server Functionality"
3364+
default:
3365+
returnstring(e)
3366+
}
3367+
}
3368+
33473369
// ExperimentsKnown should include all experiments defined above.
33483370
varExperimentsKnown=Experiments{
33493371
ExperimentExample,
@@ -3352,6 +3374,7 @@ var ExperimentsKnown = Experiments{
33523374
ExperimentWorkspaceUsage,
33533375
ExperimentWebPush,
33543376
ExperimentOAuth2,
3377+
ExperimentMCPServerHTTP,
33553378
}
33563379

33573380
// ExperimentsSafe should include all experiments that are safe for
@@ -3369,14 +3392,9 @@ var ExperimentsSafe = Experiments{}
33693392
// @typescript-ignore Experiments
33703393
typeExperiments []Experiment
33713394

3372-
//Returns a list of experiments that are enabled for the deployment.
3395+
//Enabled returns a list of experiments that are enabled for the deployment.
33733396
func (eExperiments)Enabled(exExperiment)bool {
3374-
for_,v:=rangee {
3375-
ifv==ex {
3376-
returntrue
3377-
}
3378-
}
3379-
returnfalse
3397+
returnslices.Contains(e,ex)
33803398
}
33813399

33823400
func (c*Client)Experiments(ctx context.Context) (Experiments,error) {

‎docs/reference/api/schemas.md‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎site/src/api/typesGenerated.ts‎

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp