Skip to content

feat: 添加 MCP Server 全生命周期管理、沙箱托管与第三方导入#233

Draft
githuuuuub wants to merge 42 commits intohigress-group:mainfrom
githuuuuub:AgentRuntimeIntegrate-reconstruct
Draft

feat: 添加 MCP Server 全生命周期管理、沙箱托管与第三方导入#233
githuuuuub wants to merge 42 commits intohigress-group:mainfrom
githuuuuub:AgentRuntimeIntegrate-reconstruct

Conversation

@githuuuuub
Copy link
Copy Markdown
Contributor

📝 Description

为 HiMarket 新增完整的 MCP Server 全生命周期管理能力,涵盖以下功能模块:

MCP Server 管理 + 沙箱托管 + 协议标准化(核心功能)

  • 冷热数据分离模型:mcp_server_meta(元信息)+ mcp_server_endpoint(运行时连接)+ sandbox_instance(沙箱实例),Flyway V16/V17 迁移
  • 后端服务:MCP CRUD、发布订阅、连接测试、协议解析(stdio/sse/streamable-http)、MCP 配置同步到 Higress Gateway CRD
  • 沙箱部署编排:策略模式(AgentRuntime / SelfHosted),Spring Event 异步监听,K8s CRD 创建与工具列表异步获取
  • 沙箱实例管理:CRUD + 定时健康检查
  • Open API:5 个对外接口(X-API-Key 鉴权),仅允许查询已发布产品,非管理员自动脱敏 subscribeParams
  • Admin Portal:MCP 管理面板重构、沙箱部署配置、沙箱管理控制台页面
  • Developer Portal:MCP 广场(搜索/筛选/分页)、MCP 详情页(工具列表/连接配置/订阅)、开发者自助注册 MCP、我的 MCP 管理

