mcp server
jons-mcp-docs.rs
Access docs.rs as markdown with search
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
{
"mcpServers": {
"jons-mcp-docs-rs": {
"command": "uvx",
"args": [
"jons-mcp-docs-rs"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 23, 2026Jons MCP Docs.rs
A Python MCP (Model Context Protocol) server for looking up Rust documentation from docs.rs. This server provides advanced navigation capabilities including pagination, multi-page lookup, and search functionality.
Overview
This MCP server enables AI assistants to browse and search Rust crate documentation from docs.rs. Unlike simple documentation fetchers, this server provides a complete navigation system that allows:
- Fetching main documentation pages with pagination
- Looking up specific documentation pages (structs, traits, modules, etc.)
- Searching within crate documentation
- Searching for crates by name with pagination
- Converting docs.rs URLs to navigation keys for seamless browsing
- Viewing source code for any Rust item
- Extracting code examples from documentation
- Finding trait implementors
- Analyzing crate dependencies
- Looking up compact item signatures
- Inspecting crate feature-flag graphs
- Listing project crates from Cargo manifests and Cargo.lock
- Looking up release notes, changelogs, and upgrade guides
- Exploring module hierarchies
- Comparing API changes between versions
Features
- Main Page Lookup: Fetch the main documentation page for any Rust crate with configurable version
- Multi-Page Lookup: Fetch multiple documentation pages in a single request with combined pagination and source availability detection
- Search Functionality: Search within a crate's documentation and get paginated results
- Crate Search: Search for crates by name across the entire docs.rs catalog
- Source Code Viewing: Access the source code of any Rust item directly from docs.rs
- Code Example Extraction: Extract and filter code examples from documentation
- Trait Analysis: Find all types that implement a specific trait
- Dependency Analysis: Analyze and extract crate dependencies from documentation
- Item Signatures: Fetch compact structured signatures without full-page markdown
- Feature Flag Analysis: Extract feature graph, defaults, and optional dependency flags
- Project Crate Inventory: List direct and transitive crates for the configured project
- Release Notes Lookup: Aggregate release notes/changelog/upgrade guides for dependency upgrades
- Module Hierarchy: Explore the complete module structure of a crate
- Version Comparison: Compare API surface or content between different versions
- Smart Pagination: Character-based pagination for handling large documentation
- Link Extraction: Automatically extract and convert links to navigation keys
- Version Control: Support for specific crate versions or default to latest
- Rustdoc JSON Native: Uses docs.rs rustdoc JSON and crates.io APIs with no HTML fallback
Installation
Using uv (recommended)
# Clone the repository
git clone https://github.com/jonmmease/jons-mcp-docs.rs
cd jons-mcp-docs.rs
# Install with uv
uv pip install -e .
# Run the server
uv run jons-mcp-docs-rs
# Optional: load Cargo.lock and Cargo.toml metadata from a project
uv run jons-mcp-docs-rs --project-dir /path/to/rust/project
Using pip
# Clone the repository
git clone https://github.com/jonmmease/jons-mcp-docs.rs
cd jons-mcp-docs.rs
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install
pip install -e .
# Run the server
jons-mcp-docs-rs
Adding to Claude Desktop
Add this server to Claude Desktop by running:
claude mcp add jons-mcp-docs-rs uvx -- --from git+https://github.com/jonmmease/jons-mcp-docs.rs jons-mcp-docs-rs --project-dir /path/to/rust/project
Tools
lookup_main_page
Fetch the main documentation page for a Rust crate.
Parameters:
crate_name(required): The name of the crate (e.g., "datafusion")version(optional): The version to look up (defaults to "latest")offset(optional): Character offset for pagination (default: 0)limit(optional): Maximum number of characters to return (default: 50)target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example:
{
"crate_name": "tokio",
"version": "latest",
"offset": 0,
"limit": 1000
}
Response:
{
"crate": "tokio",
"version": "latest",
"content": "# Crate tokio\n\n...",
"total_characters": 25000,
"offset": 0,
"limit": 1000,
"has_more": true,
"links": [
{
"key": "tokio/latest/tokio/runtime/struct.Runtime",
"text": "Runtime",
"url": "https://docs.rs/tokio/latest/tokio/runtime/struct.Runtime.html"
}
],
"total_links": 150,
"url": "https://docs.rs/tokio/latest/"
}
lookup_pages
Fetch one or more specific documentation pages.
Parameters:
pages(required): List of page keys (e.g., ["tokio/latest/tokio/runtime/struct.Runtime"])version(optional): Override version for all pagesoffset(optional): Character offset for combined pagination (default: 0)limit(optional): Maximum characters to return across all pages (default: 50)target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example:
{
"pages": [
"datafusion/latest/datafusion/dataframe/struct.DataFrame",
"datafusion/latest/datafusion/execution/context/struct.SessionContext"
],
"offset": 0,
"limit": 5000
}
Response:
{
"pages": [
{
"key": "datafusion/latest/datafusion/dataframe/struct.DataFrame",
"url": "https://docs.rs/datafusion/latest/datafusion/dataframe/struct.DataFrame.html",
"content_length": 15000,
"links_count": 45,
"source_available": true
}
],
"content": "# Page: datafusion/latest/datafusion/dataframe/struct.DataFrame\n\n...",
"total_characters": 30000,
"offset": 0,
"limit": 5000,
"has_more": true,
"pages_count": 2
}
Note: The source_available field indicates whether source code can be viewed for this item using the get_source_code tool.
lookup_item_signature
Fetch a compact, structured signature for a single item.
Parameters:
item(required): docs key,docs.rs://..., orhttps://docs.rs/...version(optional): Override item versioninclude_members(optional): Include methods/associated items for trait/impl sectionsmember_limit(optional): Max members to return (default: 20, max: 100)
Response fields:
item_key,resolved_url,kind,namesignature,where_clause,genericsmembers,version_source
lookup_feature_flags
Fetch feature-flag graph data for a crate.
Parameters:
crate_name(required): The crate nameversion(optional): Version to inspect
Response fields:
crate,version,version_sourcefeatures: feature list withname,enables,enabled_by,is_defaultdefault_features,optional_dependencies,feature_count,source_url
list_project_crates
List direct and transitive crates for the configured --project-dir.
Parameters:
include_transitive(optional): Include lockfile transitives (default: true)include_workspace_members(optional): Include workspace member manifests (default: true)include_dev(optional): Include dev dependencies in direct classification (default: true)
Response fields:
project_dir,cargo_lock_loadeddirect_crates,transitive_crates,unresolved_directcounts
lookup_release_notes
Find release notes, changelog sections, and upgrade guides for a crate/version interval.
Parameters:
crate_name(required): Crate namefrom_version(optional): Lower bound version (inclusive)to_version(optional): Upper bound version (inclusive)include_upgrade_guides(optional): Include docs/homepage upgrade guides (default: true)include_release_descriptions(optional): Include hosted release descriptions (default: true)include_changelog_files(optional): Include changelog/migration files from repo (default: true)max_items(optional): Maximum items to return (default: 20, max: 100)project_dir(optional): Override Cargo.lock source used forto_versionresolution
Response fields:
crate,from_version,to_version,version_sourceitems: normalized items withsource_type,title,url,published_at,version_tag,content_excerpt,content_markdown,relevance_score,provenancesummary:breaking_changes,migration_steps,deprecations,new_features,notes_qualitysources_scanned,coverageerror(when no items): may berelease_notes_not_found,tags_only_no_release_notes,release_tag_present_no_release_object,release_objects_without_notes,rate_limited,unsupported_repository_host
Notes:
- Best-effort coverage: some crates do not publish release notes/changelogs.
- Supported repository hosts in v1: GitHub and GitLab.
- Optional auth tokens improve reliability for API rate limits:
GITHUB_TOKENorGH_TOKEN
GITLAB_TOKEN- Startup convenience: if GitHub token env vars are unset and
ghis installed/authenticated, the server automatically triesgh auth tokenonce at startup. - Recommended upgrade workflow: combine
compare_versions(API/doc diffs) withlookup_release_notes(human-authored migration guidance). - Empty-result diagnostics include:
context.classificationcontext.confirmed_tag_urlscontext.release_probe(release_list_pages_scanned,release_list_items_seen,release_tag_api_hits,release_tag_api_404,empty_release_bodies)context.available_release_refs(found tags/releases without note body)
research_release_notes_coverage
Run deterministic source-availability research for workspace dependencies in one or more manifests.
Parameters:
manifest_paths(optional): List ofCargo.tomlfiles. Defaults to:/Users/jmease/repos/vl-convert/Cargo.toml/Users/jmease/repos/vegafusion/Cargo.toml/Users/jmease/repos/avenger/Cargo.toml
max_crates(optional): Limit crates analyzed (0 means all)project_dir(optional): Project root containingCargo.lock; used by transitive scan modeinclude_transitive(optional): Scan lockfile-resolved transitive crates (default: false)include_workspace_members(optional): Include workspace member manifests for direct mode (default: true)include_dev(optional): Include dev-dependencies in direct mode (default: true)
Response fields:
manifest_paths,total_cratesscan_mode:direct_manifestorlockfile_fulltruncated,truncation_reasonresultsper crate with coverage/error metadatasummarycounts (found,unsupported,not_found,rate_limited)
search_docs
Search within a crate's documentation.
Parameters:
crate_name(required): The name of the crate to search inquery(required): The search queryversion(optional): The version to search (defaults to "latest")offset(optional): Result offset for pagination (default: 0)limit(optional): Maximum number of results to return (default: 50)target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example:
{
"crate_name": "datafusion",
"query": "udf",
"version": "latest",
"offset": 0,
"limit": 10
}
Response:
{
"crate": "datafusion",
"version": "latest",
"query": "udf",
"results": [
{
"key": "datafusion/latest/datafusion/physical_plan/udf",
"title": "Module datafusion::physical_plan::udf",
"url": "https://docs.rs/datafusion/latest/datafusion/physical_plan/udf/index.html",
"snippet": ""
}
],
"total_results": 25,
"offset": 0,
"limit": 10,
"has_more": true,
"search_url": "https://docs.rs/crate/datafusion/latest/json.gz"
}
search_crates
Search for Rust crates by name using the crates.io API.
Parameters:
query(required): The search query for crate namespage(optional): Page number (1-indexed) for pagination (default: 1)
Example:
{
"query": "serde",
"page": 1
}
Response:
{
"query": "serde",
"page": 1,
"crates": [
{
"name": "serde",
"version": "1.0.219",
"description": "A generic serialization/deserialization framework",
"date": "2025-06-17T02:58:14Z",
"url": "https://docs.rs/serde/latest/serde/"
}
],
"total_on_page": 30,
"has_next_page": true,
"search_url": "https://crates.io/api/v1/crates?q=serde&page=1&per_page=30"
}
get_source_code
Get source code using rustdoc JSON spans and crates.io crate archives.
Parameters:
page_key(required): The page key for the item (e.g., "tokio/latest/tokio/runtime/struct.Runtime")offset(optional): Character offset for pagination (default: 0)limit(optional): Maximum number of characters to return (default: 50)target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example:
{
"page_key": "datafusion/latest/datafusion/logical_expr/trait.ScalarUDFImpl",
"offset": 0,
"limit": 2000
}
Response:
{
"key": "datafusion/latest/datafusion/logical_expr/trait.ScalarUDFImpl",
"content": "pub trait ScalarUDFImpl: Debug + Send + Sync {\n ...",
"total_characters": 5000,
"offset": 0,
"limit": 2000,
"has_more": true,
"source_url": "https://docs.rs/crate/datafusion/latest/source/src/logical_expr/udf.rs",
"span": {
"filename": "src/logical_expr/udf.rs",
"begin": [120, 1],
"end": [200, 2]
}
}
extract_code_examples
Extract code examples from documentation.
Parameters:
crate_name(required): The name of the cratemodule_path(optional): Limit extraction to a module subtreefilter_text(optional): Filter examples by code textonly_complete(optional): Keep only complete Rust examplesversion(optional): Version of the crate (defaults to "latest")target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example:
{
"crate_name": "datafusion",
"search_pattern": "SessionContext",
"max_examples": 5
}
Response:
{
"crate": "datafusion",
"version": "latest",
"search_pattern": "SessionContext",
"examples": [
{
"source_page": "datafusion/latest/datafusion",
"code": "use datafusion::prelude::*;\n\nlet ctx = SessionContext::new();\n...",
"language": "rust",
"context": "Creating a new SessionContext"
}
],
"total_found": 5
}
find_trait_implementors
Find types that implement a specific trait.
Parameters:
crate_name(required): The name of the crate containing the traittrait_path(required): Path to the trait (e.g., "prelude/trait.Debug")version(optional): Version of the crate (defaults to "latest")target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example:
{
"crate_name": "datafusion",
"trait_path": "logical_expr/trait.ScalarUDFImpl"
}
Response:
{
"crate": "datafusion",
"version": "latest",
"trait_path": "logical_expr/trait.ScalarUDFImpl",
"trait_url": "https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.ScalarUDFImpl.html",
"implementors": [
{
"name": "ArrayToString",
"key": "datafusion/latest/datafusion/functions_array/struct.ArrayToString",
"module": "functions_array"
}
],
"total_implementors": 15,
"direct_implementors": 10,
"blanket_implementors": 5
}
analyze_dependencies
Analyze a crate's dependencies from its documentation.
Parameters:
crate_name(required): The name of the crateversion(optional): Version of the crate (defaults to "latest")
Example:
{
"crate_name": "tokio",
"version": "latest"
}
Response:
{
"crate": "tokio",
"version": "latest",
"dependencies": {
"direct": [
{
"name": "mio",
"version_req": "^1.0.1",
"optional": true,
"url": "https://docs.rs/mio"
}
],
"dev": [],
"build": [],
"features": [
{
"name": "full",
"enables": ["rt", "macros", "sync", "time"],
"enabled_by": [],
"is_default": false
}
],
"default_features": ["rt", "macros"],
"optional_dependencies": ["mio"],
"total": 15
}
}
get_module_hierarchy
Get the module structure and hierarchy of a crate.
Parameters:
crate_name(required): The name of the cratestart_module(optional): Starting module path (defaults to root)max_depth(optional): Maximum depth to traverse (default: 3)version(optional): Version of the crate (defaults to "latest")target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example:
{
"crate_name": "datafusion",
"max_depth": 2
}
Response:
{
"crate": "datafusion",
"version": "latest",
"start_module": "root",
"modules": {
"name": "datafusion",
"path": "datafusion/latest/datafusion",
"key": "datafusion/latest/datafusion",
"submodules": [
{
"name": "prelude",
"path": "datafusion/latest/datafusion/prelude",
"items": {
"structs": ["DataFrame", "SessionContext"],
"traits": ["TableProvider"]
}
}
],
"items": {
"structs": ["DataFrame"],
"enums": ["DataFusionError"],
"traits": []
}
},
"total_modules": 25,
"max_depth": 2
}
compare_versions
Compare documentation between two versions of a crate.
Parameters:
crate_name(required): The name of the crateversion1(required): First version to compareversion2(required): Second version to comparepage_path(optional): Specific page to compare (for full_content comparison)comparison_type(optional): "api_surface" (default) or "full_content"target(optional): Rust target triple for rustdoc JSON selectionrustdoc_format(optional): Pin rustdoc JSON format version
Example (API Surface Comparison):
{
"crate_name": "tokio",
"version1": "1.0.0",
"version2": "1.35.0",
"comparison_type": "api_surface"
}
Response:
{
"crate": "tokio",
"version1": "1.0.0",
"version2": "1.35.0",
"comparison_type": "api_surface",
"differences": {
"added": {
"structs": ["JoinSet", "LocalSet"],
"functions": ["spawn_blocking"]
},
"removed": {
"structs": ["Runtime::spawn"]
},
"common": {
"structs": ["Runtime", "JoinHandle"]
},
"summary": "5 items added, 1 items removed"
}
}
Example (Full Content Comparison):
{
"crate_name": "serde",
"version1": "1.0.0",
"version2": "1.0.100",
"page_path": "ser/trait.Serialize",
"comparison_type": "full_content"
}
Quick Start Guide
Learning from a Popular Crate
Let's explore how to understand and implement a trait by learning from DataFusion:
# 1. Find real implementations of a trait
result = await find_trait_implementors("datafusion", "logical_expr/trait.ScalarUDFImpl")
# Returns 121 implementations including ArrayToString, CoalesceFunc, etc.
# 2. View the source of a specific implementation
impl = result["implementors"][0] # Pick one implementor
source = await get_source_code(impl["key"])
# Shows the complete implementation with line numbers
# 3. Understand the module structure
hierarchy = await get_module_hierarchy("datafusion", "functions", max_depth=3)
# Shows all function modules and their organization
Common Workflows
"How do I implement trait X?"
-
Find existing implementations:
impls = await find_trait_implementors("crate_name", "module/trait.TraitName") -
Pick an implementor similar to your use case
-
View its source code:
source = await get_source_code(impl["key"]) -
Look for patterns in method implementations, especially required methods
"What examples exist for this crate?"
-
Try to extract examples:
examples = await extract_code_examples("crate_name") -
If empty (common for many crates), find real usage:
# Find trait implementors and view their source impls = await find_trait_implementors("crate_name", "main_trait") source = await get_source_code(impls["implementors"][0]["key"])
"How is this crate organized?"
-
Get top-level view:
hierarchy = await get_module_hierarchy("crate_name") -
Drill down into specific modules:
detailed = await get_module_hierarchy("crate_name", "specific_module", max_depth=3) -
Navigate to specific items using the keys from hierarchy
Understanding Tool Results
When extract_code_examples Returns Empty
This is NORMAL for many popular crates! For example:
- serde: Hosts examples at serde.rs (separate site), not on docs.rs
- tokio: Has examples, but not on all pages
- datafusion: Most examples are in the implementors' source code
What to do: Use find_trait_implementors + get_source_code for real examples.
When analyze_dependencies Shows Optional Dependencies
optional: truemeans the dependency is behind a feature flag- Check the crate's features to understand when it's included
- Dependencies marked as
devare only used for testing - Dependencies marked as
buildare only used during compilation
Understanding Debug Information
All tools provide debug_info when results might be unexpected:
- Explains what was searched
- Indicates why results might be empty
- Suggests alternative approaches
Tool Philosophy
These tools embrace the reality that Rust documentation exists in multiple forms:
-
API Reference (always on docs.rs)
- Type signatures, trait definitions, module structure
- Use:
lookup_pages,get_module_hierarchy
-
Inline Examples (sometimes on docs.rs)
- Some crates include examples, many don't
- Use:
extract_code_examples
-
Real Implementations (always available via source)
- The most valuable learning resource
- Use:
find_trait_implementors+get_source_code
-
External Resources (not accessible via these tools)
- Many crates host tutorials elsewhere (serde.rs, tokio.rs, etc.)
- The tools will indicate when this might be the case
What These Tools Can and Cannot Do
✅ CAN DO:
- Navigate any crate's complete module structure
- Find all implementors of any public trait
- View source code with syntax highlighting and line numbers
- Analyze all dependencies and feature flags
- Compare API surfaces between versions
- Extract code examples when present
- Provide navigation keys for seamless browsing
❌ CANNOT DO:
- Access external documentation sites (e.g., serde.rs)
- Run or execute code examples
- Search across multiple crates simultaneously
- Access private or internal implementations
- View documentation for crates not on docs.rs
🤔 DEPENDS ON THE CRATE:
- Extract inline examples (many crates don't include them)
- Find usage examples in tests (not all test source is published)
- View macro implementations (depends on macro structure)
Troubleshooting
"Why am I getting empty results?"
-
Check the
debug_infofield - It explains what was searched and why it might be empty -
Try different approaches:
- No examples? → Use implementors + source code
- No implementors? → The trait might be in a different module or crate
- No dependencies? → The crate might be no_std or very minimal
-
Use the navigation keys:
- Results include
keyfields that work with other tools - Example: Use a key from
find_trait_implementorsinget_source_code
- Results include
"How do I know which tool to use?"
- Want to see how something is used? →
find_trait_implementors - Need the actual code? →
get_source_code - Exploring a new crate? →
get_module_hierarchy - Checking what a crate depends on? →
analyze_dependencies - Looking for examples? →
extract_code_examples(but expect empty for many crates) - Comparing versions? →
compare_versions
"The tool returned an error"
- 404 errors: The crate/version/module might not exist
- Parsing errors: The page might use a non-standard format
- Network errors: Retry the request
- Check fallback data: Look for
fallback_*fields in the response
Navigation System
The server converts docs.rs URLs into navigation keys that can be used with the lookup_pages tool. This allows AI assistants to navigate the documentation site without dealing with URLs directly.
All links in the documentation are automatically transformed to use the docs.rs:// protocol, which provides a consistent format for navigation. This includes:
- docs.rs links (e.g.,
https://docs.rs/...→docs.rs://...) - doc.rust-lang.org links (e.g.,
https://doc.rust-lang.org/...→docs.rs://rust-lang/...) - Relative links are resolved to absolute
docs.rs://format
URL to Key Conversion Examples:
https://docs.rs/tokio/latest/tokio/index.html→tokio/latest/tokio/indexhttps://docs.rs/datafusion/latest/datafusion/dataframe/struct.DataFrame.html→datafusion/latest/datafusion/dataframe/struct.DataFrame
Using Navigation Keys:
- Call
lookup_main_pageto get the main page and extract links - Use the
keyfield from links withlookup_pagesto navigate to specific pages - Search results also provide keys for direct navigation
Combining Tools for Maximum Insight
Example: Deep Understanding of a Complex Trait
# Goal: Understand how to implement AsyncRead trait
# 1. Find all implementors
impls = await find_trait_implementors("tokio", "io/trait.AsyncRead")
# 2. Group by module to understand organization patterns
by_module = {}
for impl in impls["implementors"]:
module = impl["module"]
by_module.setdefault(module, []).append(impl)
# 3. Study different implementation strategies
for module, implementors in by_module.items():
print(f"\nModule {module}:")
for impl in implementors[:2]: # First 2 from each module
source = await get_source_code(impl["key"])
# Analyze implementation patterns
# 4. Check how the trait evolved
versions = await compare_versions("tokio", "1.0.0", "1.35.0")
# See what methods were added/removed
Example: Exploring a New Crate
# Goal: Understand DataFusion's architecture
# 1. Start with dependencies
deps = await analyze_dependencies("datafusion")
print(f"Built on: {[d['name'] for d in deps['dependencies']['direct'][:5]]}")
# 2. Explore module structure
hierarchy = await get_module_hierarchy("datafusion", max_depth=2)
# Identify key modules: logical_expr, physical_plan, execution
# 3. Find core traits
logical_page = await lookup_pages(["datafusion/latest/datafusion/logical_expr"])
# Look for trait definitions in the content
# 4. See implementations
impls = await find_trait_implementors("datafusion", "logical_expr/trait.ScalarUDFImpl")
# 121 implementations! Let's study a few
# 5. Extract patterns from source
for impl in impls["implementors"][:3]:
source = await get_source_code(impl["key"])
# Look for common patterns in invoke() and return_type() methods
Development
Setup
# Clone the repository
git clone https://github.com/jonmmease/jons-mcp-docs.rs
cd jons-mcp-docs.rs
# Create virtual environment with uv
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install in development mode
uv pip install -e ".[dev,test]"
Running Tests
# Run all tests
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test file
uv run pytest tests/test_docs_rs.py
# Run with coverage
uv run pytest --cov=src
Code Quality
# Format code
black src tests
# Lint code
ruff check src tests
Architecture
The server is built with:
- FastMCP: Framework for building MCP servers
- httpx: Async HTTP client for docs.rs/crates.io APIs
- docs.rs rustdoc JSON: Structured API docs and item graph
- crates.io API + crate archives: Metadata, dependencies, features, and source extraction
Key design decisions:
- Pagination Strategy: Character-based pagination allows precise control over response sizes
- Key-based Navigation: URLs are converted to stable keys for consistent navigation
- Combined Page Loading: Multiple pages can be fetched and paginated together
- Async Operations: All HTTP operations are async for better performance
Troubleshooting
Server won't start
- Ensure Python 3.10+ is installed
- Check all dependencies:
uv pip install -e . - Look for error messages in stderr output
Documentation not loading
- Verify the crate name is correct
- Check if the crate exists on docs.rs
- Try with a known working crate like "tokio" or "serde"
Search not returning results
- Some crates may have limited search functionality
- Try broader search terms
- Check the search_url in the response to see the actual search performed
License
MIT License - see LICENSE file for details.