内容提要
本文介绍如何安全地让AI助手调用内部笔记API。直接调用存在共享令牌无法区分用户、模型可自行构造查询语句、API无登录保护等风险。方案是用MCP服务器封装笔记API,仅暴露list、get、search三个工具;在服务端校验查询、拒绝通配符等危险输入;前置网关统一入口并过滤工具描述中的恶意指令,使每次调用都对应可识别的用户或服务账号。
延伸解读
共享令牌与身份缺失的隐患
文章指出,直接让AI助手调用内部API时,若使用共享的长期令牌,API无法区分具体用户,访问日志只能记录为“机器人”。这导致无法审计、无法单独撤销某人的权限。解决方案是让每次调用都关联一个可识别的身份,如个人或服务账号,并在网关层进行身份验证和令牌交换。
服务端查询构建:防止模型编写查询语言
文章强调,模型不应直接构造查询语句,否则可能发送通配符或注入式查询。示例中通过服务端校验,只允许字母、数字、空格和连字符,并限制长度,拒绝如“title:* OR body:*”的输入。同时,对owner参数使用允许列表,限制返回结果数量,确保模型只能表达意图,而由服务端安全地构建查询。
网关的双重角色:统一入口与工具描述过滤
网关作为唯一入口,负责转发请求并过滤工具列表。文章中的教学网关会检查tools/list响应,丢弃描述过长或包含“ignore previous”等指令性短语的工具,防止恶意描述被模型执行。但作者也指出,这种过滤较为粗糙,可能误伤或漏过,因此保持工具列表简短仍是主要控制手段。
身份附加的两种模式:人员与服务账号
文章区分了两种身份附加场景:当有人员操作时,通过OAuth登录并将身份令牌传递给MCP服务器,再交换为API可理解的短期凭证;当无人值守时,使用专为任务创建的服务账号,并像管理其他工作负载身份一样轮换凭证。避免使用一个管理员令牌供所有人和任务共享,以确保审计和权限控制。
Q&A
让AI助手直接调用内部API会有什么风险?
主要风险包括:所有调用使用同一个共享令牌,API日志只能记录“机器人”而无法区分具体用户;模型可以自行构造查询语句,例如发送通配符查询来匹配所有数据;API进程没有登录保护,知道URL的人可以绕过助手直接调用;工具结果可能包含敏感信息并被带入后续提示;调用记录无法追溯具体工具和用户。
如何防止模型自己编写查询语句?
在服务端用代码构建查询,而不是让模型直接发送原始查询。例如使用safe_search.py中的build_search函数,通过正则表达式限制查询只能包含字母、数字、空格和连字符,长度1-64字符,并拒绝通配符等危险输入。owner参数必须来自允许列表,limit会被限制在最大值以内。这样模型只能发送意图,由服务器决定是否允许并构建实际查询。
MCP服务器应该暴露哪些工具?
应该只暴露少量命名明确的工具,例如list_notes_tool、get_note_tool和search_notes_tool。不要暴露一个接受HTTP方法、路径和请求体的通用代理工具,否则模型可以调用任何路由。每个工具对应一个已审查的函数,工具列表越短越容易审查。
为什么要在MCP服务器前面加一个网关?
网关作为统一入口,让助手调用网关而不是直接调用MCP服务器。这样可以集中处理登录、限流和审计日志,并过滤工具描述中的恶意指令。如果助手能直接访问MCP服务器端口,就可以跳过这些检查。网关还负责转发必要的请求头,如mcp-session-id。
如何为每次调用附加身份(人员或服务账号)?
有两种模式:当有人员发起会话时,网关通过OAuth让用户登录,然后将身份令牌转发给MCP服务器,服务器再将其兑换为笔记API能理解的短期凭证,API据此应用该用户的权限;当无人值守时,为任务创建服务账号,仅授予所需权限并定期轮换凭证。每次调用都记录为具体人员或服务账号,而不是共享令牌。
网关会检查工具描述中的恶意指令吗?
会。网关在收到MCP服务器的tools/list响应后,会调用scrub_tools_list过滤工具描述。如果描述超过280个字符或包含“ignore previous”、“system prompt”、“jailbreak”、“exfiltrate”等短语,该工具会被丢弃。但这是一个粗略的过滤器,可能漏掉巧妙措辞或误删合法工具,因此短工具列表仍是主要控制手段。