Compare commits

..

19 Commits

Author SHA1 Message Date
Dot.L c0472c8539 Merge pull request #375 from APIParkLab/feature/liujian-1.9
Feature/liujian 1.9
2025-08-08 12:06:44 +08:00
Dot.L 55f09f7542 Merge pull request #374 from APIParkLab/feature/liujian-1.9
fix: fail to delete model
2025-08-08 11:31:25 +08:00
Dot.L 7aad2174aa Merge pull request #368 from APIParkLab/feature/liujian-1.9
update service publish config
2025-07-23 20:06:32 +08:00
ningyv 2a951c2854 Merge pull request #366 from APIParkLab/feature/1.9-OAuth
feat: Add Feishu OAuth login & consumer-grade MCP
2025-07-23 15:40:50 +08:00
lcx e91a9e7726 feat: Add Feishu OAuth login & consumer-grade MCP 2025-07-23 15:40:13 +08:00
ningyv e0d97186b1 Merge pull request #363 from APIParkLab/feature/1.9-OAuth
feat: Add Feishu OAuth login & consumer-grade MCP
2025-07-22 10:45:53 +08:00
lcx dff6e722c0 feat: Add Feishu OAuth login & consumer-grade MCP 2025-07-22 10:45:16 +08:00
ningyv b8c92961c1 Merge pull request #362 from APIParkLab/feature/1.9-OAuth
feat: Add Feishu OAuth login & consumer-grade MCP
2025-07-22 10:30:18 +08:00
lcx 025bd4c6cc feat: Add Feishu OAuth login & consumer-grade MCP 2025-07-22 10:28:59 +08:00
ningyv 3d2ec67fc1 Merge pull request #361 from APIParkLab/feature/1.9-OAuth
feat: Add Feishu OAuth login & consumer-grade MCP
2025-07-22 09:55:00 +08:00
lcx b2a8c8d901 feat: Add Feishu OAuth login & consumer-grade MCP 2025-07-22 09:53:41 +08:00
ningyv 90226ac6af Merge pull request #360 from APIParkLab/feature/1.9-OAuth
feat: Add Feishu OAuth login & consumer-grade MCP
2025-07-22 09:41:09 +08:00
lcx 0e1efc9656 feat: Add Feishu OAuth login & consumer-grade MCP 2025-07-22 09:40:30 +08:00
Dot.L 061027aa36 Merge pull request #359 from APIParkLab/feature/liujian-1.9
update ap-account version
2025-07-21 18:51:07 +08:00
ningyv a083f994f4 Merge pull request #358 from APIParkLab/feature/1.9-OAuth
feat: Add Feishu OAuth login & consumer-grade MCP
2025-07-21 18:31:44 +08:00
lcx 5898337481 feat: Add Feishu OAuth login & consumer-grade MCP 2025-07-21 18:30:50 +08:00
ningyv 0f1496137d Merge pull request #357 from APIParkLab/feature/1.9-OAuth
feat: Add Feishu OAuth login & consumer-grade MCP
2025-07-21 18:14:47 +08:00
lcx aff2d1ce01 feat: Add Feishu OAuth login & consumer-grade MCP 2025-07-21 18:14:12 +08:00
Dot.L 78d10318ad Merge pull request #356 from APIParkLab/feature/liujian-1.9
Feature/liujian 1.9
2025-07-21 16:44:55 +08:00
26 changed files with 155 additions and 468 deletions
@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="356px" height="48px" viewBox="0 0 356 48" enable-background="new 0 0 356 48" xml:space="preserve"> <image id="image0" width="356" height="48" x="0" y="0"
xlink:href="data:image/png;base64,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
SUVORK5CYII=" />
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

@@ -1,8 +0,0 @@
<svg width="21" height="22" viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Microsoft">
<rect id="Rectangle 1010" y="0.5" width="10" height="10" fill="#EF4F21"/>
<rect id="Rectangle 1012" y="11.5" width="10" height="10" fill="#03A4EE"/>
<rect id="Rectangle 1011" x="11" y="0.5" width="10" height="10" fill="#7EB903"/>
<rect id="Rectangle 1013" x="11" y="11.5" width="10" height="10" fill="#FBB604"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 439 B

@@ -1,40 +0,0 @@
provider: azure_openai
label:
en_US: Azure OpenAI
icon_small:
en_US: icon_s_en.svg
icon_large:
en_US: icon_l_en.svg
background: "#E3F0FF"
help:
title:
en_US: Get your API key from Azure
zh_Hans: 从 Azure 获取 API Key
url:
en_US: https://azure.microsoft.com/en-us/products/ai-services/openai-service
supported_model_types:
- llm
configurate_methods:
- customizable-model
provider_credential_schema:
credential_form_schemas:
- variable: api_key
label:
en_US: API Key
type: secret-input
required: true
placeholder:
zh_Hans: 在此输入您的 API Key
en_US: Enter your API Key
- variable: base_url
type: text-input
required: true
placeholder:
zh_Hans: 在此输入您的 Base URL
en_US: Enter your Base URL
- variable: api_version
label:
en_US: '2024-02-01'
type: text-input
required: true
address: https://docs-test-001.openai.azure.com/
+1 -5
View File
@@ -113,13 +113,9 @@ func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string
if input.AiModel.Type != "local" {
provider = input.AiModel.Provider
}
modelName := input.AiModel.Name
if modelName == "" {
modelName = input.AiModel.Id
}
proxy.Plugins["ai_formatter"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"model": modelName,
"model": input.AiModel.Name,
"provider": provider,
"config": input.AiModel.Config,
},
+32 -72
View File
@@ -21,14 +21,13 @@ import (
var _ IMcpController = (*imlMcpController)(nil)
type imlMcpController struct {
settingModule system.ISettingModule `autowired:""`
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
appModule service.IAppModule `autowired:""`
mcpModule mcp.IMcpModule `autowired:""`
sessionKeys sync.Map
sseServers map[string]http.Handler
openSseServer http.Handler
openStreamableServer http.Handler
settingModule system.ISettingModule `autowired:""`
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
appModule service.IAppModule `autowired:""`
mcpModule mcp.IMcpModule `autowired:""`
sessionKeys sync.Map
server map[string]http.Handler
openServer http.Handler
}
func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
@@ -43,12 +42,12 @@ func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
paths := strings.Split(req.URL.Path, "/")
req.URL.Path = fmt.Sprintf("/api/v1/%s/%s", mcp_server.GlobalBasePath, paths[len(paths)-1])
locale := utils.I18n(ctx)
if v, ok := i.sseServers[locale]; ok {
if v, ok := i.server[locale]; ok {
v.ServeHTTP(ctx.Writer, req)
return
}
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
}
func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
@@ -69,7 +68,7 @@ func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
}
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/sse", mcp_server.GlobalBasePath)
i.handleSSE(ctx, i.openSseServer, SessionInfo{
i.handleSSE(ctx, i.openServer, SessionInfo{
Apikey: apikey,
App: appId,
})
@@ -82,29 +81,8 @@ func (i *imlMcpController) AppHandleMessage(ctx *gin.Context) {
return
}
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/message", mcp_server.GlobalBasePath)
//ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
i.handleMessage(ctx, i.openSseServer)
}
func (i *imlMcpController) AppHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.Header.Get("Authorization")
apikey = strings.TrimPrefix(apikey, "Bearer ")
if apikey == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid apikey", "success": "fail"})
return
}
appId := ctx.Request.Header.Get("X-Application-Id")
if appId == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid app id", "success": "fail"})
return
}
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
req = req.WithContext(utils.SetLabel(req.Context(), "app", appId))
req.URL.Path = mcp_server.OpenGlobalMCPPath
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
i.handleMessage(ctx, i.openServer)
}
func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string, error) {
@@ -116,44 +94,36 @@ func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string,
if err != nil {
return "", fmt.Errorf("get app info error: %v", err)
}
return mcp_server.NewMCPConfig(
mcp_server.TransportTypeStreamableHTTP,
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenAppMCPPath),
map[string]string{
"Authorization": "Bearer {your_api_key}",
"X-Application-Id": appId,
},
nil,
).ToString(appInfo.Name), nil
return fmt.Sprintf(mcpDefaultConfig, appInfo.Name, fmt.Sprintf("%s/openapi/v1/mcp/app/%s/sse?apikey={your_api_key}", strings.TrimSuffix(cfg.SitePrefix, "/"), appId)), nil
}
var mcpDefaultConfig = `{
"mcpServers": {
"%s": {
"url": "%s"
}
}
}
`
func (i *imlMcpController) GlobalMCPConfig(ctx *gin.Context) (string, error) {
cfg := i.settingModule.Get(ctx)
if cfg.SitePrefix == "" {
return "", fmt.Errorf("site prefix is empty")
}
return mcp_server.NewMCPConfig(
mcp_server.TransportTypeStreamableHTTP,
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenGlobalMCPPath),
map[string]string{
"Authorization": "Bearer {your_api_key}",
},
nil,
).ToString("APIPark-MCP-Server"), nil
return fmt.Sprintf(mcpDefaultConfig, "APIPark-MCP-Server", fmt.Sprintf("%s/openapi/v1/%s/sse?apikey={your_api_key}", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.GlobalBasePath)), nil
}
func (i *imlMcpController) OnComplete() {
i.sseServers = make(map[string]http.Handler)
i.server = make(map[string]http.Handler)
for language, tools := range mcpToolsByLanguage {
s := server.NewMCPServer("APIPark MCP Server", "1.0.0", server.WithLogging())
s.AddTool(tools[ToolServiceList], i.mcpModule.Services)
s.AddTool(tools[ToolOpenAPIDocument], i.mcpModule.APIs)
s.AddTool(tools[ToolInvokeAPI], i.mcpModule.Invoke)
i.sseServers[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
i.server[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
if language == languageEnUs {
i.openSseServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
i.openStreamableServer = server.NewStreamableHTTPServer(s, server.WithEndpointPath(mcp_server.OpenGlobalMCPPath))
i.openServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
}
}
}
@@ -162,16 +132,16 @@ func (i *imlMcpController) GlobalMCPHandle(ctx *gin.Context) {
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
locale := utils.I18n(ctx)
if v, ok := i.sseServers[locale]; ok {
if v, ok := i.server[locale]; ok {
v.ServeHTTP(ctx.Writer, req)
return
}
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
}
func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) {
apikey := ctx.Request.URL.Query().Get("apikey")
i.handleSSE(ctx, i.openSseServer, SessionInfo{
i.handleSSE(ctx, i.openServer, SessionInfo{
Apikey: apikey,
})
}
@@ -197,16 +167,7 @@ func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler, sIn
}
func (i *imlMcpController) GlobalHandleMessage(ctx *gin.Context) {
i.handleMessage(ctx, i.openSseServer)
}
func (i *imlMcpController) GlobalHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.Header.Get("Authorization")
apikey = strings.TrimPrefix(apikey, "Bearer ")
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
i.handleMessage(ctx, i.openServer)
}
func (i *imlMcpController) MCPHandle(ctx *gin.Context) {
@@ -243,13 +204,12 @@ func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) {
}
func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.Header.Get("Authorization")
serviceId := ctx.Request.Header.Get("X-Service-Id")
apikey := ctx.Request.URL.Query().Get("apikey")
serviceId := ctx.Param("serviceId")
if serviceId == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"})
return
}
apikey = strings.TrimPrefix(apikey, "Bearer ")
ok, err := i.authorizationModule.CheckAPIKeyAuthorizationByService(ctx, serviceId, apikey)
if err != nil {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"})
-2
View File
@@ -13,13 +13,11 @@ type IMcpController interface {
GlobalMCPHandle(ctx *gin.Context)
GlobalHandleSSE(ctx *gin.Context)
GlobalHandleMessage(ctx *gin.Context)
GlobalHandleStreamHTTP(ctx *gin.Context)
GlobalMCPConfig(ctx *gin.Context) (string, error)
AppMCPHandle(ctx *gin.Context)
AppHandleSSE(ctx *gin.Context)
AppHandleMessage(ctx *gin.Context)
AppHandleStreamHTTP(ctx *gin.Context)
AppMCPConfig(ctx *gin.Context, appId string) (string, error)
ServiceHandleSSE(ctx *gin.Context)
+10 -16
View File
@@ -520,21 +520,16 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
modelId := ""
modelCfg := ""
modelType := "online"
if input.Model != nil {
modelId = *input.Model
}
if *input.Provider == ai_provider_local.ProviderLocal {
modelType = "local"
if modelId == "" {
list, err := i.aiLocalModel.SimpleList(ctx)
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, fmt.Errorf("no local model")
}
modelId = list[0].Id
list, err := i.aiLocalModel.SimpleList(ctx)
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, fmt.Errorf("no local model")
}
modelId = list[0].Id
modelCfg = ai_provider_local.LocalConfig
} else {
pv, err := i.providerModule.Provider(ctx, *input.Provider)
@@ -545,15 +540,14 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
if !has {
return nil, fmt.Errorf("provider not found")
}
if modelId == "" {
modelId = pv.DefaultLLM
}
m, has := p.GetModel(modelId)
m, has := p.GetModel(pv.DefaultLLM)
if !has {
return nil, fmt.Errorf("model %s not found", pv.DefaultLLM)
}
//modelId = m.ID()
modelId = m.Name()
modelCfg = m.DefaultConfig()
}
var info *service_dto.Service
+1 -1
View File
@@ -8,7 +8,7 @@
"description": "",
"scripts": {
"test": "jest",
"build": "set NODE_OPTIONS=--max-old-space-size=4096 && lerna run build --scope=core --stream --verbose ",
"build": "set NODE_OPTIONS=--max-old-space-size=8192 && lerna run build --scope=core --stream --verbose ",
"serve": "lerna run preview --parallel",
"serve:remotes": "lerna run serve --scope=remote --parallel",
"dev": "lerna run dev --scope=core --stream",
+23 -3
View File
@@ -93,6 +93,11 @@ const Login: FC = () => {
const code = query.get('code')
if (code) {
feishuLogin(code)
setSpinning(false)
return
}
if (isInFeishuClient() && feishu) {
openFeishuLogin(feishu.config.client_id)
}
setSpinning(false)
}
@@ -161,10 +166,25 @@ const Login: FC = () => {
fetchLogin({ username: 'guest', password: '12345678' })
}
const isInFeishuClient = () => {
// 方法1:检查User-Agent
const ua = navigator.userAgent.toLowerCase();
const isLark = ua.includes('lark') || ua.includes('feishu');
// 方法2:检查全局对象
const hasSDK = typeof window.h5sdk !== 'undefined' || typeof window.tt !== 'undefined';
// 方法3:检查URL参数
const params = new URLSearchParams(window.location.search);
const hasFeishuParams = params.has('from') || params.has('required_launch_ability');
return isLark || hasSDK || hasFeishuParams;
}
// 打开飞书授权页面
const openFeishuLogin = () => {
const openFeishuLogin = (id?: string) => {
const href = window.location.origin + window.location.pathname
const authUrl = `https://accounts.feishu.cn/open-apis/authen/v1/authorize?client_id=${feishuAppId}&redirect_uri=${href}`
const authUrl = `https://accounts.feishu.cn/open-apis/authen/v1/authorize?client_id=${id || feishuAppId}&redirect_uri=${href}`
localStorage.setItem('feishuCallbackUrl', href)
window.location.href = authUrl
}
@@ -336,7 +356,7 @@ const Login: FC = () => {
loading={loading}
className="h-[40px] w-full inline-flex justify-center items-center"
type="default"
onClick={openFeishuLogin}
onClick={() => openFeishuLogin(feishuAppId)}
>
<img className="h-[30px]" src={FeishuLogo} />
{$t('飞书授权登录')}
@@ -20,7 +20,7 @@ export default function ManagementInsidePage() {
const { message } = App.useApp()
const { fetchData } = useFetch()
const { setBreadcrumb } = useBreadcrumb()
const [activeMenu, setActiveMenu] = useState<string>('service')
const [activeMenu, setActiveMenu] = useState<string>('authorization')
const { appId, teamId } = useParams<RouterParams>()
const navigateTo = useNavigate()
const currentUrl = useLocation().pathname
@@ -56,7 +56,7 @@ export default function ManagementInsidePage() {
}, [accessData, accessInit, TENANT_MANAGEMENT_APP_MENU])
useEffect(() => {
setActiveMenu(currentUrl.split('/').pop() || 'service')
setActiveMenu(currentUrl.split('/').pop() || 'authorization')
}, [currentUrl])
const onMenuClick: MenuProps['onClick'] = (node) => {
@@ -336,7 +336,7 @@ export default function ServiceHubManagement() {
setTableSearchWord={setTableSearchWord}
editApp={(row: ServiceHubAppListItem) => {
setAppName(row.name)
navigateTo(`/consumer/${row.team.id}/inside/${row.id}/service`)
navigateTo(`/consumer/${row.team.id}/inside/${row.id}/authorization`)
}}
/>
)}
-28
View File
@@ -1,28 +0,0 @@
package auth
func init() {
b := NewAKSK()
Register(b.Name(), b)
}
func NewAKSK() *AKSK {
return &AKSK{}
}
type AKSK struct {
}
func (a *AKSK) Name() string {
return "aksk"
}
func (a *AKSK) ToPattern(cfg map[string]interface{}) interface{} {
result := make(map[string]interface{})
result["ak"] = cfg["ak"]
result["sk"] = cfg["sk"]
return result
}
func (a *AKSK) ToConfig(cfg map[string]interface{}) interface{} {
return nil
}
-35
View File
@@ -1,35 +0,0 @@
package auth
func init() {
b := NewJWT()
Register(b.Name(), b)
}
func NewJWT() *JWT {
return &JWT{}
}
type JWT struct {
}
func (J *JWT) Name() string {
return "jwt"
}
func (J *JWT) ToPattern(cfg map[string]interface{}) interface{} {
result := make(map[string]interface{})
result["username"] = cfg["user"]
return result
}
func (J *JWT) ToConfig(cfg map[string]interface{}) interface{} {
result := make(map[string]interface{})
result["iss"] = cfg["iss"]
result["algorithm"] = cfg["algorithm"]
result["secret"] = cfg["secret"]
result["rsa_public_key"] = cfg["publicKey"]
result["path"] = cfg["userPath"]
result["claims_to_verify"] = cfg["claimsToVerify"]
result["signature_is_base_64"] = cfg["signatureIsBase64"]
return result
}
-29
View File
@@ -1,29 +0,0 @@
package auth
func init() {
b := NewOAuth2()
Register(b.Name(), b)
}
func NewOAuth2() *OAuth2 {
return &OAuth2{}
}
type OAuth2 struct {
}
func (o *OAuth2) Name() string {
return "oauth2"
}
func (o *OAuth2) ToPattern(cfg map[string]interface{}) interface{} {
result := make(map[string]interface{})
result["client_id"] = cfg["client_id"]
result["client_secret"] = cfg["client_secret"]
result["client_type"] = cfg["client_type"]
result["hash_secret"] = cfg["hash_secret"]
result["redirect_urls"] = cfg["redirect_urls"]
return result
}
func (o *OAuth2) ToConfig(cfg map[string]interface{}) interface{} {
return nil
}
+3 -5
View File
@@ -15,7 +15,7 @@ require (
github.com/go-sql-driver/mysql v1.7.0
github.com/google/uuid v1.6.0
github.com/influxdata/influxdb-client-go/v2 v2.14.0
github.com/mark3labs/mcp-go v0.42.0-beta.3
github.com/mark3labs/mcp-go v0.33.0
github.com/mitchellh/mapstructure v1.5.0
github.com/nsqio/go-nsq v1.1.0
github.com/ollama/ollama v0.5.8
@@ -27,8 +27,6 @@ require (
require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -48,7 +46,6 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
github.com/invopop/jsonschema v0.13.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
@@ -70,7 +67,6 @@ require (
github.com/spf13/cast v1.7.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
go.uber.org/atomic v1.7.0 // indirect
@@ -91,4 +87,6 @@ require (
//)
//replace github.com/eolinker/ap-account => ../../eolinker/ap-account
//
//replace github.com/eolinker/go-common => ../../eolinker/go-common
+2 -10
View File
@@ -2,8 +2,6 @@ github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
@@ -11,8 +9,6 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
@@ -84,8 +80,6 @@ github.com/influxdata/influxdb-client-go/v2 v2.14.0 h1:AjbBfJuq+QoaXNcrova8smSjw
github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -107,8 +101,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mark3labs/mcp-go v0.42.0-beta.3 h1:nmOg1HFgSOgy0bZkAQ+E6qVpPMPmE8hIkM0BO94Ks9k=
github.com/mark3labs/mcp-go v0.42.0-beta.3/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
github.com/mark3labs/mcp-go v0.33.0 h1:naxhjnTIs/tyPZmWUZFuG0lDmdA6sUyYGGf3gsHvTCc=
github.com/mark3labs/mcp-go v0.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -165,8 +159,6 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg=
-36
View File
@@ -1,36 +0,0 @@
package mcp_server
import "encoding/json"
type TransportType string
const (
TransportTypeStreamableHTTP TransportType = "streamable-http"
TransportTypeSSE TransportType = "sse"
)
func NewMCPConfig(typ TransportType, url string, headers map[string]string, alwaysAllow []string) *MCPConfig {
return &MCPConfig{
Type: typ,
URL: url,
Headers: headers,
AlwaysAllow: alwaysAllow,
}
}
type MCPConfig struct {
Type TransportType `json:"type"`
URL string `json:"url"`
Headers map[string]string `json:"headers,omitempty"`
AlwaysAllow []string `json:"alwaysAllow,omitempty"`
}
func (c *MCPConfig) ToString(name string) string {
m := map[string]interface{}{
"mcpServers": map[string]interface{}{
name: c,
},
}
data, _ := json.MarshalIndent(m, "", "\t")
return string(data)
}
+6 -24
View File
@@ -17,10 +17,6 @@ var (
ServiceBasePath = "mcp/service"
GlobalBasePath = "mcp/global"
AppBasePath = "mcp/app"
OpenGlobalMCPPath = "/openapi/v1/global/mcp"
OpenAppMCPPath = "/openapi/v1/app/mcp"
OpenServiceMCPPath = "/openapi/v1/service/mcp"
)
func NewServer() *Server {
@@ -65,7 +61,7 @@ func (s *Server) Set(id string, ser *server.MCPServer) {
}
tmp.handlers["api-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s/%s", ServiceBasePath, id)))
tmp.handlers["openapi-sse"] = server.NewSSEServer(ser, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s/%s", ServiceBasePath, id)))
tmp.handlers["openapi-stream"] = server.NewStreamableHTTPServer(ser, server.WithEndpointPath(OpenServiceMCPPath))
tmp.handlers["openapi-stream"] = server.NewStreamableHTTPServer(ser, server.WithEndpointPath(fmt.Sprintf("/openapi/v1/%s/%s/mcp", ServiceBasePath, id)))
s.servers[id] = tmp
}
@@ -95,23 +91,12 @@ func (s *Server) Get(id string) (*Handler, bool) {
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var sid string
if r.URL.Path == OpenServiceMCPPath {
sid = r.Header.Get("X-Service-Id")
if sid == "" {
http.NotFound(w, r)
return
}
} else {
id, err := genPath(r.URL.Path)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
sid = id
sid, err := genPath(r.URL.Path)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
ser, has := s.Get(sid)
if has {
ser.ServeHTTP(w, r)
@@ -171,9 +156,6 @@ func SetServerByOpenapi(sid, name, version, content string) error {
toolOptions = append(toolOptions, mcp.WithDescription(a.Description))
params := make(map[string]*Param)
for _, v := range a.Params {
if v.In == "header" && v.Name == "Authorization" {
continue
}
params[v.Name] = NewParam(Position(v.In), v.Required, v.Description)
options := make([]mcp.PropertyOption, 0, 2)
if v.Required {
@@ -6,11 +6,11 @@ import (
"fmt"
"strconv"
"strings"
auth_driver "github.com/APIParkLab/APIPark/module/application-authorization/auth-driver"
"github.com/eolinker/go-common/utils"
application_authorization_dto "github.com/APIParkLab/APIPark/module/application-authorization/dto"
)
@@ -26,12 +26,12 @@ type Config struct {
Iss string `json:"iss"`
Algorithm string `json:"algorithm"`
Secret string `json:"secret"`
PublicKey string `json:"publicKey"`
PublicKey string `json:"public_key"`
User string `json:"user"`
UserPath string `json:"userPath"`
ClaimsToVerify []string `json:"claimsToVerify"`
UserPath string `json:"user_path"`
ClaimsToVerify []string `json:"claims_to_verify"`
Label map[string]string `json:"label"`
SignatureIsBase64 bool `json:"signatureIsBase64"`
SignatureIsBase64 bool `json:"signature_is_base64"`
}
func (cfg *Config) ID() string {
@@ -46,7 +46,7 @@ func (cfg *Config) ID() string {
for _, claim := range cfg.ClaimsToVerify {
builder.WriteString(strings.TrimSpace(claim))
}
case "RS256", "RS384", "RS512", "ES256", "ES384", "ES512":
builder.WriteString(strings.TrimSpace(cfg.Iss))
builder.WriteString(strings.TrimSpace(cfg.PublicKey))
@@ -81,7 +81,7 @@ func (cfg *Config) Valid() ([]byte, error) {
default:
return nil, fmt.Errorf("unsupport algorithm")
}
//校验 校验字段
for _, claim := range cfg.ClaimsToVerify {
switch claim {
@@ -94,7 +94,7 @@ func (cfg *Config) Valid() ([]byte, error) {
}
func (cfg *Config) Detail() []application_authorization_dto.DetailItem {
items := []application_authorization_dto.DetailItem{
{Key: "Iss", Value: cfg.Iss},
{Key: "签名算法", Value: cfg.Algorithm},
@@ -102,7 +102,7 @@ func (cfg *Config) Detail() []application_authorization_dto.DetailItem {
{Key: "用户名JsonPath", Value: cfg.UserPath},
{Key: "校验字段", Value: strings.Join(cfg.ClaimsToVerify, ",")},
}
switch cfg.Algorithm {
case "HS256", "HS384", "HS512":
items = append(items, application_authorization_dto.DetailItem{Key: "Secret", Value: cfg.Secret})
@@ -110,10 +110,10 @@ func (cfg *Config) Detail() []application_authorization_dto.DetailItem {
if cfg.SignatureIsBase64 {
base64 = "true"
}
items = append(items, application_authorization_dto.DetailItem{Key: "SignatureIsBase64", Value: base64})
items = append(items, application_authorization_dto.DetailItem{Key: "Secret", Value: base64})
default:
items = append(items, application_authorization_dto.DetailItem{Key: "RSA公钥", Value: cfg.PublicKey})
}
return items
}
+38 -44
View File
@@ -219,19 +219,19 @@ func (i *imlAuthorizationModule) initGateway(ctx context.Context, partitionId st
return clientDriver.Application().Online(ctx, applications...)
}
func (i *imlAuthorizationModule) getApplicationRelease(ctx context.Context, s *service.Service) (*gateway.ApplicationRelease, error) {
func (i *imlAuthorizationModule) online(ctx context.Context, s *service.Service) error {
clusters, err := i.clusterService.List(ctx)
if err != nil {
return err
}
if len(clusters) < 1 {
return nil
}
authorizations, err := i.authorizationService.ListByApp(ctx, s.Id)
if err != nil {
return nil, err
return err
}
if len(authorizations) < 1 {
return &gateway.ApplicationRelease{
BasicItem: &gateway.BasicItem{
ID: s.Id,
},
}, nil
}
return &gateway.ApplicationRelease{
app := &gateway.ApplicationRelease{
BasicItem: &gateway.BasicItem{
ID: s.Id,
Description: s.Description,
@@ -256,40 +256,10 @@ func (i *imlAuthorizationModule) getApplicationRelease(ctx context.Context, s *s
},
}
}),
}, nil
}
func (i *imlAuthorizationModule) doOffline(ctx context.Context, clusterId string, app *gateway.ApplicationRelease) error {
client, err := i.clusterService.GatewayClient(ctx, clusterId)
if err != nil {
return err
}
defer func() {
_ = client.Close(ctx)
}()
return client.Application().Offline(ctx, app)
}
func (i *imlAuthorizationModule) online(ctx context.Context, s *service.Service) error {
clusters, err := i.clusterService.List(ctx)
if err != nil {
return err
}
if len(clusters) < 1 {
return nil
}
release, err := i.getApplicationRelease(ctx, s)
if err != nil {
return err
}
for _, c := range clusters {
if len(release.Authorizations) < 1 {
err = i.doOffline(ctx, c.Uuid, release)
if err != nil {
log.Warnf("service authorization offline for cluster[%s] %v", c.Name, err)
}
continue
}
err = i.doOnline(ctx, c.Uuid, release)
err := i.doOnline(ctx, c.Uuid, app)
if err != nil {
log.Warnf("service authorization online for cluster[%s] %v", c.Name, err)
}
@@ -405,7 +375,7 @@ func (i *imlAuthorizationModule) EditAuthorization(ctx context.Context, appId st
}
func (i *imlAuthorizationModule) DeleteAuthorization(ctx context.Context, pid string, aid string) error {
s, err := i.serviceService.Get(ctx, pid)
_, err := i.serviceService.Get(ctx, pid)
if err != nil {
return err
}
@@ -415,11 +385,35 @@ func (i *imlAuthorizationModule) DeleteAuthorization(ctx context.Context, pid st
if err != nil {
return err
}
return i.online(ctx, s)
clusters, err := i.clusterService.List(ctx)
if err != nil {
return err
}
app := &gateway.ApplicationRelease{
BasicItem: &gateway.BasicItem{
ID: pid,
},
}
for _, c := range clusters {
err := i.doOffline(ctx, c.Uuid, app)
if err != nil {
log.Warnf("service authorization offline for cluster[%s] %v", c.Name, err)
}
}
return nil
})
}
func (i *imlAuthorizationModule) doOffline(ctx context.Context, clusterId string, app *gateway.ApplicationRelease) error {
client, err := i.clusterService.GatewayClient(ctx, clusterId)
if err != nil {
return err
}
defer func() {
_ = client.Close(ctx)
}()
return client.Application().Offline(ctx, app)
}
func (i *imlAuthorizationModule) Authorizations(ctx context.Context, pid string) ([]*application_authorization_dto.AuthorizationItem, error) {
_, err := i.serviceService.Get(ctx, pid)
if err != nil {
+13 -11
View File
@@ -9,10 +9,10 @@ import (
"strings"
"time"
mcp_server "github.com/APIParkLab/APIPark/mcp-server"
service_overview "github.com/APIParkLab/APIPark/service/service-overview"
mcp_server "github.com/APIParkLab/APIPark/mcp-server"
"github.com/APIParkLab/APIPark/module/monitor/driver"
"github.com/APIParkLab/APIPark/service/monitor"
@@ -326,6 +326,15 @@ func (i *imlCatalogueModule) Subscribe(ctx context.Context, subscribeInfo *catal
})
}
var mcpDefaultConfig = `{
"mcpServers": {
"%s": {
"url": "%s"
}
}
}
`
func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*catalogue_dto.ServiceDetail, error) {
// 获取服务的基本信息
s, err := i.serviceService.Get(ctx, sid)
@@ -391,15 +400,8 @@ func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*ca
mcpAccessConfig := ""
if s.EnableMCP {
if sitePrefix != "" {
mcpAccessConfig = mcp_server.NewMCPConfig(
mcp_server.TransportTypeStreamableHTTP,
fmt.Sprintf("%s/openapi/v1/service/mcp", strings.TrimSuffix(sitePrefix, "/")),
map[string]string{
"Authorization": "Bearer {your_api_key}",
"X-Service-Id": s.Id,
},
nil,
).ToString(fmt.Sprintf("APIPark/%s", s.Name))
mcpAccessAddress = fmt.Sprintf("%s/openapi/v1/%s/%s/sse?apikey={your_api_key}", strings.TrimSuffix(sitePrefix, "/"), mcp_server.ServiceBasePath, s.Id)
mcpAccessConfig = fmt.Sprintf(mcpDefaultConfig, fmt.Sprintf("APIPark/%s", s.Name), mcpAccessAddress)
}
}
invokeMap, err := i.ProviderStatistics(ctx, time.Now().Add(-24*30*time.Hour), time.Now(), s.Id)
+1 -5
View File
@@ -236,10 +236,6 @@ func (i *imlServiceModule) AILogs(ctx context.Context, serviceId string, start i
return nil, 0, err
}
return utils.SliceToSlice(list, func(s *log_service.Item) *service_dto.AILogItem {
var tokenPerSecond int64 = 0
if s.ResponseTime > 0 {
tokenPerSecond = s.TotalToken * 1000 / s.ResponseTime
}
item := &service_dto.AILogItem{
Id: s.ID,
API: auto.UUID(s.API),
@@ -247,7 +243,7 @@ func (i *imlServiceModule) AILogs(ctx context.Context, serviceId string, start i
LogTime: auto.TimeLabel(s.RecordTime),
Ip: s.RemoteIP,
Token: s.TotalToken,
TokenPerSecond: tokenPerSecond,
TokenPerSecond: s.TotalToken * 1000 / s.ResponseTime,
Consumer: auto.UUID(s.Consumer),
Provider: auto.UUID(s.AIProvider),
Model: s.AIModel,
-4
View File
@@ -17,16 +17,12 @@ func (p *plugin) mcpAPIs() []pm3.Api {
globalMessagePath := fmt.Sprintf("/api/v1/%s/message", mcp_server.GlobalBasePath)
appSSEPath := fmt.Sprintf("/api/v1/%s/sse", mcp_server.AppBasePath)
appMessagePath := fmt.Sprintf("/api/v1/%s/message", mcp_server.AppBasePath)
globalMcpPath := fmt.Sprintf("/api/v1/%s/mcp", mcp_server.GlobalBasePath)
appMcpPath := fmt.Sprintf("/api/v1/%s/mcp", mcp_server.AppBasePath)
ignore.IgnorePath("login", http.MethodGet, serviceSSEPath)
ignore.IgnorePath("login", http.MethodPost, serviceMessagePath)
ignore.IgnorePath("login", http.MethodGet, globalSSEPath)
ignore.IgnorePath("login", http.MethodPost, globalMessagePath)
ignore.IgnorePath("login", http.MethodGet, appSSEPath)
ignore.IgnorePath("login", http.MethodPost, appMessagePath)
ignore.IgnorePath("login", http.MethodGet, globalMcpPath)
ignore.IgnorePath("login", http.MethodGet, appMcpPath)
return []pm3.Api{
pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.MCPHandle),
pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.MCPHandle),
-1
View File
@@ -60,7 +60,6 @@ func (o *openapiCheck) Handler(ginCtx *gin.Context) {
}
authorization = apikey
}
authorization = strings.TrimPrefix(authorization, "Bearer ")
if authorization == o.apikey {
return
}
+8 -21
View File
@@ -19,22 +19,17 @@ func (p *plugin) mcpAPIs() []pm3.Api {
serviceSSEPath := fmt.Sprintf("/openapi/v1/%s/:serviceId/sse", strings.Trim(mcp_server.ServiceBasePath, "/"))
serviceMessagePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/message", strings.Trim(mcp_server.ServiceBasePath, "/"))
//serviceStreamablePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/mcp", strings.Trim(mcp_server.ServiceBasePath, "/"))
serviceStreamablePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/mcp", strings.Trim(mcp_server.ServiceBasePath, "/"))
ignore.IgnorePath("openapi", http.MethodPost, globalMessagePath)
//ignore.IgnorePath("openapi", http.MethodGet, globalSSEPath)
ignore.IgnorePath("openapi", http.MethodGet, globalSSEPath)
ignore.IgnorePath("openapi", http.MethodPost, appMessagePath)
ignore.IgnorePath("openapi", http.MethodGet, appSSEPath)
ignore.IgnorePath("openapi", http.MethodGet, serviceSSEPath)
ignore.IgnorePath("openapi", http.MethodPost, serviceMessagePath)
ignore.IgnorePath("openapi", http.MethodGet, mcp_server.OpenAppMCPPath)
ignore.IgnorePath("openapi", http.MethodPost, mcp_server.OpenAppMCPPath)
ignore.IgnorePath("openapi", http.MethodDelete, mcp_server.OpenAppMCPPath)
ignore.IgnorePath("openapi", http.MethodGet, mcp_server.OpenServiceMCPPath)
ignore.IgnorePath("openapi", http.MethodPost, mcp_server.OpenServiceMCPPath)
ignore.IgnorePath("openapi", http.MethodDelete, mcp_server.OpenServiceMCPPath)
ignore.IgnorePath("openapi", http.MethodGet, serviceStreamablePath)
ignore.IgnorePath("openapi", http.MethodPost, serviceStreamablePath)
ignore.IgnorePath("openapi", http.MethodDelete, serviceStreamablePath)
return []pm3.Api{
pm3.CreateApiSimple(http.MethodGet, globalSSEPath, p.mcpController.GlobalHandleSSE),
@@ -46,17 +41,9 @@ func (p *plugin) mcpAPIs() []pm3.Api {
pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.ServiceHandleSSE),
pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.ServiceHandleMessage),
pm3.CreateApiSimple(http.MethodGet, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodPost, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodDelete, mcp_server.OpenGlobalMCPPath, p.mcpController.GlobalHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodGet, mcp_server.OpenAppMCPPath, p.mcpController.AppHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodPost, mcp_server.OpenAppMCPPath, p.mcpController.AppHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodDelete, mcp_server.OpenAppMCPPath, p.mcpController.AppHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodPost, mcp_server.OpenServiceMCPPath, p.mcpController.ServiceHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodDelete, mcp_server.OpenServiceMCPPath, p.mcpController.ServiceHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodGet, mcp_server.OpenServiceMCPPath, p.mcpController.ServiceHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodPost, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodDelete, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP),
pm3.CreateApiSimple(http.MethodGet, serviceStreamablePath, p.mcpController.ServiceHandleStreamHTTP),
}
}
+1 -2
View File
@@ -3,11 +3,10 @@ package commit
import (
"context"
"errors"
"github.com/eolinker/go-common/utils"
"strings"
"time"
"github.com/eolinker/go-common/utils"
"github.com/eolinker/go-common/store"
"github.com/google/uuid"
"gorm.io/gorm"