Voocii博客
首页博客AI 热榜作品集读书友链工具关于

© 2026 Voocii. Built with Next.js & tRPC.

GitHubXEmailRSS


MCP 最新版实战 - 让 codex 协助管理我的博客

AI & LLMrick-hayekrick-hayek2026年8月12日

过一遍最新版 MCP stdio 模式创建服务器和客户端

服务器 MCP Server

1. 初始化项目

mkdir mcp-server && cd mcp-server
npm init -y
npm pkg set type=module

2. 安装依赖

npm install @modelcontextprotocol/server zod dotenv
npm install -D typescript @types/node tsx

3. 创建源代码文件 server.ts

  • 引入依赖 新版本的依赖包从 sdk 拆分为 server 和 client。这里引入 server 包:

    import { McpServer } from '@modelcontextprotocol/server';
    import { serveStdio } from '@modelcontextprotocol/server/stdio';
    import * as z from 'zod/v4';
    import dotenv from 'dotenv';
    
  • 创建服务器

    dotenv.config(); // 确保 API_URL, API_KEY 等环境变量可以从 .env 文件中读取
    
    // 假设你已经有了一个公开的 API 接口,可以把他放在 .env 文件里:
    // API_URL=https://localhost:3000/api/v1/
    // 假如没有,可以用这个公开的天气 API 测试:
    // https://api.weather.gov/alerts/active?area=CA
    const API_URL = process.env.API_URL || ''; 
    // 用于调用需要认证的 API
    const API_KEY = process.env.API_KEY || ''; 
    
    function createServer() : McpServer {
        const server = new McpServer(
            { "name": "blog-posts", "version": "0.0.1" }
        );
    
        server.registerTool(
            'fetch-posts',
            {
                'description': 'Fetch blog posts from online API.', 
                'inputSchema': z.object({
                    'page': z.number().int().min(1).max(100).default(1).describe('page number, start from 1, default is 1'),
                    'limit': z.number().int().min(1).max(100).default(10).describe('limit of posts per page, range 1-100, default is 10')
                }),
            },
            async (input) => {
                const { page, limit } = input;
                // 以下 url 需要修改为你自己的 API 结构,
                // 或者直接用那个天气 API:https://api.weather.gov/alerts/active?area=CA
                const url = `${API_URL}/posts?page=${page}&limit=${limit}`; 
                const response = await fetch(url);                
                
                if (!response.ok) {
                    throw new Error(`Failed to fetch posts: ${response.statusText}`);
                }
                const data = await response.json();
                return { content: [
                    { type: 'text', text: JSON.stringify(data) }
                ] };
            }
        );
    
        return server;
    }
    
    serveStdio(createServer);
    
    console.error("MCP server is running. You can now connect to it using a compatible client.");
    
    

4. 运行测试

服务器代码写好后,编译一下确保没问题:

npx tsc

启动 MCP Inspector 来检查服务器是否正常:

npx @modelcontextprotocol/inspector npx tsx server.ts

会在浏览器启动一个 web app (实际上就是一个 MCP 客户端),从界面上调用服务器可用的工具:

工具列表:

mcpinspector-tools.png

选择获取博客,然后点击执行:

mcpinspector-results.png

测试没问题后可以 Ctrl + C 停止运行服务器。到时客户端运行后会自动开启服务器。

客户端 MCP Client

1. 初始化项目

mkdir mcp-client && cd mcp-client
npm init -y
npm pkg set type=module

2. 安装依赖

npm install @modelcontextprotocol/client dotenv
npm install -D typescript @types/node tsx

3. 创建源代码文件 client.ts

  • 引入依赖 新版本的依赖包从 sdk 拆分为 server 和 client。这里引入 server 包:

    import { Client } from '@modelcontextprotocol/client';
    import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
    import dotenv from 'dotenv';
    
  • 创建客户端

    dotenv.config(); // 确保 API_URL, API_KEY 等环境变量可以从 .env 文件中读取
    
    const client = new Client({ name: "blog-posts-client", version: "0.0.1" });
    
    // command 和 args 组成启动 **服务器** 的命令: npx tsx ../mcp-server/server.ts
    // server.ts 的路径也可以改成绝对路径,能让客户端/host找到就行
    // 要注意这个 env 参数,如果服务器那边向上面的代码那样用到了 process.env.xxxx 来引入环境变量,
    // 那么客户端这里必须加上服务器需要的每一个环境变量:API_URL,API_KEY
    const transport = new StdioClientTransport({
        command: "npx",
        args: ["tsx", "../mcp-server/server.ts"],
        env: {
            ...process.env,
            API_URL: process.env.API_URL || '',
            API_KEY: process.env.API_KEY || ''
        }
    });
    
    // 必须用 await,否则后面的调用服务操作将不可预料
    await client.connect(transport);
    
    // client.listTools() 能正确返回服务器注册的工具列表的前提是,创建服务器时加上 tools 的能力:
    // const server = new McpServer(
    //    { "name": "blog-posts", "version": "0.0.1" }, 
    //    { capabilities: {  tools: {} } }
    // );
    // 
    // 否则会报错:
    // Client.listTools() called but server does not advertise tools capability - returning empty list
    const {tools} = await client.listTools();
    console.log("Available tools:");
    tools.forEach((tool) => {
        console.log(`- ${tool.name}: ${tool.description}`);
    });
    
    const fetchPostsResult = await client.callTool({
        name: 'fetch-posts', // 精确匹配服务器里注册好的工具
        arguments: { page: 1, limit: 5 } // 工具参数
    });
    
    for (const block of fetchPostsResult.content) {
        if (block.type === 'text') console.log(block.text);
    }
    

4. 运行测试

客户端代码写好后,编译一下确保没问题:

npx tsc

启动客户端:

npx tsx client.ts

客户端执行结果:

client-result.png

把 MCP 服务器配置到 codex

有两种方式

1. 修改配置文件

可以直接修改 config.toml 文件:

vim ~/.codex/config.toml

添加以下内容:

[mcp_servers.blog-tools]
enabled = true
command = "npx"
args = ["tsx", "/Users/rick/src/mcp-server/server.ts"]

[mcp_servers.blog-tools.env]
API_URL = "https://localhost:3000/api/v1/"
API_KEY = "xxxYYYzzz="

上面一块内容主要是启动服务器的命令、参数和服务器代码的绝对路径;下面一块内容是环境变量。

2. codex 界面上添加

设置 \ 插件 \ 添加 \ 添加 MCP 服务器,然后填入名称,命令,参数,以及环境变量

codex-add-mcp.png

最后保存,确保工具是启动状态 enabled = true,然后重新启动 codex。

3. 对话 codex

之后就可以开始让 codex 用了。对话时可以先让 codex 知道有个博客工具的 MCP 服务器,然后让他查个博客之类的工作,有了上下文,后续就可以直接说发布哪个目录下你写好的文章:

codex-blog-command.png

评论 (0)

暂无评论,快来抢沙发吧!

目录
  • 服务器 MCP Server
  • 客户端 MCP Client
  • 把 MCP 服务器配置到 codex