我舉一個非常簡單的例子,假設我有一個電商后臺系統,除了有一個前端的控制臺之外,還有有一套現成的統一的后端 API,那如果現在我想將我的后臺系統接入大模型,通過自然語言來進行一些操作,而不是手動在控制臺上點來點去,我們只需要簡單的寫一個 MCP 服務,大概的樣子:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
// 定義 MCP 服務
server.tool('create-user', '用于創建用戶', (params) => {
    // 調用后端創建用戶的 API
    return axios.post('/api/users', params);
});
server.tool('create-order', '用于創建訂單', (params) => {
    // 調用后端創建訂單的 API
    return axios.post('/api/orders', params);
});
server.tool('get-order-status', '用于查詢訂單狀態', (orderId) => {
    // 調用后端查詢訂單狀態的 API
    return axios.get(/api/orders/${orderId}/status);
});
server.tool('update-inventory', '用于更新庫存', (productId, quantity) => {
    // 調用后端更新庫存的 API
    return axios.put(/api/inventory/${productId}, { quantity });
});

實現了這么一個服務后,我們可以將這個服務通過 cursor,cline,claude app 等 AI 客戶端進行接入,直接通過自然語言描述自己想要進行的操作,大模型就會解析你的語意以及 MCP 服務中我們自己寫的描述,去組合調用不同的 API,例如用戶輸入?請為用戶 "john_doe" 創建一個新訂單,商品是 2 件商品 ID 為 "123" 的商品,配送地址是 "上海市浦東新區"。?大模型解析用戶的自然語言輸入,提取出以下信息:

用戶ID:

john_doe

商品:

[{ productId: "123", quantity: 2 }]

配送地址: 上海市浦東新區 大模型調用

create-order

工具,傳入解析后的參數:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
{
    "userId": "john_doe",
    "products": [
        { "productId": "123", "quantity": 2 }
    ],
    "shippingAddress": "上海市浦東新區"
}

MCP 服務將請求轉發給后端 API,完成訂單創建,并返回結果給用戶:

