MCP 入门 02:爽!打通了AI和公司低代码库

337 阅读6分钟

前言

上一集,我们认识了 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,你就必须:

    1. 停止 OpenCode/IDE。

    2. 去 .env 文件或配置文件里手动修改 Token。

    3. 重启 OpenCode。

    4. 重新加载上下文。 这会严重打断开发者的心流。

  • 解决方案: 我们利用 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 的文件不一致,大致列举一下:

  1. OpenCode: AGENTS.md
  2. Cursor: .cursorrules
  3. Windsurf: .windsurfrules
  4. GitHub Copilot: copilot-instructions.md
  5. Trae: .trae/rules/project_rules.md

总之,你需要在这里面讲清楚以下几件事

  1. 如何识别出代码在调用低代码平台的 API,啥时候触发规则。
  2. 提取参数: 拿到低代码对应的code,如 A12345...。
  3. 调用工具: 自动执行 mcp的get_page_detail_by_code("A12345...")。 如:
## 自动化分析规则 (Trigger Rules)
  当你阅读的代码中出现 `<LowCodeParser>` 组件时,你**必须**严格遵守以下分析步骤:

  1. **提取 pageCode**:从组件属性中识别 `pageCode` (例如 "P2025...")。
  2. **强制调用工具**:立即使用 MCP 工具 `get_page_detail_by_code` 获取该页面的 Schema 定义。**不要询问用户是否需要查询,直接查询。**
  1. 获取数据: 此时你的 Node.js 服务请求内网 API,返回 Schema。
  2. 逻辑合并: AI 对比 Schema (True) 和 代码 (False),根据 Prompt 中的优先级规则。
3. **合并上下文 (Context Merge)**    * **基准数据**:工具返回的 `pageData` 是页面的默认配置。
    * **覆盖数据**:代码中的 `props` 属性具有更高优先级。
    * **分析逻辑**:如果 `props` 中定义了与 Schema 相同的属性(例如 `columns``actions`),代码中的配置会**覆盖**数据库中的配置。
  1. 特殊框架规则 (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 已更新,正在重新尝试刚才的查询..."

这就实现了不重启服务的热更新。

小结

本次实战你可能没办法直接使用,但类似的场景一定不少,你可以举一反三了。

下课!