Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 82ba732

Browse files
feat(plugins): Refactor Python plugin support and add new features
- Redesigned the loading and execution mechanism for Python plugins - Added new mcp_sdk.py to simplify plugin development - Updated plugin examples and related CMake configurations - Optimized Python environment initialization and error handling - Added support for exporting plugins with different Python environments - Achieved seamless compatibility between C++-developed and Python-developed plugins in terms of user experience
1 parent 5b0455f commit 82ba732

24 files changed

+1362
-800
lines changed

‎CMakeLists.txt‎

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.22)
2-
project(MCPServer.cpp LANGUAGES CXX C VERSION 1.0.5.0)
2+
project(MCPServer.cpp LANGUAGES CXX C VERSION 1.0.6.0)
33

44
# Add option for Python support
55
option(ENABLE_PYTHON_PLUGINS "Enable Python plugin support" ON)
@@ -98,20 +98,8 @@ add_subdirectory(src/Resources)
9898
add_subdirectory(src/routers)
9999
add_subdirectory(src/Prompts)
100100

101-
# Conditionally add Python support
102-
if(ENABLE_PYTHON_PLUGINS)
103-
find_package(Python COMPONENTS Interpreter Development)
104-
if(Python_FOUND)
105-
message(STATUS "Python found: ${Python_VERSION}")
106-
message(STATUS "Python executable: ${Python_EXECUTABLE}")
107-
message(STATUS "Python include dirs: ${Python_INCLUDE_DIRS}")
108-
message(STATUS "Python libraries: ${Python_LIBRARIES}")
109-
else()
110-
message(WARNING "Python not found. Disabling Python plugin support.")
111-
set(ENABLE_PYTHON_PLUGINS OFF)
112-
endif()
113-
endif()
114-
101+
include(cmake/EnablePython.cmake)
102+
enable_python()
115103
# turn off mimalloc tests and examples
116104
set(MI_BUILD_TESTS OFF CACHE BOOL "Build mimalloc tests" FORCE)
117105
set(MI_BUILD_EXAMPLES OFF CACHE BOOL "Build mimalloc examples" FORCE)

‎README.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,30 @@ MCPServer.cpp supports a powerful plugin system that allows extending functional
197197
- `safe_system_plugin`: Secure system command execution
198198
- `example_stream_plugin`: Streaming data example
199199

200+
### Python Plugins
201+
202+
MCPServer++ now supports Python plugins through a new Python SDK that makes plugin development more intuitive. Python plugins are compiled to dynamic libraries (DLL/SO) that wrap Python code using pybind11.
203+
204+
#### Creating Python Plugins
205+
206+
To create a new Python plugin, use the `plugin_ctl` tool:
207+
208+
```bash
209+
./plugin_ctl create -p my_python_plugin
210+
```
211+
212+
This will generate a Python plugin template that uses the new Python SDK with decorators and helper functions.
213+
214+
#### Python Plugin Features
215+
216+
- Decorator-based tool definition with `@tool`
217+
- Automatic JSON handling
218+
- Streaming tool support
219+
- Parameter validation helpers
220+
- Easy integration with the MCP protocol
221+
222+
For detailed information about Python plugin development, see [Python Plugins Documentation](docs/PYTHON_PLUGINS.md).
223+
200224
### Plugin Development
201225

202226
See [plugins/README.md](plugins/README.md) for detailed information on developing custom plugins.

‎README_zh.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,30 @@ MCPServer.cpp 支持强大的插件系统,允许在不修改核心服务器的
180180
- `safe_system_plugin`: 安全系统命令执行
181181
- `example_stream_plugin`: 流式数据示例
182182

