From 5ca397befa2d4826d0c22f6fb30f76d173c13953 Mon Sep 17 00:00:00 2001 From: lixiangcheng1 Date: Wed, 25 Feb 2026 10:27:16 +0800 Subject: [PATCH] [ADD]mcp market: Obtain the list of MCP services from MCP Market Source - ModelScope --- api/app/controllers/__init__.py | 4 + .../mcp_market_config_controller.py | 336 ++++++++++++++++++ api/app/controllers/mcp_market_controller.py | 262 ++++++++++++++ api/app/models/__init__.py | 4 + api/app/models/mcp_market_config_model.py | 16 + api/app/models/mcp_market_model.py | 18 + .../mcp_market_config_repository.py | 72 ++++ api/app/repositories/mcp_market_repository.py | 124 +++++++ api/app/schemas/__init__.py | 8 + api/app/schemas/mcp_market_config_schema.py | 31 ++ api/app/schemas/mcp_market_schema.py | 37 ++ api/app/services/mcp_market_config_service.py | 83 +++++ api/app/services/mcp_market_service.py | 109 ++++++ api/pyproject.toml | 1 + api/requirements.txt | 1 + 15 files changed, 1106 insertions(+) create mode 100644 api/app/controllers/mcp_market_config_controller.py create mode 100644 api/app/controllers/mcp_market_controller.py create mode 100644 api/app/models/mcp_market_config_model.py create mode 100644 api/app/models/mcp_market_model.py create mode 100644 api/app/repositories/mcp_market_config_repository.py create mode 100644 api/app/repositories/mcp_market_repository.py create mode 100644 api/app/schemas/mcp_market_config_schema.py create mode 100644 api/app/schemas/mcp_market_schema.py create mode 100644 api/app/services/mcp_market_config_service.py create mode 100644 api/app/services/mcp_market_service.py diff --git a/api/app/controllers/__init__.py b/api/app/controllers/__init__.py index 67040f40..5c33d6b0 100644 --- a/api/app/controllers/__init__.py +++ b/api/app/controllers/__init__.py @@ -19,6 +19,8 @@ from . import ( implicit_memory_controller, knowledge_controller, knowledgeshare_controller, + mcp_market_controller, + mcp_market_config_controller, memory_agent_controller, memory_dashboard_controller, memory_episodic_controller, @@ -62,6 +64,8 @@ manager_router.include_router(model_controller.router) manager_router.include_router(file_controller.router) manager_router.include_router(document_controller.router) manager_router.include_router(knowledge_controller.router) +manager_router.include_router(mcp_market_controller.router) +manager_router.include_router(mcp_market_config_controller.router) manager_router.include_router(chunk_controller.router) manager_router.include_router(test_controller.router) manager_router.include_router(knowledgeshare_controller.router) diff --git a/api/app/controllers/mcp_market_config_controller.py b/api/app/controllers/mcp_market_config_controller.py new file mode 100644 index 00000000..98012568 --- /dev/null +++ b/api/app/controllers/mcp_market_config_controller.py @@ -0,0 +1,336 @@ +import datetime +import json +from typing import Optional +import uuid + +from fastapi import APIRouter, Depends, HTTPException, status, Query +from fastapi.encoders import jsonable_encoder +import requests +from sqlalchemy import or_ +from sqlalchemy.orm import Session +from modelscope.hub.errors import raise_for_http_status +from modelscope.hub.mcp_api import MCPApi + +from app.core.logging_config import get_api_logger +from app.core.response_utils import success, fail +from app.db import get_db +from app.dependencies import get_current_user +from app.models import mcp_market_config_model +from app.models.user_model import User +from app.schemas import mcp_market_config_schema +from app.schemas.response_schema import ApiResponse +from app.services import mcp_market_config_service + +# Obtain a dedicated API logger +api_logger = get_api_logger() + +router = APIRouter( + prefix="/mcp_market_configs", + tags=["mcp_market_configs"], + dependencies=[Depends(get_current_user)] # Apply auth to all routes in this controller +) + + +@router.get("/mcp_servers", response_model=ApiResponse) +async def get_mcp_servers( + mcp_market_config_id: uuid.UUID, + page: int = Query(1, gt=0), # Default: 1, which must be greater than 0 + pagesize: int = Query(20, gt=0, le=100), # Default: 20 items per page, maximum: 100 items + keywords: Optional[str] = Query(None, description="Search keywords (Optional search query string,e.g. Chinese service name, English service name, author/owner username)"), + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + Query the mcp servers list in pages + - Support keyword search for name,author,owner + - Return paging metadata + mcp server list + """ + api_logger.info( + f"Query mcp server list: tenant_id={current_user.tenant_id}, page={page}, pagesize={pagesize}, keywords={keywords}, username: {current_user.username}") + + # 1. parameter validation + if page < 1 or pagesize < 1: + api_logger.warning(f"Error in paging parameters: page={page}, pagesize={pagesize}") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="The paging parameter must be greater than 0" + ) + + # 2. Query mcp market config information from the database + api_logger.debug(f"Query mcp market config: {mcp_market_config_id}") + db_mcp_market_config = mcp_market_config_service.get_mcp_market_config_by_id(db, + mcp_market_config_id=mcp_market_config_id, + current_user=current_user) + if not db_mcp_market_config: + api_logger.warning( + f"The mcp market config does not exist or access is denied: mcp_market_config_id={mcp_market_config_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market config does not exist or access is denied" + ) + + # 3. Execute paged query + api = MCPApi() + token = db_mcp_market_config.token + api.login(token) + + body = { + 'filter': {}, + 'page_number': page, + 'page_size': pagesize, + 'search': keywords + } + + try: + cookies = api.get_cookies(token) + r = api.session.put( + url=api.mcp_base_url, + headers=api.builder_headers(api.headers), + json=body, + cookies=cookies) + raise_for_http_status(r) + except requests.exceptions.RequestException as e: + api_logger.error(f"mFailed to get MCP servers: {str(e)}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Failed to get MCP servers: {str(e)}" + ) + + data = api._handle_response(r) + total = data.get('total_count', 0) + mcp_server_list = data.get('mcp_server_list', []) + # items = [{ + # 'name': item.get('name', ''), + # 'id': item.get('id', ''), + # 'description': item.get('description', '') + # } for item in mcp_server_list] + + # 4. Return structured response + result = { + "items": mcp_server_list, + "page": { + "page": page, + "pagesize": pagesize, + "total": total, + "has_next": True if page * pagesize < total else False + } + } + return success(data=result, msg="Query of mcp servers list successful") + + +@router.get("/mcp_server", response_model=ApiResponse) +async def get_mcp_server( + mcp_market_config_id: uuid.UUID, + server_id: str, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + Get detailed information for a specific MCP Server + """ + api_logger.info( + f"Query mcp server: tenant_id={current_user.tenant_id}, mcp_market_config_id={mcp_market_config_id}, server_id={server_id}, username: {current_user.username}") + + # 1. Query mcp market config information from the database + api_logger.debug(f"Query mcp market config: {mcp_market_config_id}") + db_mcp_market_config = mcp_market_config_service.get_mcp_market_config_by_id(db, + mcp_market_config_id=mcp_market_config_id, + current_user=current_user) + if not db_mcp_market_config: + api_logger.warning( + f"The mcp market config does not exist or access is denied: mcp_market_config_id={mcp_market_config_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market config does not exist or access is denied" + ) + + # 2. Get detailed information for a specific MCP Server + api = MCPApi() + token = db_mcp_market_config.token + api.login(token) + + result = api.get_mcp_server(server_id=server_id) + return success(data=result, msg="Query of mcp servers list successful") + + +@router.post("/mcp_market_config", response_model=ApiResponse) +async def create_mcp_market_config( + create_data: mcp_market_config_schema.McpMarketConfigCreate, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + create mcp market config + """ + api_logger.info( + f"Request to create a mcp market config: mcp_market_id={create_data.mcp_market_id}, tenant_id={current_user.tenant_id}, username: {current_user.username}") + + try: + api_logger.debug(f"Start creating the mcp market config: {create_data.mcp_market_id}") + # 1. Check if the mcp market name already exists + db_mcp_market_config_exist = mcp_market_config_service.get_mcp_market_config_by_mcp_market_id(db, mcp_market_id=create_data.mcp_market_id, current_user=current_user) + if db_mcp_market_config_exist: + api_logger.warning(f"The mcp market id already exists: {create_data.mcp_market_id}") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"The mcp market id already exists: {create_data.mcp_market_id}" + ) + db_mcp_market_config = mcp_market_config_service.create_mcp_market_config(db=db, mcp_market_config=create_data, current_user=current_user) + api_logger.info( + f"The mcp market config has been successfully created: (ID: {db_mcp_market_config.id})") + return success(data=jsonable_encoder(mcp_market_config_schema.McpMarketConfig.model_validate(db_mcp_market_config)), + msg="The mcp market config has been successfully created") + except Exception as e: + api_logger.error(f"The creation of the mcp market config failed: {create_data.mcp_market_id} - {str(e)}") + raise + + +@router.get("/{mcp_market_config_id}", response_model=ApiResponse) +async def get_mcp_market_config( + mcp_market_config_id: uuid.UUID, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + Retrieve mcp market config information based on mcp_market_config_id + """ + api_logger.info( + f"Obtain details of the mcp market config: mcp_market_config_id={mcp_market_config_id}, username: {current_user.username}") + + try: + # 1. Query mcp market config information from the database + api_logger.debug(f"Query mcp market config: {mcp_market_config_id}") + db_mcp_market_config = mcp_market_config_service.get_mcp_market_config_by_id(db, mcp_market_config_id=mcp_market_config_id, current_user=current_user) + if not db_mcp_market_config: + api_logger.warning(f"The mcp market config does not exist or access is denied: mcp_market_config_id={mcp_market_config_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market config does not exist or access is denied" + ) + + api_logger.info(f"mcp market config query successful: (ID: {db_mcp_market_config.id})") + return success(data=jsonable_encoder(mcp_market_config_schema.McpMarketConfig.model_validate(db_mcp_market_config)), + msg="Successfully obtained mcp market config information") + except HTTPException: + raise + except Exception as e: + api_logger.error(f"mcp market config query failed: mcp_market_config_id={mcp_market_config_id} - {str(e)}") + raise + + +@router.get("/mcp_market_id/{mcp_market_id}", response_model=ApiResponse) +async def get_mcp_market_config_by_mcp_market_id( + mcp_market_id: uuid.UUID, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + Retrieve mcp market config information based on mcp_market_id + """ + api_logger.info( + f"Request to create a mcp market config: mcp_market_id={mcp_market_id}, tenant_id={current_user.tenant_id}, username: {current_user.username}") + + try: + # 1. Query mcp market config information from the database + api_logger.debug(f"Query mcp market config: mcp_market_id={mcp_market_id}") + db_mcp_market_config = mcp_market_config_service.get_mcp_market_config_by_mcp_market_id(db, mcp_market_id=mcp_market_id, current_user=current_user) + if not db_mcp_market_config: + api_logger.warning(f"The mcp market config does not exist or access is denied: mcp_market_id={mcp_market_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market config does not exist or access is denied" + ) + + api_logger.info(f"mcp market config query successful: (ID: {db_mcp_market_config.id})") + return success(data=jsonable_encoder(mcp_market_config_schema.McpMarketConfig.model_validate(db_mcp_market_config)), + msg="Successfully obtained mcp market config information") + except HTTPException: + raise + except Exception as e: + api_logger.error(f"mcp market config query failed: mcp_market_id={mcp_market_id} - {str(e)}") + raise + + +@router.put("/{mcp_market_config_id}", response_model=ApiResponse) +async def update_mcp_market_config( + mcp_market_config_id: uuid.UUID, + update_data: mcp_market_config_schema.McpMarketConfigUpdate, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + # 1. Check if the mcp market config exists + api_logger.debug(f"Query the mcp market config to be updated: {mcp_market_config_id}") + db_mcp_market_config = mcp_market_config_service.get_mcp_market_config_by_id(db, mcp_market_config_id=mcp_market_config_id, current_user=current_user) + + if not db_mcp_market_config: + api_logger.warning( + f"The mcp market config does not exist or you do not have permission to access it: mcp_market_config_id={mcp_market_config_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market config does not exist or you do not have permission to access it" + ) + + # 2. Update fields (only update non-null fields) + api_logger.debug(f"Start updating the mcp market config fields: {mcp_market_config_id}") + update_dict = update_data.dict(exclude_unset=True) + updated_fields = [] + for field, value in update_dict.items(): + if hasattr(db_mcp_market_config, field): + old_value = getattr(db_mcp_market_config, field) + if old_value != value: + # update value + setattr(db_mcp_market_config, field, value) + updated_fields.append(f"{field}: {old_value} -> {value}") + + if updated_fields: + api_logger.debug(f"updated fields: {', '.join(updated_fields)}") + + # 3. Save to database + try: + db.commit() + db.refresh(db_mcp_market_config) + api_logger.info(f"The mcp market config has been successfully updated: (ID: {db_mcp_market_config.id})") + except Exception as e: + db.rollback() + api_logger.error(f"The mcp market config update failed: mcp_market_config_id={mcp_market_config_id} - {str(e)}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"The mcp market config update failed: {str(e)}" + ) + + # 4. Return the updated mcp market config + return success(data=jsonable_encoder(mcp_market_config_schema.McpMarketConfig.model_validate(db_mcp_market_config)), + msg="The mcp market config information updated successfully") + + +@router.delete("/{mcp_market_config_id}", response_model=ApiResponse) +async def delete_mcp_market_config( + mcp_market_config_id: uuid.UUID, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + delete mcp market config + """ + api_logger.info(f"Request to delete mcp market config: mcp_market_config_id={mcp_market_config_id}, username: {current_user.username}") + + try: + # 1. Check whether the mcp market config exists + api_logger.debug(f"Check whether the mcp market config exists: {mcp_market_config_id}") + db_mcp_market_config = mcp_market_config_service.get_mcp_market_config_by_id(db, mcp_market_config_id=mcp_market_config_id, current_user=current_user) + + if not db_mcp_market_config: + api_logger.warning( + f"The mcp market config does not exist or you do not have permission to access it: mcp_market_config_id={mcp_market_config_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market config does not exist or you do not have permission to access it" + ) + + # 2. Deleting mcp market config + mcp_market_config_service.delete_mcp_market_config_by_id(db, mcp_market_config_id=mcp_market_config_id, current_user=current_user) + api_logger.info(f"The mcp market config has been successfully deleted: (ID: {mcp_market_config_id})") + return success(msg="The mcp market config has been successfully deleted") + except Exception as e: + api_logger.error(f"Failed to delete from the mcp market config: mcp_market_config_id={mcp_market_config_id} - {str(e)}") + raise diff --git a/api/app/controllers/mcp_market_controller.py b/api/app/controllers/mcp_market_controller.py new file mode 100644 index 00000000..61531a0f --- /dev/null +++ b/api/app/controllers/mcp_market_controller.py @@ -0,0 +1,262 @@ +import datetime +import json +from typing import Optional +import uuid + +from fastapi import APIRouter, Depends, HTTPException, status, Query +from fastapi.encoders import jsonable_encoder +from sqlalchemy import or_ +from sqlalchemy.orm import Session + +from app.core.logging_config import get_api_logger +from app.core.response_utils import success, fail +from app.db import get_db +from app.dependencies import get_current_user +from app.models import mcp_market_model +from app.models.user_model import User +from app.schemas import mcp_market_schema +from app.schemas.response_schema import ApiResponse +from app.services import mcp_market_service + +# Obtain a dedicated API logger +api_logger = get_api_logger() + +router = APIRouter( + prefix="/mcp_markets", + tags=["mcp_markets"], + dependencies=[Depends(get_current_user)] # Apply auth to all routes in this controller +) + + +@router.get("/mcp_markets", response_model=ApiResponse) +async def get_mcp_markets( + page: int = Query(1, gt=0), # Default: 1, which must be greater than 0 + pagesize: int = Query(20, gt=0, le=100), # Default: 20 items per page, maximum: 100 items + orderby: Optional[str] = Query(None, description="Sort fields, such as: category, created_at"), + desc: Optional[bool] = Query(False, description="Is it descending order"), + keywords: Optional[str] = Query(None, description="Search keywords (mcp_market base name)"), + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + Query the mcp markets list in pages + - Support keyword search for name,description + - Support dynamic sorting + - Return paging metadata + mcp_market list + """ + api_logger.info( + f"Query mcp market list: tenant_id={current_user.tenant_id}, page={page}, pagesize={pagesize}, keywords={keywords}, username: {current_user.username}") + + # 1. parameter validation + if page < 1 or pagesize < 1: + api_logger.warning(f"Error in paging parameters: page={page}, pagesize={pagesize}") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="The paging parameter must be greater than 0" + ) + + # 2. Construct query conditions + filters = [] + + # Keyword search (fuzzy matching of mcp market name,description) + if keywords: + api_logger.debug(f"Add keyword search criteria: {keywords}") + filters.append( + or_( + mcp_market_model.McpMarket.name.ilike(f"%{keywords}%"), + mcp_market_model.McpMarket.description.ilike(f"%{keywords}%") + ) + ) + # 3. Execute paged query + try: + api_logger.debug("Start executing mcp market paging query") + total, items = mcp_market_service.get_mcp_markets_paginated( + db=db, + filters=filters, + page=page, + pagesize=pagesize, + orderby=orderby, + desc=desc, + current_user=current_user + ) + api_logger.info(f"mcp market query successful: total={total}, returned={len(items)} records") + except Exception as e: + api_logger.error(f"mcp market query failed: {str(e)}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Query failed: {str(e)}" + ) + + # 4. Return structured response + result = { + "items": items, + "page": { + "page": page, + "pagesize": pagesize, + "total": total, + "has_next": True if page * pagesize < total else False + } + } + return success(data=jsonable_encoder(result), msg="Query of mcp market list successful") + + +@router.post("/mcp_market", response_model=ApiResponse) +async def create_mcp_market( + create_data: mcp_market_schema.McpMarketCreate, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + create mcp market + """ + api_logger.info( + f"Request to create a mcp market: name={create_data.name}, tenant_id={current_user.tenant_id}, username: {current_user.username}") + + try: + api_logger.debug(f"Start creating the mcp market: {create_data.name}") + # 1. Check if the mcp market name already exists + db_mcp_market_exist = mcp_market_service.get_mcp_market_by_name(db, name=create_data.name, current_user=current_user) + if db_mcp_market_exist: + api_logger.warning(f"The mcp market name already exists: {create_data.name}") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"The mcp market name already exists: {create_data.name}" + ) + db_mcp_market = mcp_market_service.create_mcp_market(db=db, mcp_market=create_data, current_user=current_user) + api_logger.info( + f"The mcp market has been successfully created: {db_mcp_market.name} (ID: {db_mcp_market.id})") + return success(data=jsonable_encoder(mcp_market_schema.McpMarket.model_validate(db_mcp_market)), + msg="The mcp market has been successfully created") + except Exception as e: + api_logger.error(f"The creation of the mcp market failed: {create_data.name} - {str(e)}") + raise + + +@router.get("/{mcp_market_id}", response_model=ApiResponse) +async def get_mcp_market( + mcp_market_id: uuid.UUID, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + Retrieve mcp market information based on mcp_market_id + """ + api_logger.info( + f"Obtain details of the mcp market: mcp_market_id={mcp_market_id}, username: {current_user.username}") + + try: + # 1. Query mcp market information from the database + api_logger.debug(f"Query mcp market: {mcp_market_id}") + db_mcp_market = mcp_market_service.get_mcp_market_by_id(db, mcp_market_id=mcp_market_id, current_user=current_user) + if not db_mcp_market: + api_logger.warning(f"The mcp market does not exist or access is denied: mcp_market_id={mcp_market_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market does not exist or access is denied" + ) + + api_logger.info(f"mcp market query successful: {db_mcp_market.name} (ID: {db_mcp_market.id})") + return success(data=jsonable_encoder(mcp_market_schema.McpMarket.model_validate(db_mcp_market)), + msg="Successfully obtained mcp market information") + except HTTPException: + raise + except Exception as e: + api_logger.error(f"mcp market query failed: mcp_market_id={mcp_market_id} - {str(e)}") + raise + + +@router.put("/{mcp_market_id}", response_model=ApiResponse) +async def update_mcp_market( + mcp_market_id: uuid.UUID, + update_data: mcp_market_schema.McpMarketUpdate, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + # 1. Check if the mcp market exists + api_logger.debug(f"Query the mcp market to be updated: {mcp_market_id}") + db_mcp_market = mcp_market_service.get_mcp_market_by_id(db, mcp_market_id=mcp_market_id, current_user=current_user) + + if not db_mcp_market: + api_logger.warning( + f"The mcp market does not exist or you do not have permission to access it: mcp_market_id={mcp_market_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market does not exist or you do not have permission to access it" + ) + + # 2. not updating the name (name already exists) + update_dict = update_data.dict(exclude_unset=True) + if "name" in update_dict: + name = update_dict["name"] + if name != db_mcp_market.name: + # Check if the mcp market name already exists + db_mcp_market_exist = mcp_market_service.get_mcp_market_by_name(db, name=name, current_user=current_user) + if db_mcp_market_exist: + api_logger.warning(f"The mcp market name already exists: {name}") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"The mcp market name already exists: {name}" + ) + # 3. Update fields (only update non-null fields) + api_logger.debug(f"Start updating the mcp market fields: {mcp_market_id}") + updated_fields = [] + for field, value in update_dict.items(): + if hasattr(db_mcp_market, field): + old_value = getattr(db_mcp_market, field) + if old_value != value: + # update value + setattr(db_mcp_market, field, value) + updated_fields.append(f"{field}: {old_value} -> {value}") + + if updated_fields: + api_logger.debug(f"updated fields: {', '.join(updated_fields)}") + + # 4. Save to database + try: + db.commit() + db.refresh(db_mcp_market) + api_logger.info(f"The mcp market has been successfully updated: {db_mcp_market.name} (ID: {db_mcp_market.id})") + except Exception as e: + db.rollback() + api_logger.error(f"The mcp market update failed: mcp_market_id={mcp_market_id} - {str(e)}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"The mcp market update failed: {str(e)}" + ) + + # 5. Return the updated mcp market + return success(data=jsonable_encoder(mcp_market_schema.McpMarket.model_validate(db_mcp_market)), + msg="The mcp market information updated successfully") + + +@router.delete("/{mcp_market_id}", response_model=ApiResponse) +async def delete_mcp_market( + mcp_market_id: uuid.UUID, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user) +): + """ + delete mcp market + """ + api_logger.info(f"Request to delete mcp market: mcp_market_id={mcp_market_id}, username: {current_user.username}") + + try: + # 1. Check whether the mcp market exists + api_logger.debug(f"Check whether the mcp market exists: {mcp_market_id}") + db_mcp_market = mcp_market_service.get_mcp_market_by_id(db, mcp_market_id=mcp_market_id, current_user=current_user) + + if not db_mcp_market: + api_logger.warning( + f"The mcp market does not exist or you do not have permission to access it: mcp_market_id={mcp_market_id}") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="The mcp market does not exist or you do not have permission to access it" + ) + + # 2. Deleting mcp market + mcp_market_service.delete_mcp_market_by_id(db, mcp_market_id=mcp_market_id, current_user=current_user) + api_logger.info(f"The mcp market has been successfully deleted: (ID: {mcp_market_id})") + return success(msg="The mcp market has been successfully deleted") + except Exception as e: + api_logger.error(f"Failed to delete from the mcp market: mcp_market_id={mcp_market_id} - {str(e)}") + raise diff --git a/api/app/models/__init__.py b/api/app/models/__init__.py index daf03841..b1b723e9 100644 --- a/api/app/models/__init__.py +++ b/api/app/models/__init__.py @@ -9,6 +9,8 @@ from .generic_file_model import GenericFile from .models_model import ModelConfig, ModelProvider, ModelType, ModelApiKey, ModelBase, LoadBalanceStrategy from .memory_short_model import ShortTermMemory, LongTermMemory from .knowledgeshare_model import KnowledgeShare +from .mcp_market_model import McpMarket +from .mcp_market_config_model import McpMarketConfig from .app_model import App from .agent_app_config_model import AgentConfig from .app_release_model import AppRelease @@ -50,6 +52,8 @@ __all__ = [ "ModelType", "ModelApiKey", "KnowledgeShare", + "McpMarket", + "McpMarketConfig", "App", "AgentConfig", "AppRelease", diff --git a/api/app/models/mcp_market_config_model.py b/api/app/models/mcp_market_config_model.py new file mode 100644 index 00000000..a7051a91 --- /dev/null +++ b/api/app/models/mcp_market_config_model.py @@ -0,0 +1,16 @@ +import datetime +import uuid +from sqlalchemy import Column, Integer, String, DateTime, ForeignKey +from sqlalchemy.dialects.postgresql import UUID +from app.db import Base + +class McpMarketConfig(Base): + __tablename__ = "mcp_market_configs" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) + mcp_market_id = Column(UUID(as_uuid=True), nullable=False, comment="mcp_markets.id") + token = Column(String, nullable=True, comment="mcp market token") + status = Column(Integer, default=0, comment="connect status(0: Not connected, 1: connected)") + tenant_id = Column(UUID(as_uuid=True), nullable=False, comment="tenant.id") + created_by = Column(UUID(as_uuid=True), nullable=False, comment="users.id") + created_at = Column(DateTime, default=datetime.datetime.now) \ No newline at end of file diff --git a/api/app/models/mcp_market_model.py b/api/app/models/mcp_market_model.py new file mode 100644 index 00000000..95c9cec4 --- /dev/null +++ b/api/app/models/mcp_market_model.py @@ -0,0 +1,18 @@ +import datetime +import uuid +from sqlalchemy import Column, Integer, String, DateTime, ForeignKey +from sqlalchemy.dialects.postgresql import UUID +from app.db import Base + +class McpMarket(Base): + __tablename__ = "mcp_markets" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) + name = Column(String, index=True, nullable=False, comment="mcp market name") + description = Column(String, index=True, nullable=True, comment="mcp market description") + logo_url = Column(String, index=True, nullable=True, comment="logo url") + mcp_count = Column(Integer, default=1, comment="mcp count") + url = Column(String, index=True, nullable=False, comment="mcp market url") + category = Column(String, index=True, nullable=False, comment="category") + created_by = Column(UUID(as_uuid=True), nullable=False, comment="users.id") + created_at = Column(DateTime, default=datetime.datetime.now) \ No newline at end of file diff --git a/api/app/repositories/mcp_market_config_repository.py b/api/app/repositories/mcp_market_config_repository.py new file mode 100644 index 00000000..ec31becf --- /dev/null +++ b/api/app/repositories/mcp_market_config_repository.py @@ -0,0 +1,72 @@ +import uuid +import datetime +from sqlalchemy.orm import Session +from app.models.mcp_market_config_model import McpMarketConfig +from app.schemas import mcp_market_config_schema +from app.core.logging_config import get_db_logger + +# Obtain a dedicated logger for the database +db_logger = get_db_logger() + + +def create_mcp_market_config(db: Session, mcp_market_config: mcp_market_config_schema.McpMarketConfigCreate) -> McpMarketConfig: + db_logger.debug(f"Create a mcp market config record: mcp_market_id={mcp_market_config.mcp_market_id}") + + try: + db_mcp_market_config = McpMarketConfig(**mcp_market_config.model_dump()) + db.add(db_mcp_market_config) + db.commit() + db_logger.info(f"McpMarketConfig record created successfully: {mcp_market_config.mcp_market_id} (ID: {db_mcp_market_config.id})") + return db_mcp_market_config + except Exception as e: + db_logger.error(f"Failed to create a mcp market config record: mcp_market_id={mcp_market_config.mcp_market_id} - {str(e)}") + db.rollback() + raise + + +def get_mcp_market_config_by_id(db: Session, mcp_market_config_id: uuid.UUID) -> McpMarketConfig | None: + db_logger.debug(f"Query mcp market config based on ID: mcp_market_config_id={mcp_market_config_id}") + + try: + db_mcp_market_config = db.query(McpMarketConfig).filter(McpMarketConfig.id == mcp_market_config_id).first() + if db_mcp_market_config: + db_logger.debug(f"McpMarketConfig query successful: (ID: {mcp_market_config_id})") + else: + db_logger.debug(f"McpMarketConfig does not exist: mcp_market_config_id={mcp_market_config_id}") + return db_mcp_market_config + except Exception as e: + db_logger.error(f"Failed to query the mcp market config based on the ID: {mcp_market_config_id} - {str(e)}") + raise + + +def get_mcp_market_config_by_mcp_market_id(db: Session, mcp_market_id: uuid.UUID, tenant_id: uuid.UUID) -> McpMarketConfig | None: + db_logger.debug(f"Query mcp market config based on mcp_market_id: {mcp_market_id}") + + try: + db_mcp_market_config = db.query(McpMarketConfig).filter(McpMarketConfig.mcp_market_id == mcp_market_id, McpMarketConfig.tenant_id == tenant_id).first() + if db_mcp_market_config: + db_logger.debug(f"McpMarketConfig query successful: (mcp_market_id: {mcp_market_id})") + else: + db_logger.debug(f"McpMarketConfig does not exist: mcp_market_id={mcp_market_id}") + return db_mcp_market_config + except Exception as e: + db_logger.error(f"Failed to query the mcp market config based on the mcp_market_id: {mcp_market_id} - {str(e)}") + raise + + +def delete_mcp_market_config_by_id(db: Session, mcp_market_config_id: uuid.UUID): + db_logger.debug(f"Delete McpMarketConfig record: mcp_market_config_id={mcp_market_config_id}") + + try: + # First, query the mcp market config information for logging purposes + result = db.query(McpMarketConfig).filter(McpMarketConfig.id == mcp_market_config_id).delete() + db.commit() + + if result > 0: + db_logger.info(f"McpMarketConfig record deleted successfully: (ID: {mcp_market_config_id})") + else: + db_logger.warning(f"The mcp market config record does not exist, and cannot be deleted: id={mcp_market_config_id}") + except Exception as e: + db_logger.error(f"Failed to delete mcp market config record: id={mcp_market_config_id} - {str(e)}") + db.rollback() + raise diff --git a/api/app/repositories/mcp_market_repository.py b/api/app/repositories/mcp_market_repository.py new file mode 100644 index 00000000..d5089815 --- /dev/null +++ b/api/app/repositories/mcp_market_repository.py @@ -0,0 +1,124 @@ +import uuid +import datetime +from sqlalchemy.orm import Session +from app.models.mcp_market_model import McpMarket +from app.schemas import mcp_market_schema +from app.core.logging_config import get_db_logger + +# Obtain a dedicated logger for the database +db_logger = get_db_logger() + + +def get_mcp_markets_paginated( + db: Session, + filters: list, + page: int, + pagesize: int, + orderby: str = None, + desc: bool = False +) -> tuple[int, list]: + """ + Paged query mcp market (with filtering and sorting) + """ + db_logger.debug( + f"Query mcp market in pages: page={page}, pagesize={pagesize}, orderby={orderby}, desc={desc}, filters_count={len(filters)}") + + try: + query = db.query(McpMarket) + + # Apply filter conditions + for filter_cond in filters: + query = query.filter(filter_cond) + + # Calculate the total count (for pagination) + total = query.count() + db_logger.debug(f"Total number of mcp_market queries: {total}") + + # sort + if orderby: + order_attr = getattr(McpMarket, orderby, None) + if order_attr is not None: + if desc: + query = query.order_by(order_attr.desc()) + else: + query = query.order_by(order_attr.asc()) + db_logger.debug(f"sort: {orderby}, desc={desc}") + + # pagination + items = query.offset((page - 1) * pagesize).limit(pagesize).all() + db_logger.info( + f"The mcp market paging query has been successful: total={total}, Number of current page={len(items)}") + + return total, [mcp_market_schema.McpMarket.model_validate(item) for item in items] + except Exception as e: + db_logger.error(f"Querying mcp_market pagination failed: page={page}, pagesize={pagesize} - {str(e)}") + raise + + +def create_mcp_market(db: Session, mcp_market: mcp_market_schema.McpMarketCreate) -> McpMarket: + db_logger.debug(f"Create a mcp market record: name={mcp_market.name}") + + try: + db_mcp_market = McpMarket(**mcp_market.model_dump()) + db.add(db_mcp_market) + db.commit() + db_logger.info(f"McpMarket record created successfully: {mcp_market.name} (ID: {db_mcp_market.id})") + return db_mcp_market + except Exception as e: + db_logger.error(f"Failed to create a mcp market record: title={mcp_market.name} - {str(e)}") + db.rollback() + raise + + +def get_mcp_market_by_id(db: Session, mcp_market_id: uuid.UUID) -> McpMarket | None: + db_logger.debug(f"Query mcp market based on ID: mcp_market_id={mcp_market_id}") + + try: + db_mcp_market = db.query(McpMarket).filter(McpMarket.id == mcp_market_id).first() + if db_mcp_market: + db_logger.debug(f"McpMarket query successful: {db_mcp_market.name} (ID: {mcp_market_id})") + else: + db_logger.debug(f"McpMarket does not exist: mcp_market_id={mcp_market_id}") + return db_mcp_market + except Exception as e: + db_logger.error(f"Failed to query the mcp market based on the ID: mcp_market_id={mcp_market_id} - {str(e)}") + raise + + +def get_mcp_market_by_name(db: Session, name: str) -> McpMarket | None: + db_logger.debug(f"Query mcp market based on name: name={name}") + + try: + db_mcp_market = db.query(McpMarket).filter(McpMarket.name == name).first() + if db_mcp_market: + db_logger.debug(f"mcp market query successful: {name} (ID: {db_mcp_market.id})") + else: + db_logger.debug(f"mcp market does not exist: name={name}") + return db_mcp_market + except Exception as e: + db_logger.error(f"Failed to query the mcp market based on the name: {name} - {str(e)}") + raise + + +def delete_mcp_market_by_id(db: Session, mcp_market_id: uuid.UUID): + db_logger.debug(f"Delete McpMarket record: mcp_market_id={mcp_market_id}") + + try: + # First, query the mcp market information for logging purposes + db_mcp_market = db.query(McpMarket).filter(McpMarket.id == mcp_market_id).first() + if db_mcp_market: + name = db_mcp_market.name + else: + name = "unknown" + + result = db.query(McpMarket).filter(McpMarket.id == mcp_market_id).delete() + db.commit() + + if result > 0: + db_logger.info(f"McpMarket record deleted successfully: {name} (ID: {mcp_market_id})") + else: + db_logger.warning(f"The mcp market record does not exist, and cannot be deleted: mcp_market_id={mcp_market_id}") + except Exception as e: + db_logger.error(f"Failed to delete mcp market record: mcp_market_id={mcp_market_id} - {str(e)}") + db.rollback() + raise diff --git a/api/app/schemas/__init__.py b/api/app/schemas/__init__.py index 299251f4..96c42ce7 100644 --- a/api/app/schemas/__init__.py +++ b/api/app/schemas/__init__.py @@ -8,6 +8,8 @@ from .file_schema import File, FileCreate, FileUpdate from .tenant_schema import Tenant, TenantCreate, TenantUpdate from .chunk_schema import ChunkCreate, ChunkUpdate, ChunkRetrieve from .knowledgeshare_schema import KnowledgeShare, KnowledgeShareCreate +from .mcp_market_schema import McpMarketCreate, McpMarketUpdate, McpMarket +from .mcp_market_config_schema import McpMarketConfigCreate, McpMarketConfigUpdate, McpMarketConfig from .order_schema import CreateOrderRequest, OrderResponse, ExternalOrderResponse from .app_schema import ( AppChatRequest, @@ -78,6 +80,12 @@ __all__ = [ "ChunkRetrieve", "KnowledgeShare", "KnowledgeShareCreate", + "McpMarketCreate", + "McpMarketUpdate", + "McpMarket", + "McpMarketConfigCreate", + "McpMarketConfigUpdate", + "McpMarketConfig", "CreateOrderRequest", "OrderResponse", "ExternalOrderResponse", diff --git a/api/app/schemas/mcp_market_config_schema.py b/api/app/schemas/mcp_market_config_schema.py new file mode 100644 index 00000000..c33239cf --- /dev/null +++ b/api/app/schemas/mcp_market_config_schema.py @@ -0,0 +1,31 @@ +from pydantic import BaseModel, Field, field_serializer, ConfigDict +import datetime +import uuid + + +class McpMarketConfigBase(BaseModel): + mcp_market_id: uuid.UUID + token: str | None = None + status: int | None = None + tenant_id: uuid.UUID | None = None + created_by: uuid.UUID | None = None + + +class McpMarketConfigCreate(McpMarketConfigBase): + pass + + +class McpMarketConfigUpdate(BaseModel): + token: str | None = None + status: int | None = None + + +class McpMarketConfig(McpMarketConfigBase): + id: uuid.UUID + created_at: datetime.datetime + + model_config = ConfigDict(from_attributes=True) + + @field_serializer("created_at", when_used="json") + def _serialize_created_at(self, dt: datetime.datetime): + return int(dt.timestamp() * 1000) if dt else None diff --git a/api/app/schemas/mcp_market_schema.py b/api/app/schemas/mcp_market_schema.py new file mode 100644 index 00000000..54d3b35e --- /dev/null +++ b/api/app/schemas/mcp_market_schema.py @@ -0,0 +1,37 @@ +from pydantic import BaseModel, Field, field_serializer, ConfigDict +import datetime +import uuid + + +class McpMarketBase(BaseModel): + name: str + description: str | None = None + logo_url: str | None = None + mcp_count: int + url: str + category: str + created_by: uuid.UUID | None = None + + +class McpMarketCreate(McpMarketBase): + pass + + +class McpMarketUpdate(BaseModel): + name: str | None = Field(None) + description: str | None = Field(None) + logo_url: str | None = Field(None) + mcp_count: int | None = Field(None) + url: str | None = Field(None) + category: str | None = Field(None) + + +class McpMarket(McpMarketBase): + id: uuid.UUID + created_at: datetime.datetime + + model_config = ConfigDict(from_attributes=True) + + @field_serializer("created_at", when_used="json") + def _serialize_created_at(self, dt: datetime.datetime): + return int(dt.timestamp() * 1000) if dt else None diff --git a/api/app/services/mcp_market_config_service.py b/api/app/services/mcp_market_config_service.py new file mode 100644 index 00000000..86485902 --- /dev/null +++ b/api/app/services/mcp_market_config_service.py @@ -0,0 +1,83 @@ +import uuid +from sqlalchemy.orm import Session +from app.models.user_model import User +from app.models.mcp_market_config_model import McpMarketConfig +from app.schemas.mcp_market_config_schema import McpMarketConfigCreate, McpMarketConfigUpdate +from app.repositories import mcp_market_config_repository +from app.core.logging_config import get_business_logger + +# Obtain a dedicated logger for business logic +business_logger = get_business_logger() + + +def create_mcp_market_config( + db: Session, mcp_market_config: McpMarketConfigCreate, current_user: User +) -> McpMarketConfig: + business_logger.info(f"Create a mcp market config base: {mcp_market_config.mcp_market_id}, creator: {current_user.username}") + + try: + mcp_market_config.tenant_id = current_user.tenant_id + mcp_market_config.created_by = current_user.id + business_logger.debug(f"Start creating the mcp market config on mcp_market_id: {mcp_market_config.mcp_market_id}") + db_mcp_market_config = mcp_market_config_repository.create_mcp_market_config( + db=db, mcp_market_config=mcp_market_config + ) + business_logger.info( + f"The mcp market config has been successfully created: {mcp_market_config.mcp_market_id} (ID: {db_mcp_market_config.id}), creator: {current_user.username}") + return db_mcp_market_config + except Exception as e: + business_logger.error(f"Failed to create a mcp marke config: {mcp_market_config.mcp_market_id} - {str(e)}") + raise + + +def get_mcp_market_config_by_id(db: Session, mcp_market_config_id: uuid.UUID, current_user: User) -> McpMarketConfig | None: + business_logger.debug( + f"Query mcp market config based on ID: mcp_market_config_id={mcp_market_config_id}, username: {current_user.username}") + + try: + mcpMarketConfig = mcp_market_config_repository.get_mcp_market_config_by_id(db=db, mcp_market_config_id=mcp_market_config_id) + if mcpMarketConfig: + business_logger.info(f"mcp market config query successful: (ID: {mcp_market_config_id})") + else: + business_logger.warning(f"mcp market config does not exist: mcp_market_config_id={mcp_market_config_id}") + return mcpMarketConfig + except Exception as e: + business_logger.error( + f"Failed to query the mcp market config based on the ID: {mcp_market_config_id} - {str(e)}") + raise + + +def get_mcp_market_config_by_mcp_market_id(db: Session, mcp_market_id: uuid.UUID, current_user: User) -> McpMarketConfig | None: + business_logger.debug( + f"Query mcp market config based on mcp_market_id: {mcp_market_id}, username: {current_user.username}") + + try: + mcpMarketConfig = mcp_market_config_repository.get_mcp_market_config_by_mcp_market_id(db=db, mcp_market_id=mcp_market_id, tenant_id=current_user.tenant_id) + if mcpMarketConfig: + business_logger.info(f"mcp market config query successful: (mcp_market_id: {mcp_market_id})") + else: + business_logger.warning(f"mcp market config does not exist: mcp_market_id={mcp_market_id}") + return mcpMarketConfig + except Exception as e: + business_logger.error( + f"Failed to query the mcp market config based on the mcp_market_id: {mcp_market_id} - {str(e)}") + raise + + +def delete_mcp_market_config_by_id(db: Session, mcp_market_config_id: uuid.UUID, current_user: User) -> None: + business_logger.info(f"Delete mcp market config: mcp_market_config_id={mcp_market_config_id}, operator: {current_user.username}") + + try: + # First, query the mcp market config information for logging purposes + mcpMarketConfig = mcp_market_config_repository.get_mcp_market_config_by_id(db=db, mcp_market_config_id=mcp_market_config_id) + if mcpMarketConfig: + business_logger.debug(f"Execute mcp market config deletion: (ID: {mcp_market_config_id})") + else: + business_logger.warning(f"The mcp market config to be deleted does not exist: mcp_market_config_id={mcp_market_config_id}") + + mcp_market_config_repository.delete_mcp_market_config_by_id(db=db, mcp_market_config_id=mcp_market_config_id) + business_logger.info( + f"mcp market config record deleted successfully: mcp_market_config_id={mcp_market_config_id}, operator: {current_user.username}") + except Exception as e: + business_logger.error(f"Failed to delete mcp market config: mcp_market_config_id={mcp_market_config_id} - {str(e)}") + raise diff --git a/api/app/services/mcp_market_service.py b/api/app/services/mcp_market_service.py new file mode 100644 index 00000000..6d9d26fc --- /dev/null +++ b/api/app/services/mcp_market_service.py @@ -0,0 +1,109 @@ +import uuid +from sqlalchemy.orm import Session +from app.models.user_model import User +from app.models.mcp_market_model import McpMarket +from app.schemas.mcp_market_schema import McpMarketCreate, McpMarketUpdate +from app.repositories import mcp_market_repository +from app.core.logging_config import get_business_logger + +# Obtain a dedicated logger for business logic +business_logger = get_business_logger() + + +def get_mcp_markets_paginated( + db: Session, + current_user: User, + filters: list, + page: int, + pagesize: int, + orderby: str = None, + desc: bool = False +) -> tuple[int, list]: + business_logger.debug( + f"Query mcp market in pages: username={current_user.username}, page={page}, pagesize={pagesize}, orderby={orderby}, desc={desc}") + + try: + total, items = mcp_market_repository.get_mcp_markets_paginated( + db=db, + filters=filters, + page=page, + pagesize=pagesize, + orderby=orderby, + desc=desc + ) + business_logger.info( + f"The mcp market paging query has been successful: username={current_user.username}, total={total}, Number of current page={len(items)}") + return total, items + except Exception as e: + business_logger.error(f"Querying mcp market pagination failed: username={current_user.username} - {str(e)}") + raise + + +def create_mcp_market( + db: Session, mcp_market: McpMarketCreate, current_user: User +) -> McpMarket: + business_logger.info(f"Create a mcp market base: {mcp_market.name}, creator: {current_user.username}") + + try: + mcp_market.created_by = current_user.id + business_logger.debug(f"Start creating the mcp market: {mcp_market.name}") + db_mcp_market = mcp_market_repository.create_mcp_market( + db=db, mcp_market=mcp_market + ) + business_logger.info( + f"The mcp market has been successfully created: {mcp_market.name} (ID: {db_mcp_market.id}), creator: {current_user.username}") + return db_mcp_market + except Exception as e: + business_logger.error(f"Failed to create a mcp market: {mcp_market.name} - {str(e)}") + raise + + +def get_mcp_market_by_id(db: Session, mcp_market_id: uuid.UUID, current_user: User) -> McpMarket | None: + business_logger.debug( + f"Query mcp market based on ID: mcp_market_id={mcp_market_id}, username: {current_user.username}") + + try: + mcpMarket = mcp_market_repository.get_mcp_market_by_id(db=db, mcp_market_id=mcp_market_id) + if mcpMarket: + business_logger.info(f"mcp market query successful: {mcpMarket.name} (ID: {mcp_market_id})") + else: + business_logger.warning(f"mcp market does not exist: mcp_market_id={mcp_market_id}") + return mcpMarket + except Exception as e: + business_logger.error( + f"Failed to query the mcp market based on the ID: {mcp_market_id} - {str(e)}") + raise + + +def get_mcp_market_by_name(db: Session, name: str, current_user: User) -> McpMarket | None: + business_logger.debug(f"Query mcp market based on name: name={name}, username: {current_user.username}") + + try: + db_mcp_market = mcp_market_repository.get_mcp_market_by_name(db=db, name=name) + if db_mcp_market: + business_logger.info(f"mcp market query successful: {name} (ID: {db_mcp_market.id})") + else: + business_logger.warning(f"mcp market does not exist: name={name}") + return db_mcp_market + except Exception as e: + business_logger.error(f"Failed to query the mcp market based on the name: name={name} - {str(e)}") + raise + + +def delete_mcp_market_by_id(db: Session, mcp_market_id: uuid.UUID, current_user: User) -> None: + business_logger.info(f"Delete mcp market: mcp_market_id={mcp_market_id}, operator: {current_user.username}") + + try: + # First, query the mcp market information for logging purposes + mcpMarket = mcp_market_repository.get_mcp_market_by_id(db=db, mcp_market_id=mcp_market_id) + if mcpMarket: + business_logger.debug(f"Execute mcp market deletion: {mcpMarket.name} (ID: {mcp_market_id})") + else: + business_logger.warning(f"The mcp market to be deleted does not exist: mcp_market_id={mcp_market_id}") + + mcp_market_repository.delete_mcp_market_by_id(db=db, mcp_market_id=mcp_market_id) + business_logger.info( + f"mcp market record deleted successfully: mcp_market_id={mcp_market_id}, operator: {current_user.username}") + except Exception as e: + business_logger.error(f"Failed to delete mcp market: mcp_market_id={mcp_market_id} - {str(e)}") + raise diff --git a/api/pyproject.toml b/api/pyproject.toml index 66b1a295..51c0b3e3 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -143,6 +143,7 @@ dependencies = [ "owlready2>=0.46", "lxml>=4.9.0", "httpx>=0.28.0", + "modelscope>=1.34.0", ] [tool.pytest.ini_options] diff --git a/api/requirements.txt b/api/requirements.txt index 144c0db2..2cdd2bd0 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -136,3 +136,4 @@ boto3>=1.28.0 aiofiles>=23.0.0 lxml>=4.9.0 httpx>=0.28.0 +modelscope>=1.34.0