Chapter 1: Project Architecture & Module Organization
Introduction
Pierre Fitness Platform is a production Rust application with 330 source files organized into a coherent module hierarchy. This chapter teaches you how to navigate the codebase, understand the module system, and recognize organizational patterns used throughout.
The codebase follows a “library + binaries” pattern where most functionality lives in src/lib.rs and binary entry points import from the library.
Project Structure Overview
pierre_mcp_server/
├── src/ # main rust source (library + modules)
│ ├── lib.rs # library root - central module hub
│ ├── bin/ # binary entry points
│ │ ├── pierre-mcp-server.rs # main server binary
│ │ └── admin_setup.rs # admin utilities
│ ├── mcp/ # mcp protocol implementation
│ ├── a2a/ # agent-to-agent protocol
│ ├── protocols/ # universal protocol layer
│ ├── oauth2_server/ # oauth2 authorization server
│ ├── oauth2_client/ # oauth2 client (for providers)
│ ├── providers/ # fitness provider integrations
│ ├── intelligence/ # sports science algorithms
│ ├── database/ # database repositories (13 focused traits)
│ ├── database_plugins/ # pluggable database backends (SQLite/PostgreSQL)
│ ├── middleware/ # http middleware (auth, tracing, etc)
│ ├── routes/ # http route handlers
│ └── [30+ other modules]
│
├── sdk/ # typescript sdk for stdio transport
│ ├── src/
│ │ ├── bridge.ts # stdio ↔ http bridge (2309 lines)
│ │ ├── types.ts # auto-generated tool types
│ │ └── secure-storage.ts # os keychain integration
│ └── test/ # sdk e2e tests
│
├── tests/ # integration & e2e tests
│ ├── helpers/
│ │ ├── synthetic_data.rs # fitness data generator
│ │ └── test_utils.rs # shared test utilities
│ └── [194 test files]
│
├── scripts/ # build & utility scripts
│ ├── generate-sdk-types.js # typescript type generation
│ └── lint-and-test.sh # ci validation script
│
├── templates/ # html templates (oauth pages)
├── docs/ # documentation
└── Cargo.toml # rust dependencies & config
Key Observation: The codebase is split into library code (src/lib.rs) and binary code (src/bin/). This is a Rust best practice for testability and reusability.
The Library Root: src/lib.rs
The src/lib.rs file is the central hub of the Pierre library. It declares all public modules and controls what’s exported to consumers.
File Header Pattern
Source: src/lib.rs:1-9
#![allow(unused)]
fn main() {
// ABOUTME: Main library entry point for Pierre fitness API platform
// ABOUTME: Provides MCP, A2A, and REST API protocols for fitness data analysis
//
// Licensed under either of Apache License, Version 2.0 or MIT License at your option.
// Copyright ©2025 Async-IO.org
#![recursion_limit = "256"]
#![deny(unsafe_code)]
}
Rust Idioms Explained:
-
// ABOUTME:comments - Human-readable file purpose (not rustdoc)- Quick context for developers scanning the codebase
- Appears at top of all 330 source files
-
Crate-level attributes
#![...]-
#![recursion_limit = "256"]: Increases macro recursion limit- Required for complex derive macros (serde, thiserror)
- Default is 128, Pierre uses 256 for deeply nested types
-
#![deny(unsafe_code)]: Zero-tolerance unsafe code policy- Compiler error if
unsafeblock appears anywhere - Exception:
src/health.rs(Windows FFI, approved via validation script) - See:
scripts/architectural-validation.shfor enforcement
- Compiler error if
-
Reference: Rust Reference - Crate Attributes
Module Documentation
Source: src/lib.rs:10-55
//! # Pierre MCP Server
//!
//! A Model Context Protocol (MCP) server for fitness data aggregation and analysis.
//! This server provides a unified interface to access fitness data from various providers
//! like Strava and Fitbit through the MCP protocol.
//!
//! ## Features
//!
//! - **Multi-provider support**: Connect to Strava, Fitbit, and more
//! - **OAuth2 authentication**: Secure authentication flow for fitness providers
//! - **MCP protocol**: Standard interface for Claude and other AI assistants
//! - **Real-time data**: Access to activities, athlete profiles, and statistics
//! - **Extensible architecture**: Easy to add new fitness providers
//!
//! ## Quick Start
//!
//! 1. Set up authentication credentials using the `auth-setup` binary
//! 2. Start the MCP server with `pierre-mcp-server`
//! 3. Connect from Claude or other MCP clients
//!
//! ## Architecture
//!
//! The server follows a modular architecture:
//! - **Providers**: Abstract fitness provider implementations
//! - **Models**: Common data structures for fitness data
//! - **MCP**: Model Context Protocol server implementation
//! - **OAuth2**: Authentication client for secure API access
//! - **Config**: Configuration management and persistence
//!
//! ## Example Usage
//!
//! ```rust,no_run
//! use pierre_mcp_server::config::environment::ServerConfig;
//! use pierre_mcp_server::errors::AppResult;
//!
//! #[tokio::main]
//! async fn main() -> AppResult<()> {
//! // Load configuration
//! let config = ServerConfig::from_env()?;
//!
//! // Start Pierre MCP Server with loaded configuration
//! println!("Pierre MCP Server configured with port: HTTP={}",
//! config.http_port);
//!
//! Ok(())
//! }
//! ```
Rust Idioms Explained:
-
Module-level docs
//!(three slashes + bang)- Appears in
cargo docoutput - Documents the containing module/crate
- Markdown formatted for rich documentation
- Appears in
-
```rust,no_run` code blocks
- Syntax highlighted in docs
,no_runflag: compile-checked but not executed in doc tests- Ensures examples stay up-to-date with code
Reference: Rust Book - Documentation Comments
Module Declarations
Source: src/lib.rs:57-189
#![allow(unused)]
fn main() {
/// Fitness provider implementations for various services
pub mod providers;
/// Common data models for fitness data
pub mod models;
/// Cursor-based pagination for efficient data traversal
pub mod pagination;
/// Configuration management and persistence
pub mod config;
/// Focused dependency injection contexts
pub mod context;
/// Application constants and configuration values
pub mod constants;
/// OAuth 2.0 client (Pierre as client to fitness providers)
pub mod oauth2_client;
/// Model Context Protocol server implementation
pub mod mcp;
/// Athlete Intelligence for activity analysis and insights
pub mod intelligence;
/// External API clients (USDA, weather services)
pub mod external;
/// Configuration management and runtime parameter system
pub mod configuration;
// ... 30+ more module declarations
}
Rust Idioms Explained:
-
pub moddeclarations- Makes module public to external crates
- Each
pub mod foo;looks for:src/foo.rs(single-file module), ORsrc/foo/mod.rs(directory module)
-
Documentation comments
///(three slashes)- Documents the item below (not the containing module)
- Brief one-line summaries for each module
- Visible in IDE tooltips and
cargo doc
-
Module ordering - Logical grouping:
- Core domain (providers, models, pagination)
- Configuration (config, context, constants)
- Protocols (oauth2_client, mcp, a2a, protocols)
- Data layer (database, database_plugins, cache)
- Infrastructure (auth, crypto, routes, middleware)
- Features (intelligence, external, plugins)
- Utilities (types, utils, test_utils)
Reference: Rust Book - Modules
Conditional Compilation
Source: src/lib.rs:188-189
#![allow(unused)]
fn main() {
/// Test utilities for creating consistent test data
#[cfg(any(test, feature = "testing"))]
pub mod test_utils;
}
Rust Idioms Explained:
-
#[cfg(...)]attribute- Conditional compilation based on configuration
- Code only included if conditions are met
-
#[cfg(any(test, feature = "testing"))]test: Built-in flag when runningcargo testfeature = "testing": Custom feature flag fromCargo.toml:47any(...): Include if ANY condition is true
-
Why use this?
test_utilsmodule only needed during testing- Excluded from production binary (reduces binary size)
- Can be enabled in other crates via
features = ["testing"]
Cargo.toml configuration:
[features]
default = ["sqlite"]
sqlite = []
postgresql = ["sqlx/postgres"]
testing = [] # Feature flag for test utilities
Reference: Rust Book - Conditional Compilation
Binary Entry Points: src/bin/
Rust crates can define multiple binary targets. Pierre has two main binaries:
Main Server Binary
Source: src/bin/pierre-mcp-server.rs:1-61
// ABOUTME: Server implementation for serving users with isolated data access
// ABOUTME: Production-ready server with authentication and user isolation capabilities
#![recursion_limit = "256"]
#![deny(unsafe_code)]
//! # Pierre Fitness API Server Binary
//!
//! This binary starts the multi-protocol Pierre Fitness API with user authentication,
//! secure token storage, and database management.
use anyhow::Result;
use clap::Parser;
use pierre_mcp_server::{
config::environment::{ServerConfig, TokioRuntimeConfig},
database_plugins::factory::Database,
mcp::{multitenant::MultiTenantMcpServer, resources::ServerResources},
// ... other imports
};
use tokio::runtime::{Builder, Runtime};
/// Command-line arguments for the Pierre MCP server
#[derive(Parser)]
#[command(name = "pierre-mcp-server")]
#[command(version = env!("CARGO_PKG_VERSION"))]
#[command(about = "Pierre Fitness API - Multi-protocol fitness data API for LLMs")]
pub struct Args {
/// Configuration file path for providers
#[arg(short, long)]
config: Option<String>,
/// Override HTTP port
#[arg(long)]
http_port: Option<u16>,
}
fn main() -> Result<()> {
let args = parse_args_or_default();
// Load runtime config first to build the Tokio runtime
let runtime_config = TokioRuntimeConfig::from_env();
let runtime = build_tokio_runtime(&runtime_config)?;
// Run the async server on our configured runtime
runtime.block_on(async {
let config = setup_configuration(&args)?;
bootstrap_server(config).await
})
}
Rust Idioms Explained:
-
Binary crate attributes - Same as library (
#![...])- Each binary can have its own attributes
- Often mirrors library settings
-
use pierre_mcp_server::...- Importing from library- Binary depends on library crate
- Imports only what’s needed
- Absolute paths from crate root
-
clap::Parserderive macro- Auto-generates CLI argument parser
#[command(...)]attributes for metadata#[arg(...)]attributes for options- Generates
--helpautomatically
-
Manual Tokio runtime building
- Pierre uses
TokioRuntimeConfig::from_env()for configurable runtime - Worker threads and stack size configurable via environment
- More control than
#[tokio::main]macro:
- Pierre uses
#![allow(unused)]
fn main() {
// Pierre's configurable runtime builder
fn build_tokio_runtime(config: &TokioRuntimeConfig) -> Result<Runtime> {
let mut builder = Builder::new_multi_thread();
if let Some(workers) = config.worker_threads {
builder.worker_threads(workers);
}
builder.enable_all().build().map_err(Into::into)
}
}
Reference:
Cargo.toml Binary Declarations
Source: Cargo.toml:14-29
[lib]
name = "pierre_mcp_server"
path = "src/lib.rs"
[[bin]]
name = "pierre-mcp-server"
path = "src/bin/pierre-mcp-server.rs"
[[bin]]
name = "admin-setup"
path = "src/bin/admin_setup.rs"
[[bin]]
name = "diagnose-weather-api"
path = "src/bin/diagnose_weather_api.rs"
Explanation:
[lib]: Single library target[[bin]]: Multiple binary targets (double brackets = array)- Binary names can differ from file names (kebab-case vs snake_case)
Build commands:
# Build all binaries
cargo build --release
# Run specific binary
cargo run --bin pierre-mcp-server
# Install binary to ~/.cargo/bin
cargo install --path . --bin pierre-mcp-server
Module Organization Patterns
Pierre uses several module organization patterns consistently.
Single-File Modules
Example: src/errors.rs
src/
├── lib.rs # Contains: pub mod errors;
└── errors.rs # The module implementation
When module fits in one file (~100-500 lines), use single-file pattern.
Directory Modules
Example: src/mcp/ directory
src/
├── lib.rs # Contains: pub mod mcp;
└── mcp/
├── mod.rs # Module root, declares submodules
├── protocol.rs # Submodule
├── tool_handlers.rs # Submodule
├── multitenant.rs # Submodule
└── [8 more files]
Source: src/mcp/mod.rs:1-40
#![allow(unused)]
fn main() {
// ABOUTME: MCP (Model Context Protocol) server implementation
// ABOUTME: JSON-RPC 2.0 protocol for AI assistant tool execution
//! MCP Protocol Implementation
//!
//! This module implements the Model Context Protocol (MCP) for AI assistant integration.
//! MCP is a JSON-RPC 2.0 based protocol that enables AI assistants like Claude to execute
//! tools and access resources from external services.
// Submodule declarations
pub mod protocol;
pub mod tool_handlers;
pub mod multitenant;
pub mod resources;
pub mod tenant_isolation;
pub mod oauth_flow_manager;
pub mod transport_manager;
pub mod mcp_request_processor;
pub mod server_lifecycle;
pub mod progress;
pub mod schema;
// Re-exports for convenience
pub use multitenant::MultiTenantMcpServer;
pub use resources::ServerResources;
pub use protocol::{McpRequest, McpResponse};
}
Rust Idioms Explained:
-
mod.rsconvention- Directory modules need a
mod.rsfile - Acts as the “index” file for the directory
- Declares and organizes submodules
- Directory modules need a
-
Re-exports
pub use ...- Makes deeply nested types accessible at module root
- Users can write
use pierre_mcp_server::mcp::MultiTenantMcpServer - Instead of
use pierre_mcp_server::mcp::multitenant::MultiTenantMcpServer
-
Submodule visibility
pub modmakes submodule publicmod(withoutpub) keeps it private to parent module- All Pierre submodules are public for flexibility
Reference: Rust Book - Separating Modules into Different Files
Nested Directory Modules
Example: src/protocols/universal/handlers/
src/
└── protocols/
├── mod.rs
└── universal/
├── mod.rs
└── handlers/
├── mod.rs
├── fitness_api.rs
├── intelligence.rs
├── goals.rs
├── configuration.rs
├── sleep_recovery.rs
├── nutrition.rs
├── recipes.rs
└── connections.rs
Source: src/protocols/universal/handlers/mod.rs
#![allow(unused)]
fn main() {
//! MCP tool handlers for all tool categories
pub mod fitness_api;
pub mod intelligence;
pub mod goals;
pub mod configuration;
pub mod sleep_recovery;
pub mod nutrition;
pub mod recipes;
pub mod connections;
// Re-export all handler functions
pub use fitness_api::*;
pub use intelligence::*;
pub use goals::*;
pub use configuration::*;
pub use sleep_recovery::*;
pub use nutrition::*;
pub use recipes::*;
pub use connections::*;
}
Pattern: Deep hierarchies use mod.rs at each level to organize related functionality.
Feature Flags & Conditional Compilation
Pierre uses feature flags for optional dependencies and database backends.
Source: Cargo.toml:42-47
[features]
default = ["sqlite"]
sqlite = []
postgresql = ["sqlx/postgres"]
testing = []
telemetry = []
Feature Flag Usage
1. Default features
default = ["sqlite"]
Builds with SQLite by default. Users can opt out:
cargo build --no-default-features
2. Database backend selection
Source: src/database_plugins/factory.rs:30-50
#![allow(unused)]
fn main() {
pub async fn new(
connection_string: &str,
encryption_key: Vec<u8>,
#[cfg(feature = "postgresql")]
postgres_pool_config: &PostgresPoolConfig,
) -> Result<Self, DatabaseError> {
#[cfg(feature = "sqlite")]
if connection_string.starts_with("sqlite:") {
let sqlite_db = SqliteDatabase::new(connection_string, encryption_key).await?;
return Ok(Database::Sqlite(sqlite_db));
}
#[cfg(feature = "postgresql")]
if connection_string.starts_with("postgres://") || connection_string.starts_with("postgresql://") {
let postgres_db = PostgresDatabase::new(
connection_string,
encryption_key,
postgres_pool_config,
).await?;
return Ok(Database::Postgres(postgres_db));
}
Err(DatabaseError::ConfigurationError(
"Unsupported database type in connection string".to_string()
))
}
}
Rust Idioms Explained:
-
#[cfg(feature = "...")]- Code only compiled if feature is enabled
sqlitefeature compiles SQLite codepostgresqlfeature compiles PostgreSQL code
-
Function parameter attributes
#![allow(unused)] fn main() { #[cfg(feature = "postgresql")] postgres_pool_config: &PostgresPoolConfig, }- Parameter only exists if feature is enabled
- Type checking happens only when feature is active
-
Build commands:
# SQLite (default) cargo build # PostgreSQL cargo build --no-default-features --features postgresql # Both cargo build --features postgresql
Reference: Cargo Book - Features
Documentation Patterns
Pierre follows consistent documentation practices across all 330 source files.
Dual-Comment Pattern
Every file has both // ABOUTME: and //! comments:
#![allow(unused)]
fn main() {
// ABOUTME: Brief human-readable purpose
// ABOUTME: Additional context
//
// License header
//! # Module Title
//!
//! Detailed rustdoc documentation
//! with markdown formatting
}
Benefits:
// ABOUTME:: Quick context when browsing files (shows in editors)//!: Full documentation forcargo docoutput- Separation of concerns: quick ref vs comprehensive docs
Rustdoc Formatting
Source: src/mcp/protocol.rs:1-30
#![allow(unused)]
fn main() {
//! # MCP Protocol Implementation
//!
//! Core protocol handlers for the Model Context Protocol (MCP).
//! Implements JSON-RPC 2.0 message handling and tool execution.
//!
//! ## Supported Methods
//!
//! - `initialize`: Protocol version negotiation
//! - `tools/list`: List available tools
//! - `tools/call`: Execute a tool
//! - `resources/list`: List available resources
//!
//! ## Example
//!
//! ```rust,ignore
//! use pierre_mcp_server::mcp::protocol::handle_mcp_request;
//!
//! let response = handle_mcp_request(request).await?;
//! ```
}
Markdown features:
#headers (h1, h2, h3)-bullet lists`inline code```rustcode blocks**bold**and*italic*
Generate docs:
cargo doc --open # Generate & open in browser
Reference: Rust Book - Documentation
Import Conventions
Pierre follows consistent import patterns for clarity.
Absolute vs Relative Imports
Preferred: Absolute imports from crate root
#![allow(unused)]
fn main() {
use crate::errors::AppError;
use crate::database::DatabaseError;
use crate::providers::ProviderError;
}
Avoid: Relative imports
#![allow(unused)]
fn main() {
// Don't do this
use super::super::errors::AppError;
use ../database::DatabaseError; // Not valid Rust
}
Exception: Sibling modules in same directory can use super::
#![allow(unused)]
fn main() {
// In src/protocols/universal/handlers/goals.rs
use super::super::executor::UniversalToolExecutor; // Acceptable
use crate::protocols::universal::executor::UniversalToolExecutor; // Better
}
Grouping Imports
Source: src/bin/pierre-mcp-server.rs:15-24
#![allow(unused)]
fn main() {
// Group 1: External crates
use clap::Parser;
use std::sync::Arc;
use tracing::{error, info};
// Group 2: Internal crate imports
use pierre_mcp_server::{
auth::AuthManager,
cache::factory::Cache,
config::environment::ServerConfig,
database_plugins::{factory::Database, DatabaseProvider},
errors::AppResult,
logging,
mcp::{multitenant::MultiTenantMcpServer, resources::ServerResources},
};
}
Convention:
- External dependencies (
clap,std,tracing) - Internal crate (
pierre_mcp_server::...) - Blank line between groups
Reference: Rust Style Guide
Navigating the Codebase
Finding Functionality
Strategy 1: Start from src/lib.rs module declarations
- Each
pub modhas a one-line summary - Navigate to module’s
mod.rsfor details
Strategy 2: Use grep or IDE search
# Find all files containing "OAuth"
grep -r "OAuth" src/
# Find struct definitions
grep -r "pub struct" src/
Strategy 3: Follow imports
- Open a file, read its
usestatements - Imports show dependencies and related modules
Understanding Module Responsibilities
MCP Protocol (src/mcp/):
- protocol.rs: Core JSON-RPC handlers
- tool_handlers.rs: Tool execution routing
- multitenant.rs: Multi-tenant server wrapper
- resources.rs: Shared server resources
Protocols Layer (src/protocols/universal/):
- tool_registry.rs: Type-safe tool routing
- executor.rs: Tool execution engine
- handlers/: Business logic for each tool
Database (src/database_plugins/):
- factory.rs: Database abstraction
- sqlite.rs: SQLite implementation
- postgres.rs: PostgreSQL implementation
Diagram: Module Dependency Graph
┌─────────────────────────────────────────────────────────────┐
│ src/lib.rs │
│ (central module hub) │
└─────────────┬────────────────────────┬──────────────────────┘
│ │
┌────────▼────────┐ ┌───────▼────────┐
│ src/bin/ │ │ Public Modules │
│ - main server │ │ (40+ modules) │
│ - admin tools │ └───────┬─────────┘
└─────────────────┘ │
│
┌───────────────────────┼──────────────────────┐
│ │ │
┌────────▼────────┐ ┌─────────▼────────┐ ┌─────────▼────────┐
│ Protocols │ │ Data Layer │ │ Infrastructure │
│ - mcp/ │ │ - database/ │ │ - auth │
│ - a2a/ │ │ - database_ │ │ - middleware │
│ - protocols/ │ │ plugins/ │ │ - routes │
│ - jsonrpc/ │ │ - cache/ │ │ - logging │
└─────────────────┘ └──────────────────┘ └──────────────────┘
│ │ │
│ │ │
┌────────▼────────────────┐ │ ┌────────────▼──────────┐
│ Domain Logic │ │ │ External Services │
│ - providers/ │ │ │ - oauth2_client │
│ - intelligence/ │ │ │ - oauth2_server │
│ - configuration/ │ │ │ - external/ │
└─────────────────────────┘ │ └───────────────────────┘
│
┌────────────▼──────────┐
│ Shared Utilities │
│ - models │
│ - errors │
│ - types │
│ - utils │
│ - constants │
└───────────────────────┘
Key Observations:
- lib.rs is the hub connecting all modules
- Protocols layer is protocol-agnostic (shared by MCP & A2A)
- Data layer is abstracted (pluggable backends)
- Infrastructure is cross-cutting (auth, middleware, logging)
- Domain logic is isolated (providers, intelligence)
Rust Idioms Summary
| Idiom | Purpose | Example Location |
|---|---|---|
Crate attributes #![...] | Set compiler flags/limits | src/lib.rs:7-8 |
Module docs //! | Document containing module | All mod.rs files |
Item docs /// | Document following item | src/lib.rs:58+ |
pub mod | Public module declaration | src/lib.rs:57-189 |
Re-exports pub use | Convenience exports | src/mcp/mod.rs:24-26 |
Feature flags #[cfg(...)] | Conditional compilation | src/database_plugins/factory.rs |
Binary targets [[bin]] | Multiple executables | Cargo.toml:15-29 |
References:
Key Takeaways
- Library + Binaries Pattern: Core logic in
lib.rs, entry points inbin/ - Module Hierarchy: Use
pub modin parent,mod.rsfor directory modules - Dual Documentation:
// ABOUTME:for humans,//!for rustdoc - Feature Flags: Enable optional functionality (
sqlite,postgresql,testing) - Import Conventions: Absolute paths from
crate::, grouped by origin - Zero Unsafe Code:
#![deny(unsafe_code)]enforced via CI
Next Chapter
Chapter 2: Error Handling & Type-Safe Errors - Learn how Pierre uses thiserror for structured error types and eliminates anyhow! from production code.