update
This commit is contained in:
148
src/mcp/server.rs
Normal file
148
src/mcp/server.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
use anyhow::Result;
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
http::StatusCode,
|
||||
response::Json,
|
||||
routing::{get, post},
|
||||
Router,
|
||||
};
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tower_http::cors::CorsLayer;
|
||||
use crate::mcp::types::*;
|
||||
use crate::mcp::tools::BlogTools;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
blog_tools: Arc<BlogTools>,
|
||||
}
|
||||
|
||||
pub struct McpServer {
|
||||
app_state: AppState,
|
||||
}
|
||||
|
||||
impl McpServer {
|
||||
pub fn new(base_path: PathBuf) -> Self {
|
||||
let blog_tools = Arc::new(BlogTools::new(base_path));
|
||||
let app_state = AppState { blog_tools };
|
||||
|
||||
Self { app_state }
|
||||
}
|
||||
|
||||
pub fn create_router(&self) -> Router {
|
||||
Router::new()
|
||||
.route("/", get(root_handler))
|
||||
.route("/mcp/tools/list", get(list_tools))
|
||||
.route("/mcp/tools/call", post(call_tool))
|
||||
.route("/health", get(health_check))
|
||||
.layer(CorsLayer::permissive())
|
||||
.with_state(self.app_state.clone())
|
||||
}
|
||||
|
||||
pub async fn serve(&self, port: u16) -> Result<()> {
|
||||
let app = self.create_router();
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port)).await?;
|
||||
println!("ai.log MCP Server listening on port {}", port);
|
||||
|
||||
axum::serve(listener, app).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn root_handler() -> Json<Value> {
|
||||
Json(json!({
|
||||
"name": "ai.log MCP Server",
|
||||
"version": "0.1.0",
|
||||
"description": "AI-powered static blog generator with MCP integration",
|
||||
"tools": ["create_blog_post", "list_blog_posts", "build_blog", "get_post_content"]
|
||||
}))
|
||||
}
|
||||
|
||||
async fn health_check() -> Json<Value> {
|
||||
Json(json!({
|
||||
"status": "healthy",
|
||||
"timestamp": chrono::Utc::now().to_rfc3339()
|
||||
}))
|
||||
}
|
||||
|
||||
async fn list_tools() -> Json<Value> {
|
||||
let tools = BlogTools::get_tools();
|
||||
Json(json!({
|
||||
"tools": tools
|
||||
}))
|
||||
}
|
||||
|
||||
async fn call_tool(
|
||||
State(state): State<AppState>,
|
||||
Json(request): Json<McpRequest>,
|
||||
) -> Result<Json<McpResponse>, StatusCode> {
|
||||
let tool_name = request.params
|
||||
.as_ref()
|
||||
.and_then(|p| p.get("name"))
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or(StatusCode::BAD_REQUEST)?;
|
||||
|
||||
let arguments = request.params
|
||||
.as_ref()
|
||||
.and_then(|p| p.get("arguments"))
|
||||
.cloned()
|
||||
.unwrap_or(json!({}));
|
||||
|
||||
let result = match tool_name {
|
||||
"create_blog_post" => {
|
||||
let req: CreatePostRequest = serde_json::from_value(arguments)
|
||||
.map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||
state.blog_tools.create_post(req).await
|
||||
}
|
||||
"list_blog_posts" => {
|
||||
let req: ListPostsRequest = serde_json::from_value(arguments)
|
||||
.map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||
state.blog_tools.list_posts(req).await
|
||||
}
|
||||
"build_blog" => {
|
||||
let req: BuildRequest = serde_json::from_value(arguments)
|
||||
.map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||
state.blog_tools.build_blog(req).await
|
||||
}
|
||||
"get_post_content" => {
|
||||
let slug = arguments.get("slug")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or(StatusCode::BAD_REQUEST)?;
|
||||
state.blog_tools.get_post_content(slug).await
|
||||
}
|
||||
_ => {
|
||||
return Ok(Json(McpResponse {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: request.id,
|
||||
result: None,
|
||||
error: Some(McpError {
|
||||
code: -32601,
|
||||
message: format!("Method not found: {}", tool_name),
|
||||
data: None,
|
||||
}),
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(tool_result) => Ok(Json(McpResponse {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: request.id,
|
||||
result: Some(serde_json::to_value(tool_result).unwrap()),
|
||||
error: None,
|
||||
})),
|
||||
Err(e) => Ok(Json(McpResponse {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: request.id,
|
||||
result: None,
|
||||
error: Some(McpError {
|
||||
code: -32000,
|
||||
message: e.to_string(),
|
||||
data: None,
|
||||
}),
|
||||
})),
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user