Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

  1. // ABOUTME: comments - Human-readable file purpose (not rustdoc)

    • Quick context for developers scanning the codebase
    • Appears at top of all 330 source files
  2. 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 unsafe block appears anywhere
      • Exception: src/health.rs (Windows FFI, approved via validation script)
      • See: scripts/architectural-validation.sh for enforcement

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:

  1. Module-level docs //! (three slashes + bang)

    • Appears in cargo doc output
    • Documents the containing module/crate
    • Markdown formatted for rich documentation
  2. ```rust,no_run` code blocks

    • Syntax highlighted in docs
    • ,no_run flag: 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:

  1. pub mod declarations

    • Makes module public to external crates
    • Each pub mod foo; looks for:
      • src/foo.rs (single-file module), OR
      • src/foo/mod.rs (directory module)
  2. 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
  3. 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:

  1. #[cfg(...)] attribute

    • Conditional compilation based on configuration
    • Code only included if conditions are met
  2. #[cfg(any(test, feature = "testing"))]

    • test: Built-in flag when running cargo test
    • feature = "testing": Custom feature flag from Cargo.toml:47
    • any(...): Include if ANY condition is true
  3. Why use this?

    • test_utils module 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:

  1. Binary crate attributes - Same as library (#![...])

    • Each binary can have its own attributes
    • Often mirrors library settings
  2. use pierre_mcp_server::... - Importing from library

    • Binary depends on library crate
    • Imports only what’s needed
    • Absolute paths from crate root
  3. clap::Parser derive macro

    • Auto-generates CLI argument parser
    • #[command(...)] attributes for metadata
    • #[arg(...)] attributes for options
    • Generates --help automatically
  4. 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:
#![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:

  1. mod.rs convention

    • Directory modules need a mod.rs file
    • Acts as the “index” file for the directory
    • Declares and organizes submodules
  2. 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
  3. Submodule visibility

    • pub mod makes submodule public
    • mod (without pub) 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:

  1. #[cfg(feature = "...")]

    • Code only compiled if feature is enabled
    • sqlite feature compiles SQLite code
    • postgresql feature compiles PostgreSQL code
  2. 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
  3. 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 for cargo doc output
  • 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
  • ```rust code 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:

  1. External dependencies (clap, std, tracing)
  2. Internal crate (pierre_mcp_server::...)
  3. Blank line between groups

Reference: Rust Style Guide


Finding Functionality

Strategy 1: Start from src/lib.rs module declarations

  • Each pub mod has a one-line summary
  • Navigate to module’s mod.rs for 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 use statements
  • 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

IdiomPurposeExample Location
Crate attributes #![...]Set compiler flags/limitssrc/lib.rs:7-8
Module docs //!Document containing moduleAll mod.rs files
Item docs ///Document following itemsrc/lib.rs:58+
pub modPublic module declarationsrc/lib.rs:57-189
Re-exports pub useConvenience exportssrc/mcp/mod.rs:24-26
Feature flags #[cfg(...)]Conditional compilationsrc/database_plugins/factory.rs
Binary targets [[bin]]Multiple executablesCargo.toml:15-29

References:


Key Takeaways

  1. Library + Binaries Pattern: Core logic in lib.rs, entry points in bin/
  2. Module Hierarchy: Use pub mod in parent, mod.rs for directory modules
  3. Dual Documentation: // ABOUTME: for humans, //! for rustdoc
  4. Feature Flags: Enable optional functionality (sqlite, postgresql, testing)
  5. Import Conventions: Absolute paths from crate::, grouped by origin
  6. 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.