Skip to main content

rustfs_mcp/
lib.rs

1// Copyright 2024 RustFS Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![cfg_attr(docsrs, feature(doc_cfg))]
16//! RustFS MCP server library.
17//!
18//! This crate exposes a Model Context Protocol (MCP) server that provides
19//! S3-compatible storage operations, plus reusable configuration and client
20//! primitives for embedding into other Rust applications.
21//!
22//! # Optional features
23//!
24//! - `io-uring`: Enables Tokio's `io-uring` integration. This requires building
25//!   with `RUSTFLAGS="--cfg tokio_unstable"`.
26
27#[cfg(all(feature = "io-uring", not(tokio_unstable)))]
28compile_error!(
29    "feature `io-uring` requires cfg `tokio_unstable` (set RUSTFLAGS/RUSTDOCFLAGS to \"--cfg tokio_unstable\")"
30);
31
32/// Command-line and environment configuration parsing/validation.
33pub mod config;
34/// S3 client wrapper and operation/result data types.
35pub mod s3_client;
36/// MCP server and tool handlers.
37pub mod server;
38
39/// Runtime configuration for the server.
40pub use config::Config;
41/// Bucket metadata and async S3 client wrapper.
42pub use s3_client::{BucketInfo, S3Client};
43/// MCP service implementation.
44pub use server::RustfsMcpServer;
45
46use anyhow::{Context, Result};
47use rmcp::ServiceExt;
48use tokio::io::{stdin, stdout};
49use tracing::info;
50
51/// Start the MCP server with an explicit [`Config`].
52pub async fn run_server_with_config(config: Config) -> Result<()> {
53    info!("Starting RustFS MCP Server with provided configuration");
54
55    config
56        .validate()
57        .context("Configuration validation failed")?;
58
59    let server = RustfsMcpServer::new(config).await?;
60
61    info!("Running MCP server with stdio transport");
62
63    // Run the server with stdio
64    server
65        .serve((stdin(), stdout()))
66        .await
67        .context("Failed to serve MCP server")?
68        .waiting()
69        .await
70        .context("Error while waiting for server shutdown")?;
71
72    Ok(())
73}
74
75/// Start the MCP server with [`Config::default`].
76pub async fn run_server() -> Result<()> {
77    info!("Starting RustFS MCP Server with default configuration");
78
79    let config = Config::default();
80    run_server_with_config(config).await
81}
82
83/// Validate required AWS credentials in environment variables.
84///
85/// This function is kept for backward compatibility.
86pub fn validate_environment() -> Result<()> {
87    use std::env;
88
89    if env::var("AWS_ACCESS_KEY_ID").is_err() {
90        anyhow::bail!("AWS_ACCESS_KEY_ID environment variable is required");
91    }
92
93    if env::var("AWS_SECRET_ACCESS_KEY").is_err() {
94        anyhow::bail!("AWS_SECRET_ACCESS_KEY environment variable is required");
95    }
96
97    Ok(())
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_config_creation() {
106        let config = Config {
107            access_key_id: Some("test_key".to_string()),
108            secret_access_key: Some("test_secret".to_string()),
109            ..Config::default()
110        };
111
112        assert!(config.validate().is_ok());
113        assert_eq!(config.access_key_id(), "test_key");
114        assert_eq!(config.secret_access_key(), "test_secret");
115    }
116
117    #[tokio::test]
118    async fn test_run_server_with_invalid_config() {
119        let config = Config::default();
120
121        let result = run_server_with_config(config).await;
122        assert!(result.is_err());
123    }
124}