IMA知识库接入Trae_MCP
IMA 知识库接入 Trae MCP 完整教程
本文档记录了在 Trae IDE 中通过 MCP 协议接入腾讯 IMA 知识库的完整流程,包括踩坑和最终解决方案。
适用环境:Windows + Python 3.14 + Trae IDE
“内容由AI整理生成,如有不当之处请指正!”
一、前置准备
1.1 获取 IMA OpenAPI 凭证
IMA 知识库的 MCP 接入使用官方 OpenAPI 认证,需要两个凭证:
- Client ID:应用标识
- API Key:访问密钥
获取地址:https://ima.qq.com/agent-interface
操作步骤:
- 打开上述网址,登录你的 IMA 账号
- 页面会显示你的 Client ID 和 API Key
- 复制保存好这两个值(API Key 可能会过期,需定期检查更新)
⚠️ 重要提醒:API Key 会过期!如果调用 API 返回错误码
200002(skill auth failed),说明 Key 已失效,需要回到官网重新获取或刷新。
1.2 安装 Python 环境
确保系统有 Python 3.11+ 环境,并能正常运行。Windows 上用 PowerShell 验证:
python --version
建议记下 Python 的绝对路径(如
D:\workSpace\Python314\python.exe),Trae 配置中需要用到。
1.3 安装依赖包
# 用你的 Python 绝对路径安装
D:\workSpace\Python314\python.exe -m pip install mcp httpx
依赖说明:
mcp:官方 MCP Python SDK,提供 FastMCP 框架,正确实现 stdio 协议httpx:HTTP 客户端,用于调用 IMA OpenAPI 接口
二、为什么不能用社区现有的 MCP 包?
2.1踩坑记录
| 项目 | 问题 |
|---|---|
| duhanjun/ima-mcp(pip 包) | ❌ stdio 实现是自写的简易版,用 json.loads() 直接解析 stdin,不符合 MCP 协议规范。Trae 发送多行 JSON-RPC 消息时解析报错:JSONDecodeError: Extra data |
| suraimu/tencent-ima-copilot-mcp | ❌ 使用浏览器 Cookie/Bkn 认证(需 F12 抓包),Cookie 会过期需反复重新抓取;仅支持 HTTP 传输模式 |
| hdsz25/tencent_ima_mcp | ❌ 功能最丰富但仅支持 Cookie 认证,官方 OpenAPI 的 ClientID/APIKey 尚未实现 |
| wangjianghu/ima-note-mcp | ❌ 仅支持笔记操作,不支持知识库;要求 macOS + Python 3.13+ |
核心问题:社区 MCP 包要么 stdio 协议实现不规范(Trae 不兼容),要么认证方式依赖浏览器 Cookie(不稳定),要么功能覆盖不全。
2.2 最终方案:自建 MCP Server
使用官方 mcp Python SDK(FastMCP)自建 Server,正确实现 stdio 协议,使用官方 OpenAPI 凭证认证,最稳定可靠。
三、自建 MCP Server 实现
3.1 源码文件
创建文件 ima_mcp_server.py,内容如下:
"""
IMA Knowledge Base MCP Server
基于官方 mcp SDK 实现 stdio 协议,兼容 Trae / Cursor / Claude Desktop 等IDE
使用 IMA OpenAPI (ClientID + APIKey) 认证
"""
import json
import os
import re
import httpx
from mcp.server.fastmcp import FastMCP
# ============================================================
# 认证配置:从环境变量读取
# ============================================================
IMA_CLIENT_ID = os.environ.get("IMA_OPENAPI_CLIENTID", "")
IMA_API_KEY = os.environ.get("IMA_OPENAPI_APIKEY", "")
IMA_BASE_URL = "https://ima.qq.com"
# ============================================================
# ElementPlus 组件中英文映射表
# 当 search_knowledge 搜中文无结果时,自动用英文关键词重试
# ============================================================
COMPONENT_NAME_MAP = {
# 常见中文别名 → 英文文件名关键词
"卡片": "card", "对话框": "dialog", "弹窗": "dialog", "模态框": "dialog",
"上传": "upload", "图片上传": "upload", "文件上传": "upload",
"表格": "table", "数据表格": "table",
"表单": "form", "按钮": "button",
"输入框": "input", "输入": "input",
"选择器": "select", "下拉选择": "select", "下拉框": "select",
"复选框": "checkbox", "多选框": "checkbox",
"单选框": "radio", "开关": "switch",
"日期选择器": "date-picker", "日期选择": "date-picker", "日期": "date-picker",
"时间选择器": "time-picker", "时间选择": "time-picker", "时间": "time-picker",
"颜色选择器": "color-picker", "颜色": "color-picker",
"轮播": "carousel", "走马灯": "carousel",
"折叠面板": "collapse", "折叠": "collapse",
"容器": "container", "布局容器": "container",
"下拉菜单": "dropdown", "菜单": "menu",
"分页": "pagination", "标签页": "tabs", "标签": "tag",
"树形控件": "tree", "树": "tree", "穿梭框": "transfer",
"滑块": "slider", "评分": "rate", "进度条": "progress",
"消息提示": "message", "消息弹框": "message-box",
"通知": "notification", "气泡确认框": "popconfirm",
"气泡卡片": "popover", "文字提示": "tooltip",
"加载": "loading", "骨架屏": "skeleton", "空状态": "empty",
"结果": "result", "步骤条": "steps", "时间线": "timeline",
"统计数值": "statistic", "分割线": "divider",
"描述列表": "descriptions", "导航": "nav", "页头": "page-header",
"面包屑": "breadcrumb", "头像": "avatar", "日历": "calendar",
"无限滚动": "infinite-scroll", "虚拟化表格": "table-v2",
"虚拟化选择器": "select-v2", "分段控制器": "segmented",
"浮层": "affix", "回到顶部": "backtop",
"水印": "watermark", "排版": "typography",
"链接": "link", "间距": "space", "分割": "splitter",
"引导": "tour", "滚动条": "scrollbar",
"数字输入框": "input-number", "标签输入框": "input-tag",
"OTP输入框": "input-otp", "树形选择": "tree-select",
}
# ElXxx 组件名 → 去掉 El 前缀,映射到文件名关键词
# e.g. ElCard → card, ElDialog → dialog
def extract_component_keyword(query: str) -> str | None:
"""从 query 中提取 ElXxx 组件名,转换为英文关键词"""
m = re.match(r'El([A-Z][a-zA-Z]*)', query)
if m:
# ElDatePicker → date-picker
name = m.group(1)
# 在驼峰位置插入连字符并转小写
parts = re.findall(r'[A-Z][a-z]*', name)
return '-'.join(parts).lower()
return None
# ============================================================
# MCP Server 实例
# ============================================================
mcp = FastMCP("IMA Knowledge Base")
# ============================================================
# HTTP 请求工具
# ============================================================
def ima_post(endpoint: str, body: dict) -> dict:
"""调用 IMA OpenAPI POST 接口"""
url = f"{IMA_BASE_URL}/{endpoint}"
headers = {
"ima-openapi-clientid": IMA_CLIENT_ID,
"ima-openapi-apikey": IMA_API_KEY,
"Content-Type": "application/json",
}
with httpx.Client(timeout=30) as client:
resp = client.post(url, headers=headers, json=body)
data = resp.json()
if data.get("code") != 0:
return {"error": f"API error: code={data.get('code')}, msg={data.get('msg')}"}
return data.get("data", {})
# ============================================================
# MCP 工具定义
# ============================================================
@mcp.tool()
def search_knowledge_base(query: str = "", limit: int = 20) -> str:
"""搜索用户的知识库列表。可按名称搜索,或传入空字符串列出所有知识库。返回知识库ID、名称、描述等信息。
Args:
query: 搜索关键词,空字符串则列出所有知识库
limit: 返回数量上限,默认20
"""
result = ima_post("openapi/wiki/v1/search_knowledge_base", {
"query": query,
"cursor": "",
"limit": limit,
})
if "error" in result:
return result["error"]
info_list = result.get("info_list", [])
if not info_list:
return "没有找到知识库"
lines = []
for kb in info_list:
lines.append(
f"- 名称: {kb.get('kb_name')}\n"
f" ID: {kb.get('kb_id')}\n"
f" 描述: {kb.get('description', '无')}\n"
f" 内容数: {kb.get('content_count', 0)}\n"
f" 成员数: {kb.get('member_count', 0)}"
)
return "\n\n".join(lines)
@mcp.tool()
def list_knowledge_contents(knowledge_base_id: str, folder_id: str = "", limit: int = 50) -> str:
"""浏览知识库中的文件和文件夹列表。可逐级浏览,不传 folder_id 则列出根目录。
Args:
knowledge_base_id: 知识库ID(可通过 search_knowledge_base 获取)
folder_id: 文件夹ID,空字符串则列出根目录
limit: 返回数量上限,默认50
"""
body = {
"cursor": "",
"limit": limit,
"knowledge_base_id": knowledge_base_id,
}
if folder_id:
body["folder_id"] = folder_id
result = ima_post("openapi/wiki/v1/get_knowledge_list", body)
if "error" in result:
return result["error"]
knowledge_list = result.get("knowledge_list", [])
if not knowledge_list:
return "该目录下没有内容"
lines = []
for item in knowledge_list:
type_map = {
1: "PDF", 2: "网页", 3: "Word", 4: "PPT", 5: "Excel",
6: "公众号文章", 7: "Markdown", 9: "图片", 11: "笔记",
99: "文件夹"
}
media_type = item.get("media_type", 0)
type_name = type_map.get(media_type, f"类型{media_type}")
lines.append(
f"- {item.get('title')}\n"
f" ID: {item.get('media_id')}\n"
f" 类型: {type_name}\n"
f" 标签: {', '.join(item.get('tags', [])) or '无'}"
)
# 显示当前路径
current_path = result.get("current_path", [])
if current_path:
path_str = " > ".join([p.get("name", "") for p in current_path])
lines.insert(0, f"📍 当前路径: {path_str}")
is_end = result.get("is_end", True)
if not is_end:
lines.append("⚠️ 还有更多内容,可继续翻页获取")
return "\n\n".join(lines)
@mcp.tool()
def search_knowledge(query: str, knowledge_base_id: str) -> str:
"""在指定知识库中搜索文件或文件夹。支持中文描述和英文关键词。
会自动将中文组件名(如"卡片组件"、"对话框")和 ElXxx 名(如 ElCard、ElDialog)
映射为对应的英文文件名关键词进行搜索。
Args:
query: 搜索关键词,支持中文描述(如"卡片"、"对话框")或英文(如"card"、"dialog")
knowledge_base_id: 目标知识库ID
"""
# 首先直接搜索
result = ima_post("openapi/wiki/v1/search_knowledge", {
"query": query,
"knowledge_base_id": knowledge_base_id,
})
if "error" in result:
return result["error"]
info_list = result.get("info_list", [])
# 如果直接搜索没结果,尝试自动映射
if not info_list:
mapped_keywords = []
# 1. 尝试提取 ElXxx 组件名
el_keyword = extract_component_keyword(query)
if el_keyword:
mapped_keywords.append(el_keyword)
# 2. 尝试中文→英文映射
for cn_name, en_name in COMPONENT_NAME_MAP.items():
if cn_name in query:
mapped_keywords.append(en_name)
# 用映射后的关键词重试搜索
for kw in mapped_keywords:
retry_result = ima_post("openapi/wiki/v1/search_knowledge", {
"query": kw,
"knowledge_base_id": knowledge_base_id,
})
if "error" not in retry_result:
retry_list = retry_result.get("info_list", [])
if retry_list:
info_list = retry_list
query = f"{query} → (映射为: {kw})"
break
# 3. 如果中文映射也失败,尝试把 query 分词后用每个词搜
if not info_list and not mapped_keywords:
# 简单分词:去掉中文标点和"组件使用方法"等后缀
cleaned = re.sub(r'(组件|使用|方法|用法|的|El)', '', query)
words = cleaned.strip().split()
for word in words:
if len(word) >= 2:
retry_result = ima_post("openapi/wiki/v1/search_knowledge", {
"query": word,
"knowledge_base_id": knowledge_base_id,
})
if "error" not in retry_result:
retry_list = retry_result.get("info_list", [])
if retry_list:
info_list = retry_list
query = f"{query} → (尝试关键词: {word})"
break
if not info_list:
return f"在知识库中未找到 '{query}' 相关内容。建议用英文组件名搜索,如 card、dialog、upload 等。"
type_map = {
1: "PDF", 2: "网页", 3: "Word", 4: "PPT", 5: "Excel",
6: "公众号文章", 7: "Markdown", 9: "图片", 11: "笔记",
99: "文件夹"
}
lines = []
for item in info_list:
media_type = item.get("media_type", 0)
type_name = type_map.get(media_type, f"类型{media_type}")
lines.append(
f"- {item.get('title')}\n"
f" ID: {item.get('media_id')}\n"
f" 类型: {type_name}\n"
f" 父文件夹ID: {item.get('parent_folder_id', '根目录')}"
)
return "\n\n".join(lines)
@mcp.tool()
def get_knowledge_base_detail(knowledge_base_id: str) -> str:
"""获取指定知识库的详细信息,包括名称、描述、成员数、内容数等。
Args:
knowledge_base_id: 知识库ID
"""
result = ima_post("openapi/wiki/v1/search_knowledge_base", {
"query": "",
"cursor": "",
"limit": 1,
"knowledge_base_id": knowledge_base_id,
})
if "error" in result:
return result["error"]
info_list = result.get("info_list", [])
if not info_list:
return f"未找到知识库 {knowledge_base_id}"
kb = info_list[0]
return (
f"名称: {kb.get('kb_name')}\n"
f"ID: {kb.get('kb_id')}\n"
f"描述: {kb.get('description', '无')}\n"
f"内容数: {kb.get('content_count', 0)}\n"
f"成员数: {kb.get('member_count', 0)}\n"
f"创建者: {kb.get('creator', '未知')}\n"
f"类型: {kb.get('base_type', '未知')}\n"
f"你的角色: {kb.get('role_type', '未知')}"
)
# ============================================================
# 启动
# ============================================================
if __name__ == "__main__":
if not IMA_CLIENT_ID or not IMA_API_KEY:
print("ERROR: 请设置环境变量 IMA_OPENAPI_CLIENTID 和 IMA_OPENAPI_APIKEY")
print("获取方式: https://ima.qq.com/agent-interface")
exit(1)
mcp.run(transport="stdio")
3.2 提供的 MCP 工具
| 工具名 | 功能 | 参数 |
|---|---|---|
search_knowledge_base |
搜索/列出知识库 | query(搜索关键词,空=全部),limit |
list_knowledge_contents |
浏览知识库目录 | knowledge_base_id,folder_id(空=根目录),limit |
search_knowledge |
搜索知识库内文件 | query(关键词),knowledge_base_id |
get_knowledge_base_detail |
知识库详细信息 | knowledge_base_id |
四、Trae 配置步骤
4.1 复制脚本文件
将 ima_mcp_server.py 复制到一个固定目录,例如:
mkdir D:\workSpace\mcp
# 把 ima_mcp_server.py 放到这个目录下
4.2 测试脚本能否启动
PowerShell 中执行:
$env:IMA_OPENAPI_CLIENTID="你的ClientID"
$env:IMA_OPENAPI_APIKEY="你的APIKey"
D:\workSpace\Python314\python.exe D:\workSpace\mcp\ima_mcp_server.py
⚠️ PowerShell 用
$env:变量名="值",不是 CMD 的set 变量名=值如果启动后出现
JSONRPCMessage验证错误是正常的——那是你手动敲空行导致的,Trae 通过程序化管道发送不会出现这个问题。
4.3 配置 Trae MCP
打开 Trae → 设置 → MCP → 手动添加,粘贴以下 JSON:
{
"mcpServers": {
"ima": {
"command": "D:\\workSpace\\Python314\\python.exe",
"args": ["D:\\workSpace\\mcp\\ima_mcp_server.py"],
"env": {
"IMA_OPENAPI_CLIENTID": "你的ClientID",
"IMA_OPENAPI_APIKEY": "你的APIKey"
}
}
}
}
⚠️ 注意事项:
- JSON 中路径反斜杠要双写:
D:\→D:\\command和args都要用绝对路径,Trae 的进程 PATH 和终端不一样- 不要用
python、uvx这种短命令,容易找不到(ENOENT 错误)- 配置完成后需要重启 Trae
4.4 验证连接
重启 Trae 后,在对话窗口测试:
- “列出我的知识库” → 应返回知识库列表
- “搜索前端-elementPlus组件知识库里的 button” → 应返回搜索结果
五、常见问题与解决
Q1: spawn uvx ENOENT 或 'ima-mcp' 不是内部或外部命令
原因:Trae 启动进程的 PATH 和终端不同,短命令找不到。
解决:所有路径都用绝对路径,不要用 python、uvx、ima-mcp 等短命令。
Q2: JSONDecodeError: Extra data 或 MCP 连接立即断开
原因:社区 ima-mcp pip 包的 stdio 实现不符合 MCP 协议规范——它用 json.loads() 解析 stdin,无法处理多行 JSON-RPC 消息。
解决:使用本文的自建 MCP Server(基于官方 mcp SDK),正确实现 stdio 协议。
Q3: API 返回错误码 200002(skill auth failed)
原因:API Key 过期或失效。
解决:
- 回到 https://ima.qq.com/agent-interface 检查/重新获取凭证
- 更新 Trae 配置中的
IMA_OPENAPI_APIKEY值 - 重启 Trae
Q4: PowerShell 中 $env: 设置的环境变量重启后丢失
说明:$env: 是临时的,仅当前 PowerShell 会话有效。但 Trae 配置中的 env 字段是永久生效的——每次启动 MCP Server 时 Trae 都会注入这些环境变量,所以不需要在系统层面持久设置。
Q5: 想在其他 IDE 中使用(Cursor / Claude Desktop)
同样的 MCP Server 脚本和配置格式适用于 Cursor 和 Claude Desktop,只需调整配置文件位置:
| IDE | 配置文件位置 |
|---|---|
| Trae | 项目级:.trae/mcp.json,或全局:设置 → MCP |
| Cursor | 项目级:.cursor/mcp.json,或全局:设置 → MCP |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json(macOS) |
六、技术要点总结
-
MCP 协议核心:Trae/Cursor/Claude Desktop 通过 stdio 管道与 MCP Server 通信,使用 JSON-RPC 2.0 协议。Server 必须用官方 SDK 实现,自写 stdin 解析会不兼容。
-
认证方式选择:IMA 有两种认证方式:
- OpenAPI 认证(ClientID + APIKey):稳定,从官网获取,推荐使用
- Cookie 认证(x-ima-cookie + x-ima-bkn):需从浏览器 F12 抓包,Cookie 会过期,不推荐
-
Windows 特殊注意:路径要用绝对路径,JSON 中反斜杠要双写,PowerShell 环境变量用
$env:语法。
七、参考链接
- IMA OpenAPI 凭证获取:https://ima.qq.com/agent-interface
- MCP 协议官方文档:https://modelcontextprotocol.io
- MCP Python SDK:https://github.com/modelcontextprotocol/python-sdk
- Trae MCP 配置文档:https://docs.trae.ai/ide/add-mcp-servers
更多推荐





所有评论(0)