fix: sync MarketApp MCP records to admin MCP Client management

This commit is contained in:
QihuAI Design committed 2026-07-16 18:12:07 +08:00
1 parent c9b5f964be
commit feb9865b00
3 files changed
+114 -4

No files matched your search

+62
View File
@@ -11,6 +11,7 @@ from datetime import datetime
import uuid
import json
import logging
import re
from ...database import get_db
from ...models import gen_uuid
@@ -99,6 +100,63 @@ def server_to_dict(server) -> dict:
}
def _extract_url_from_text(text: str) -> Optional[str]:
"""Extract first http/https URL from text."""
if not text:
return None
match = re.search(r"https?://[^\s\"'<>\)\]\}]+", text)
return match.group(0) if match else None
def _sync_market_mcp_to_servers(db: Session):
"""
Synchronize MarketApp MCP records (type='mcp') into mcp_servers table.
Uses MarketApp.id as MCPServer.id so detail/edit endpoints can work directly.
"""
from ...models import MarketApp, MCPServer
market_mcps = db.query(MarketApp).filter(
MarketApp.type == "mcp",
MarketApp.status == "published",
).all()
existing_ids = {row[0] for row in db.query(MCPServer.id).all()}
for ma in market_mcps:
if ma.id in existing_ids:
continue
transport = ma.mcp_transport or "streamable_http"
code = ma.skill_content or ""
url = _extract_url_from_text(code) or _extract_url_from_text(ma.description or "") or ""
command = ""
if not url and ma.agent_endpoint:
url = ma.agent_endpoint
now = datetime.now()
server = MCPServer(
id=ma.id,
name=ma.name,
description=ma.description or "",
transport_type=transport,
command=command,
args="{}",
env_vars="{}",
url=url,
headers="{}",
is_enabled=True,
status="disconnected",
tools_count=0,
resources_count=0,
created_at=ma.created_at or now,
updated_at=ma.updated_at or now,
)
db.add(server)
if market_mcps:
db.commit()
# ============================================================
# API Endpoints
# ============================================================
@@ -110,6 +168,7 @@ async def get_mcp_stats(
):
"""Get overview statistics for MCP servers"""
from ...models import MCPServer
_sync_market_mcp_to_servers(db)
total = db.query(func.count(MCPServer.id)).scalar() or 0
enabled = db.query(func.count(MCPServer.id)).filter(MCPServer.is_enabled == True).scalar() or 0
connected = db.query(func.count(MCPServer.id)).filter(MCPServer.status == "connected").scalar() or 0
@@ -152,6 +211,7 @@ async def list_mcp_servers(
):
"""List all MCP servers with pagination and filters"""
from ...models import MCPServer
_sync_market_mcp_to_servers(db)
query = db.query(MCPServer)
if search:
@@ -188,6 +248,7 @@ async def get_mcp_server(
):
"""Get a single MCP server by ID"""
from ...models import MCPServer
_sync_market_mcp_to_servers(db)
server = db.query(MCPServer).filter(MCPServer.id == server_id).first()
if not server:
raise HTTPException(status_code=404, detail="MCP server not found")
@@ -447,3 +508,4 @@ async def list_mcp_resources(
},
"message": "ok",
}
+44 -1
View File
@@ -7,11 +7,12 @@ import uuid
from datetime import datetime
import httpx
from urllib.parse import urlparse
import re
from ..database import get_db
from ..models import (
User, MarketApp, AppPurchase, AppReview, AppInstallation, Order,
AdBanner, gen_uuid
AdBanner, MCPServer, gen_uuid
)
from ..auth import get_current_user, get_current_user_id, get_current_user_id_optional
from ..middleware.log_service import LogService
@@ -19,6 +20,14 @@ from ..middleware.log_service import LogService
router = APIRouter()
def _extract_url_from_text(text: Optional[str]) -> Optional[str]:
"""Extract first http/https URL from text."""
if not text:
return None
match = re.search(r"https?://[^\s\"'<>\)\]\}]+", text)
return match.group(0) if match else None
# ===== Agent 接入前连通性 / 鉴权校验 =====
def _normalize_dify_url(endpoint: str) -> str:
ep = endpoint.rstrip("/")
@@ -375,6 +384,39 @@ def upload_app(
db.commit()
db.refresh(app)
# MCP 应用同步注册到后台 MCP Client 管理(mcp_servers 表)
if app.type == "mcp":
transport = "streamable_http"
code = req.download_url or ""
if code:
app.skill_content = code
app.mcp_transport = transport
db.commit()
db.refresh(app)
existing_server = db.query(MCPServer).filter(MCPServer.id == app.id).first()
if not existing_server:
url = _extract_url_from_text(code) or _extract_url_from_text(req.description or "") or ""
server = MCPServer(
id=app.id,
name=app.name,
description=app.description or "",
transport_type=transport,
command="",
args="{}",
env_vars="{}",
url=url,
headers="{}",
is_enabled=True,
status="disconnected",
tools_count=0,
resources_count=0,
created_at=app.created_at or datetime.now(),
updated_at=app.updated_at or datetime.now(),
)
db.add(server)
db.commit()
# 用户创建/导入的应用自动标记为已安装
existing_install = db.query(AppInstallation).filter(
AppInstallation.user_id == current_user.id,
@@ -769,3 +811,4 @@ def get_agent_resources(
},
"message": "ok",
}
+8 -3
View File
@@ -1491,8 +1491,9 @@ const MarketPage: React.FC = () => {
// Handle hub import - 调用后端 API 创建应用
const handleHubImport = async (platformName: string, url: string, skillName: string, price?: number, description?: string) => {
try {
const desc = description || `从 ${platformName} 导入的${showHubImport === 'skill' ? 'Skills工具' : 'MCP应用'} (来源: ${url})`;
await marketAPI.createApp({
const isMcp = showHubImport === 'mcp';
const desc = description || `从 ${platformName} 导入的${isMcp ? 'MCP应用' : 'Skills工具'}${!isMcp ? ` (来源: ${url})` : ''}`;
const payload: any = {
name: skillName,
type: showHubImport || 'skill',
description: desc,
@@ -1500,7 +1501,11 @@ const MarketPage: React.FC = () => {
is_member_free: (price || 0) === 0,
join_promotion: false,
source: 'user',
});
};
if (isMcp && url) {
payload.download_url = url;
}
await marketAPI.createApp(payload);
// 重新加载列表
loadApps();
} catch (e: any) {