mcp_server_collection now also a library
own_assist now bundles the server collection by default
This commit is contained in:
Generated
+2
-2
@@ -995,7 +995,6 @@ dependencies = [
|
||||
"toml",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
@@ -1109,12 +1108,13 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
||||
|
||||
[[package]]
|
||||
name = "own_assist_common"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -12,7 +12,6 @@ tokio = { version = "1.51.0", features = ["full"] }
|
||||
own_assist_common = { path = "../common" }
|
||||
tokio-util = "0.7.18"
|
||||
tracing = "0.1.44"
|
||||
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
|
||||
url = { version = "2.5.8", features = ["serde"] }
|
||||
uuid = { version = "1.23.0", features = ["v4"], optional = true }
|
||||
tower-http = { version = "0.6.8", features = ["auth"], optional = true }
|
||||
|
||||
@@ -11,8 +11,8 @@ use rmcp::ErrorData;
|
||||
use rmcp::model::ErrorCode;
|
||||
use thiserror::Error;
|
||||
use tower_http::auth::AddAuthorization;
|
||||
use tracing::event;
|
||||
use tracing::Level;
|
||||
use tracing::event;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) type AuthorizedCaldavClient =
|
||||
|
||||
@@ -5,18 +5,18 @@ use serde::{Deserialize, Serialize};
|
||||
use toml::map::Map;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub(crate) struct Config {
|
||||
pub struct Config {
|
||||
#[serde(rename = "bind-address")]
|
||||
pub(crate) bind_address: Option<url::Url>,
|
||||
pub(crate) servers: Vec<ServerConfig>,
|
||||
pub bind_address: Option<url::Url>,
|
||||
pub servers: Vec<ServerConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub(crate) struct ServerConfig {
|
||||
pub(crate) path: String,
|
||||
pub(crate) r#type: McpServiceType,
|
||||
#[serde(rename = "additional-properties")]
|
||||
pub(crate) additional_properties: Map<String, toml::Value>,
|
||||
pub struct ServerConfig {
|
||||
pub path: String,
|
||||
pub r#type: McpServiceType,
|
||||
#[serde(rename = "additional-properties", default = "Map::new")]
|
||||
pub additional_properties: Map<String, toml::Value>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
||||
@@ -62,7 +62,8 @@ impl DateTimeHandler {
|
||||
Fri => "Friday",
|
||||
Sat => "Saturday",
|
||||
Sun => "Sunday",
|
||||
}.to_string()
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
pub mod config;
|
||||
#[cfg(feature = "datetime")]
|
||||
pub mod datetime;
|
||||
|
||||
#[cfg(feature = "caldav")]
|
||||
pub mod caldav;
|
||||
mod server_handler;
|
||||
|
||||
#[cfg(feature = "caldav")]
|
||||
use crate::caldav::CalDavHandler;
|
||||
use crate::config::{Config, ServerConfig};
|
||||
#[cfg(feature = "datetime")]
|
||||
use crate::datetime::DateTimeHandler;
|
||||
use crate::server_handler::{McpServerHandler, McpServerHandlerError};
|
||||
use axum::Router;
|
||||
use axum::response::Json;
|
||||
use own_assist_common::exit_msg;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{Level, event};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum McpServiceType {
|
||||
#[cfg(feature = "datetime")]
|
||||
DateTime,
|
||||
#[cfg(feature = "caldav")]
|
||||
CalDav,
|
||||
}
|
||||
|
||||
pub(crate) async fn mcp_router(
|
||||
server_configs: &Vec<ServerConfig>,
|
||||
) -> Result<Router, McpServerHandlerError> {
|
||||
let mut router = Router::new();
|
||||
|
||||
for config in server_configs {
|
||||
router = match config.r#type {
|
||||
#[cfg(feature = "datetime")]
|
||||
McpServiceType::DateTime => router.route_service(
|
||||
config.path.as_str(),
|
||||
DateTimeHandler::mcp_service(config.additional_properties.clone()).await?,
|
||||
),
|
||||
#[cfg(feature = "caldav")]
|
||||
McpServiceType::CalDav => router.route_service(
|
||||
config.path.as_str(),
|
||||
CalDavHandler::mcp_service(config.additional_properties.clone()).await?,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(router)
|
||||
}
|
||||
|
||||
fn bind_address_format(url: url::Url) -> String {
|
||||
format!(
|
||||
"{}:{}",
|
||||
url.host_str().expect("No host specified"),
|
||||
url.port().unwrap_or(8000)
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn serve(config: Config) {
|
||||
let routes = Json(
|
||||
config
|
||||
.servers
|
||||
.clone()
|
||||
.iter()
|
||||
.map(|server| server.path.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let router = mcp_router(&config.servers)
|
||||
.await
|
||||
.inspect_err(exit_msg!("Error handling server: {e}"))
|
||||
.unwrap()
|
||||
.route("/", axum::routing::get(|| async { routes }));
|
||||
|
||||
let bind_address = config
|
||||
.bind_address
|
||||
.unwrap_or(url::Url::parse("http://localhost:8000").unwrap());
|
||||
event!(Level::INFO, "binding address at {bind_address}");
|
||||
|
||||
let tcp_listener = tokio::net::TcpListener::bind(bind_address_format(bind_address))
|
||||
.await
|
||||
.inspect_err(exit_msg!("Error bind tcp listener: {e:#?}"))
|
||||
.unwrap();
|
||||
|
||||
let ct = tokio_util::sync::CancellationToken::new();
|
||||
|
||||
let _ = axum::serve(tcp_listener, router)
|
||||
.with_graceful_shutdown(async move {
|
||||
tokio::signal::ctrl_c().await.unwrap();
|
||||
ct.cancel();
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -1,111 +1,15 @@
|
||||
mod config;
|
||||
#[cfg(feature = "datetime")]
|
||||
pub mod datetime;
|
||||
|
||||
#[cfg(feature = "caldav")]
|
||||
pub mod caldav;
|
||||
mod server_handler;
|
||||
|
||||
#[cfg(feature = "caldav")]
|
||||
use crate::caldav::CalDavHandler;
|
||||
use crate::config::{Config, ServerConfig};
|
||||
#[cfg(feature = "datetime")]
|
||||
use crate::datetime::DateTimeHandler;
|
||||
use crate::server_handler::{McpServerHandler, McpServerHandlerError};
|
||||
use axum::Router;
|
||||
use axum::response::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use mcp_server_collection::config::Config;
|
||||
use mcp_server_collection::serve;
|
||||
use own_assist_common::{exit_msg, init_tracing_subscriber};
|
||||
use tokio::main;
|
||||
use tracing::{event, Level};
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use own_assist_common::exit_msg;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum McpServiceType {
|
||||
#[cfg(feature = "datetime")]
|
||||
DateTime,
|
||||
#[cfg(feature = "caldav")]
|
||||
CalDav,
|
||||
}
|
||||
|
||||
pub(crate) async fn mcp_router(
|
||||
server_configs: &Vec<ServerConfig>,
|
||||
) -> Result<Router, McpServerHandlerError> {
|
||||
let mut router = Router::new();
|
||||
|
||||
for config in server_configs {
|
||||
router = match config.r#type {
|
||||
#[cfg(feature = "datetime")]
|
||||
McpServiceType::DateTime => router.route_service(
|
||||
config.path.as_str(),
|
||||
DateTimeHandler::mcp_service(config.additional_properties.clone()).await?,
|
||||
),
|
||||
#[cfg(feature = "caldav")]
|
||||
McpServiceType::CalDav => router.route_service(
|
||||
config.path.as_str(),
|
||||
CalDavHandler::mcp_service(config.additional_properties.clone()).await?,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(router)
|
||||
}
|
||||
|
||||
fn bind_address_format(url: url::Url) -> String {
|
||||
format!(
|
||||
"{}:{}",
|
||||
url.host_str().expect("No host specified"),
|
||||
url.port().unwrap_or(8000)
|
||||
)
|
||||
}
|
||||
|
||||
#[main]
|
||||
async fn main() {
|
||||
tracing_subscriber::registry()
|
||||
.with(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "debug".to_string().into()),
|
||||
)
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
init_tracing_subscriber();
|
||||
|
||||
let config = Config::from_file()
|
||||
.inspect_err(exit_msg!("Error loading config: {e}"))
|
||||
.inspect_err(exit_msg!("Error loading config"))
|
||||
.unwrap();
|
||||
|
||||
let routes = Json(
|
||||
config
|
||||
.servers
|
||||
.clone()
|
||||
.iter()
|
||||
.map(|server| server.path.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let router = mcp_router(&config.servers)
|
||||
.await
|
||||
.inspect_err(exit_msg!("Error handling server: {e}"))
|
||||
.unwrap()
|
||||
.route("/", axum::routing::get(|| async { routes }));
|
||||
|
||||
let bind_address = config
|
||||
.bind_address
|
||||
.unwrap_or(url::Url::parse("http://localhost:8000").unwrap());
|
||||
event!(Level::INFO,"binding address at {bind_address}");
|
||||
|
||||
let tcp_listener = tokio::net::TcpListener::bind(bind_address_format(bind_address))
|
||||
.await
|
||||
.inspect_err(exit_msg!("Error bind tcp listener: {e:#?}"))
|
||||
.unwrap();
|
||||
|
||||
let ct = tokio_util::sync::CancellationToken::new();
|
||||
|
||||
let _ = axum::serve(tcp_listener, router)
|
||||
.with_graceful_shutdown(async move {
|
||||
tokio::signal::ctrl_c().await.unwrap();
|
||||
ct.cancel();
|
||||
})
|
||||
.await;
|
||||
serve(config).await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user