pforge_runtime/
server.rs

1use crate::{Error, HandlerRegistry, Result};
2use pforge_config::ForgeConfig;
3use std::sync::Arc;
4use tokio::sync::RwLock;
5
6/// MCP Server implementation
7pub struct McpServer {
8    config: ForgeConfig,
9    registry: Arc<RwLock<HandlerRegistry>>,
10}
11
12impl McpServer {
13    /// Create a new MCP server from configuration
14    pub fn new(config: ForgeConfig) -> Self {
15        Self {
16            config,
17            registry: Arc::new(RwLock::new(HandlerRegistry::new())),
18        }
19    }
20
21    /// Register all handlers from configuration
22    pub async fn register_handlers(&self) -> Result<()> {
23        let mut registry = self.registry.write().await;
24
25        for tool in &self.config.tools {
26            match tool {
27                pforge_config::ToolDef::Native { name, .. } => {
28                    // Native handlers will be registered by generated code
29                    eprintln!("Note: Native handler '{}' requires handler implementation", name);
30                }
31                pforge_config::ToolDef::Cli {
32                    name,
33                    command,
34                    args,
35                    cwd,
36                    env,
37                    stream,
38                    ..
39                } => {
40                    use crate::handlers::cli::CliHandler;
41                    let handler = CliHandler::new(
42                        command.clone(),
43                        args.clone(),
44                        cwd.clone(),
45                        env.clone(),
46                        None, // timeout from tool config
47                        *stream,
48                    );
49                    registry.register(name, handler);
50                    eprintln!("Registered CLI handler: {}", name);
51                }
52                pforge_config::ToolDef::Http {
53                    name,
54                    endpoint,
55                    method,
56                    headers,
57                    auth,
58                    ..
59                } => {
60                    use crate::handlers::http::{AuthConfig as HttpAuthConfig, HttpHandler, HttpMethod as HandlerHttpMethod};
61
62                    let handler_method = match method {
63                        pforge_config::HttpMethod::Get => HandlerHttpMethod::Get,
64                        pforge_config::HttpMethod::Post => HandlerHttpMethod::Post,
65                        pforge_config::HttpMethod::Put => HandlerHttpMethod::Put,
66                        pforge_config::HttpMethod::Delete => HandlerHttpMethod::Delete,
67                        pforge_config::HttpMethod::Patch => HandlerHttpMethod::Patch,
68                    };
69
70                    let handler_auth = auth.as_ref().map(|a| match a {
71                        pforge_config::AuthConfig::Bearer { token } => {
72                            HttpAuthConfig::Bearer {
73                                token: token.clone(),
74                            }
75                        }
76                        pforge_config::AuthConfig::Basic { username, password } => {
77                            HttpAuthConfig::Basic {
78                                username: username.clone(),
79                                password: password.clone(),
80                            }
81                        }
82                        pforge_config::AuthConfig::ApiKey { key, header } => {
83                            HttpAuthConfig::ApiKey {
84                                key: key.clone(),
85                                header: header.clone(),
86                            }
87                        }
88                    });
89
90                    let handler = HttpHandler::new(
91                        endpoint.clone(),
92                        handler_method,
93                        headers.clone(),
94                        handler_auth,
95                    );
96                    registry.register(name, handler);
97                    eprintln!("Registered HTTP handler: {}", name);
98                }
99                pforge_config::ToolDef::Pipeline { name, .. } => {
100                    eprintln!("Note: Pipeline handler '{}' pending implementation", name);
101                }
102            }
103        }
104
105        Ok(())
106    }
107
108    /// Run the MCP server
109    pub async fn run(&self) -> Result<()> {
110        eprintln!("Starting MCP server: {} v{}", self.config.forge.name, self.config.forge.version);
111        eprintln!("Transport: {:?}", self.config.forge.transport);
112        eprintln!("Tools registered: {}", self.config.tools.len());
113
114        // Register handlers
115        self.register_handlers().await?;
116
117        // TODO: Implement actual MCP protocol loop
118        // For now, just keep the server alive
119        eprintln!("\n⚠ MCP protocol loop not yet implemented");
120        eprintln!("Server configuration loaded and handlers registered successfully");
121        eprintln!("Press Ctrl+C to exit");
122
123        // Wait indefinitely (will be replaced with actual MCP loop)
124        tokio::signal::ctrl_c().await.map_err(|e| Error::Io(e))?;
125
126        eprintln!("\nShutting down...");
127        Ok(())
128    }
129
130    /// Get the handler registry (for testing)
131    pub fn registry(&self) -> Arc<RwLock<HandlerRegistry>> {
132        self.registry.clone()
133    }
134}