publicmcp.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. package controller
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "strconv"
  7. "github.com/bytedance/sonic"
  8. "github.com/gin-gonic/gin"
  9. "github.com/labring/aiproxy/core/common/config"
  10. "github.com/labring/aiproxy/core/controller/utils"
  11. "github.com/labring/aiproxy/core/middleware"
  12. "github.com/labring/aiproxy/core/model"
  13. )
  14. type MCPEndpoint struct {
  15. Host string `json:"host"`
  16. SSE string `json:"sse"`
  17. StreamableHTTP string `json:"streamable_http"`
  18. }
  19. type PublicMCPResponse struct {
  20. model.PublicMCP
  21. Endpoints MCPEndpoint `json:"endpoints"`
  22. }
  23. func (mcp *PublicMCPResponse) MarshalJSON() ([]byte, error) {
  24. type Alias PublicMCPResponse
  25. a := &struct {
  26. *Alias
  27. CreatedAt int64 `json:"created_at"`
  28. UpdateAt int64 `json:"update_at"`
  29. }{
  30. Alias: (*Alias)(mcp),
  31. }
  32. if !mcp.CreatedAt.IsZero() {
  33. a.CreatedAt = mcp.CreatedAt.UnixMilli()
  34. }
  35. if !mcp.UpdateAt.IsZero() {
  36. a.UpdateAt = mcp.UpdateAt.UnixMilli()
  37. }
  38. return sonic.Marshal(a)
  39. }
  40. func NewPublicMCPEndpoint(host string, mcp model.PublicMCP) MCPEndpoint {
  41. ep := MCPEndpoint{}
  42. switch mcp.Type {
  43. case model.PublicMCPTypeProxySSE,
  44. model.PublicMCPTypeProxyStreamable,
  45. model.PublicMCPTypeEmbed,
  46. model.PublicMCPTypeOpenAPI:
  47. publicMCPHost := config.GetPublicMCPHost()
  48. if publicMCPHost == "" {
  49. ep.Host = host
  50. if defaultHost := config.GetDefaultMCPHost(); defaultHost != "" {
  51. ep.Host = defaultHost
  52. }
  53. ep.SSE = fmt.Sprintf("/mcp/public/%s/sse", mcp.ID)
  54. ep.StreamableHTTP = "/mcp/public/" + mcp.ID
  55. } else {
  56. ep.Host = fmt.Sprintf("%s.%s", mcp.ID, publicMCPHost)
  57. ep.SSE = "/sse"
  58. ep.StreamableHTTP = "/mcp"
  59. }
  60. case model.PublicMCPTypeDocs:
  61. }
  62. return ep
  63. }
  64. func NewPublicMCPResponse(host string, mcp model.PublicMCP) PublicMCPResponse {
  65. return PublicMCPResponse{
  66. PublicMCP: mcp,
  67. Endpoints: NewPublicMCPEndpoint(host, mcp),
  68. }
  69. }
  70. func NewPublicMCPResponses(host string, mcps []model.PublicMCP) []PublicMCPResponse {
  71. responses := make([]PublicMCPResponse, len(mcps))
  72. for i, mcp := range mcps {
  73. responses[i] = NewPublicMCPResponse(host, mcp)
  74. }
  75. return responses
  76. }
  77. func getHostedMCPTypes() []model.PublicMCPType {
  78. return []model.PublicMCPType{
  79. model.PublicMCPTypeProxySSE,
  80. model.PublicMCPTypeProxyStreamable,
  81. model.PublicMCPTypeEmbed,
  82. model.PublicMCPTypeOpenAPI,
  83. }
  84. }
  85. func getLocalMCPTypes() []model.PublicMCPType {
  86. return []model.PublicMCPType{model.PublicMCPTypeDocs}
  87. }
  88. // GetPublicMCPs godoc
  89. //
  90. // @Summary Get MCPs
  91. // @Description Get a list of MCPs with pagination and filtering
  92. // @Tags mcp
  93. // @Produce json
  94. // @Security ApiKeyAuth
  95. // @Param page query int false "Page number"
  96. // @Param per_page query int false "Items per page"
  97. // @Param type query string false "hosted or local"
  98. // @Param id query string false "MCP id"
  99. // @Param keyword query string false "Search keyword"
  100. // @Param status query int false "MCP status"
  101. // @Success 200 {object} middleware.APIResponse{data=[]PublicMCPResponse}
  102. // @Router /api/mcp/publics/ [get]
  103. func GetPublicMCPs(c *gin.Context) {
  104. page, perPage := utils.ParsePageParams(c)
  105. mcpType := c.Query("type")
  106. id := c.Query("id")
  107. keyword := c.Query("keyword")
  108. status, _ := strconv.Atoi(c.Query("status"))
  109. var mcpTypes []model.PublicMCPType
  110. switch mcpType {
  111. case "hosted":
  112. mcpTypes = getHostedMCPTypes()
  113. case "local":
  114. mcpTypes = getLocalMCPTypes()
  115. }
  116. mcps, total, err := model.GetPublicMCPs(
  117. page,
  118. perPage,
  119. id,
  120. mcpTypes,
  121. keyword,
  122. model.PublicMCPStatus(status),
  123. )
  124. if err != nil {
  125. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  126. return
  127. }
  128. middleware.SuccessResponse(c, gin.H{
  129. "mcps": NewPublicMCPResponses(c.Request.Host, mcps),
  130. "total": total,
  131. })
  132. }
  133. // GetAllPublicMCPs godoc
  134. //
  135. // @Summary Get all MCPs
  136. // @Description Get all MCPs with filtering
  137. // @Tags mcp
  138. // @Produce json
  139. // @Security ApiKeyAuth
  140. // @Param status query int false "MCP status"
  141. // @Success 200 {object} middleware.APIResponse{data=[]PublicMCPResponse}
  142. // @Router /api/mcp/publics/all [get]
  143. func GetAllPublicMCPs(c *gin.Context) {
  144. status, _ := strconv.Atoi(c.Query("status"))
  145. mcps, err := model.GetAllPublicMCPs(model.PublicMCPStatus(status))
  146. if err != nil {
  147. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  148. return
  149. }
  150. middleware.SuccessResponse(c, NewPublicMCPResponses(c.Request.Host, mcps))
  151. }
  152. // GetPublicMCPByID godoc
  153. //
  154. // @Summary Get MCP by ID
  155. // @Description Get a specific MCP by its ID
  156. // @Tags mcp
  157. // @Produce json
  158. // @Security ApiKeyAuth
  159. // @Param id path string true "MCP ID"
  160. // @Success 200 {object} middleware.APIResponse{data=PublicMCPResponse}
  161. // @Router /api/mcp/public/{id} [get]
  162. func GetPublicMCPByID(c *gin.Context) {
  163. id := c.Param("id")
  164. if id == "" {
  165. middleware.ErrorResponse(c, http.StatusBadRequest, "MCP ID is required")
  166. return
  167. }
  168. mcp, err := model.GetPublicMCPByID(id)
  169. if err != nil {
  170. middleware.ErrorResponse(c, http.StatusNotFound, err.Error())
  171. return
  172. }
  173. middleware.SuccessResponse(c, NewPublicMCPResponse(c.Request.Host, mcp))
  174. }
  175. // CreatePublicMCP godoc
  176. //
  177. // @Summary Create MCP
  178. // @Description Create a new MCP
  179. // @Tags mcp
  180. // @Accept json
  181. // @Produce json
  182. // @Security ApiKeyAuth
  183. // @Param mcp body model.PublicMCP true "MCP object"
  184. // @Success 200 {object} middleware.APIResponse{data=PublicMCPResponse}
  185. // @Router /api/mcp/public/ [post]
  186. func CreatePublicMCP(c *gin.Context) {
  187. var mcp model.PublicMCP
  188. if err := c.ShouldBindJSON(&mcp); err != nil {
  189. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  190. return
  191. }
  192. if err := model.CreatePublicMCP(&mcp); err != nil {
  193. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  194. return
  195. }
  196. middleware.SuccessResponse(c, NewPublicMCPResponse(c.Request.Host, mcp))
  197. }
  198. type SavePublicMCPRequest struct {
  199. model.PublicMCP
  200. CreatedAt json.RawMessage `json:"created_at"`
  201. UpdateAt json.RawMessage `json:"update_at"`
  202. }
  203. // SavePublicMCP godoc
  204. //
  205. // @Summary Save MCP
  206. // @Description Save a MCP
  207. // @Tags mcp
  208. // @Accept json
  209. // @Produce json
  210. // @Security ApiKeyAuth
  211. // @Param id path string true "MCP ID"
  212. // @Param mcp body model.PublicMCP true "MCP object"
  213. // @Success 200 {object} middleware.APIResponse{data=PublicMCPResponse}
  214. // @Router /api/mcp/public/{id} [put]
  215. func SavePublicMCP(c *gin.Context) {
  216. id := c.Param("id")
  217. if id == "" {
  218. middleware.ErrorResponse(c, http.StatusBadRequest, "MCP ID is required")
  219. return
  220. }
  221. var mcp SavePublicMCPRequest
  222. if err := c.ShouldBindJSON(&mcp); err != nil {
  223. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  224. return
  225. }
  226. mcp.ID = id
  227. if err := model.SavePublicMCP(&mcp.PublicMCP); err != nil {
  228. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  229. return
  230. }
  231. middleware.SuccessResponse(c, NewPublicMCPResponse(c.Request.Host, mcp.PublicMCP))
  232. }
  233. // SavePublicMCPs godoc
  234. //
  235. // @Summary Save MCPs
  236. // @Description Save a list of MCPs
  237. // @Tags mcp
  238. // @Accept json
  239. // @Produce json
  240. // @Security ApiKeyAuth
  241. // @Param mcp body []model.PublicMCP true "MCP object"
  242. // @Success 200 {object} middleware.APIResponse
  243. // @Router /api/mcp/publics/ [post]
  244. func SavePublicMCPs(c *gin.Context) {
  245. var mcps []SavePublicMCPRequest
  246. if err := c.ShouldBindJSON(&mcps); err != nil {
  247. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  248. return
  249. }
  250. pmcps := make([]model.PublicMCP, len(mcps))
  251. for i, mcp := range mcps {
  252. pmcps[i] = mcp.PublicMCP
  253. }
  254. if err := model.SavePublicMCPs(pmcps); err != nil {
  255. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  256. return
  257. }
  258. middleware.SuccessResponse(c, nil)
  259. }
  260. type UpdatePublicMCPStatusRequest struct {
  261. Status model.PublicMCPStatus `json:"status"`
  262. }
  263. // UpdatePublicMCPStatus godoc
  264. //
  265. // @Summary Update MCP status
  266. // @Description Update the status of an MCP
  267. // @Tags mcp
  268. // @Accept json
  269. // @Produce json
  270. // @Security ApiKeyAuth
  271. // @Param id path string true "MCP ID"
  272. // @Param status body UpdatePublicMCPStatusRequest true "MCP status"
  273. // @Success 200 {object} middleware.APIResponse
  274. // @Router /api/mcp/public/{id}/status [post]
  275. func UpdatePublicMCPStatus(c *gin.Context) {
  276. id := c.Param("id")
  277. if id == "" {
  278. middleware.ErrorResponse(c, http.StatusBadRequest, "MCP ID is required")
  279. return
  280. }
  281. var status UpdatePublicMCPStatusRequest
  282. if err := c.ShouldBindJSON(&status); err != nil {
  283. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  284. return
  285. }
  286. if err := model.UpdatePublicMCPStatus(id, status.Status); err != nil {
  287. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  288. return
  289. }
  290. middleware.SuccessResponse(c, nil)
  291. }
  292. // UpdatePublicMCP godoc
  293. //
  294. // @Summary Update MCP
  295. // @Description Update an existing MCP
  296. // @Tags mcp
  297. // @Accept json
  298. // @Produce json
  299. // @Security ApiKeyAuth
  300. // @Param id path string true "MCP ID"
  301. // @Param mcp body model.PublicMCP true "MCP object"
  302. // @Success 200 {object} middleware.APIResponse{data=PublicMCPResponse}
  303. // @Router /api/mcp/public/{id} [post]
  304. func UpdatePublicMCP(c *gin.Context) {
  305. id := c.Param("id")
  306. if id == "" {
  307. middleware.ErrorResponse(c, http.StatusBadRequest, "MCP ID is required")
  308. return
  309. }
  310. var mcp model.PublicMCP
  311. if err := c.ShouldBindJSON(&mcp); err != nil {
  312. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  313. return
  314. }
  315. mcp.ID = id
  316. if err := model.UpdatePublicMCP(&mcp); err != nil {
  317. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  318. return
  319. }
  320. middleware.SuccessResponse(c, NewPublicMCPResponse(c.Request.Host, mcp))
  321. }
  322. // DeletePublicMCP godoc
  323. //
  324. // @Summary Delete MCP
  325. // @Description Delete an MCP by ID
  326. // @Tags mcp
  327. // @Produce json
  328. // @Security ApiKeyAuth
  329. // @Param id path string true "MCP ID"
  330. // @Success 200 {object} middleware.APIResponse
  331. // @Router /api/mcp/public/{id} [delete]
  332. func DeletePublicMCP(c *gin.Context) {
  333. id := c.Param("id")
  334. if id == "" {
  335. middleware.ErrorResponse(c, http.StatusBadRequest, "MCP ID is required")
  336. return
  337. }
  338. if err := model.DeletePublicMCP(id); err != nil {
  339. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  340. return
  341. }
  342. middleware.SuccessResponse(c, nil)
  343. }
  344. // GetGroupPublicMCPReusingParam godoc
  345. //
  346. // @Summary Get group MCP reusing parameters
  347. // @Description Get reusing parameters for a specific group and MCP
  348. // @Tags mcp
  349. // @Produce json
  350. // @Security ApiKeyAuth
  351. // @Param id path string true "MCP ID"
  352. // @Param group path string true "Group ID"
  353. // @Success 200 {object} middleware.APIResponse{data=model.PublicMCPReusingParam}
  354. // @Router /api/mcp/public/{id}/group/{group}/params [get]
  355. func GetGroupPublicMCPReusingParam(c *gin.Context) {
  356. mcpID := c.Param("id")
  357. groupID := c.Param("group")
  358. if mcpID == "" || groupID == "" {
  359. middleware.ErrorResponse(c, http.StatusBadRequest, "MCP ID and Group ID are required")
  360. return
  361. }
  362. param, err := model.GetPublicMCPReusingParam(mcpID, groupID)
  363. if err != nil {
  364. middleware.ErrorResponse(c, http.StatusNotFound, err.Error())
  365. return
  366. }
  367. middleware.SuccessResponse(c, param)
  368. }
  369. // SaveGroupPublicMCPReusingParam godoc
  370. //
  371. // @Summary Create or update group MCP reusing parameters
  372. // @Description Create or update reusing parameters for a specific group and MCP
  373. // @Tags mcp
  374. // @Accept json
  375. // @Produce json
  376. // @Security ApiKeyAuth
  377. // @Param id path string true "MCP ID"
  378. // @Param group path string true "Group ID"
  379. // @Param params body model.PublicMCPReusingParam true "Reusing parameters"
  380. // @Success 200 {object} middleware.APIResponse
  381. // @Router /api/mcp/public/{id}/group/{group}/params [post]
  382. func SaveGroupPublicMCPReusingParam(c *gin.Context) {
  383. mcpID := c.Param("id")
  384. groupID := c.Param("group")
  385. if mcpID == "" || groupID == "" {
  386. middleware.ErrorResponse(c, http.StatusBadRequest, "MCP ID and Group ID are required")
  387. return
  388. }
  389. var param model.PublicMCPReusingParam
  390. if err := c.ShouldBindJSON(&param); err != nil {
  391. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  392. return
  393. }
  394. param.MCPID = mcpID
  395. param.GroupID = groupID
  396. if err := model.SavePublicMCPReusingParam(&param); err != nil {
  397. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  398. return
  399. }
  400. middleware.SuccessResponse(c, param)
  401. }