| 1 |
pub mod health; |
| 2 |
pub mod tests; |
| 3 |
|
| 4 |
use rmcp::tool; |
| 5 |
use rmcp::model::{ServerCapabilities, ServerInfo}; |
| 6 |
use rmcp::ServerHandler; |
| 7 |
use sqlx::SqlitePool; |
| 8 |
use tracing::instrument; |
| 9 |
|
| 10 |
use crate::config::Config; |
| 11 |
|
| 12 |
#[derive(Clone)] |
| 13 |
pub struct PomServer { |
| 14 |
pub pool: SqlitePool, |
| 15 |
pub config: Config, |
| 16 |
} |
| 17 |
|
| 18 |
impl PomServer { |
| 19 |
pub fn new(pool: SqlitePool, config: Config) -> Self { |
| 20 |
Self { pool, config } |
| 21 |
} |
| 22 |
} |
| 23 |
|
| 24 |
#[tool(tool_box)] |
| 25 |
impl PomServer { |
| 26 |
|
| 27 |
#[tool(description = "Get overall status dashboard: all targets' latest health check and test run results. Use this for a quick overview.")] |
| 28 |
#[instrument(skip_all)] |
| 29 |
pub async fn get_status(&self) -> String { |
| 30 |
match self.get_status_impl().await { |
| 31 |
Ok(result) => result, |
| 32 |
Err(e) => format!("Error getting status: {e}"), |
| 33 |
} |
| 34 |
} |
| 35 |
|
| 36 |
|
| 37 |
#[tool(description = "Run a live health check against a target's health endpoint. Stores the result and returns the snapshot. Omit target to check all.")] |
| 38 |
#[instrument(skip_all)] |
| 39 |
pub async fn check_health( |
| 40 |
&self, |
| 41 |
#[tool(aggr)] params: health::CheckHealthParams, |
| 42 |
) -> String { |
| 43 |
match self.check_health_impl(params).await { |
| 44 |
Ok(result) => result, |
| 45 |
Err(e) => format!("Error checking health: {e}"), |
| 46 |
} |
| 47 |
} |
| 48 |
|
| 49 |
|
| 50 |
#[tool(description = "Get recent health check history. Optionally filter by target and limit results (default 10).")] |
| 51 |
#[instrument(skip_all)] |
| 52 |
pub async fn health_history( |
| 53 |
&self, |
| 54 |
#[tool(aggr)] params: health::HealthHistoryParams, |
| 55 |
) -> String { |
| 56 |
match self.health_history_impl(params).await { |
| 57 |
Ok(result) => result, |
| 58 |
Err(e) => format!("Error getting health history: {e}"), |
| 59 |
} |
| 60 |
} |
| 61 |
|
| 62 |
|
| 63 |
#[tool(description = "List all configured targets with their labels and capabilities (health check, test suite).")] |
| 64 |
#[instrument(skip_all)] |
| 65 |
pub async fn list_targets(&self) -> String { |
| 66 |
match self.list_targets_impl().await { |
| 67 |
Ok(result) => result, |
| 68 |
Err(e) => format!("Error listing targets: {e}"), |
| 69 |
} |
| 70 |
} |
| 71 |
|
| 72 |
|
| 73 |
#[tool(description = "Run the test suite on a target via SSH. Returns a summary with pass/fail counts. Optionally provide a filter to run specific tests.")] |
| 74 |
#[instrument(skip_all)] |
| 75 |
pub async fn run_tests( |
| 76 |
&self, |
| 77 |
#[tool(aggr)] params: tests::RunTestsParams, |
| 78 |
) -> String { |
| 79 |
match self.run_tests_impl(params).await { |
| 80 |
Ok(result) => result, |
| 81 |
Err(e) => format!("Error running tests: {e}"), |
| 82 |
} |
| 83 |
} |
| 84 |
|
| 85 |
|
| 86 |
#[tool(description = "Get recent test run history (without raw output). Optionally filter by target and limit results (default 10).")] |
| 87 |
#[instrument(skip_all)] |
| 88 |
pub async fn test_history( |
| 89 |
&self, |
| 90 |
#[tool(aggr)] params: tests::TestHistoryParams, |
| 91 |
) -> String { |
| 92 |
match self.test_history_impl(params).await { |
| 93 |
Ok(result) => result, |
| 94 |
Err(e) => format!("Error getting test history: {e}"), |
| 95 |
} |
| 96 |
} |
| 97 |
|
| 98 |
|
| 99 |
#[tool(description = "Get the full raw stdout/stderr output of the most recent test run for a target. Useful for debugging failures.")] |
| 100 |
#[instrument(skip_all)] |
| 101 |
pub async fn last_test_output( |
| 102 |
&self, |
| 103 |
#[tool(aggr)] params: tests::LastTestOutputParams, |
| 104 |
) -> String { |
| 105 |
match self.last_test_output_impl(params).await { |
| 106 |
Ok(result) => result, |
| 107 |
Err(e) => format!("Error getting test output: {e}"), |
| 108 |
} |
| 109 |
} |
| 110 |
|
| 111 |
|
| 112 |
#[tool(description = "Get the peer mesh status showing all PoM instances, their connectivity, versions, and target health. Requires serve mode to be running.")] |
| 113 |
#[instrument(skip_all)] |
| 114 |
pub async fn get_mesh_status(&self) -> String { |
| 115 |
match self.get_mesh_status_impl().await { |
| 116 |
Ok(result) => result, |
| 117 |
Err(e) => format!("Error getting mesh status: {e}"), |
| 118 |
} |
| 119 |
} |
| 120 |
} |
| 121 |
|
| 122 |
#[tool(tool_box)] |
| 123 |
impl ServerHandler for PomServer { |
| 124 |
fn get_info(&self) -> ServerInfo { |
| 125 |
ServerInfo { |
| 126 |
instructions: Some( |
| 127 |
"Peace of Mind (PoM) server for monitoring production health and running tests. \ |
| 128 |
Tools: get_status (dashboard), check_health (live health check), health_history, \ |
| 129 |
list_targets, run_tests (SSH test execution), test_history, last_test_output, \ |
| 130 |
get_mesh_status (peer mesh overview)." |
| 131 |
.into(), |
| 132 |
), |
| 133 |
capabilities: ServerCapabilities::builder().enable_tools().build(), |
| 134 |
..Default::default() |
| 135 |
} |
| 136 |
} |
| 137 |
} |
| 138 |
|