ounter(lineounter(lineounter(line
訂單創建成功,訂單ID為 "ORDER_123456"。

目前已有許多成熟的 MCP 服務,例如 GitHub 的 MCP 支持創建倉庫、提交 PR 等操作;Figma 的 MCP 可以直接生成 UI 設計圖;瀏覽器和操作系統的 MCP 則能增強 cursor 的能力,甚至可以讓 cursor 基于瀏覽器中的錯誤信息自動調試代碼。這些服務極大地擴展了 LLM 的應用場景,使其能夠更智能地完成復雜任務。下圖是 Cline 中可以直接快速集成的一些 MCP 服務:

image

具體實現 MCP 服務

具體如何實現一個 MCP 服務上面簡單提了一下 MCP 服務的大致實現原理,接下來我們根據官方文檔[1]中介紹,從零開始實現一個 MCP 服務。

首先我們需要有一套現有的后端服務 API,可以是我們曾經開發過的小項目,或者是一些開源的帶有開放 API 的庫,這里我選擇了開源的 APISIX[2] 網關,因為它有一套現成的 Admin API[3],并且還有 API 文檔,這可以提供給 cursor 作為參考幫助我們快速將所有 API 轉換成 MCP 服務中的操作。

設置環境

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
# 創建一個新的項目目錄
mkdir apisix-mcp
cd apisix-mcp
# 初始化一個新的 npm 項目
npm init -y
# 安裝依賴
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript
# 創建項目文件
mkdir src
touch src/index.ts

更新

package.json

文件,添加

type: "module"

和一個構建腳本:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
{
    "type": "module",
    "bin": {
        "apisix-mcp": "./build/index.js"
    },
    "scripts": {
        "build": "tsc && chmod 755 build/index.js"
    },
    "files": [
        "build"
    ]
}

在項目根目錄下創建一個

tsconfig.json

文件:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
{
    "compilerOptions": {
        "target": "ES2022",
        "module": "Node16",
        "moduleResolution": "Node16",
        "outDir": "./build",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
}

構建服務

src/index.ts

文件的頂部添加以下內容:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// Configuration for APISIX MCP server
const APISIX_API_BASE = "http://127.0.0.1:9180/apisix/admin";
const APISIX_API_KEY = "edd1c9f034335f136f87ad84b625c8f1";

// Create server instance
const server = new McpServer({
    name: "apisix-mcp",
    version: "1.0.0",
    config: {
        apiKey: {
            type: "string",
            description: "API key for APISIX Admin API authentication",
            default: APISIX_API_KEY
        },
        apiBase: {
            type: "string",
            description: "Base URL for APISIX Admin API",
            default: APISIX_API_BASE
        }
    }
});

這段代碼用于創建一個 APISIX MCP 服務實例:「導入依賴」:

McpServer

StdioServerTransport

是用于創建 MCP 服務的工具。

z

是 Zod 庫,用于數據驗證。「配置 APISIX MCP 服務」:

APISIX_API_BASE

是 APISIX Admin API 的基礎 URL。

APISIX_API_KEY

是用于身份驗證的 API 密鑰。「創建服務實例」:使用

McpServer

創建一個名為

apisix-mcp

的服務實例,版本為

1.0.0

。配置了

apiKey

apiBase

兩個參數,分別用于指定 API 密鑰和基礎 URL,并提供了默認值。這段代碼用于初始化一個 MCP 服務,為后續與 APISIX Admin API 的交互做準備,大家可以根據自己的業務進行簡單的調整。

創建請求文件

然后我們添加一個單獨的文件用于發送請求,官方的文檔中使用的是

fetch

,但我覺得用

axios

在執行不同的請求方法時會更加方便一點,所以就改用

axios

發送請求 :

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
/**
 * Define the common data structure returned by APISIX Admin API
 */
import axios from 'axios';

interface ApiResponse {
    value?: any;
    modifiedIndex?: number;
    createdIndex?: number;
    error?: string;
    message?: string;
}

/**
 * 使用axios發送請求到APISIX管理API
 * @param url 請求的完整URL
 * @param method HTTP方法,默認為'GET'
 * @param data 請求數據,用于PUT/POST/PATCH請求
 * @param apiKey API密鑰,用于認證,默認使用環境變量或硬編碼值
 * @returns 返回API響應或null(如果發生錯誤)
 */
export async function makeAdminAPIRequest(
    url: string,
    method: string = 'GET',
    data?: any,
    apiKey: string = process.env.APISIX_API_KEY || "edd1c9f034335f136f87ad84b625c8f1"
): Promise {
    try {
        // 配置axios請求
        const response = await axios({
            method,
            url,
            data,
            headers: {
                'X-API-KEY': apiKey,
                'Content-Type': 'application/json'
            }
        });
        console.log(Axios請求成功: ${method} ${url});
        return response.data;
    } catch (error) {
        if (axios.isAxiosError(error)) {
            console.error(請求失敗: ${method} ${url});
            console.error(狀態碼: ${error.response?.status}, 錯誤信息: ${error.message});
            console.error(響應數據:, error.response?.data);
        } else {
            console.error('發送API請求時出錯:', error);
        }
        return null;
    }
}

export default makeAdminAPIRequest;

實現執行工具

創建好了服務實例,并且實現了一個請求方法后,接下來到最核心的一步,也就是實現執行工具:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
const idSchema = z.object({
    id: z.string().describe("資源 id")
});

server.tool('get-routes',
    '列出所有路由',
    {},
    async (args, extra) => {
        const response = await makeAdminAPIRequest(${APISIX_API_BASE}/routes);
        return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify(response, null, 2),
                },
            ],
        };
    }
);

server.tool('create-route',
    '創建一個新的路由',
    routeSchema.shape,
    async (args, extra) => {
        try {
            const routeId = args.id || Date.now().toString();
            console.log(Starting route creation, ID: ${routeId}, path: ${args.route.uri});
            const response = await makeAdminAPIRequest(
                ${APISIX_API_BASE}/routes/${routeId},
                'PUT',
                args.route
            );
            if (!response) {
                console.error(Failed to create route, ID: ${routeId});
                return {
                    content: [
                        {
                            type: "text",
                            text: JSON.stringify({ error: "Failed to create route, please check the APISIX connection and logs" }, null, 2),
                        },
                    ],
                };
            }
            console.log(Route created successfully, ID: ${routeId});
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify(response, null, 2),
                    },
                ],
            };
        } catch (error: unknown) {
            console.error(Exception occurred:, error);
            const err = error instanceof Error ? error : new Error(String(error));
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify({ error: Failed to create route: ${err.message} }, null, 2),
                    },
                ],
            };
        }
    }
);

server.tool

函數定義了兩個個工具,分別用于獲取路由數據和新增路由,我們在第二個參數中用中文描述了我們這個工具的作用,這個描述就是用來給大模型調用時進行語意分析后進行觸發的,所以描述我們可以寫的更加詳盡一些,讓沒那么聰明的模型也號理解一點,這里只是一個簡單示例,兩個工具都通過

makeAdminAPIRequest

函數與 APISIX Admin API 交互。

接下來我們執行

npm build

將項目構建一下,可以看到

build

目錄也就是構建成功了

image

調試

在我們的 MCP 服務基礎框架完成后,就到了調試環節。 MCP 服務的接入需要用到一些 AI 客戶端,例如 cursor,vscode 中的 cline 插件,或者是 Claude 的官方應用,考慮到我們開發用的就是 curosr,所以這里我們直接使用 cursor 作為客戶端進行調試。

第一步我們需要在

.cursor

目錄中創建

mcp.json

文件用于聲明 MCP 服務,在我的 windows 電腦上路徑如下圖:

image

創建完成后,我們在文件中寫入配置:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
{
    "mcpServers": {
        "apisix-mcp": {
            "command": "node",
            "args": [
                "E:\projects\apisix-mcp\build\index.js"
            ]
        }
    }
}

mcpServers字段代表我們聲明的 MCP 服務,值的類型是對象,其中鍵名為服務名稱,這里我們叫

apisix-mcp

,可以根據自己的業務修改,

apisix-mcp

的值也是一個對象,其中包含了

command

args

兩個字段。

command

代表啟動 MCP 服務要執行的命令,因為我們的服務是用 node.js 寫的,那么這里我們的

command

就是

node

args是要傳入的參數,也就是拼接在

command

后面的內容,這里我們寫的是上一步構建出來的產物的路徑

當配置完成后,我們打開 cursor 設置中 MCP 菜單項,如果沒有看到這個菜單需要升級一下 cursor 的版本,然后我們會看到一個 apisix-mcp 的服務,而且還亮著綠燈,說明已經連接成功了,如果沒有連接成功我們可以點一下刷新按鈕。MCP 服務中還會展示我們的代碼里定義了哪些工具和資源,(這里截圖中的工具比較多是因為我后續實現了比較多個工具了,正常應該只展示我們實現的那兩個工具):

image

要注意的是 cursor 在執行腳本時會彈出一個黑色的終端,代表我們 MCP 服務的進程是執行在這個終端的,在后臺掛著就好了,不要關掉它。

image

接下來,我們在 cursor 的輸入框中,選擇

agent

模式,然后選擇一個比較聰明的模型,例如

claude 3.5/3.7

或者

gpt4oo3-mini

,不要選擇

cursor-small

gpt-4o-mini

這種,因為我自己實測這兩個模型似乎不具備

agent

能力,可能是上下文太小了,所以不會調用 MCP 服務。這里我們選擇

claude-3.7-sonnet

,然后輸入如下圖的操作:

image

然后我們會看到 cursor 執行了

called MCP tool

的操作,一共執行了四次,對應調用的

tool

我們都能直接看到:

image

雖然大模型說創建成功了,但是我們還是自己檢查一下,看看是不是真的成功了,這里我在終端輸入:

ounter(lineounter(lineounter(line
curl http://127.0.0.1:9180/apisix/admin/routes -H "X-API-KEY: $admin_key" | jq

可以看到控制臺打印出了我們創建的路由,并且插件也按照我們的要求配置了,說明真的創建成功了。

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
{
    "key": "/apisix/routes/1742721614502",
    "modifiedIndex": 98,
    "createdIndex": 98,
    "value": {
        "id": "1742721614502",
        "uri": "/api/httpbin/*",
        "upstream": {
            "pass_host": "pass",
            "nodes": {
                "httpbin.org:80": 1
            },
            "type": "roundrobin",
            "scheme": "http",
            "hash_on": "vars"
        },
        "status": 1,
        "create_time": 1742721614,
        "update_time": 1742721614,
        "priority": 0,
        "plugins": {
            "limit-req": {
                "key_type": "var",
                "allow_degradation": false,
                "rate": 2,
                "nodelay": false,
                "key": "remote_addr",
                "burst": 4,
                "rejected_code": 429,
                "policy": "local"
            },
            "cors": {
                "allow_headers": "*",
                "allow_origins": "*",
                "max_age": 3600,
                "expose_headers": "Content-Length,Content-Type",
                "allow_methods": "GET,POST,PUT,DELETE,PATCH,OPTIONS",
                "allow_credential": false
            },
            "limit-count": {
                "show_limit_quota_header": true,
                "count": 5,
                "key_type": "var",
                "time_window": 60,
                "key": "remote_addr",
                "allow_degradation": false,
                "rejected_code": 429,
                "policy": "local"
            }
        }
    }
}

至此為止,我們花了不用兩個小時就能把一個現有服務接入大模型,通過自然語言進行交互。

后續我們要做的就是將所有的 API 轉換為 MCP 中的工具,讓大模型按需調用即可,這一步也很簡單,直接把我們的 OpenAPI 文檔提供給 cursor 就能批量生成了,我用一輪對話就全部生成好了,也就是上面截圖中展示的所有 MCP 工具:

image

而且這里我非常推薦大家直接是用 curosr 去調試 MCP 服務,因為在我們實現 MCP 服務的項目中,如果發現 MCP 服務沒法正常調用,我們可以直接讓 cursor 自己調試,下面貼一個我調試過程中 cursor 自己的執行記錄:

image

cursor 會一邊調用 MCP 服務,根據服務的響應結果去調整我們的源碼,然后自己重新構建新的產物再重新嘗試調用 MCP 服務,直到服務正常工作,從開發到測試的流程自己閉環,真的很強!

總結

MCP 中的概念不僅僅有

tool

這一種,但是目前我實現的功能只用到了這個工具,后續我將繼續完善這個 MCP 服務的項目,等其他功能都摸清楚了再給大家完整的介紹 MCP 中的各種功能的實現。

我花了幾個小時就把這個服務構建出來,而且最終的效果讓我感覺蠻驚訝的,用自然語言去和系統交互的感覺很奇妙,如果再開發一個 MCP 的客戶端,那都不需要寫一個功能健全的控制臺了,可玩性很強,上手又很簡單,非常推薦大家去嘗試寫一下。

目前唯一的問題就是依賴能力比較強的模型,因此調用成本會比較高,但是未來隨著大模型的能力越來越強,調用成本越來越低,后續 MCP 服務可能替代現有傳統前端控制臺成為主流。

如果文章對你有幫助,歡迎點個贊??,respect~點擊關注公眾號,“技術干貨” 及時達!

原文轉載自:https://mp.weixin.qq.com/s/YaQuGQeWhwBWU-aMTle6-A

上一篇:

SpringAI-MCP技術初探

下一篇:

騰訊云DeepSeek API對接微信小程序完全指南
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費