前言
上一集,我们认识了 MCP 的基本概念和脚手架搭建。
这一集,我们要解决具体的问题:
AI 不了解低代码库和存储的schema,无法做上下文关联给出正确的提示和代码修改。
这是 MCP 擅长的领域之一,学会它就能解决一大批类似的场景。
这篇文章侧重于实战闭环:让 AI 识别代码中的低代码组件,自动去公司内网 API 查询该页面的数据库 Schema,并结合代码中的属性进行智能分析。
🎯 本课目标
-
连接公司内网的低代码API:使用
Axios调用内网接口,不再是返回假数据。 -
动态 Token 管理:解决 Access Token 容易过期的问题,无需重启服务即可更新。
-
Agentic Workflow (闭环):通过系统提示词(System Prompt),给 AI 植入“条件反射”,让它看到特定代码就自动查库。
-
业务逻辑注入:教 AI 理解“数据库配置”与“代码覆盖”之间的优先级关系。
先看看效果:
提了一些要求,核心数据并不在本地工程里,而是在低代码平台的
schema里,正常情况下AI是无法读取的。
但是有了我们的MCP和提示词优化,AI就可以正常读取和修改本地代码覆写了。
一、 添加部分依赖库
我们将使用 axios 来发起网络请求,并引入一个内存变量来管理 Token。
确保 package.json 包含以下核心库:
{
"type": "module",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"axios": "^1.0.0",
"dotenv": "^16.0.0",
"zod": "^3.0.0"
}
}
二、 确定 tools 和工具逻辑
在 index.js 中,我们并没有胡乱堆砌功能,而是精准设计了两个工具,分别解决了低代码开发场景下的 “读取schema” 和 “Token续期” 两大核心难题。
以上是我们要实现的主体思路。
2.1 🔧 工具一:get_page_detail_by_code
解决痛点:AI 的“黑盒盲区” (The Black Box Problem)
-
现状: 当 AI 在代码中看到 时,对它来说,这只是一串毫无意义的字符。它不知道这个页面里是有 3 个按钮还是 5 个输入框,更不知道数据库里默认的配置是什么。因此,AI 无法判断你写的 customProps 代码是对的还是错的。
-
解决方案: 这个工具相当于给 AI 装上了 “透视眼”。 它打通了从 前端组件引用 到 后端数据库定义 的路径。当 AI 调用这个工具时,它能瞬间拿到该页面的“出厂设置”(Schema)。
-
意义: 只有拿到了这份“出厂设置”,AI 才能执行我们在 Prompt 里定义的 “Context Merge(上下文合并)” 逻辑——即对比“出厂设置”和“你的代码覆写”,从而精准地告诉你:“嘿,你在这里把原本显示的按钮给隐藏了。”
2.2 💉 工具二:update_auth_token
解决痛点:解决Token注入和过期续期
-
现状: 在企业级开发中,安全令牌(Access Token)通常有效期很短(如 2 小时)。 如果没有这个工具,一旦 Token 过期,API 报错 401,你就必须:
-
停止 OpenCode/IDE。
-
去 .env 文件或配置文件里手动修改 Token。
-
重启 OpenCode。
-
重新加载上下文。 这会严重打断开发者的心流。
-
-
解决方案: 我们利用 Node.js 的内存特性,定义了一个全局变量 let memoryToken。 update_auth_token 是一个允许 AI(或用户通过 AI)在运行时动态修改这个变量 的接口。
-
价值闭环: 当 AI 收到 401 错误时,它会提示你。你只需要把新 Token 丢给它,它调用这个工具更新内存变量,然后立即重试刚才失败的请求。整个过程无需重启,丝般顺滑。
这是我们的核心逻辑。注意看我们如何处理 memoryToken,这是一种简单有效的“热更新”策略。
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import axios from 'axios';
// 1. Token 状态管理
// 我们从环境变量读取初始 Token,但允许运行过程中通过工具更新它
let memoryToken = process.env.ACCESS_TOKEN || "";
console.error('Initial Token:', memoryToken ? "Loaded" : "Empty");
const server = new Server(
{ name: "lowcode-assistant", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// 2. 注册工具 (API 定义)
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
// 核心工具:查 Schema
name: "get_page_detail_by_code",
description: "根据 Code 获取低代码页面的完整 Schema 配置。分析 <LowCodeParser> 时必须调用。",
inputSchema: {
type: "object",
properties: {
code: { type: "string", description: "页面Code (例如 A12345...)" },
},
required: ["code"],
},
},
{
// 辅助工具:热更新 Token
name: "update_auth_token",
description: "当 API 返回 401/403 或 Token 过期时,调用此工具更新 Token",
inputSchema: {
type: "object",
properties: { newToken: { type: "string" } },
required: ["newToken"]
}
},
],
};
});
// 3. 业务逻辑实现
server.setRequestHandler(CallToolRequestSchema, async (request) => {
// === 场景 A: 查询页面详情 ===
if (request.params.name === "get_page_detail_by_code") {
const args = z.object({ code: z.string() }).parse(request.params.arguments);
try {
// 发起真实请求 (URL 和 Headers 请替换为你公司的实际配置)
const response = await axios.get('https://api.internal-lowcode.com/page/queryDetailByCode', {
headers: {
'Authorization': `Bearer ${memoryToken}`, // 使用内存中的 Token
},
params: { code: args.code }
});
// 直接返回 API 数据
return {
content: [{ type: "text", text: JSON.stringify(response.data) }],
};
} catch (error) {
// 优雅处理错误,让 AI 知道发生了什么
return {
content: [{ type: "text", text: `API 请求失败: ${error.message}` }],
isError: true
};
}
}
// === 场景 B: 更新 Token ===
if (request.params.name === "update_auth_token") {
const args = z.object({ newToken: z.string() }).parse(request.params.arguments);
memoryToken = args.newToken; // 更新内存变量
return { content: [{ type: "text", text: "Token 已更新,请重试刚才的操作。" }] };
}
throw new Error("Tool not found");
});
// 4. 启动服务
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP Server running...");
}
main().catch(console.error);
三、 提示工程:给 AI 植入“条件反射”
有了工具还不够,我们需要教 OpenCode 什么时候用 以及 怎么用。 这是通过配置 System Prompt 实现的。
不同 IDE 的文件不一致,大致列举一下:
- OpenCode:
AGENTS.md - Cursor:
.cursorrules - Windsurf:
.windsurfrules - GitHub Copilot:
copilot-instructions.md - Trae:
.trae/rules/project_rules.md
总之,你需要在这里面讲清楚以下几件事
- 如何识别出代码在调用低代码平台的 API,啥时候触发规则。
- 提取参数: 拿到低代码对应的code,如 A12345...。
- 调用工具: 自动执行 mcp的get_page_detail_by_code("A12345...")。 如:
## 自动化分析规则 (Trigger Rules)
当你阅读的代码中出现 `<LowCodeParser>` 组件时,你**必须**严格遵守以下分析步骤:
1. **提取 pageCode**:从组件属性中识别 `pageCode` (例如 "P2025...")。
2. **强制调用工具**:立即使用 MCP 工具 `get_page_detail_by_code` 获取该页面的 Schema 定义。**不要询问用户是否需要查询,直接查询。**
- 获取数据: 此时你的 Node.js 服务请求内网 API,返回 Schema。
- 逻辑合并: AI 对比 Schema (True) 和 代码 (False),根据 Prompt 中的优先级规则。
3. **合并上下文 (Context Merge)**:
* **基准数据**:工具返回的 `pageData` 是页面的默认配置。
* **覆盖数据**:代码中的 `props` 属性具有更高优先级。
* **分析逻辑**:如果 `props` 中定义了与 Schema 相同的属性(例如 `columns` 或 `actions`),代码中的配置会**覆盖**数据库中的配置。
- 特殊框架规则 (Framework Quirks) 每个公司的低代码平台都有自己的“方言”。比如表格列的定义方式可能有多种。我们通过 Prompt 把这些知识传授给 AI:
当你发现xxx时,你按xx处理...
四、 Token 过期了怎么办?
在开发过程中,如果 Token 过期,Axios 会抛出 401 错误。 由于我们在 index.js 注册了 update_auth_token 工具,并在 Prompt 里定义了 Token 异常处理:
User: (操作失败) "Token 好像过期了?" User: "这是新 Token: sk_new_token_123..." AI: (自动调用 update_auth_token) "Token 已更新,正在重新尝试刚才的查询..."
这就实现了不重启服务的热更新。
小结
本次实战你可能没办法直接使用,但类似的场景一定不少,你可以举一反三了。
下课!