Skip to content

Commit fb917d2

Browse files
committed
Implement MCP Proxy support
1 parent 64bb992 commit fb917d2

84 files changed

Lines changed: 10045 additions & 91 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
2+
//
3+
// WSO2 LLC. licenses this file to you under the Apache License,
4+
// Version 2.0 (the "License"); you may not use this file except
5+
// in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing,
11+
// software distributed under the License is distributed on an
12+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13+
// KIND, either express or implied. See the License for the
14+
// specific language governing permissions and limitations
15+
// under the License.
16+
17+
package api
18+
19+
import (
20+
"net/http"
21+
22+
"github.com/wso2/agent-manager/agent-manager-service/controllers"
23+
"github.com/wso2/agent-manager/agent-manager-service/middleware"
24+
)
25+
26+
// RegisterAgentMCPProxyRoutes registers agent MCP proxy binding routes.
27+
func RegisterAgentMCPProxyRoutes(mux *http.ServeMux, ctrl controllers.AgentMCPProxyController) {
28+
middleware.HandleFuncWithValidation(mux,
29+
"GET /orgs/{orgName}/projects/{projName}/agents/{agentName}/mcp-proxies",
30+
ctrl.ListAgentMCPProxies)
31+
32+
middleware.HandleFuncWithValidation(mux,
33+
"POST /orgs/{orgName}/projects/{projName}/agents/{agentName}/mcp-proxies",
34+
ctrl.AddAgentMCPProxy)
35+
36+
middleware.HandleFuncWithValidation(mux,
37+
"PUT /orgs/{orgName}/projects/{projName}/agents/{agentName}/mcp-proxies/{proxyId}",
38+
ctrl.UpdateAgentMCPProxy)
39+
40+
middleware.HandleFuncWithValidation(mux,
41+
"DELETE /orgs/{orgName}/projects/{projName}/agents/{agentName}/mcp-proxies/{proxyId}",
42+
ctrl.RemoveAgentMCPProxy)
43+
}

