Newer
Older
TelosDB / src / backend / src / mcp / tools / registry.rs
//! MCP ツールの一覧定義。ツール追加時はここと dispatch_tool の match の両方に追加すること。

/// tools/list で返すツール定義の配列。
pub fn tool_list() -> Vec<serde_json::Value> {
    vec![
        serde_json::json!({
            "name": "get_item_by_id",
            "description": "Get a specific document chunk by ID",
            "inputSchema": {
                "type": "object",
                "properties": { "id": { "type": "integer" } },
                "required": ["id"]
            }
        }),
        serde_json::json!({
            "name": "add_item_text",
            "description": "Add or overwrite a document by path. Chunks are generated automatically.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "content": { "type": "string" },
                    "path": { "type": "string" },
                    "mime": { "type": "string" },
                    "category": { "type": "string", "description": "Optional. Category label for the document." }
                },
                "required": ["content", "path"]
            }
        }),
        serde_json::json!({
            "name": "search_text",
            "description": "Search document chunks using Hybrid Hybrid/Vector search (BM25 + LSA/HNSW)",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "content": { "type": "string" },
                    "limit": { "type": "integer", "default": 5 },
                    "min_score": { "type": "number", "default": 0.3, "description": "Minimum similarity (0-1). Results below this are dropped. Default 0.3." },
                    "category": { "type": "string", "description": "Optional. Filter results to a specific category." }
                },
                "required": ["content"]
            }
        }),
        serde_json::json!({
            "name": "update_item",
            "description": "Update an existing chunk's content",
            "inputSchema": {
                "type": "object",
                "properties": { "id": { "type": "integer" }, "content": { "type": "string" } },
                "required": ["id", "content"]
            }
        }),
        serde_json::json!({
            "name": "delete_item",
            "description": "Delete a chunk by ID",
            "inputSchema": {
                "type": "object",
                "properties": { "id": { "type": "integer" } },
                "required": ["id"]
            }
        }),
        serde_json::json!({
            "name": "list_documents",
            "description": "List documents with paging (path, mime, chunk count, category). Returns items, total_count, total_pages, page.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "limit": { "type": "integer", "default": 20, "description": "Items per page (1–100). Default 20." },
                    "page": { "type": "integer", "default": 1, "description": "1-based page number. Out-of-range returns empty items." }
                }
            }
        }),
        serde_json::json!({
            "name": "list_categories",
            "description": "List distinct category names assigned to documents (for search_text category filter)",
            "inputSchema": { "type": "object", "properties": {} }
        }),
        serde_json::json!({
            "name": "get_document_count",
            "description": "Get the total count of documents stored in the database",
            "inputSchema": { "type": "object", "properties": {} }
        }),
        serde_json::json!({
            "name": "get_document",
            "description": "Get full document content by document ID",
            "inputSchema": {
                "type": "object",
                "properties": { "document_id": { "type": "integer" }, "id": { "type": "integer" } }
            }
        }),
        serde_json::json!({
            "name": "delete_document",
            "description": "Delete a document and all its chunks",
            "inputSchema": {
                "type": "object",
                "properties": { "document_id": { "type": "integer" }, "id": { "type": "integer" } }
            }
        }),
        serde_json::json!({
            "name": "lsa_retrain",
            "description": "Manually trigger LSA model retraining and vector rebuild",
            "inputSchema": { "type": "object", "properties": {} }
        }),
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn tool_list_has_expected_tools() {
        let list = tool_list();
        let names: Vec<String> = list
            .iter()
            .filter_map(|v| v.get("name").and_then(|n| n.as_str()).map(String::from))
            .collect();
        let expected = [
            "get_item_by_id",
            "add_item_text",
            "search_text",
            "update_item",
            "delete_item",
            "list_documents",
            "list_categories",
            "get_document_count",
            "get_document",
            "delete_document",
            "lsa_retrain",
        ];
        assert_eq!(list.len(), expected.len(), "tool_list length");
        for name in &expected {
            assert!(names.contains(&name.to_string()), "tool_list contains {}", name);
        }
    }
}