prism_mcp_rs/plugin/
api.rs1use crate::core::error::McpResult;
7use crate::protocol::types::{CallToolResult as ToolResult, Tool};
8use async_trait::async_trait;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use std::any::Any;
12
13#[async_trait]
15pub trait ToolPlugin: Send + Sync {
16 fn metadata(&self) -> PluginMetadata;
18
19 fn tool_definition(&self) -> Tool;
21
22 async fn execute(&self, arguments: Value) -> McpResult<ToolResult>;
24
25 async fn initialize(&mut self) -> McpResult<()> {
27 Ok(())
28 }
29
30 async fn shutdown(&mut self) -> McpResult<()> {
32 Ok(())
33 }
34
35 async fn health_check(&self) -> McpResult<()> {
37 Ok(())
38 }
39
40 async fn configure(&mut self, _config: Value) -> McpResult<()> {
42 Ok(())
43 }
44
45 fn as_any(&self) -> &dyn Any;
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct PluginMetadata {
52 pub id: String,
54
55 pub name: String,
57
58 pub version: String,
60
61 pub author: Option<String>,
63
64 pub description: Option<String>,
66
67 pub homepage: Option<String>,
69
70 pub license: Option<String>,
72
73 pub mcp_version: String,
75
76 pub capabilities: PluginCapabilities,
78
79 pub dependencies: Vec<PluginDependency>,
81}
82
83#[derive(Debug, Clone, Default, Serialize, Deserialize)]
85pub struct PluginCapabilities {
86 pub hot_reload: bool,
88
89 pub configurable: bool,
91
92 pub health_check: bool,
94
95 pub thread_safe: bool,
97
98 pub multi_instance: bool,
100
101 pub custom: Value,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct PluginDependency {
108 pub plugin_id: String,
110
111 pub version: String,
113
114 pub optional: bool,
116}
117
118pub type PluginFactory = unsafe extern "C" fn() -> *mut Box<dyn ToolPlugin>;
120
121pub trait PluginBuilder: Send + Sync {
123 fn build(self) -> Box<dyn ToolPlugin>;
125
126 fn build_with_config(self, _config: Value) -> McpResult<Box<dyn ToolPlugin>>
128 where
129 Self: Sized,
130 {
131 Ok(self.build())
132 }
133}
134
135pub struct StandardPluginBuilder<T: ToolPlugin + Default + 'static> {
137 config: Option<Value>,
138 _phantom: std::marker::PhantomData<T>,
139}
140
141impl<T: ToolPlugin + Default + 'static> Default for StandardPluginBuilder<T> {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147impl<T: ToolPlugin + Default + 'static> StandardPluginBuilder<T> {
148 pub fn new() -> Self {
150 Self {
151 config: None,
152 _phantom: std::marker::PhantomData,
153 }
154 }
155
156 pub fn with_config(mut self, config: Value) -> Self {
158 self.config = Some(config);
159 self
160 }
161}
162
163impl<T: ToolPlugin + Default + 'static> PluginBuilder for StandardPluginBuilder<T> {
164 fn build(self) -> Box<dyn ToolPlugin> {
165 Box::new(T::default())
166 }
167
168 fn build_with_config(self, config: Value) -> McpResult<Box<dyn ToolPlugin>> {
169 let mut plugin = T::default();
170 let runtime = tokio::runtime::Handle::current();
172 runtime.block_on(plugin.configure(config))?;
173 Ok(Box::new(plugin))
174 }
175}
176
177#[macro_export]
179macro_rules! export_plugin {
180 ($plugin_type:ty) => {
181 #[unsafe(no_mangle)]
183 pub unsafe extern "C" fn _mcp_plugin_create() -> *mut Box<dyn $crate::plugin::ToolPlugin> {
184 let plugin = Box::new(<$plugin_type>::default());
185 let boxed: Box<dyn $crate::plugin::ToolPlugin> = plugin;
186 Box::into_raw(Box::new(boxed))
187 }
188
189 #[unsafe(no_mangle)]
191 pub extern "C" fn _mcp_plugin_version() -> *const u8 {
192 concat!(env!("CARGO_PKG_VERSION"), "\0").as_ptr()
193 }
194
195 #[unsafe(no_mangle)]
197 pub extern "C" fn _mcp_plugin_metadata() -> *const u8 {
198 let metadata = <$plugin_type>::default().metadata();
199 let json = serde_json::to_string(&metadata).unwrap_or_default();
200 let c_str = std::ffi::CString::new(json).unwrap_or_default();
201 c_str.into_raw() as *const u8
202 }
203 };
204}