1+ import { z } from "zod" ;
2+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" ;
3+
4+ // 1. 枚举定义
5+ const KnowledgeBaseEnum = z . enum ( [ "cloudbase" , "scf" ] ) ;
6+ // 2. 枚举到后端 id 的映射
7+ const KnowledgeBaseIdMap : Record < z . infer < typeof KnowledgeBaseEnum > , string > = {
8+ cloudbase : "ykfzskv4_ad28" ,
9+ scf : "scfsczskzyws_4bdc" ,
10+ } ;
11+
12+ // 安全 JSON.parse
13+ function safeParse ( str : string ) {
14+ try {
15+ return JSON . parse ( str ) ;
16+ } catch ( e ) {
17+ return { } ;
18+ }
19+ }
20+
21+ // 安全 JSON.stringify,处理循环引用
22+ function safeStringify ( obj : any ) {
23+ const seen = new WeakSet ( ) ;
24+ try {
25+ return JSON . stringify ( obj , function ( key , value ) {
26+ if ( typeof value === "object" && value !== null ) {
27+ if ( seen . has ( value ) ) return ;
28+ seen . add ( value ) ;
29+ }
30+ return value ;
31+ } ) ;
32+ } catch ( e ) {
33+ return "" ;
34+ }
35+ }
36+
37+ export function registerRagTools ( server : McpServer ) {
38+ // 知识库检索
39+ server . tool (
40+ 'search_knowledge_base' ,
41+ '云开发知识库智能检索工具,支持云开发与云函数知识的向量查询' ,
42+ {
43+ threshold : z . number ( ) . default ( 0.5 ) . optional ( ) . describe ( "相似性检索阈值" ) ,
44+ id : KnowledgeBaseEnum . describe ( "知识库范围,cloudbase=云开发全量知识,scf=云开发的云函数知识" ) ,
45+ content : z . string ( ) . describe ( "检索内容" ) ,
46+ options : z . object ( {
47+ chunkExpand : z . array ( z . number ( ) ) . min ( 2 ) . max ( 2 ) . default ( [ 3 , 3 ] ) . describe ( "指定返回的文档内容的展开长度,例如 [3,3]代表前后展开长度" ) ,
48+ } ) . optional ( ) . describe ( "其他选项" ) ,
49+ limit : z . number ( ) . default ( 5 ) . optional ( ) . describe ( "指定返回最相似的 Top K 的 K 的值" )
50+ } ,
51+ async ( {
52+ id,
53+ content,
54+ options : {
55+ chunkExpand = [ 3 , 3 ]
56+ } = { } ,
57+ limit = 5 ,
58+ threshold = 0.5
59+ } ) => {
60+ // 枚举到后端 id 映射
61+ const backendId = KnowledgeBaseIdMap [ id as keyof typeof KnowledgeBaseIdMap ] || id ;
62+ const signInRes = await fetch ( 'https://tcb-advanced-a656fc.api.tcloudbasegateway.com/auth/v1/signin/anonymously' , {
63+ method : 'POST' ,
64+ headers : {
65+ 'Content-Type' : 'application/json' ,
66+ 'Accept' : 'application/json' ,
67+ 'x-device-id' : 'cloudbase-ai-toolkit'
68+ } ,
69+ body : safeStringify ( {
70+ collectionView : backendId ,
71+ options : {
72+ chunkExpand
73+ } ,
74+ search : {
75+ content : content ,
76+ limit
77+ }
78+ } )
79+ } )
80+ const token = ( await signInRes . json ( ) ) . access_token
81+ const res = await fetch ( `https://tcb-advanced-a656fc.api.tcloudbasegateway.com/v1/knowledge/search` , {
82+ method : 'POST' ,
83+ headers : {
84+ 'Content-Type' : 'application/json' ,
85+ 'Authorization' : `Bearer ${ token } `
86+ } ,
87+ body : safeStringify ( {
88+ collectionView : backendId ,
89+ options : {
90+ chunkExpand
91+ } ,
92+ search : {
93+ content : content ,
94+ limit
95+ }
96+ } )
97+ } )
98+ const result = await res . json ( )
99+
100+ if ( result . code ) {
101+ throw new Error ( result . message )
102+ }
103+ console . log ( result )
104+ return {
105+ content : [ {
106+ type : "text" ,
107+ text : safeStringify ( result . data . documents
108+ . filter ( ( item : any ) => item . score >= threshold )
109+ . map ( ( item : any ) => {
110+ return {
111+ score : item . score ,
112+ fileTile : item . documentSet . fileTitle ,
113+ url : safeParse ( item . documentSet . fileMetaData ) . url ,
114+ paragraphTitle : item . data . paragraphTitle ,
115+ text :`${ item . data . pre ?. join ( '\n' ) || '' }
116+ ${ item . data . text }
117+ ${ item . data . next ?. join ( '\n' ) || '' } `,
118+ }
119+ } )
120+ )
121+ } ]
122+ }
123+ } )
124+ }
0 commit comments