Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import lombok.Getter;
import lombok.Setter;
import org.springaicommunity.mcp.annotation.McpToolParam;

/**
* CreateCleaningTaskRequest
Expand All @@ -14,21 +15,29 @@
@Getter
@Setter
public class CreateCleaningTaskRequest {
@McpToolParam(description = "新建清洗任务名称")
private String name;

private String name;
@McpToolParam(description = "新建清洗任务描述")
private String description;

private String description;
@McpToolParam(description = "清洗任务使用的源数据集ID")
private String srcDatasetId;

private String srcDatasetId;
@McpToolParam(description = "清洗任务使用的源数据集名称")
private String srcDatasetName;

private String srcDatasetName;
@McpToolParam(description = "清洗任务创建的目标数据集名称")
private String destDatasetName;

private String destDatasetName;
@McpToolParam(description = "清洗任务创建的目标数据集类型,取值范围为TEXT/IMAGE/VIDEO/AUDIO/OTHER")
private String destDatasetType;

private String destDatasetType;
@McpToolParam(description = "清洗任务使用的模板名称,与instance参数二选一,至少指定一个,优先级更高", required = false)
private String templateId;

private String templateId;

private List<OperatorInstanceDto> instance = new ArrayList<>();
@McpToolParam(description = "清洗任务使用的算子列表,与templateId参数二选一,至少指定一个。" +
"注意:单个任务只能使用一种归属的算子,无法混合使用,如全部使用DataMate算子或全部使用DataJuicer算子。", required = false)
private List<OperatorInstanceDto> instance = new ArrayList<>();
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import lombok.Getter;
import lombok.Setter;
import org.springaicommunity.mcp.annotation.McpToolParam;

/**
* OperatorInstance
Expand All @@ -15,17 +16,22 @@
@Getter
@Setter
public class OperatorInstanceDto {

@McpToolParam(description = "算子ID")
private String id;

@McpToolParam(description = "算子名称")
private String name;

@McpToolParam(description = "算子输入类型,取值范围为text/image/audio/video/multimodal")
private String inputs;

@McpToolParam(description = "算子输出类型,取值范围为text/image/audio/video/multimodal")
private String outputs;

@McpToolParam(description = "算子所属分类的所有ID组成的列表。", required = false)
private List<String> categories;

@McpToolParam(description = "算子需要覆盖的参数", required = false)
private Map<String, Object> overrides = new HashMap<>();
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.datamate.common.interfaces.PagedResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand All @@ -28,7 +30,9 @@ public PagedResponse<CleaningTaskDto> cleaningTasksGet(
}

@PostMapping
public CleaningTaskDto cleaningTasksPost(@RequestBody CreateCleaningTaskRequest request) {
@McpTool(name = "create_cleaning_task", description = "根据模板ID或算子列表创建清洗任务。")
public CleaningTaskDto cleaningTasksPost(@McpToolParam(description = "创建任务请求体,需要将参数包装在request对象中。")
@RequestBody CreateCleaningTaskRequest request) {
if (request.getInstance().isEmpty() && StringUtils.isNotBlank(request.getTemplateId())) {
request.setInstance(cleaningTaskService.getInstanceByTemplateId(request.getTemplateId()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import com.datamate.cleaning.interfaces.dto.UpdateCleaningTemplateRequest;
import com.datamate.common.interfaces.PagedResponse;
import lombok.RequiredArgsConstructor;
import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -27,10 +29,14 @@ public class CleaningTemplateController {
private final CleaningTemplateService cleaningTemplateService;

@GetMapping
@McpTool(name = "query_cleaning_template", description = "查询模板列表")
public PagedResponse<CleaningTemplateDto> cleaningTemplatesGet(
@RequestParam(value = "page", required = false) Integer page,
@RequestParam(value = "size", required = false) Integer size,
@RequestParam(value = "keyword", required = false) String keyword) {
@RequestParam(value = "page", required = false)
@McpToolParam(description = "页码,从0开始", required = false) Integer page,
@RequestParam(value = "size", required = false)
@McpToolParam(description = "每页大小", required = false) Integer size,
@RequestParam(value = "keyword", required = false)
@McpToolParam(description = "关键词,从名称与描述中查询", required = false) String keyword) {
List<CleaningTemplateDto> templates = cleaningTemplateService.getTemplates(keyword);
if (page == null || size == null) {
return PagedResponse.of(templates.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springaicommunity.mcp.annotation.McpToolParam;

import java.util.List;

Expand All @@ -22,19 +23,26 @@ public class CreateDatasetRequest {
/** 数据集名称 */
@Size(min = 1, max = 100)
@NotBlank(message = "数据集名称不能为空")
@McpToolParam(description = "数据集名称")
private String name;
/** 数据集描述 */
@Size(max = 500)
@McpToolParam(description = "数据集描述", required = false)
private String description;
/** 数据集类型 */
@NotNull(message = "数据集类型不能为空")
@McpToolParam(description = "数据集类型,取值范围为TEXT/IMAGE/VIDEO/AUDIO/OTHER")
private DatasetType datasetType;
/** 标签列表 */
@McpToolParam(description = "标签列表", required = false)
private List<String> tags;
/** 数据源 */
@McpToolParam(description = "数据源", required = false)
private String dataSource;
/** 保留天数 */
@McpToolParam(description = "保留天数", required = false)
private Integer retentionDays;
/** 数据集状态 */
@McpToolParam(description = "数据集状态", required = false)
private String status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springaicommunity.mcp.annotation.McpToolParam;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -23,20 +24,24 @@ public class DatasetPagingQuery extends PagingQuery {
/**
* 数据集类型过滤
*/
@McpToolParam(description = "数据集类型过滤,取值范围为text/image/video/audio/other", required = false)
private DatasetType type;

/**
* 标签名过滤
*/
@McpToolParam(description = "标签名过滤", required = false)
private List<String> tags = new ArrayList<>();

/**
* 关键词搜索(名称或描述)
*/
@McpToolParam(description = "关键词搜索(名称或描述)", required = false)
private String keyword;

/**
* 状态过滤
*/
@McpToolParam(description = "状态过滤", required = false)
private DatasetStatusType status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springaicommunity.mcp.annotation.McpTool;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -34,6 +35,7 @@ public class DatasetController {
* @return 分页的数据集列表
*/
@GetMapping
@McpTool(name = "query_datasets", description = "根据参数查询满足条件的数据集列表")
public PagedResponse<DatasetResponse> getDatasets(DatasetPagingQuery query) {
return datasetApplicationService.getDatasets(query);
}
Expand All @@ -45,6 +47,7 @@ public PagedResponse<DatasetResponse> getDatasets(DatasetPagingQuery query) {
* @return 创建的数据集响应
*/
@PostMapping
@McpTool(name = "create_dataset", description = "创建数据集")
public DatasetResponse createDataset(@RequestBody @Valid CreateDatasetRequest createDatasetRequest) {
Dataset dataset = datasetApplicationService.createDataset(createDatasetRequest);
return DatasetConverter.INSTANCE.convertToResponse(dataset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ spring:
min-idle: 5
max-wait: 1000ms

ai:
mcp:
server:
enabled: true
name: datamate-mcp-server
protocol: STATELESS
capabilities:
completion: false
resource: false
prompt: false
tool: true
mcp-endpoint: /mcp


# MyBatis配置(需在顶层,不在 spring 下)
mybatis-plus:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.datamate.common.interfaces.PagingQuery;
import lombok.Getter;
import lombok.Setter;
import org.springaicommunity.mcp.annotation.McpToolParam;

/**
* OperatorsListPostRequest
Expand All @@ -15,12 +16,16 @@
@Getter
@Setter
public class OperatorsListPostRequest extends PagingQuery {
private List<List<String>> categories = new ArrayList<>();
@McpToolParam(description = "算子分类id列表,每个父分类下的id放到一个列表中,最后汇总成一个大的列表", required = false)
private List<List<String>> categories = new ArrayList<>();

private String keyword;
@McpToolParam(description = "算子关键词,支持查询算子名称和算子描述关键词查询", required = false)
private String keyword;

private String labelName;
@McpToolParam(description = "算子关联的标签名称,当前暂不支持", required = false)
private String labelName;

private Boolean isStar;
@McpToolParam(description = "算子是否被收藏", required = false)
private Boolean isStar;
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.datamate.operator.interfaces.dto.CategoryTreePagedResponse;
import com.datamate.operator.interfaces.dto.CategoryTreeResponse;
import lombok.RequiredArgsConstructor;
import org.springaicommunity.mcp.annotation.McpTool;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -22,6 +23,8 @@ public class CategoryController {
private final OperatorRepository operatorRepo;

@GetMapping("/tree")
@McpTool(name = "query_category_tree",
description = "算子树状分类查询,获取包含分组维度(如语言、模态)及资源统计数量的分页层级分类数据。")
public PagedResponse<CategoryTreeResponse> categoryTreeGet() {
List<CategoryTreeResponse> allCategories = categoryService.getAllCategories();
return CategoryTreePagedResponse.of(allCategories, operatorRepo.countOperatorByStar(true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.datamate.operator.interfaces.dto.OperatorsListPostRequest;
import com.datamate.operator.interfaces.dto.UploadOperatorRequest;
import lombok.RequiredArgsConstructor;
import org.springaicommunity.mcp.annotation.McpTool;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
Expand All @@ -24,6 +25,7 @@ public class OperatorController {
private final OperatorService operatorService;

@PostMapping("/list")
@McpTool(name = "query_operator_list", description = "根据参数查询算子列表")
public PagedResponse<OperatorDto> operatorsListPost(@RequestBody OperatorsListPostRequest request) {
List<List<String>> categories = request.getCategories();
List<OperatorDto> responses = operatorService.getOperators(request.getPage(), request.getSize(),
Expand Down
6 changes: 6 additions & 0 deletions backend/services/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springaicommunity.mcp.annotation.McpToolParam;

@Getter
@NoArgsConstructor
public class PagingQuery {
/**
* 页码,从0开始
*/
@McpToolParam(description = "页码,从0开始")
private Integer page = 0;

/**
* 每页大小
*/
@McpToolParam(description = "每页大小")
private Integer size = 20;

public void setPage(Integer page) {
Expand Down
4 changes: 4 additions & 0 deletions runtime/datamate-python/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi_mcp import FastApiMCP
from sqlalchemy import text
from starlette.exceptions import HTTPException as StarletteHTTPException

Expand Down Expand Up @@ -102,6 +103,9 @@ async def root():
}
)

mcp = FastApiMCP(app, name="DataMate MCP", description="DataMate python mcp server", include_tags=["mcp"])
mcp.mount_http(mount_path="/api/mcp")

if __name__ == "__main__":
import uvicorn

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
logger = get_logger(__name__)


@router.post("", response_model=StandardResponse[CollectionTaskBase])
@router.post("", response_model=StandardResponse[CollectionTaskBase], operation_id="create_collect_task", tags=["mcp"])
async def create_task(
request: CollectionTaskCreate,
db: AsyncSession = Depends(get_db)
Expand Down
Loading
Loading