3.5 KiB
3.5 KiB
Development Guide
This guide provides information for developers who want to contribute to or modify the CrateDocs MCP server.
Architecture Overview
The server consists of several key components:
-
DocRouter (
src/docs.rs
):- Core implementation of the MCP Router trait
- Handles tool calls for documentation lookup
- Implements caching to avoid redundant API requests
-
Transport Implementations:
- STDIN/STDOUT server (
src/bin/doc_server.rs
) - HTTP/SSE server (
src/bin/axum_docs.rs
)
- STDIN/STDOUT server (
-
Utilities:
- JSON-RPC frame codec for byte stream handling
Adding New Features
Adding a New Tool
To add a new tool to the documentation server:
- Add the implementation function in
DocRouter
struct - Add the tool definition to the
list_tools()
method - Add the tool handler in the
call_tool()
match statement
Example:
// 1. Add the implementation function
async fn get_crate_examples(&self, crate_name: String, limit: Option<u32>) -> Result<String, ToolError> {
// Implementation details...
}
// 2. In list_tools() add:
Tool::new(
"get_crate_examples".to_string(),
"Get usage examples for a Rust crate".to_string(),
json!({
"type": "object",
"properties": {
"crate_name": {
"type": "string",
"description": "The name of the crate"
},
"limit": {
"type": "integer",
"description": "Maximum number of examples to return"
}
},
"required": ["crate_name"]
}),
),
// 3. In call_tool() match statement:
"get_crate_examples" => {
let crate_name = arguments
.get("crate_name")
.and_then(|v| v.as_str())
.ok_or_else(|| ToolError::InvalidParameters("crate_name is required".to_string()))?
.to_string();
let limit = arguments
.get("limit")
.and_then(|v| v.as_u64())
.map(|v| v as u32);
let examples = this.get_crate_examples(crate_name, limit).await?;
Ok(vec![Content::text(examples)])
}
Enhancing the Cache
The current cache implementation is basic. To enhance it:
- Add TTL (Time-To-Live) for cache entries
- Add cache size limits to prevent memory issues
- Consider using a more sophisticated caching library
Testing
Create test files that implement basic tests for the server:
#[cfg(test)]
mod tests {
use super::*;
use tokio::test;
#[test]
async fn test_search_crates() {
let router = DocRouter::new();
let result = router.search_crates("tokio".to_string(), Some(2)).await;
assert!(result.is_ok());
let data = result.unwrap();
assert!(data.contains("crates"));
}
#[test]
async fn test_lookup_crate() {
let router = DocRouter::new();
let result = router.lookup_crate("serde".to_string(), None).await;
assert!(result.is_ok());
let data = result.unwrap();
assert!(data.contains("serde"));
}
}
Deployment
For production deployment, consider:
- Rate limiting to prevent abuse
- Authentication for sensitive documentation
- HTTPS for secure communication
- Docker containerization for easier deployment
Example Dockerfile:
FROM rust:1.74-slim as builder
WORKDIR /usr/src/app
COPY . .
RUN cargo build --release
FROM debian:stable-slim
RUN apt-get update && apt-get install -y libssl-dev ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/src/app/target/release/axum-docs /usr/local/bin/
EXPOSE 8080
CMD ["axum-docs"]