Fix build: add response module, fix http_server, update Cargo.toml
Continuous Integration / Test Suite (macos-latest, nightly) (push) Has been cancelled
Continuous Integration / Test Suite (macos-latest, stable) (push) Has been cancelled
Continuous Integration / Test Suite (ubuntu-latest, 1.70.0) (push) Has been cancelled
Continuous Integration / Test Suite (ubuntu-latest, beta) (push) Has been cancelled
Continuous Integration / Test Suite (ubuntu-latest, nightly) (push) Has been cancelled
Continuous Integration / Test Suite (ubuntu-latest, stable) (push) Has been cancelled
Continuous Integration / Test Suite (windows-latest, stable) (push) Has been cancelled
Continuous Integration / Security Audit (push) Has been cancelled
Continuous Integration / Code Coverage (push) Has been cancelled
Continuous Integration / Performance Benchmarks (push) Has been cancelled
Continuous Integration / Memory Safety Check (push) Has been cancelled
Continuous Integration / Docker Build Test (push) Has been cancelled
Continuous Integration / Release Readiness (push) Has been cancelled
Continuous Integration / Integration Tests (push) Has been cancelled
Continuous Integration / Stress Testing (push) Has been cancelled
Continuous Integration / Notify Results (push) Has been cancelled

This commit is contained in:
2026-06-13 04:02:52 +00:00
parent bb547888bf
commit c5416bf745
4 changed files with 55 additions and 47 deletions
+1
View File
@@ -29,6 +29,7 @@ mcp-spec = "0.1"
# Async runtime # Async runtime
tokio = { version = "1.40", features = ["full"] } tokio = { version = "1.40", features = ["full"] }
async-trait = "0.1" async-trait = "0.1"
futures = "0.3"
# DOCX manipulation (pure Rust) # DOCX manipulation (pure Rust)
docx-rs = "0.4" docx-rs = "0.4"
-8
View File
@@ -1,12 +1,4 @@
use mcp_core::types::{Tool, CallToolResponse, ToolResponseContent, TextContent}; use mcp_core::types::{Tool, CallToolResponse, ToolResponseContent, TextContent};
// Adapt to latest MCP: we'll integrate via mcp-server Router separately
use serde_json::{json, Value};
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use tracing::{debug, info};
use crate::docx_handler::{DocxHandler, DocxStyle, TableData};
use crate::converter::DocumentConverter;
use crate::response::{ToolOutcome, ErrorCode}; use crate::response::{ToolOutcome, ErrorCode};
#[cfg(feature = "advanced-docx")] #[cfg(feature = "advanced-docx")]
use crate::advanced_docx::AdvancedDocxHandler; use crate::advanced_docx::AdvancedDocxHandler;
+11 -5
View File
@@ -1,9 +1,9 @@
use axum::{ use axum::{
extract::{ extract::{
ws::{Message, WebSocket}, ws::{Message},
State, WebSocketUpgrade, State, WebSocketUpgrade,
}, },
response::{Html, Response}, response::Html,
routing::{get, post}, routing::{get, post},
Router, Router,
Json, Json,
@@ -12,6 +12,7 @@ use futures::{SinkExt, StreamExt};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
net::SocketAddr, net::SocketAddr,
str::FromStr,
sync::Arc, sync::Arc,
}; };
use tower_http::cors::{Any, CorsLayer}; use tower_http::cors::{Any, CorsLayer};
@@ -51,14 +52,18 @@ pub async fn start_http_server(addr: &str, provider: DocxToolsProvider) -> anyho
let state = Arc::new(AppState { provider }); let state = Arc::new(AppState { provider });
let app = Router::new() let app = Router::new()
.state(state.clone()) .with_state(state.clone())
// Serve HTML interface // Serve HTML interface
.route("/", get(index_handler)) .route("/", get(index_handler))
.route("/api/tools", get(list_tools_handler)) .route("/api/tools", get(list_tools_handler))
.route("/api/call", post(call_tool_handler)) .route("/api/call", post(call_tool_handler))
.route("/ws", get(ws_handler)) .route("/ws", get(ws_handler))
// CORS policy - allow all origins on LAN // CORS policy - allow all origins on LAN
.layer(CorsLayer::new().allow_origin(Any()).allow_methods(tower_http::cors::Method::any())); .layer(
CorsLayer::new()
.allow_origin(Any)
.allow_methods([axum::http::Method::GET, axum::http::Method::POST])
);
let addr = SocketAddr::from_str(addr).unwrap_or_else(|_| { let addr = SocketAddr::from_str(addr).unwrap_or_else(|_| {
info!("Invalid address format, using default 0.0.0.0:3000"); info!("Invalid address format, using default 0.0.0.0:3000");
@@ -117,6 +122,7 @@ async fn call_tool_handler(
"mimeType": image.mime_type "mimeType": image.mime_type
}) })
}, },
_ => serde_json::json!({}),
} }
} else { } else {
serde_json::json!({}) serde_json::json!({})
@@ -133,7 +139,7 @@ async fn call_tool_handler(
async fn ws_handler( async fn ws_handler(
ws: WebSocketUpgrade, ws: WebSocketUpgrade,
State(state): State<Arc<AppState>> State(state): State<Arc<AppState>>
) -> Result<Response, axum::http::StatusCode> { ) -> axum::response::Response {
ws.on_upgrade(move |socket| async move { ws.on_upgrade(move |socket| async move {
let provider = state.provider.clone(); let provider = state.provider.clone();
let mut ws = socket; let mut ws = socket;
+43 -34
View File
@@ -1,42 +1,51 @@
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ToolOutcome {
Ok { message: Option<String> },
Created { document_id: String, message: Option<String> },
Text { text: String },
Metadata { metadata: serde_json::Value },
Documents { documents: serde_json::Value },
Images { images: Vec<String>, message: Option<String> },
Security { security: serde_json::Value },
Storage { storage: serde_json::Value },
Statistics { statistics: serde_json::Value },
Structure { structure: serde_json::Value },
Error { code: ErrorCode, error: String, hint: Option<String> },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ErrorCode { pub enum ErrorCode {
DocNotFound,
ValidationError, ValidationError,
SecurityDenied, DocNotFound,
LimitExceeded,
UnknownTool,
InternalError, InternalError,
UnknownTool,
} }
impl ToolOutcome { #[derive(Debug, Clone)]
pub fn success(&self) -> bool { pub enum ToolOutcome {
!matches!(self, ToolOutcome::Error { .. }) Ok {
} message: Option<String>,
},
pub fn into_json(self) -> serde_json::Value { Created {
serde_json::to_value(self).unwrap_or_else(|e| serde_json::json!({ document_id: String,
"type": "error", message: Option<String>,
"code": ErrorCode::InternalError, },
"error": format!("serialization failed: {}", e), Text {
})) text: String,
} },
Metadata {
metadata: Value,
},
Documents {
documents: Value,
},
Images {
images: Vec<String>,
message: Option<String>,
},
Security {
security: Value,
},
Storage {
storage: Value,
},
Statistics {
statistics: Value,
},
Structure {
structure: Value,
},
Error {
code: ErrorCode,
error: String,
hint: Option<String>,
},
} }