183+
### Python 插件
184+
185+
MCPServer++ 现在通过新的 Python SDK 支持 Python 插件,这使得插件开发更加直观。Python 插件被编译为动态库 (DLL/SO),使用 pybind11 包装 Python 代码。
186+
187+
#### 创建 Python 插件
188+
189+
要创建新的 Python 插件,请使用 [plugin_ctl](file:///D:/codespace/MCPServer++/tools/plugin_ctl.cpp#L759-L759) 工具:
190+
191+
```bash
192+
./plugin_ctl create -p my_python_plugin
193+
```
194+
195+
这将生成一个使用新的 Python SDK 的 Python 插件模板,其中包含装饰器和辅助函数。
196+
197+
#### Python 插件特性
198+
199+
- 基于装饰器的工具定义,使用 [@tool](file://d:\codespace\MCPServer++\plugins\sdk\mcp_sdk.py#L173-L186)
200+
- 自动 JSON 处理
201+
- 流式工具支持
202+
- 参数验证辅助函数
203+
- 与 MCP 协议的轻松集成
204+
205+
有关 Python 插件开发的详细信息,请参阅 [Python 插件文档](docs/PYTHON_PLUGINS_zh.md)
206+
183207
### 插件开发
184208

185209
有关开发自定义插件的详细信息,请参阅 [plugins/README_zh.md](plugins/README_zh.md)

‎cmake/EnablePython.cmake‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
include_guard(GLOBAL)
2+
3+
function(target_enable_python target_name)
4+
if(ENABLE_PYTHON_PLUGINS)
5+
find_package(Python COMPONENTS Interpreter Development)
6+
if(Python_FOUND)
7+
target_include_directories(${target_name} PUBLIC ${Python_INCLUDE_DIRS})
8+
else()
9+
message(WARNING "Python not found. Disabling Python plugin support.")
10+
set(ENABLE_PYTHON_PLUGINS OFF)
11+
endif()
12+
endif()
13+
endfunction()
14+
15+
function(enable_python)
16+
if(ENABLE_PYTHON_PLUGINS)
17+
find_package(Python COMPONENTS Interpreter Development)
18+
if(Python_FOUND)
19+
message(STATUS "Python found: ${Python_VERSION}")
20+
message(STATUS "Python executable: ${Python_EXECUTABLE}")
21+
message(STATUS "Python include dirs: ${Python_INCLUDE_DIRS}")
22+
message(STATUS "Python libraries: ${Python_LIBRARIES}")
23+
else()
24+
message(WARNING "Python not found. Disabling Python plugin support.")
25+
set(ENABLE_PYTHON_PLUGINS OFF)
26+
endif()
27+
endif()
28+
endfunction()

‎cmake/PluginCommon.cmake‎

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,122 @@ function(configure_plugin plugin_name src_files)
124124
endforeach()
125125
endif()
126126
endif()
127+
endfunction()
128+
129+
# Common function to configure a Python plugin
130+
# args:
131+
# plugin_name - Name of the plugin
132+
# python_module - Path to the Python module file (.py)
133+
function(configure_python_plugin plugin_name python_module)
134+
# Find required packages
135+
find_package(Python COMPONENTS Interpreter Development REQUIRED)
136+
137+
# Add the plugin library using the pybind wrapper
138+
add_library(${plugin_name} SHARED
139+
${PROJECT_SOURCE_DIR}/plugins/sdk/pybind_module_plugin.cpp
140+
)
141+
142+
# Include directories
143+
target_include_directories(${plugin_name} PRIVATE
144+
# MCPServer++ include directories
145+
${PROJECT_SOURCE_DIR}/plugins/sdk
146+
${PROJECT_SOURCE_DIR}/include
147+
${PROJECT_SOURCE_DIR}/third_party/nlohmann
148+
${PROJECT_SOURCE_DIR}/third_party/pybind11/include
149+
${PROJECT_SOURCE_DIR}/src
150+
)
151+
152+
# Add preprocessor definition for DLL export
153+
target_compile_definitions(${plugin_name} PRIVATE MCPSERVER_API_EXPORTS PYBIND11_EXPORT_OVERRIDE)
154+
155+
# Link libraries
156+
target_link_libraries(${plugin_name} PRIVATE
157+
pybind11::embed
158+
mcp_business
159+
)
160+
161+
# Set output directory for plugins to bin/plugins
162+
set_target_properties(${plugin_name} PROPERTIES
163+
PREFIX ""
164+
RUNTIME_OUTPUT_DIRECTORY ${PLUGINS_OUTPUT_DIR}
165+
LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_OUTPUT_DIR}
166+
)
167+
168+
if(WIN32)
169+
set_target_properties(${plugin_name} PROPERTIES SUFFIX ".dll")
170+
else()
171+
set_target_properties(${plugin_name} PROPERTIES SUFFIX ".so")
172+
endif()
173+
174+
# Install the plugin to bin/plugins (always install plugins)
175+
install(TARGETS ${plugin_name}
176+
RUNTIME DESTINATION bin/plugins
177+
LIBRARY DESTINATION bin/plugins
178+
)
179+
180+
# Copy the Python module file to the output directory after build
181+
add_custom_command(TARGET ${plugin_name} POST_BUILD
182+
COMMAND ${CMAKE_COMMAND} -E copy
183+
${python_module}
184+
$<TARGET_FILE_DIR:${plugin_name}>
185+
)
186+
187+
# Copy the SDK file to the output directory after build if it exists
188+
set(sdk_file "${PROJECT_SOURCE_DIR}/plugins/sdk/mcp_sdk.py")
189+
if(EXISTS ${sdk_file})
190+
add_custom_command(TARGET ${plugin_name} POST_BUILD
191+
COMMAND ${CMAKE_COMMAND} -E copy
192+
${sdk_file}
193+
$<TARGET_FILE_DIR:${plugin_name}>
194+
)
195+
endif()
196+
197+
# Install the Python module file
198+
install(FILES ${python_module}
199+
DESTINATION bin/plugins
200+
)
201+
202+
# Install the SDK file if it exists
203+
if(EXISTS ${sdk_file})
204+
install(FILES ${sdk_file}
205+
DESTINATION bin/plugins
206+
)
207+
endif()
208+
209+
# automatically generate tools.json - always do this for runtime configs
210+
set(json_source_file "${CMAKE_CURRENT_SOURCE_DIR}/tools.json")
211+
set(json_target_file "${plugin_name}_tools.json")
212+
213+
if(EXISTS ${json_source_file})
214+
# Create configs directory if not exists
215+
file(MAKE_DIRECTORY ${CONFIGS_OUTPUT_DIR})
216+
217+
configure_file(
218+
${json_source_file}
219+
${CONFIGS_OUTPUT_DIR}/${json_target_file}
220+
COPYONLY
221+
)
222+
223+
# build when the plugin is built
224+
add_custom_command(
225+
OUTPUT ${CONFIGS_OUTPUT_DIR}/${json_target_file}
226+
COMMAND ${CMAKE_COMMAND} -E copy_if_different
227+
${json_source_file}
228+
${CONFIGS_OUTPUT_DIR}/${json_target_file}
229+
DEPENDS ${json_source_file}
230+
COMMENT "Copying ${plugin_name} tools.json file to configs directory"
231+
)
232+
233+
add_custom_target(${plugin_name}_json ALL
234+
DEPENDS ${CONFIGS_OUTPUT_DIR}/${json_target_file}
235+
)
236+
237+
add_dependencies(${plugin_name} ${plugin_name}_json)
238+
239+
# Install configs to bin/configs (always install configs)
240+
install(FILES ${json_source_file}
241+
DESTINATION bin/configs
242+
RENAME ${json_target_file}
243+
)
244+
endif()
127245
endfunction()

‎docs/PYTHON_PLUGINS.md‎

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Python Plugins for MCP Server++
2+
3+
Python plugins provide an easy way to extend the functionality of the MCP Server++ using Python. With the new Python SDK, developers can create plugins more intuitively using decorators and other syntactic sugar.
4+
5+
## Table of Contents
6+
7+
- [Introduction](#introduction)
8+
- [Python SDK Overview](#python-sdk-overview)
9+
- [Creating a Python Plugin](#creating-a-python-plugin)
10+
- [Plugin Structure](#plugin-structure)
11+
- [Using the Python SDK](#using-the-python-sdk)
12+
- [Building Python Plugins](#building-python-plugins)
13+
- [Best Practices](#best-practices)
14+
15+
## Introduction
16+
17+
Python plugins are dynamic libraries (DLL on Windows, so on Linux) that wrap Python code using pybind11. They implement the standard MCP plugin interface while allowing the actual plugin logic to be written in Python.
18+
19+
## Python SDK Overview
20+
21+
The Python SDK (`mcp_sdk.py`) provides a set of utilities and decorators to make plugin development more intuitive:
22+
23+
1. `@tool` decorator - Register functions as MCP tools
24+
2. Parameter helper functions - Easily define tool parameters
25+
3. `ToolType` enum - Specify standard or streaming tools
26+
4. Automatic JSON handling - Automatically convert between Python objects and JSON
27+
28+
## Creating a Python Plugin
29+
30+
Use the `plugin_ctl` tool to generate a new Python plugin template:
31+
32+
```bash
33+
./plugin_ctl create -p my_python_plugin
34+
```
35+
36+
This will create a new directory `my_python_plugin` with the basic Python plugin structure.
37+
38+
## Plugin Structure
39+
40+
A typical Python plugin consists of:
41+
42+
- `plugin_name.py` - The main Python plugin implementation using the SDK
43+
- `tools.json` - JSON file describing the tools provided by the plugin
44+
- `CMakeLists.txt` - CMake configuration for building the plugin
45+
- `mcp_sdk.py` - The Python SDK (automatically copied during build)
46+
47+
## Using the Python SDK
48+
49+
### Basic Tool Definition
50+
51+
```python
52+
from mcp_sdk import tool, string_param
53+
54+
@tool(
55+
name="hello_world",
56+
description="A simple greeting tool",
57+
name_param=string_param(description="The name to greet", required=True)
58+
)
59+
def hello_world_tool(name_param: str):
60+
return f"Hello, {name_param}!"
61+
```
62+
63+
### Streaming Tool Definition
64+
65+
```python
66+
from mcp_sdk import tool, integer_param, ToolType
67+
68+
@tool(
69+
name="stream_counter",
70+
description="Stream a sequence of numbers",
71+
tool_type=ToolType.STREAMING,
72+
count=integer_param(description="Number of items to stream", default=5)
73+
)
74+
def stream_counter_tool(count: int = 5):
75+
for i in range(count):
76+
yield {"number": i, "text": f"Item {i}"}
77+
```
78+
79+
### Parameter Helper Functions
80+
81+
The SDK provides helper functions for defining common parameter types:
82+
83+
- `string_param()` - Define a string parameter
84+
- `integer_param()` - Define an integer parameter
85+
- `number_param()` - Define a float parameter
86+
- `boolean_param()` - Define a boolean parameter
87+
- `array_param()` - Define an array parameter
88+
- `object_param()` - Define an object parameter
89+
90+
## Building Python Plugins
91+
92+
Python plugins are built using CMake, just like C++ plugins. The build process automatically:
93+
94+
1. Compiles the C++ wrapper code
95+
2. Copies the Python plugin file
96+
3. Copies the Python SDK
97+
98+
To build a Python plugin:
99+
100+
```bash
101+
cd my_python_plugin
102+
mkdir build
103+
cd build
104+
cmake ..
105+
cmake --build .
106+
```
107+
108+
The resulting DLL/SO file can then be used with the MCP Server++.
109+
110+
## Best Practices
111+
112+
1. **Use the SDK decorators**: They handle JSON conversion and tool registration automatically
113+
2. **Define clear parameter schemas**: Use parameter helper functions to document your tool's interface
114+
3. **Handle errors gracefully**: Python exceptions will be automatically converted to MCP error responses
115+
4. **Use type hints**: They improve code readability and help catch errors early
116+
5. **Test streaming tools**: Ensure your generators work correctly and clean up resources properly
117+
6. **Document your tools**: Provide clear descriptions for tools and parameters
118+
7. **Keep plugin files organized**: For complex plugins, consider splitting code into multiple modules

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /