使用说明
mcpp
一个轻量级的MCP服务器,从单个进程加载多个工具。mcpp不是为每个工具运行单独的MCP服务器,而是充当多路复用器:一个stdio服务器,许多工具模块,零协调开销。
为什么
这 模型上下文协议 为AI代理(Claude Code、Codex等)提供了一种调用外部工具的标准方法。但默认模式是 每个工具一台服务器 --每个都有自己的流程、启动成本和配置条目。这很快就会变得笨拙。
mcpp扭转了这一局面。您可以在单个注册表中注册工具模块 tools.yaml 文件。每个模块都是一个目录,其中包含 tool.yaml 舱单和a mcpptool.py 实施。服务器在启动时发现它们,通过一个 tools/list,以及路线 tools/call 请求到正确的模块。添加新工具意味着创建一个目录并重新启动服务器。服务器代码没有更改。没有新的MCP配置条目。
特性
- 一台服务器,多种工具 --单进程、单配置条目、无限制的工具模块
- 声明性合同 --每个工具在中定义其模式
tool.yaml(JSON模式),与实现完全分离 - 延迟加载 --Python代码仅在第一次调用时导入,而不是在启动时导入。损坏的模块不会阻止服务器启动
- 外部工具 --模块可以存在于磁盘上的任何地方;只要指向他们
tools.yaml - 双重受众反应 --工具可以使用MCP内容注释为代理返回人类可读的显示文本和结构化数据
- 多用户、多项目 --the
mcpp-plan该工具从单个共享数据库中跟踪每个用户每个项目的任务 - 超时执行 --每次呼叫超时通过
SIGALRM防止失控的工具阻塞服务器 - 内置帮助 --代理可以查询
help在不导入任何工具代码的情况下发现可用工具及其运行时配置 - 人工CLI --
cli.py提供用于测试和直接使用的命令行界面
快速开始
1.安装
克隆仓库并确保Python 3.10+可用。唯一的外部依赖是 pyyaml.
git clone https://github.com/pacmac/mcpp.git
cd mcpp
pip install pyyaml
包括 计划 任务管理器(可选):
git clone https://github.com/pacmac/mcpp-plan.git ../mcpp-plan
然后将其添加到 tools.yaml:
modules:
- path: ../mcpp-plan
2.配置您的代理
克劳德代码:
claude mcp add mcpp --scope user \
-- python3 /path/to/mcpp/mcpp.py
Codex CLI (~/.codex/config.toml):
[mcp_servers.mcpp]
command = "python3"
args = ["/path/to/mcpp/mcpp.py"]
env = { MCPP_LOG_LEVEL = "error", MCPP_TIMEOUT_SECONDS = "30" }
任何兼容MCP的客户端 --mcpp通过stdio使用JSON-RPC 2.0:
python3 /path/to/mcpp/mcpp.py
3.使用它
配置后,您的代理将看到所有已注册的工具。在克劳德代码中,它们显示为 mcp__mcpp__<tool_name>:
> What tools do you have from mcpp?
I have these tools available:
- fetch_page -- fetch and cache web content
- what_add -- scaffold a new plan directory
- plan_task_new -- create a new task with steps
- plan_task_list -- list all tasks
... (19 plan tools total)
建筑
┌─────────────────────────────────────────────────────┐
│ AI Agent (Claude Code, Codex, etc.) │
│ │
│ tools/list ──► all tool schemas (from tool.yaml) │
│ tools/call ──► routed to correct module │
└──────────────┬──────────────────────────────────────┘
│ stdin/stdout (JSON-RPC 2.0)
┌──────────────▼──────────────────────────────────────┐
│ mcpp.py (single process) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │tools.yaml│ │ tool │ │ routing │ │
│ │ registry │─►│ discovery│─►│ table │ │
│ └──────────┘ └──────────┘ └────┬─────┘ │
│ │ │
│ ┌──────────┬───────────┼──────────┐ │
│ ▼ ▼ ▼ ▼ │
│ fetch_page what plan your_tool │
│ tool.yaml tool.yaml tool.yaml tool.yaml │
│ mcpptool.py mcpptool.py mcpptool.py ... │
└─────────────────────────────────────────────────────┘
启动: 阅读 tools.yaml 注册表,解析每个模块的 tool.yaml 显示。尚未导入Python。
第一通电话: 懒散地导入模块 mcpptool.py,缓存它,路由呼叫。
后续通话: 直接命中缓存的模块。
工具如何工作
工具模块是一个包含两个文件的目录:
tools/my_tool/
tool.yaml # declares the contract (schema)
mcpptool.py # implements the logic
tool.yaml——合约
这是服务器在启动时读取的唯一文件。它定义了该工具在没有任何Python代码的情况下的功能。
name: my_tool # unique module identifier
scope: local # "local" (workspace-relative) or "global"
about: "One-line description." # shown in help listings
tools:
- name: my_tool_search # globally unique tool name
description: "Search for items matching a query."
inputSchema:
type: object
properties:
query:
type: string
description: "Search query"
limit:
type: integer
description: "Max results (default: 10)"
minimum: 1
maximum: 100
required:
- query
领域:
| 字段 | 必填 | 描述 |
|---|---|---|
name |
是 | 模块标识符。在所有注册的模块中必须是唯一的 |
scope |
没有 | "local" (默认)--工具对工作区文件进行操作。 "global" --独立工作空间 |
about |
否 | 仅显示一行描述 help 工具 |
tools |
是 | 工具定义列表,每个都有 name, description,以及 inputSchema |
一个模块可以定义多个工具。这 mcpp-plan 模块在一个模块名称下定义了19个工具。
工具命名约定: <module>_<entity>_<action>例如。 plan_task_new, plan_step_done.
mcpptool.py的实现
必须导出 execute() 功能:
def execute(tool_name: str, arguments: dict, context: dict | None = None) -> dict:
"""Handle a tool call.
Args:
tool_name: Which tool was called (matches a name from tool.yaml)
arguments: Parameters from the agent, validated against inputSchema
context: Runtime info from the server:
{
"workspace_dir": "/abs/path/to/cwd",
"module_dir": "/abs/path/to/this/module",
"module_scope": "local" # or "global"
}
Returns:
{"success": True, "result": <any>} # success
{"success": True, "result": <data>, "display": "..."} # success with display text
{"success": False, "error": "description"} # failure
"""
这就是整个合同。 一个函数,三个参数,一个字典返回。
可选出口
def get_info(context: dict | None = None) -> dict:
"""Return runtime configuration for agent discoverability.
Called by the built-in help tool."""
return {
"params": {
"query": {"values": None, "default": None},
"limit": {"values": None, "default": 10},
}
}
def initialize() -> dict:
"""Called once at module import time. Return {"success": False, ...} to warn."""
return {"success": True}
显示键
当工具同时返回时 result 和 display,服务器发出两个带有观众注释的MCP内容项:
return {
"success": True,
"result": {"tasks": [...]}, # structured data for the agent
"display": "**Tasks**\n- alpha\n- beta" # markdown for the human
}
代理接收结构化数据以进行推理。人类看到格式化的标记。这种分离使工具能够通过一次调用向两个受众提供丰富的输出。
注册表(tools.yaml)
顶级 tools.yaml 列出要加载的模块:
modules:
- path: tools/fetch_page # built-in, relative to tools.yaml
- path: tools/what # built-in
- path: ../mcpp-plan # external: github.com/pacmac/mcpp-plan
- path: /opt/custom/my_tool # absolute paths work too
路径是相对于包含以下内容的目录解析的 tools.yaml.以开头的目录 _ 被忽略(用于模板)。
要添加工具,请执行以下操作: 创建目录,向添加条目 tools.yaml,重新启动服务器。
要删除工具,请执行以下操作: 从中删除其条目 tools.yaml,重新启动。
创建新工具
来自模板
cp -r tools/_template_pkg tools/my_tool
编辑 tools/my_tool/tool.yaml 要定义架构,请编辑 tools/my_tool/mcpptool.py 实现你的逻辑。
从零开始
1.创建目录:
mkdir tools/my_tool
2.编写工具.yaml:
name: my_tool
scope: local
about: "Does something useful."
tools:
- name: my_tool_run
description: "Run the tool with given parameters."
inputSchema:
type: object
properties:
target:
type: string
required:
- target
3.编写mcpptool.py:
from __future__ import annotations
from typing import Any
def execute(tool_name: str, arguments: dict[str, Any], context: dict[str, Any] | None = None) -> dict[str, Any]:
if tool_name == "my_tool_run":
target = arguments["target"]
workspace = (context or {}).get("workspace_dir", ".")
# ... do work ...
return {"success": True, "result": {"target": target, "status": "done"}}
return {"success": False, "error": f"Unknown tool: {tool_name}"}
4.注册:
增添 tools.yaml:
modules:
- path: tools/my_tool
# ... existing modules ...
5.重新启动服务器。 新工具出现在 tools/list 立即。
外部工具
工具模块不需要位于mcpp目录中。磁盘上的任何目录都可以是一个工具模块——只需指向它:
modules:
- path: /home/user/projects/my-tool # absolute path
- path: ../../other-repo/tool-module # relative to tools.yaml
这就是 mcpp-plan 该工具是集成的,它位于一个单独的存储库中,由注册表中的路径引用。该模块有自己的git历史、测试和发布周期。mcpp只是加载它。
外部工具的要求是相同的: 一 tool.yaml 舱单和a mcpptool.py 随着 execute().无需特殊包装,无需setup.py,无需pip安装。
多模块工具
一个模块可以暴露许多工具。这 mcpp-plan 该模块通过四组中的19个工具演示了这一点:
name: plan
scope: local
about: "Manage project tasks and steps."
tools:
# Task management (7 tools)
- name: plan_task_new
- name: plan_task_list
- name: plan_task_show
- name: plan_task_status
- name: plan_task_switch
- name: plan_task_archive
- name: plan_task_notes
# Step tracking (7 tools)
- name: plan_step_list
- name: plan_step_show
- name: plan_step_switch
- name: plan_step_done
- name: plan_step_new
- name: plan_step_delete
- name: plan_step_notes
# User identity (2 tools)
- name: plan_user_show
- name: plan_user_set
# Project metadata (3 tools)
- name: plan_project_show
- name: plan_project_set
- name: plan_readme
这 execute() 内部功能路线:
tool_map = {
"plan_task_new": _cmd_task_new,
"plan_task_list": _cmd_task_list,
# ...
}
def execute(tool_name, arguments, context=None):
handler = tool_map.get(tool_name)
if not handler:
return {"success": False, "error": f"Unknown tool: {tool_name}"}
return handler(workspace_dir, arguments)
内置帮助
每个mcpp实例都包含一个 help 工具自动。代理商可以调用它来发现可用的内容:
# No arguments: list all modules
help()
# Returns: module names and their 'about' descriptions (no Python imports needed)
# With tool name: get runtime details
help(tool="fetch_page")
# Returns: output of that module's get_info(), including param defaults and valid values
多用户、多项目支持
这 mcpp-plan 该工具演示了mcpp对复杂、有状态工具的支持:
- 单一共享数据库 (
~/.config/plan/plan.db)--所有项目、所有用户、一个SQLite文件 - 自动项目检测 --工作空间目录映射到项目;每个项目都有独立的任务列表
- 每个用户状态 --每个操作系统用户在每个项目中都有自己的活动任务;
su让其他用户看到他们的任务 - 跨项目隔离 --奔跑从
/project-a显示项目a的任务;逃避/project-b显示了项目b。相同的服务器、相同的数据库、不同的作用域
~/.config/plan/plan.db
├── project: webapp (CWD: /home/user/webapp)
│ ├── user: alice → active task: auth-refactor
│ └── user: bob → active task: api-migration
├── project: cli-tool (CWD: /home/user/cli-tool)
│ └── user: alice → active task: add-flags
这 scope: local 融入 tool.yaml 告诉服务器通过 workspace_dir 在上下文中,该工具用于解析正确的项目。
配置
环境变量
| 变量 | 默认值 | 描述 |
|---|---|---|
MCPP_BASE_DIR |
目录包含 mcpp.py |
在哪里可以找到 tools.yaml |
MCPP_LOG_LEVEL |
info |
debug, info, warning, error |
MCPP_TIMEOUT_SECONDS |
30 |
每次工具调用超时(秒) |
克劳德代码
# Add with environment overrides
claude mcp add mcpp --scope user \
--env MCPP_LOG_LEVEL=error \
--env MCPP_TIMEOUT_SECONDS=60 \
-- python3 /path/to/mcpp/mcpp.py
直接JSON配置(任何MCP客户端)
{
"mcpServers": {
"mcpp": {
"command": "python3",
"args": ["/path/to/mcpp/mcpp.py"],
"env": {
"MCPP_LOG_LEVEL": "error"
}
}
}
}
人工CLI
对于没有AI代理的测试和直接使用:
# List all registered tools
python3 cli.py list
# Call a tool
python3 cli.py call fetch_page --url https://example.com --max_chars 5000
# Get help on a specific tool
python3 cli.py call help --tool plan_task_new
项目布局
mcpp/
├── mcpp.py # MCP server (reads stdin, writes stdout)
├── cli.py # Human CLI wrapper
├── tools.yaml # Module registry
├── tools/
│ ├── _template_pkg/ # Copy-paste starter for new tools
│ │ ├── tool.yaml
│ │ ├── mcpptool.py
│ │ └── helper.py
│ ├── fetch_page/ # URL fetcher with disk cache
│ │ ├── tool.yaml
│ │ └── mcpptool.py
│ └── what/ # Project scaffolding
│ ├── tool.yaml
│ └── mcpptool.py
└── README.md
协议遵从
mcpp实现了 模型上下文协议 使用JSON-RPC 2.0通过stdio:
| MCP方法 | 支持 | 注意事项 |
|---|---|---|
initialize |
是 | 返回协议版本 2025-06-18 |
tools/list |
是 | 返回所有模块的所有工具模式 |
tools/call |
是 | 路由到正确的模块,强制超时 |
shutdown |
是 | 设置关机标志 |
notifications/* |
是 | 默默承认 |
| 内容注释 | 是 | audience: ["user"] / ["assistant"] 通过显示键 |
受启发于
这个项目的灵感来自 安德烈亚斯·斯皮斯 (GitHub)和他的 人工智能辅助编码视频.
许可证
免费供个人使用、研究、教育、非营利组织和政府使用。不允许用于商业用途。看 许可证 全文。