agent-manager-service/api/app.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ func MakeHTTPHandler(params *wiring.AppParams, extraAPIRoutes func(*http.ServeMu
7373
RegisterLLMProxyAPIKeyRoutes(apiMux, params.LLMProxyAPIKeyController)
7474
RegisterAgentAPIKeyRoutes(apiMux, params.AgentAPIKeyController)
7575
RegisterLLMProxyDeploymentRoutes(apiMux, params.LLMProxyDeploymentController)
76+
RegisterMCPProxyRoutes(apiMux, params.MCPProxyController)
77+
RegisterAgentMCPProxyRoutes(apiMux, params.AgentMCPProxyController)
7678
RegisterAgentConfigRoutes(apiMux, params.AgentConfigurationController)
7779
RegisterMonitorPublisherRoutes(apiMux, params.MonitorScoresPublisherController)
7880
RegisterGitSecretRoutes(apiMux, params.GitSecretController)

agent-manager-service/api/gateway_internal_routes.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,7 @@ func RegisterGatewayInternalRoutes(mux *http.ServeMux, ctrl controllers.GatewayI
4141

4242
// LLM Proxy endpoints
4343
mux.HandleFunc("GET /llm-proxies/{proxyId}", ctrl.GetLLMProxy)
44+
45+
// MCP Proxy endpoints
46+
mux.HandleFunc("GET /mcp-proxies/{proxyId}", ctrl.GetMCPProxy)
4447
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
2+
//
3+
// WSO2 LLC. licenses this file to you under the Apache License,
4+
// Version 2.0 (the "License"); you may not use this file except
5+
// in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing,
11+
// software distributed under the License is distributed on an
12+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13+
// KIND, either express or implied. See the License for the
14+
// specific language governing permissions and limitations
15+
// under the License.
16+
17+
package api
18+
19+
import (
20+
"net/http"
21+
22+
"github.com/wso2/agent-manager/agent-manager-service/controllers"
23+
"github.com/wso2/agent-manager/agent-manager-service/middleware"
24+
)
25+
26+
// RegisterMCPProxyRoutes registers MCP proxy routes.
27+
func RegisterMCPProxyRoutes(mux *http.ServeMux, ctrl controllers.MCPProxyController) {
28+
middleware.HandleFuncWithValidation(mux, "POST /orgs/{orgName}/mcp-proxies/fetch-server-info", ctrl.FetchServerInfo)
29+
middleware.HandleFuncWithValidation(mux, "GET /orgs/{orgName}/mcp-proxies/policies", ctrl.ListAvailableMCPPolicies)
30+
middleware.HandleFuncWithValidation(mux, "POST /orgs/{orgName}/mcp-proxies", ctrl.CreateMCPProxy)
31+
middleware.HandleFuncWithValidation(mux, "GET /orgs/{orgName}/mcp-proxies", ctrl.ListMCPProxies)
32+
middleware.HandleFuncWithValidation(mux, "GET /orgs/{orgName}/mcp-proxies/{proxyId}", ctrl.GetMCPProxy)
33+
middleware.HandleFuncWithValidation(mux, "PUT /orgs/{orgName}/mcp-proxies/{proxyId}", ctrl.UpdateMCPProxy)
34+
middleware.HandleFuncWithValidation(mux, "DELETE /orgs/{orgName}/mcp-proxies/{proxyId}", ctrl.DeleteMCPProxy)
35+
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
2+
//
3+
// WSO2 LLC. licenses this file to you under the Apache License,
4+
// Version 2.0 (the "License"); you may not use this file except
5+
// in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing,
11+
// software distributed under the License is distributed on an
12+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13+
// KIND, either express or implied. See the License for the
14+
// specific language governing permissions and limitations
15+
// under the License.
16+
17+
package controllers
18+
19+
import (
20+
"encoding/json"
21+
"errors"
22+
"net/http"
23+
24+
"github.com/wso2/agent-manager/agent-manager-service/middleware/logger"
25+
"github.com/wso2/agent-manager/agent-manager-service/models"
26+
"github.com/wso2/agent-manager/agent-manager-service/services"
27+
"github.com/wso2/agent-manager/agent-manager-service/utils"
28+
)
29+
30+
// AgentMCPProxyController defines HTTP handlers for agent-MCP proxy bindings.
31+
type AgentMCPProxyController interface {
32+
ListAgentMCPProxies(w http.ResponseWriter, r *http.Request)
33+
AddAgentMCPProxy(w http.ResponseWriter, r *http.Request)
34+
UpdateAgentMCPProxy(w http.ResponseWriter, r *http.Request)
35+
RemoveAgentMCPProxy(w http.ResponseWriter, r *http.Request)
36+
}
37+
38+
type agentMCPProxyController struct {
39+
svc *services.AgentMCPProxyService
40+
}
41+
42+
// NewAgentMCPProxyController creates a new controller.
43+
func NewAgentMCPProxyController(svc *services.AgentMCPProxyService) AgentMCPProxyController {
44+
return &agentMCPProxyController{svc: svc}
45+
}
46+
47+
// ListAgentMCPProxies handles GET /orgs/{orgName}/projects/{projName}/agents/{agentName}/mcp-proxies.
48+
func (c *agentMCPProxyController) ListAgentMCPProxies(w http.ResponseWriter, r *http.Request) {
49+
ctx := r.Context()
50+
log := logger.GetLogger(ctx)
51+
orgName := r.PathValue(utils.PathParamOrgName)
52+
projName := r.PathValue(utils.PathParamProjName)
53+
agentName := r.PathValue(utils.PathParamAgentName)
54+
55+
log.Info("ListAgentMCPProxies: starting", "orgName", orgName, "agentName", agentName)
56+
57+
resp, err := c.svc.List(ctx, orgName, projName, agentName)
58+
if err != nil {
59+
log.Error("ListAgentMCPProxies: failed", "error", err)
60+
utils.WriteErrorResponse(w, http.StatusInternalServerError, "Failed to list agent MCP proxies")
61+
return
62+
}
63+
64+
log.Info("ListAgentMCPProxies: completed", "count", resp.Count)
65+
utils.WriteSuccessResponse(w, http.StatusOK, resp)
66+
}
67+
68+
// AddAgentMCPProxy handles POST /orgs/{orgName}/projects/{projName}/agents/{agentName}/mcp-proxies.
69+
func (c *agentMCPProxyController) AddAgentMCPProxy(w http.ResponseWriter, r *http.Request) {
70+
ctx := r.Context()
71+
log := logger.GetLogger(ctx)
72+
orgName := r.PathValue(utils.PathParamOrgName)
73+
projName := r.PathValue(utils.PathParamProjName)
74+
agentName := r.PathValue(utils.PathParamAgentName)
75+
76+
var req models.AddAgentMCPProxyRequest
77+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
78+
utils.WriteErrorResponse(w, http.StatusBadRequest, "Invalid request body")
79+
return
80+
}
81+
if req.ProxyID == "" {
82+
utils.WriteErrorResponse(w, http.StatusBadRequest, "proxyId is required")
83+
return
84+
}
85+
if req.Name == "" {
86+
utils.WriteErrorResponse(w, http.StatusBadRequest, "name is required")
87+
return
88+
}
89+
90+
log.Info("AddAgentMCPProxy: starting", "orgName", orgName, "agentName", agentName, "proxyId", req.ProxyID, "name", req.Name)
91+
92+
if err := c.svc.Add(ctx, orgName, projName, agentName, req); err != nil {
93+
switch {
94+
case errors.Is(err, utils.ErrInvalidInput):
95+
utils.WriteErrorResponseWithReason(w, http.StatusBadRequest, "Bad request", err.Error(), utils.ErrCodeBadRequest)
96+
case errors.Is(err, utils.ErrMCPProxyNotFound):
97+
utils.WriteErrorResponse(w, http.StatusNotFound, "MCP proxy not found")
98+
case errors.Is(err, utils.ErrMCPProxyAlreadyBound):
99+
utils.WriteErrorResponse(w, http.StatusConflict, "MCP proxy mapping name already exists for this agent")
100+
default:
101+
log.Error("AddAgentMCPProxy: failed", "error", err)
102+
utils.WriteErrorResponse(w, http.StatusInternalServerError, "Failed to add MCP proxy")
103+
}
104+
return
105+
}
106+
107+
log.Info("AddAgentMCPProxy: completed", "agentName", agentName, "proxyId", req.ProxyID, "name", req.Name)
108+
utils.WriteSuccessResponse(w, http.StatusCreated, struct{}{})
109+
}
110+
111+
func (c *agentMCPProxyController) UpdateAgentMCPProxy(w http.ResponseWriter, r *http.Request) {
112+
ctx := r.Context()
113+
log := logger.GetLogger(ctx)
114+
orgName := r.PathValue(utils.PathParamOrgName)
115+
projName := r.PathValue(utils.PathParamProjName)
116+
agentName := r.PathValue(utils.PathParamAgentName)
117+
mappingName := r.PathValue(utils.PathParamProxyId)
118+
119+
var req models.UpdateAgentMCPProxyRequest
120+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
121+
utils.WriteErrorResponse(w, http.StatusBadRequest, "Invalid request body")
122+
return
123+
}
124+
125+
log.Info("UpdateAgentMCPProxy: starting", "orgName", orgName, "agentName", agentName, "mappingName", mappingName)
126+
127+
if err := c.svc.Update(ctx, orgName, projName, agentName, mappingName, req); err != nil {
128+
switch {
129+
case errors.Is(err, utils.ErrInvalidInput):
130+
utils.WriteErrorResponseWithReason(w, http.StatusBadRequest, "Bad request", err.Error(), utils.ErrCodeBadRequest)
131+
case errors.Is(err, utils.ErrMCPProxyNotFound):
132+
utils.WriteErrorResponse(w, http.StatusNotFound, "MCP proxy binding not found")
133+
default:
134+
log.Error("UpdateAgentMCPProxy: failed", "error", err)
135+
utils.WriteErrorResponse(w, http.StatusInternalServerError, "Failed to update MCP proxy binding")
136+
}
137+
return
138+
}
139+
140+
log.Info("UpdateAgentMCPProxy: completed", "agentName", agentName, "mappingName", mappingName)
141+
utils.WriteSuccessResponse(w, http.StatusOK, struct{}{})
142+
}
143+
144+
// RemoveAgentMCPProxy handles DELETE /orgs/{orgName}/projects/{projName}/agents/{agentName}/mcp-proxies/{proxyId}.
145+
func (c *agentMCPProxyController) RemoveAgentMCPProxy(w http.ResponseWriter, r *http.Request) {
146+
ctx := r.Context()
147+
log := logger.GetLogger(ctx)
148+
orgName := r.PathValue(utils.PathParamOrgName)
149+
projName := r.PathValue(utils.PathParamProjName)
150+
agentName := r.PathValue(utils.PathParamAgentName)
151+
mappingName := r.PathValue(utils.PathParamProxyId)
152+
153+
log.Info("RemoveAgentMCPProxy: starting", "orgName", orgName, "agentName", agentName, "mappingName", mappingName)
154+
155+
if err := c.svc.Remove(ctx, orgName, projName, agentName, mappingName); err != nil {
156+
switch {
157+
case errors.Is(err, utils.ErrInvalidInput):
158+
utils.WriteErrorResponseWithReason(w, http.StatusBadRequest, "Bad request", err.Error(), utils.ErrCodeBadRequest)
159+
case errors.Is(err, utils.ErrMCPProxyNotFound):
160+
utils.WriteErrorResponse(w, http.StatusNotFound, "MCP proxy binding not found")
161+
default:
162+
log.Error("RemoveAgentMCPProxy: failed", "error", err)
163+
utils.WriteErrorResponse(w, http.StatusInternalServerError, "Failed to remove MCP proxy")
164+
}
165+
return
166+
}
167+
168+
log.Info("RemoveAgentMCPProxy: completed", "agentName", agentName, "mappingName", mappingName)
169+
utils.WriteSuccessResponse(w, http.StatusNoContent, struct{}{})
170+
}

0 commit comments

Comments
 (0)