Skip to content

Commit afa7b79

Browse files
authored
Merge pull request #19 from openSVM/copilot/fix-7
[CRITICAL] Implement Robust Error Handling and Logging for Solana MCP Server RPC Calls
2 parents 5a779c9 + 2ae7da9 commit afa7b79

File tree

10 files changed

+2194
-115
lines changed

10 files changed

+2194
-115
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ env_logger = "0.10"
99
chrono = "0.4"
1010
url = { version = "2.4.1", features = ["serde"] }
1111
anyhow = "1.0"
12+
thiserror = "1.0"
1213
serde = { version = "1.0", features = ["derive"] }
1314
serde_json = "1.0"
1415
tokio = { version = "1.0", features = ["full"] }
16+
tracing = "0.1"
17+
tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] }
18+
uuid = { version = "1.0", features = ["v4"] }
19+
once_cell = "1.19"
20+
dashmap = "6.1"
1521
solana-client = "1.17"
1622
solana-sdk = "1.17"
1723
solana-account-decoder = "1.17"

docs/developer/error_handling.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Error Handling and Logging Guidelines
2+
3+
## Overview
4+
5+
This document describes the robust error handling and logging patterns implemented in the Solana MCP Server.
6+
7+
## Error Handling Architecture
8+
9+
### Error Types
10+
11+
The server uses a centralized error hierarchy defined in `src/error.rs`:
12+
13+
- **`McpError::Client`** - Client-side errors (invalid input, malformed requests)
14+
- **`McpError::Server`** - Server-side errors (internal failures, service unavailable)
15+
- **`McpError::Rpc`** - RPC-specific errors (Solana client failures)
16+
- **`McpError::Validation`** - Validation errors (invalid parameters, security checks)
17+
- **`McpError::Network`** - Network errors (connectivity issues, timeouts)
18+
- **`McpError::Auth`** - Authentication/Authorization errors
19+
20+
### Error Context
21+
22+
All errors include contextual information:
23+
- Request ID for tracing
24+
- Method name being executed
25+
- Relevant parameters (sanitized)
26+
- Source error information
27+
28+
### Error Usage Pattern
29+
30+
```rust
31+
use crate::error::{McpError, McpResult};
32+
33+
pub async fn example_rpc_call(client: &RpcClient, param: &str) -> McpResult<Value> {
34+
let request_id = new_request_id();
35+
let start_time = Instant::now();
36+
let method = "exampleCall";
37+
38+
// Log request start
39+
log_rpc_request_start(request_id, method, Some(&client.url()), Some("param info"));
40+
41+
match client.some_rpc_call(param).await {
42+
Ok(result) => {
43+
let duration = start_time.elapsed().as_millis() as u64;
44+
log_rpc_request_success(request_id, method, duration, Some("success message"));
45+
Ok(serde_json::json!({ "result": result }))
46+
}
47+
Err(e) => {
48+
let duration = start_time.elapsed().as_millis() as u64;
49+
let error = McpError::from(e)
50+
.with_request_id(request_id)
51+
.with_method(method)
52+
.with_rpc_url(&client.url());
53+
54+
log_rpc_request_failure(request_id, method, error.error_type(), duration, Some(&error.to_log_value()));
55+
Err(error)
56+
}
57+
}
58+
}
59+
```
60+
61+
## Logging Architecture
62+
63+
### Structured Logging
64+
65+
The server uses `tracing` with JSON output for structured logging:
66+
67+
- All logs include timestamps, levels, and contextual metadata
68+
- Sensitive data is automatically sanitized
69+
- Request IDs enable distributed tracing
70+
- Performance metrics are captured
71+
72+
### Log Levels
73+
74+
- **ERROR** - RPC failures, server errors, critical issues
75+
- **WARN** - Validation failures, recoverable errors
76+
- **INFO** - Successful operations, server lifecycle events
77+
- **DEBUG** - Detailed debugging information (testing only)
78+
79+
### Metrics Collection
80+
81+
The logging system automatically collects metrics:
82+
83+
- Total RPC calls
84+
- Successful RPC calls
85+
- Failed calls by error type
86+
- Failed calls by method
87+
- Request duration timing
88+
89+
Access metrics via `get_metrics().to_json()`.
90+
91+
## Security Considerations
92+
93+
### Data Sanitization
94+
95+
- URLs are sanitized to hide sensitive paths/parameters
96+
- Long strings are truncated to prevent log flooding
97+
- Parameter values are summarized, not logged in full
98+
- Error messages distinguish between safe and internal errors
99+
100+
### Safe Error Messages
101+
102+
Client-facing error messages use `error.safe_message()` which:
103+
- Shows validation errors to help with debugging
104+
- Hides internal server errors to prevent information leakage
105+
- Returns generic messages for auth errors
106+
107+
## Implementation Status
108+
109+
### Completed
110+
- ✅ Error type hierarchy and context
111+
- ✅ Structured logging with tracing
112+
- ✅ Metrics collection
113+
- ✅ Accounts RPC module
114+
- ✅ System RPC module (partially)
115+
116+
### Remaining Work
117+
- [ ] Complete system RPC module error handling
118+
- [ ] Update blocks RPC module
119+
- [ ] Update tokens RPC module
120+
- [ ] Update transactions RPC module
121+
- [ ] Integration tests for error scenarios
122+
123+
## Testing
124+
125+
Run error handling tests:
126+
```bash
127+
cargo test error::tests
128+
cargo test logging::tests
129+
```
130+
131+
## Configuration
132+
133+
Initialize logging in `main.rs`:
134+
```rust
135+
use solana_mcp_server::init_logging;
136+
137+
if let Err(e) = init_logging(Some("info")) {
138+
eprintln!("Failed to initialize logging: {}", e);
139+
std::process::exit(1);
140+
}
141+
```
142+
143+
Set log level via environment variable:
144+
```bash
145+
RUST_LOG=debug cargo run
146+
```
147+
148+
## Best Practices
149+
150+
1. **Always use McpResult<T>** for RPC functions
151+
2. **Include request IDs** for tracing correlation
152+
3. **Log request start/success/failure** for all RPC calls
153+
4. **Provide meaningful error context** using error builders
154+
5. **Sanitize sensitive data** before logging
155+
6. **Use appropriate error types** for categorization
156+
7. **Test error handling paths** in integration tests

0 commit comments

Comments
 (0)