一、sdk介绍FastMCP支持写 MCP Server写 MCP Client传输方式包括 stdio、SSE、Streamable HTTP二、自定义mcp server demo代码1说明文档使用手册# tools_demo 轻量示例在内存中实现 **User** 与 **School** 数据通过 **MCP**Model Context Protocol对外提供工具业务数据在 **service/store.py**MCP 在 **mcp/server.py** 中直接调用 store。 --- ## 环境要求 - **Python 3.10**建议 3.12 - 依赖见 requirements.txtmcp[cli]、pydantic、email-validator 等 --- ## 项目结构 text tools_demo/ ├── README.md ├── pyproject.toml ├── requirements.txt ├── .gitignore │ ├── service/ │ ├── __init__.py │ └── store.py # 内存数据与 Pydantic 模型MCP 使用 │ └── mcp/ └── server.py # MCP 服务默认 stdio | 路径 | 说明 | |------|------| | service/store.py | 演示数据线程安全内存字典带种子用户与学校。 | | mcp/server.py | 注册 MCP 工具user_list、user_create、school_list。 | --- ## 首次使用 **Windowscmd** cmd cd /d C:\path\to\tools_demo python -m venv .venv .venv\Scripts\activate pip install -r requirements.txt **Linux / macOS** bash cd /path/to/tools_demo python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt --- ## 在 Cursor 中使用 MCP 1. 完成依赖安装。 2. 在 MCP 配置如 mcp.json中增加路径改成你的本机目录 json mcpServers: { tools-demo: { command: C:\\path\\to\\tools_demo\\.venv\\Scripts\\python.exe, args: [ C:\\path\\to\\tools_demo\\mcp\\server.py ], cwd: C:\\path\\to\\tools_demo, env: {} } } 3. 重载 MCP 或重启 Cursor在对话中调用 **user_list**、**user_create**、**school_list**。 --- ## 仅手动启动 MCP 进程stdio bash python mcp/server.py 其它传输若客户端支持--transport streamable-http 或 sse。 --- ## MCP 工具一览 | 工具名 | 作用 | |--------|------| | user_list | 列出全部用户 | | user_create | 创建用户必填 name可选 email、school_id | | school_list | 列出全部学校 | --- ## 常见问题 | 现象 | 处理 | |------|------| | ModuleNotFoundError: No module named mcp | 用 venv 里的 Python 执行 pip install -r requirements.txt且 MCP 的 command 指向同一解释器。 | | mcp.json 无法解析 | 检查括号与路径转义Windows 可用 /。 | --- ## 开发说明 - 工作目录应为项目根目录含 service/、mcp/MCP 配置里 cwd 指向该目录。 - **mcp/ 下不要添加 mcp/__init__.py**以免与 PyPI 的 mcp 包冲突。2requirements.txtmcp[cli]1.2.0 pydantic2.0.0 email-validator2.0.03业务代码store.py这里没有写具体的service而是mock数据了Shared in-memory store for API and MCP (single process each; same module one store per process). from __future__ import annotations import uuid from threading import Lock from typing import Any from pydantic import BaseModel, EmailStr, Field class User(BaseModel): id: str name: str email: EmailStr | None None school_id: str | None Field(defaultNone) class School(BaseModel): id: str name: str region: str | None None class InMemoryStore: def __init__(self) - None: self._lock Lock() self._users: dict[str, dict[str, Any]] {} self._schools: dict[str, dict[str, Any]] {} self._seed() def _seed(self) - None: s1 str(uuid.uuid4()) s2 str(uuid.uuid4()) self._schools[s1] {id: s1, name: North Institute, region: US-West} self._schools[s2] {id: s2, name: East Academy, region: EU-Central} u1 str(uuid.uuid4()) self._users[u1] { id: u1, name: Ada Lovelace, email: adaexample.com, school_id: s1, } def list_users(self) - list[User]: with self._lock: return [User.model_validate(u) for u in self._users.values()] def get_user(self, user_id: str) - User | None: with self._lock: raw self._users.get(user_id) return User.model_validate(raw) if raw else None def create_user(self, name: str, email: str | None, school_id: str | None) - User: if school_id is not None and school_id not in self._schools: raise ValueError(school_id does not exist) uid str(uuid.uuid4()) row {id: uid, name: name, email: email, school_id: school_id} with self._lock: self._users[uid] row return User.model_validate(row) def update_user( self, user_id: str, name: str | None, email: str | None, school_id: str | None, ) - User | None: with self._lock: row self._users.get(user_id) if not row: return None if school_id is not None and school_id not in self._schools: raise ValueError(school_id does not exist) if name is not None: row[name] name if email is not None: row[email] email if school_id is not None: row[school_id] school_id return User.model_validate(dict(row)) def delete_user(self, user_id: str) - bool: with self._lock: return self._users.pop(user_id, None) is not None def list_schools(self) - list[School]: with self._lock: return [School.model_validate(s) for s in self._schools.values()] def get_school(self, school_id: str) - School | None: with self._lock: raw self._schools.get(school_id) return School.model_validate(raw) if raw else None def create_school(self, name: str, region: str | None) - School: sid str(uuid.uuid4()) row {id: sid, name: name, region: region} with self._lock: self._schools[sid] row return School.model_validate(row) def update_school( self, school_id: str, name: str | None, region: str | None, ) - School | None: with self._lock: row self._schools.get(school_id) if not row: return None if name is not None: row[name] name if region is not None: row[region] region return School.model_validate(dict(row)) def delete_school(self, school_id: str) - bool: with self._lock: if school_id not in self._schools: return False for u in self._users.values(): if u.get(school_id) school_id: u[school_id] None del self._schools[school_id] return True store InMemoryStore()4mcp服务 MCP server: tools call service/store.py in-process. Run from project root: python mcp/server.py Do not add mcp/__init__.py so the PyPI mcp package imports correctly. from __future__ import annotations import argparse import os import sys from pathlib import Path from typing import Any from mcp.server.fastmcp import FastMCP _root Path(__file__).resolve().parent.parent if str(_root) not in sys.path: sys.path.insert(0, str(_root)) from service.store import store mcp FastMCP( tools-demo-bridge, json_responseTrue, ) mcp.tool() def user_list() - list[dict[str, Any]]: List all users. return [u.model_dump(modejson) for u in store.list_users()] mcp.tool() def user_create(name: str, email: str | None None, school_id: str | None None) - dict[str, Any]: Create a user. Optional email and school_id (must reference an existing school). try: u store.create_user(name, email, school_id) except ValueError as e: return {ok: False, detail: str(e)} return u.model_dump(modejson) mcp.tool() def school_list() - list[dict[str, Any]]: List all schools. return [s.model_dump(modejson) for s in store.list_schools()] def main() - None: parser argparse.ArgumentParser(descriptionMCP server for tools_demo) parser.add_argument( --transport, defaultos.environ.get(MCP_TRANSPORT, stdio), choices(stdio, streamable-http, sse), helpMCP transport (default: stdio), ) args parser.parse_args() mcp.run(transportargs.transport) if __name__ __main__: main()cursor使用1首次需要installpython3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt目的python3 -m venv .venv用当前系统的python3在当前目录里建一个名叫.venv的文件夹。里面是一套单独的 Python 解释器 pip和系统自带的 Python 分开。这样不同项目可以用不同版本的库互不干扰。source .venv/bin/activate激活 这个虚拟环境。激活后当前终端里打的python、pip都会指向.venv里的而不是系统全局的。前面一般会多显示(.venv)之类提示。退出虚拟环境deactivatepip install -r requirements.txt用当前已激活环境里的 pip按requirements.txt里列出的包名和版本 批量安装例如mcp、fastapi等。包装在.venv里不会乱改系统 Python 的包。2首次需要配置mcptools-demo: { command: C:\\python-project\\tools_demo\\.venv\\Scripts\\python.exe, args: [ C:\\python-project\\tools_demo\\mcp\\server.py ], cwd: C:\\python-project\\tools_demo, env: {} }3调用