AgentRuntime 沙箱部署 API Key 鉴权(对应 spec: sandbox-auth-apikey

  • 管理员可选启用 API Key 鉴权,系统自动生成 sk_ 前缀随机密钥(SecureRandom,≥35 字符)
  • 创建 K8s Secret 下发到目标集群,ToolServer CRD accesses 引用 Secret
  • API Key 持久化到 Endpoint 的 subscribeParams,HiChat/HiCoding 调用时自动携带 Authorization header
  • 取消部署时同步清理 Secret,每个沙箱独立 API Key(一对一绑定)

第三方供应商批量导入 MCP(对应 spec: batch-import-mcp

  • 适配器模式接入三个供应商:ModelScope(无需认证)、MCP Registry(公开 API,cursor 分页适配)、LobeHub(JWT client assertion OAuth2,后端自动处理)
  • 所有供应商均不需要管理员输入 API Key
  • 复用 registerMcp() 创建 Product + McpMeta + ProductRef,origin 设为 VENDOR_IMPORT
  • 单次导入上限 50 条,失败不中断,前端支持搜索/分页/多选/已存在标记

其他改进

  • Encryptor 升级 AES-ECB → AES-CBC(兼容旧数据解密),新增 EncryptedStringConverter
  • SecurityConfig 新增 /mcp/create 路由鉴权
  • fillProducts 批量加载 MCP meta/endpoint,减少 N+1 查询
  • 前端合并 consumer API 调用
  • SSE endpoint URL 归一化防止 double-slash bug
  • HiChat MCP 工具详情弹窗、MCP 卡片交互优化

🔗 Related Issues

✅ Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Build/CI configuration change
  • Other (please describe):

🧪 Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing completed
  • All tests pass locally

📋 Checklist

  • Code has been formatted (mvn spotless:apply for backend, npm run lint:fix for frontend)
  • Code is self-reviewed
  • Comments added for complex code
  • Documentation updated (if applicable)
  • No breaking changes (or migration guide provided)
  • All CI checks pass

📊 Test Coverage

📚 Additional Notes

  • 需要执行数据库迁移:V16(sandbox_instance 表)、V17(mcp_server_meta + mcp_server_endpoint 表)
  • 新增配置项 open-api.api-key(环境变量 OPEN_API_KEY),用于 Open API 鉴权
  • 128 files changed, +17,094 / -776(后端 Java 87 files, 前端 TS/TSX 31 files)
  • 新增 3 张数据库表、5 个 Open API 接口、4 条前端路由(/mcp/square/mcp/create/mcp/my/mcp/:id
  • 接口文档:docs/open-api-mcp-servers-v3.md
  • 表设计文档:docs/mcp-cold-hot-table.mddocs/sandbox-instance-table.md

githuuuuub and others added 30 commits March 19, 2026 10:33
## 沙箱管理
- SandboxInstance 实体/Service/Controller,支持导入/更新/删除/健康检查
- K8sClientUtils:Fabric8 客户端封装 + Caffeine 缓存
- Admin 前端沙箱管理页面

## MCP Server 管理
- McpServerMeta(冷数据)+ McpServerEndpoint(热数据)双表模型
- McpServerService:saveMeta/registerMcp/deploySandbox/refreshTools
- AgentRuntimeDeployStrategy + SelfHostedDeployStrategy:CRD 部署
- OpenApiMcpController:外部系统注册 MCP
- 部署后自动获取工具列表(带重试)

## 协议标准化
- McpProtocolUtils.normalize():统一 stdio/sse/streamableHttp
- transportType 只影响热数据,metaProtocolType 控制 CRD PROTOCOL
- CRD PROTOCOL:http 映射为 streamableHttp

## Admin 前端
- McpCustomConfigModal:自定义 MCP 配置向导
- ApiProductLinkApi:冷热数据分 Tab,热数据优先
- 支持 query 参数解析 + URL 去重合并
- 产品名自动填充到 MCP 中文名称

## Portal 前端
- McpDetail:连接配置优先热数据,协议重叠时只显示热数据
- McpSquare / McpCreatePage
- 显示名称优先级:product.name > meta.displayName > meta.mcpName
- resolvedConfig 增加 type 字段

## 其他
- ChatService:buildMCPConfigs null 安全 + 优先 endpoint 热数据
- Flyway V14/V15,FlywayConfig outOfOrder + auto-repair
- Fabric8 6.1.1 -> 6.13.4
- Helm 模板 hub 空值兼容
…igress-group#181)

The "开始对话测试" button was clickable even without an active subscription,
allowing users to enter the chat page without proper access. Now the button
shows "订阅并开始对话" when unsubscribed and opens the subscription management
modal on click, guiding users to subscribe first.

🤖 Generated with [Qoder][https://qoder.com]
…i-arch build support (higress-group#183)

* fix(deploy): 修正Nacos启动配置及API响应处理

- 删除Nacos镜像的多余入口脚本配置,使用默认启动方式
- 修改Helm部署Nacos模板,去除多余的启动命令部分
- 优化post_ready脚本中查询消费者ID和产品ID的JSON解析逻辑,改为使用jq稳定提取
- 新增判断产品是否未关联网关的逻辑,避免订阅时因错误导致失败
- 修正artifactDetector中未识别扩展名时返回null的行为
- 在模型详情页面中动态替换cURL示例中的模型名称,避免使用占位符
- 增加模型名称缺失时的提示信息显示
- 更新产品接口中的IProductDetail,补充model字段类型声明
- 扩展artifact类型支持,添加Excel格式文件扩展名判断

* fix(scripts): 更新镜像版本并支持多架构构建

- 修改 push.sh 和 push-podman.sh 中的镜像版本为 latest
- 在 push.sh 中启用多架构平台 linux/amd64 和 linux/arm64
- 在 push-podman.sh 中增加清理残留镜像操作,避免冲突
- 保持多架构镜像构建流程的稳定性与兼容性
- 沙箱托管部署后的工具列表获取改为异步执行,不再阻塞部署接口响应
- 管理后台 MCP 来源展示增加 ADMIN(管理员配置) 和 AGENTRUNTIME(AgentRuntime导入) 映射
# Conflicts:
#	himarket-bootstrap/src/main/java/com/alibaba/himarket/config/SecurityConfig.java
#	himarket-web/himarket-frontend/src/pages/ModelDetail.tsx
#	himarket-web/himarket-frontend/src/router.tsx
# Conflicts:
#	himarket-bootstrap/src/main/resources/application.yml
#	himarket-web/himarket-frontend/src/router.tsx
#	pom.xml
feat: add public MCP meta API and cascade delete MCP resources on product removal
- Add McpMetaPublicResult DTO with sanitized fields for anonymous access
- Add @publicaccess endpoints for batch/single MCP meta queries in McpServerController and ProductController
- Add forceDeleteMetaByProduct to cascade delete meta, endpoints and sandbox resources
- Fix ProductServiceImpl to properly cascade MCP cleanup on product delete/unlink
- Add filter_mcp_server_options preset query in SlsPresetSqlRegistry

Frontend:
feat: support anonymous browsing for MCP square and detail pages
- Add getProductMcpMetaPublic/getProductMcpMetaBatchPublic API calls for unauthenticated users
- Toggle between public/authenticated APIs based on login state in McpSquare and McpDetail
- Hide "My MCP" tab, "Create MCP" button, and subscribe actions when not logged in
- Show login prompt instead of connection config for anonymous users in McpDetail
- Replace plain text empty state with EmptyState component
- Add McpProtocolType enum with fromString/normalize/resolveTransportMode
- Fix streamableHttp transport falling through to SSE in HiChat
- Replace all string-based protocol comparisons with enum across backend
- Add frontend MCP protocol constants for admin and developer portals
- Hide cold data tabs for remote-imported MCPs when hot data exists
- Show origin-based labels on hot data tabs in admin portal
- Fix JSON highlighting breaking URLs with ports in developer portal
- Show hot/cold config regardless of subscription status
- Add sandbox deploy/undeploy event handling
Extract normalizeEndpointUrl() into McpProtocolUtils to centralize
the trailing-slash stripping and /sse suffix logic. Replace three
separate inline implementations in McpSandboxDeployListener,
McpServerServiceImpl.syncPublicEndpoint(), and resolveTransportConfigs()
with calls to the shared utility.

Fixes a bug where McpSandboxDeployListener did not strip trailing
slashes before appending /sse, producing URLs like https://host//sse
when the sandbox deploy service returned a URL with a trailing slash.
- Add published-only query methods to McpServerService and impl
- Switch OpenApiMcpController to use getPublishedMeta/listPublishedMeta variants
- Add findProductIdsByTypeAndStatus to ProductRepository
- Add findByProductIdIn/findByProductIdInAndOrigin to McpServerMetaRepository
- Disable self-hosted Sandbox tab (coming soon)
…Registry, LobeHub)

- Add McpVendorType enum, McpOrigin.VENDOR_IMPORT
- Add vendor DTOs: RemoteMcpItem, BatchImportParam/Result, RemoteMcpItemParam/Result
- Add McpVendorAdapter interface with enrichForImport() default method
- Add ModelScopeAdapter, McpRegistryAdapter, LobeHubAdapter
- Add VendorAdapterRegistry, McpVendorService/Impl, McpVendorController
- Add ImportMcpModal (two-step vendor selection + card grid), RemoteMcpTable
- Add mcpVendorApi with 300s timeout for batch import
- Add edit button to MCP config page (disabled when deployed)
- Fix MCP Registry pagination: cursor-based with version=latest
- Fix icon JSON format to use {"type":"URL","value":"..."}
- Fix Chinese locale priority for ModelScope and LobeHub adapters
…oy mismatch

Deploy uses adminUserId to build CRD resourceName, but endpoint stores
userId="*". Undeploy recomputes resourceName with "*", resulting in a
different name that fails to match the actual CRD.

- Store resourceName in endpoint subscribe_params at creation time
- Pass resourceName through undeploy chain via 5-param overload
- Add resourceName field to McpSandboxUndeployEvent
- Fix deploy rollback and old CRD cleanup to pass correct resourceName
- Remove dead code: McpRegistryAdapter containsIgnoreCase/isActiveAndLatest
Replace in-memory ConcurrentHashMap token blacklist with MariaDB-backed
persistence to survive application restarts and support multi-instance
deployments.

Changes:
- Add Flyway V14 migration for revoked_token table (SHA-256 hash indexed)
- Add RevokedToken JPA entity and RevokedTokenRepository
- Add RevokedTokenService with Caffeine L1 cache and scheduled cleanup
- Refactor TokenUtil to delegate revocation to RevokedTokenService
- Add jqwik property-based tests for bug condition and preservation

Closes higress-group#202
…#198)

- Add FileUploadValidator with extension whitelist, MIME cross-validation,
  file size limit (20MB), magic bytes verification, and filename sanitization
- Integrate validator into ChatAttachmentServiceImpl.uploadAttachment()
- Add 9 jqwik property-based tests for bug condition and preservation
- Improve frontend error messages to show backend validation errors
Hide subscribeParams (namespace, resourceName and other K8s deployment
parameters) from developer-facing API responses. Admin endpoints with
@Adminauth are unaffected.

Changes:
- Add McpMetaResult.sanitize() to null out subscribeParams
- McpServerController: sanitize responses in getMeta, listMetaByProduct,
  listMetaByProductIds, listPublished, register for non-admin users
- ProductController: sanitize responses in listMcpMeta for non-admin users
- Generate sk_ prefixed API Key on deploy when authType=apikey
- Create K8s Secret with labels (managed-by, user-id, mcp-name, mcp-server-id, ref-toolserver)
- Reference Secret in ToolServer CRD accesses and add ref-secret label
- Clean up Secret on undeploy (pass secretName through full undeploy chain)
- Write secretName back to subscribeParams after successful deploy
- Add SANDBOX branch in resolveAuthHeaders for HiChat/HiCoding auth
- Enable API Key option in admin deploy modal (replace disabled bearer)
- Display Secret name and masked API Key in hosting config area
- Fix JPA flush issue for endpoint delete+insert unique constraint
Resolved 6 conflicts:
- Resources.java: merged both AGENT_SPEC/SKILL (main) and SANDBOX/MCP constants (ours)
- ProductController.java: kept both ContextHolder import and wildcard import
- api.ts (admin): merged main's skillApi enhancements + workerApi with our mcpServerApi/sandboxApi/mcpVendorApi
- ApiProducts.tsx: merged MCP import button (ours) with Nacos import + sort (main)
- iconUtils.tsx (frontend): merged parseMetaIcon (ours) with getFirstChar + enhanced getIconString (main)
- McpDetail.tsx: kept our rewrite, discarded main's minor Spin->DetailSkeleton change

DB migrations renumbered: main's V14/V15 kept, ours moved to V16/V17, duplicate V16 removed.
- Fix saveMeta creating duplicate records when mcpName is changed
- Allow mcpName to be updated via saveMeta (remove from ignoreProperties)
- Add mcpName length check (max 32 chars) before sandbox deploy
- Add authType selector to McpCustomConfigModal sandbox config
- Add endpoint polling after save-and-deploy in McpCustomConfigModal
- Add timeout warning when sandbox deploy polling exceeds max attempts
- Remove duplicate Modal.success in ImportMcpModal (keep component modal only)
…nto AgentRuntimeIntegrate-reconstruct

- higress-group#223: Docker install script improvements (configurable data dir, upgrade mode)
- higress-group#224: Skill/Worker version management improvements and Nacos state handling

Resolved 1 conflict in ProductServiceImpl.java: kept both MCP service deps (ours) and Worker/Skill service deps (main).
- Remove hardcoded default Open API Key, disable when OPEN_API_KEY env not set
- Add @ModelAttribute auth guard to OpenApiMcpController (prevents unauthenticated endpoints)
- Add Apache License 2.0 headers to 3 missing files
- Extract McpServerServiceImpl (2001 lines) into 4 focused classes:
  - McpServerServiceImpl (~960 lines) - core CRUD coordination
  - McpConfigSyncHelper (~600 lines) - config sync, ProductRef, endpoint URL extraction
  - McpSandboxOrchestrator (~260 lines) - sandbox deploy/undeploy orchestration
  - McpTransportResolver (~230 lines) - transport config resolution for HiChat/HiCoding
…gh McpConfigSyncHelper

- Restore V15 migration file to original content (avoid Flyway checksum mismatch)
- Move endpoint repository access from McpSandboxOrchestrator to McpConfigSyncHelper
  to eliminate duplicate repository dependency and centralize endpoint operations
1. Remove Thread.sleep blocking in refreshTools - fail fast instead of retrying
   with 10s sleep that blocks Tomcat threads
2. Replace HTTPS→HTTP hack with configurable sandbox.ssl-verify property
   (defaults to true, set to false to disable SSL verification)
3. Add @PreDestroy shutdown for POLL_SCHEDULER thread pool, convert from
   static to instance field for proper lifecycle management
4. K8sClientUtils: auto-evict and recreate client on connectivity failure
   (handles expired OIDC tokens without waiting 6h cache expiry)
16. Subscription: respect product autoApprove setting for non-gateway sources
    instead of blindly approving all non-gateway subscriptions
17. XSS fix: sanitize HTML entities in highlightJson before dangerouslySetInnerHTML
…anup

Security:
- Encrypt kubeConfig at rest via JPA EncryptedStringConverter (AES-CBC)
- Upgrade Encryptor from AES-ECB to AES-CBC with ECB fallback for legacy data
- Encrypt failure now throws instead of silently storing plaintext
- Add @Adminauth to listEndpoints (was exposing subscribeParams with API keys)
- Centralize SSL trust config in K8sClientUtils.shouldTrustCerts()
- Replace navigator.clipboard with copyToClipboard fallback (HTTP compat)

Code quality:
- Replace magic strings with enum constants (McpEndpointStatus, McpHostingType)
- Extract resolveAutoApprove() to eliminate duplicate logic in ConsumerServiceImpl
- Extract listPublishedMetaInternal() to deduplicate McpServerServiceImpl
- Replace Map<String,String> body with typed DTOs (DeploySandboxParam, UpdateServiceIntroParam)
- Fix N+1 queries in McpVendorServiceImpl with batch findByMcpNameIn
- Add findByMcpNameIn to McpServerMetaRepository
- Add findAllSandboxIds to avoid loading kubeConfig in health checks
- Server-side search in McpSquare instead of client-side filtering

Bug fixes:
- Fix PortalDevelopers duplicate .then() chain
- Fix Consumers refresh button (was using unused _refreshIndex state)
- Fix SandboxConsoles kubeConfig required validation in edit mode

Cleanup:
- Remove unused ClusterAttribute, ClusterAttributeConverter
- Remove unused /mcp-servers/sandboxes endpoint and frontend getActiveSandboxes
- Remove unused Agent page import and /agents route
- Remove console.log debug statements from ImportMcpModal
- Merge latest main branch changes (frontend refactoring, UI improvements)
- Fix publishProduct: correct product status when already published to portal
  but status was inconsistent (defensive fix for edge case)
- Vertical layout with centered search bar (matching Square page design)
- Sticky search area with IntersectionObserver shadow effect
- Debounce auto-search (300ms) instead of enter-only search
- CardGridSkeleton loading state instead of Spin
- Pagination instead of infinite scroll (PAGE_SIZE=12)
- Create button: black circle with hover expand animation
- My MCP button: absolute right, navigates to /mcp/my page
- Smaller cards (160px height, 4-column grid)
- Category/search changes reset to page 1
…nsumer calls

Backend:
- Batch-load McpServerMeta and McpServerEndpoint for all MCP_SERVER products
  in fillProducts, eliminating N+1 queries (2 queries instead of 2*N)
- Add buildMcpConfigFromPreloaded() that takes pre-loaded data without DB access
- Reuse productRefMap in listProductsWithFilter to avoid duplicate query

Frontend:
- Merge fetchSubscribedProducts and fetchMyMcps into single fetchConsumerData
  that shares getPrimaryConsumer + getConsumerSubscriptions results
- Cache consumerId in ref to avoid redundant API calls on subscribe/unsubscribe
@githuuuuub githuuuuub marked this pull request as draft April 1, 2026 03:14
@githuuuuub githuuuuub changed the title feat: MCP Server 全生命周期管理、AgentRuntime沙箱托管、第三方导入 feat: 添加 MCP Server 全生命周期管理、沙箱托管与第三方导入 Apr 1, 2026
@githuuuuub githuuuuub marked this pull request as ready for review April 1, 2026 03:22
@githuuuuub githuuuuub marked this pull request as draft April 1, 2026 07:22
@githuuuuub githuuuuub marked this pull request as draft April 1, 2026 07:22
…id SnakeYAML 2.x incompatibility

fabric8 6.1.1's Serialization.unmarshal calls SafeConstructor() (no-arg),
which was removed in SnakeYAML 2.0. Use Jackson ObjectMapper with YAMLFactory
instead, which doesn't depend on SnakeYAML's constructor API.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants