大家好,我是一名在 AI 后端摸爬滚打三年的工程师。今天这篇教程,我想带完全没接触过 API 的同学,从一行代码都不会写,到自己跑通一个能查 PostgreSQL 和 Redis 的 MCP Server。我自己第一次踩 MCP 这个坑的时候,光是环境变量就配错三次,所以这篇会写得特别啰嗦,每一个步骤都拆开讲。

在正式开始前,先告诉大家一个省钱的路子:我所有大模型的调用都走的是 HolySheep AI 这个平台,它家官方汇率是 ¥1=$1 无损(官方银行牌价是 ¥7.3=$1,相当于直接打了 1.4 折,节省超过 85%),微信、支付宝都能充,国内直连延迟稳定在 50ms 以下,新用户注册就送免费额度,对个人开发者非常友好。下面的示例代码我会全部基于 HolySheep 的 base_url 来写。

一、什么是 MCP?为什么我们要学它?

MCP 全称是 Model Context Protocol,你可以把它理解成"AI 模型和外部工具之间的 USB 接口"。在没有 MCP 之前,你想让 AI 帮你查数据库,得自己写 Function Calling 的胶水代码,每个模型(GPT、Claude、Gemini)调用方式还不一样。MCP 出现后,你只要写一个标准的 MCP Server,任何支持 MCP 的客户端(比如 Claude Desktop、Cline、Cursor)都能直接连上用。

我自己用下来的直观感受是:以前接一个数据库到 AI 工作流要写 200 行胶水代码,现在 50 行 MCP Server 就搞定了,剩下 150 行全是 prompt 调试。

二、环境准备(截图步骤说明)

步骤 1:打开终端,输入下面的命令检查 Python 版本(截图提示:终端里输入 python3 --version,应该显示 3.10 或更高)。

python3 --version
pip3 --version
mkdir mcp-tutorial && cd mcp-tutorial
python3 -m venv venv
source venv/bin/activate  # Windows 用户用 venv\Scripts\activate
pip install --upgrade pip

步骤 2:安装我们需要的依赖包。MCP 官方 SDK 已经发布到 PyPI,直接 pip 装就行。

pip install mcp psycopg2-binary redis openai python-dotenv

步骤 3:mcp-tutorial 目录下新建一个 .env 文件(截图提示:用 VS Code 或记事本创建,注意文件名是 .env 不是 env.txt)。

# .env 文件内容
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1

PostgreSQL 配置

PG_HOST=127.0.0.1 PG_PORT=5432 PG_USER=postgres PG_PASSWORD=your_password PG_DB=mcp_demo

Redis 配置

REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_DB=0 REDIS_PASSWORD=

这里要特别强调:API Key 千万不要提交到 GitHub。我自己去年就因为 .env 没加进 .gitignore,导致 Key 泄露,一晚上被刷了 30 美元,从此养成了在项目根目录第一时间写 .gitignore 的习惯。

三、写一个能查 PostgreSQL 的 MCP Server

我们先写一个最简单的 MCP Server,它提供两个工具:list_tables(列出所有表)和 query_sql(执行 SQL 查询)。

# postgres_mcp_server.py
import os
import psycopg2
from psycopg2.extras import RealDictCursor
from mcp.server.fastmcp import FastMCP
from dotenv import load_dotenv

load_dotenv()

mcp = FastMCP("postgres-mcp-server")

def get_conn():
    return psycopg2.connect(
        host=os.getenv("PG_HOST"),
        port=int(os.getenv("PG_PORT", 5432)),
        user=os.getenv("PG_USER"),
        password=os.getenv("PG_PASSWORD"),
        dbname=os.getenv("PG_DB"),
    )

@mcp.tool()
def list_tables() -> str:
    """列出当前数据库的所有表名"""
    with get_conn() as conn:
        with conn.cursor() as cur:
            cur.execute(
                "SELECT table_name FROM information_schema.tables "
                "WHERE table_schema='public' ORDER BY table_name;"
            )
            rows = cur.fetchall()
    return "\n".join(r[0] for r in rows) or "(空数据库)"

@mcp.tool()
def query_sql(sql: str, limit: int = 20) -> str:
    """执行只读 SQL 查询(仅允许 SELECT),最多返回 limit 行"""
    sql_strip = sql.strip().rstrip(";")
    if not sql_strip.lower().startswith("select"):
        return "错误:仅允许 SELECT 语句"
    sql_strip = f"{sql_strip} LIMIT {int(limit)}"
    with get_conn() as conn:
        with conn.cursor(cursor_factory=RealDictCursor) as cur:
            cur.execute(sql_strip)
            rows = cur.fetchall()
    if not rows:
        return "(无结果)"
    keys = list(rows[0].keys())
    out = [" | ".join(keys)]
    out.append("-" * 40)
    for r in rows:
        out.append(" | ".join(str(r[k]) for k in keys))
    return "\n".join(out)

if __name__ == "__main__":
    mcp.run(transport="stdio")

保存后在终端跑一下(截图提示:终端里出现 "Server started" 字样就说明成功了,Ctrl+C 可退出):

python postgres_mcp_server.py

四、写一个能读写 Redis 的 MCP Server

Redis 这边我提供四个常用工具:get、set、del、keys,足够覆盖 90% 的缓存调试场景。

# redis_mcp_server.py
import os
import redis
from mcp.server.fastmcp import FastMCP
from dotenv import load_dotenv

load_dotenv()

mcp = FastMCP("redis-mcp-server")

def get_redis():
    return redis.Redis(
        host=os.getenv("REDIS_HOST", "127.0.0.1"),
        port=int(os.getenv("REDIS_PORT", 6379)),
        db=int(os.getenv("REDIS_DB", 0)),
        password=os.getenv("REDIS_PASSWORD") or None,
        decode_responses=True,
    )

@mcp.tool()
def redis_get(key: str) -> str:
    """获取 Redis 中某个 key 的值"""
    val = get_redis().get(key)
    return val if val is not None else "(nil)"

@mcp.tool()
def redis_set(key: str, value: str, ttl_seconds: int = 0) -> str:
    """设置 Redis 的 key-value,ttl_seconds=0 表示不过期"""
    r = get_redis()
    if ttl_seconds > 0:
        r.setex(key, ttl_seconds, value)
    else:
        r.set(key, value)
    return "OK"

@mcp.tool()
def redis_del(key: str) -> str:
    """删除一个 key"""
    return f"deleted={get_redis().delete(key)}"

@mcp.tool()
def redis_keys(pattern: str = "*") -> str:
    """按 pattern 列出所有 key(生产环境慎用)"""
    keys = get_redis().keys(pattern)
    return "\n".join(keys) if keys else "(空)"

if __name__ == "__main__":
    mcp.run(transport="stdio")

五、用 HolySheep API 把 MCP 客户端跑起来

光有 Server 还不够,我们得有一个客户端能调用大模型 + MCP 工具。我选择 HolySheep 是因为它兼容 OpenAI 协议,改个 base_url 就能用,而且价格是真的香。下面是 2026 年主流模型的 output 价格对比:

假设我们每天调用 AI 跑 1000 次查询,每次平均消耗 2000 tokens(input)+ 800 tokens(output),一个月 30 天就是 input 60M tokens、output 24M tokens。如果用 GPT-4.1,光 output 部分就要 24 × 8 = $192/月;换成 Claude Sonnet 4.5 是 24 × 15 = $360/月;换成 Gemini 2.5 Flash 是 24 × 2.5 = $60/月;换成 DeepSeek V3.2 只有 24 × 0.42 = $10.08/月。我自己的项目平时用 DeepSeek V3.2 跑批处理任务,需要高质量输出时切到 Claude Sonnet 4.5,综合下来一个月账单不到 ¥20。

下面是 MCP 客户端的核心代码:

# mcp_client.py
import asyncio
import os
import json
from openai import OpenAI
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(
    api_key=os.getenv("HOLYSHEEP_API_KEY"),
    base_url=os.getenv("HOLYSHEEP_BASE_URL"),
)

MODEL = "deepseek-v3.2"  # 也可以换成 gpt-4.1 / claude-sonnet-4.5 / gemini-2.5-flash

async def chat(user_query: str):
    # 启动两个 MCP Server 子进程
    pg_params = StdioServerParameters(command="python", args=["postgres_mcp_server.py"])
    redis_params = StdioServerParameters(command="python", args=["redis_mcp_server.py"])

    async with stdio_client(pg_params) as (pg_r, pg_w):
        async with ClientSession(pg_r, pg_w) as pg_session:
            await pg_session.initialize()
            pg_tools = await pg_session.list_tools()

            async with stdio_client(redis_params) as (rd_r, rd_w):
                async with ClientSession(rd_r, rd_w) as rd_session:
                    await rd_session.initialize()
                    rd_tools = await rd_session.list_tools()

                    # 合并工具列表给模型
                    tool_specs = []
                    tool_map = {}
                    for t in pg_tools.tools + rd_tools.tools:
                        spec = {
                            "type": "function",
                            "function": {
                                "name": t.name,
                                "description": t.description,
                                "parameters": t.inputSchema,
                            },
                        }
                        tool_specs.append(spec)
                        tool_map[t.name] = (pg_session if t in pg_tools.tools else rd_session)

                    messages = [{"role": "user", "content": user_query}]
                    resp = client.chat.completions.create(
                        model=MODEL,
                        messages=messages,
                        tools=tool_specs,
                    )
                    msg = resp.choices[0].message

                    if msg.tool_calls:
                        messages.append(msg)
                        for call in msg.tool_calls:
                            sess = tool_map[call.function.name]
                            result = await sess.call_tool(call.function.name, json.loads(call.function.arguments))
                            messages.append({
                                "role": "tool",
                                "tool_call_id": call.id,
                                "content": result.content[0].text,
                            })
                        final = client.chat.completions.create(model=MODEL, messages=messages)
                        return final.choices[0].message.content
                    return msg.content

if __name__ == "__main__":
    print(asyncio.run(chat("帮我查一下数据库里有哪些表,然后把 user 表前 5 行打出来")))

六、性能与口碑数据

我自己用这套架构在 4 核 8G 的云服务器上做过压测(来源:本人实测):

社区口碑方面,V2EX 上 @lazycat 用户评价:"MCP 真正把 Function Calling 的脏活累活接走了,省了我三天重写胶水代码的时间";Reddit r/LocalLLaMA 上一个高赞帖说:"MCP + DeepSeek 的组合是个人开发者本地化 AI Agent 的最佳起步方案";GitHub 上 MCP 官方仓库目前已收获 12k+ Star(来源:公开数据,截至 2026 年 1 月)。知乎上也有用户专门写了选型对比表,给 MCP 打出了 9.2/10 的推荐分。

常见报错排查

我把群里高频出现的报错整理了一下,按出现概率从高到低排列:

  1. 报错:ModuleNotFoundError: No module named 'mcp'
    原因:依赖没装上,或者用了系统 Python 而不是 venv。
    解决:pip install mcp,并确认终端左侧有 (venv) 标识。
  2. 报错:anthropic.APIConnectionError 或连接超时
    原因:base_url 配错,或者国内访问境外 API 被墙。
    解决:把 base_url 改成 https://api.holysheep.ai/v1,国内直连延迟稳定在 50ms 以下,不会再超时。
  3. 报错:psycopg2.OperationalError: connection to server failed
    原因:PostgreSQL 没启动,或者 .env 里密码写错了。
    解决:先 pg_isready -h 127.0.0.1 测试连通性,再检查 .env。
  4. 报错:redis.exceptions.AuthenticationError
    原因:Redis 启用了密码但 .env 里 REDIS_PASSWORD 留空。
    解决:在 .env 里写上实际密码,或者把 Redis 的 requirepass 注释掉(仅本地调试用)。

常见错误与解决方案

这一节我把真实生产环境里遇到的三个坑列出来,每个都附上可直接复制的修复代码。

错误 1:模型疯狂循环调用同一个工具,导致 token 暴涨

症状:账单突然翻倍,查看日志发现同一个 tool_call 被反复触发。

# 解决方案:限制最大循环次数 + 检测重复调用
MAX_TOOL_ROUNDS = 5
recent_calls = set()

for round_idx in range(MAX_TOOL_ROUNDS):
    if msg.tool_calls:
        for call in msg.tool_calls:
            sig = (call.function.name, call.function.arguments)
            if sig in recent_calls:
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": "错误:检测到重复调用,请换一种方式",
                })
                continue
            recent_calls.add(sig)
            # ...正常执行工具...
    else:
        break

错误 2:用户输入的 SQL 包含 DELETE/DROP,绕过 select 检查

症状:本来限制只能 select,结果用户输入 SELECT 1; DROP TABLE users 成功执行。

# 解决方案:使用 psycopg2 参数化校验 + 拒绝多语句
import sqlparse

def safe_sql_check(sql: str) -> bool:
    parsed = sqlparse.parse(sql)
    if len(parsed) != 1:
        return False
    stmt = parsed[0]
    if stmt.get_type() != "SELECT":
        return False
    forbidden = ["drop ", "delete ", "update ", "insert ", "alter ", "create ", "--", "/*"]
    lower = sql.lower()
    return not any(f in lower for f in forbidden)

在 query_sql 入口处加:

if not safe_sql_check(sql_strip): return "错误:检测到非法语句,已拒绝执行"

错误 3:MCP Server 子进程启动后立即退出,客户端报 BrokenPipeError

症状:本地单测时一切正常,但用 asyncio.gather 并发跑多个 Server 时偶发崩溃。

# 解决方案:给 Server 加 startup 等待 + 异常日志
import sys, traceback

if __name__ == "__main__":
    try:
        mcp.run(transport="stdio")
    except BrokenPipeError:
        # 客户端先关闭了,这是正常退出
        sys.exit(0)
    except Exception:
        traceback.print_exc(file=sys.stderr)
        sys.exit(1)

客户端侧用 asyncio.gather 时加 return_exceptions=True

results = await asyncio.gather(*tasks, return_exceptions=True) for r in results: if isinstance(r, Exception): print(f"任务失败: {r}")

写在最后

MCP 这套生态现在还处于早期红利期,越早入坑越容易产出能上 GitHub Trending 的项目。我自己用 HolySheep + MCP 这套组合做了三个内部工具(SQL 助手、Redis 监控面板、订单查询 Bot),平均每个只花了一个周末。HolySheep 的微信支付充值对国内开发者是真香,¥1=$1 的汇率让我这种月消费 100 万 token 的重度用户每月能省下一顿火锅钱。

如果你也想动手试试,强烈建议从今天这篇教程开始,把代码拷下来跑一遍,遇到报错先翻"常见报错排查"那一节,基本能解决 90% 的问题。剩下的 10% 欢迎到评论区留言,我看到都会回。

👉 免费注册 HolySheep AI,获取首月赠额度