diff --git a/README.md b/README.md index 1d62917..a6e6ddd 100644 --- a/README.md +++ b/README.md @@ -13,192 +13,43 @@ A Model Context Protocol (MCP) server providing comprehensive tools for interact - **Docker Support**: Production-ready Docker images with multi-platform support (amd64/arm64) - **Type Safety**: Full type hints and Pydantic validation throughout the codebase - **Async Operations**: Non-blocking HTTP operations for optimal performance -- **Robust Error Handling**: Comprehensive error handling across all API interactions ## Quick Start -### Option 1: Docker (Recommended) - -The fastest way to get started is using the published Docker image: - -```bash -# Pull the latest image -docker pull ghcr.io/radcod3/lampyrid:latest +### Prerequisites -# Run with stdio mode (for Claude Desktop) -docker run --rm -i \ - -e MCP_TRANSPORT=stdio \ - -e FIREFLY_BASE_URL=https://your-firefly-instance.com \ - -e FIREFLY_TOKEN=your-api-token \ - ghcr.io/radcod3/lampyrid:latest +- Access to a Firefly III instance with a [Personal Access Token](https://docs.firefly-iii.org/how-to/firefly-iii/features/api/#personal-access-token) +- For local installation: Python 3.14+ and [uv](https://github.com/astral-sh/uv) package manager +- For Docker: Docker installed on your system -# Or use docker-compose -cat > docker-compose.yml < **Add More** +3. Enter your server URL: `https://your-server-url.com` +4. LamPyrid is now available on all your Claude devices! -### Account Management (3 tools) -- `list_accounts` - List accounts by type (asset, expense, revenue, etc.) -- `search_accounts` - Search accounts by name with optional type filtering -- `get_account` - Get detailed information for a single account +> **Security Note**: If hosting on a public server, it is strongly recommended to enable authentication. LamPyrid currently supports Google OAuth - see the [Authentication Setup](#google-oauth-authentication-optional) section for configuration. -### Transaction Management (10 tools) -- `get_transactions` - Retrieve transactions with time range and type filtering -- `search_transactions` - Search transactions by description or text fields -- `get_transaction` - Get detailed information for a single transaction -- `create_withdrawal` - Create withdrawal transactions with budget allocation -- `create_deposit` - Create deposit transactions -- `create_transfer` - Create transfer transactions between accounts -- `create_bulk_transactions` - Create multiple transactions efficiently in a single operation -- `update_transaction` - Update existing transaction details (amount, description, accounts, budget, etc.) -- `bulk_update_transactions` - Update multiple transactions efficiently in a single operation -- `delete_transaction` - Delete transactions by ID +## Configuration -### Budget Management (5 tools) -- `list_budgets` - List all budgets with optional filtering -- `get_budget` - Get detailed budget information -- `get_budget_spending` - Analyze spending for specific budgets and periods -- `get_budget_summary` - Comprehensive summary of all budgets with spending -- `get_available_budget` - Check available budget amounts for periods +LamPyrid uses environment variables for configuration: -All tools include comprehensive error handling and return structured data optimized for MCP integration. +### Required -## Development +| Variable | Description | +|----------|-------------| +| `FIREFLY_BASE_URL` | URL of your Firefly III instance | +| `FIREFLY_TOKEN` | Personal access token for API authentication | -### Setup Development Environment +### Server Options -```bash -# Install dependencies -uv sync +| Variable | Default | Description | +|----------|---------|-------------| +| `MCP_TRANSPORT` | `stdio` | Transport protocol: `stdio`, `http`, or `sse` | +| `MCP_HOST` | `0.0.0.0` | Host binding for HTTP/SSE transports | +| `MCP_PORT` | `3000` | Port binding for HTTP/SSE transports | +| `LOGGING_LEVEL` | `INFO` | Logging verbosity: DEBUG/INFO/WARNING/ERROR/CRITICAL | -# Format code -uv run ruff format +### Google OAuth Authentication (Optional) -# Lint code -uv run ruff check --fix +Recommended for remote server deployments to secure access to your financial data. Currently, Google OAuth is the only supported authentication provider. -# Build Docker image locally -docker build -t lampyrid:dev . +| Variable | Description | +|----------|-------------| +| `GOOGLE_CLIENT_ID` | Google OAuth 2.0 client ID | +| `GOOGLE_CLIENT_SECRET` | Google OAuth 2.0 client secret | +| `SERVER_BASE_URL` | Your server's public URL (e.g., `https://lampyrid.example.com`) | -# Run local development server -uv run lampyrid -``` +**Setting up Google OAuth:** -### Project Structure +1. Go to [Google Cloud Console](https://console.cloud.google.com) +2. Create or select a project +3. Navigate to **APIs & Services** > **OAuth consent screen** and configure +4. Go to **Credentials** > **Create Credentials** > **OAuth client ID** +5. Application type: **Web application** +6. Add authorized redirect URI: `{SERVER_BASE_URL}/auth/callback` +7. Copy the Client ID and Client Secret to your environment -```text -LamPyrid/ -├── src/lampyrid/ -│ ├── __init__.py # Package initialization -│ ├── __main__.py # Main entry point for MCP server -│ ├── server.py # FastMCP server initialization and tool composition -│ ├── config.py # Environment configuration -│ ├── utils.py # Custom HTTP routes (favicon, etc.) -│ ├── clients/ -│ │ └── firefly.py # HTTP client for Firefly III API -│ ├── models/ -│ │ ├── firefly_models.py # Auto-generated Firefly III API models -│ │ └── lampyrid_models.py# Simplified MCP interface models -│ ├── services/ -│ │ ├── __init__.py # Services layer exports -│ │ ├── accounts.py # AccountService - account business logic -│ │ ├── transactions.py # TransactionService - transaction business logic -│ │ └── budgets.py # BudgetService - budget business logic -│ └── tools/ -│ ├── __init__.py # Tool server composition coordinator -│ ├── accounts.py # Account management tools (3 tools) -│ ├── transactions.py # Transaction management tools (10 tools) -│ └── budgets.py # Budget management tools (5 tools) -├── tests/ # Unit and integration tests -├── .github/workflows/ # CI/CD workflows -├── assets/ # Project assets -├── Dockerfile # Docker image definition -├── docker-compose.yml # Docker Compose configuration -├── pyproject.toml # Project configuration and dependencies -└── README.md # Project documentation -``` +### OAuth Token Persistence (Optional) -## Architecture - -LamPyrid follows a clean layered architecture with modular tool organization: - -- **Server Layer** (`server.py`): FastMCP server initialization, authentication setup, and tool registration orchestration -- **Tools Layer** (`tools/`): Thin MCP tool wrappers organized by domain that delegate to services - - `accounts.py`: Account management tools (3 tools) - - `transactions.py`: Transaction management tools (10 tools) - - `budgets.py`: Budget management tools (5 tools) -- **Services Layer** (`services/`): Business logic services that orchestrate operations between tools and the client - - `accounts.py`: `AccountService` - account operations and model conversion - - `transactions.py`: `TransactionService` - transaction CRUD, bulk operations, search query building - - `budgets.py`: `BudgetService` - budget operations, spending calculations, multi-call aggregations -- **Client Layer** (`clients/firefly.py`): HTTP client for Firefly III API with full CRUD support -- **Models Layer**: - - `firefly_models.py`: Auto-generated Pydantic models from Firefly III OpenAPI spec - - `lampyrid_models.py`: Simplified models for MCP tool interfaces -- **Configuration** (`config.py`): Environment-based settings using pydantic-settings - -### Tool Registration Pattern -Tools are registered using FastMCP's native static composition pattern: -- Each tool module exports a `create_*_server(client)` function that returns a standalone FastMCP instance -- Tool functions are thin wrappers that delegate to corresponding service classes -- The `tools/__init__.py` module provides `compose_all_servers()` to coordinate composition -- The `server.py` uses `mcp.import_server()` to compose all domain servers into the main server -- This leverages FastMCP's built-in server composition while keeping modular organization - -### Services Layer Pattern -The services layer separates business logic from tool definitions: -- Each service class takes a `FireflyClient` instance via constructor injection -- Services handle model conversion (Firefly API models to LamPyrid models) -- Complex operations (bulk transactions, spending calculations) are encapsulated in services -- This enables easier unit testing with mocked clients - -The architecture enables easy extension and modification while maintaining type safety and comprehensive error handling throughout. +Enable persistent authentication across server restarts: -## Docker Deployment +| Variable | Description | +|----------|-------------| +| `JWT_SIGNING_KEY` | JWT signing key (generate: `python -c "import secrets; print(secrets.token_urlsafe(32))"`) | +| `OAUTH_STORAGE_ENCRYPTION_KEY` | Fernet key (generate: `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"`) | +| `OAUTH_STORAGE_PATH` | Storage path (default: `/app/data/oauth` for Docker) | -LamPyrid provides production-ready Docker images published to GitHub Container Registry. +## Available MCP Tools -### Available Images +### Account Management (3 tools) +| Tool | Description | +|------|-------------| +| `list_accounts` | List accounts by type (asset, expense, revenue, etc.) | +| `search_accounts` | Search accounts by name with optional type filtering | +| `get_account` | Get detailed information for a single account | -- **Latest Stable**: `ghcr.io/radcod3/lampyrid:latest` (latest release - recommended for production) -- **Development**: `ghcr.io/radcod3/lampyrid:edge` (main branch - latest features, may be unstable) -- **Versioned**: `ghcr.io/radcod3/lampyrid:0.2.0`, `ghcr.io/radcod3/lampyrid:0.2`, `ghcr.io/radcod3/lampyrid:0` -- **Platforms**: linux/amd64, linux/arm64 +### Transaction Management (10 tools) +| Tool | Description | +|------|-------------| +| `get_transactions` | Retrieve transactions with time range and type filtering | +| `search_transactions` | Search transactions by description or text fields | +| `get_transaction` | Get detailed information for a single transaction | +| `create_withdrawal` | Create withdrawal transactions with budget allocation | +| `create_deposit` | Create deposit transactions | +| `create_transfer` | Create transfer transactions between accounts | +| `create_bulk_transactions` | Create multiple transactions in a single operation | +| `update_transaction` | Update existing transaction details | +| `bulk_update_transactions` | Update multiple transactions in a single operation | +| `delete_transaction` | Delete transactions by ID | -### Running with Docker +### Budget Management (5 tools) +| Tool | Description | +|------|-------------| +| `list_budgets` | List all budgets with optional filtering | +| `get_budget` | Get detailed budget information | +| `get_budget_spending` | Analyze spending for specific budgets and periods | +| `get_budget_summary` | Comprehensive summary of all budgets with spending | +| `get_available_budget` | Check available budget amounts for periods | -```bash -# Run in stdio mode (for Claude Desktop integration) -docker run --rm -i \ - -e MCP_TRANSPORT=stdio \ - -e FIREFLY_BASE_URL=https://your-firefly-instance.com \ - -e FIREFLY_TOKEN=your-api-token \ - ghcr.io/radcod3/lampyrid:latest - -# Run in HTTP mode -docker run -d \ - -p 3000:3000 \ - -e FIREFLY_BASE_URL=https://your-firefly-instance.com \ - -e FIREFLY_TOKEN=your-api-token \ - --name lampyrid \ - ghcr.io/radcod3/lampyrid:latest -``` +## Docker Deployment + +### Available Images + +| Tag | Description | +|-----|-------------| +| `latest` | Latest stable release (recommended) | +| `edge` | Main branch (latest features, may be unstable) | +| `0.3.0`, `0.3`, `0` | Specific versions | + +All images support `linux/amd64` and `linux/arm64` platforms. ### Using Docker Compose +The repository includes a `docker-compose.yml` for easy deployment: + ```yaml services: lampyrid: image: ghcr.io/radcod3/lampyrid:latest ports: - "3000:3000" - environment: - FIREFLY_BASE_URL: https://your-firefly-instance.com - FIREFLY_TOKEN: your-api-token - # Optional: Configure transport and logging - MCP_TRANSPORT: http - LOGGING_LEVEL: INFO - # Optional: Enable OAuth token persistence - # JWT_SIGNING_KEY: your-jwt-signing-key - # OAUTH_STORAGE_ENCRYPTION_KEY: your-fernet-encryption-key - # OAUTH_STORAGE_PATH: /app/data/oauth + env_file: + - .env volumes: - # Persist OAuth tokens across container restarts (if OAuth is enabled) + # Persist OAuth tokens across container restarts - ./data/oauth:/app/data/oauth restart: unless-stopped ``` -### Volume Permissions for OAuth Storage +Create a `.env` file with your configuration: -When using Docker with OAuth token persistence, you may encounter permission issues where the container cannot write to the mounted volume at `./data/oauth`. +```bash +# Required +FIREFLY_BASE_URL=https://your-firefly-instance.com +FIREFLY_TOKEN=your-api-token -**The Issue**: The container runs as the `nonroot` user (UID 65532) for security. When Docker creates the volume mount from the host (typically when the host directory doesn't exist before the container starts), it may have root:root ownership, preventing the nonroot user from writing to the directory. +# Optional - Server settings +MCP_TRANSPORT=http +LOGGING_LEVEL=INFO -**Symptoms**: If you see errors like `sqlite3.OperationalError: unable to open database file` or other permission-related errors in the container logs, this is likely the cause. +# Optional - For remote authentication +GOOGLE_CLIENT_ID=your-client-id +GOOGLE_CLIENT_SECRET=your-client-secret +SERVER_BASE_URL=https://your-domain.com -**Solution**: Set the correct ownership on the host directory before starting the container: +# Optional - For persistent OAuth tokens +JWT_SIGNING_KEY=your-jwt-key +OAUTH_STORAGE_ENCRYPTION_KEY=your-encryption-key +OAUTH_STORAGE_PATH=/app/data/oauth +``` -```bash -# Create the directory if it doesn't exist -mkdir -p ./data/oauth +Then start the server: -# Set ownership to UID 65532 (nonroot user) -sudo chown -R 65532:65532 ./data/oauth +```bash +docker compose up -d ``` -**Note**: This is environment-dependent and may not be required on all systems. Some Docker configurations handle volume permissions automatically. If you encounter permission errors, apply this fix. - -### Building Custom Images +**Note on Volume Permissions**: If you encounter permission errors with OAuth storage, set the correct ownership: ```bash -# Build locally -docker build -t lampyrid:custom . - -# Build for specific platform -docker buildx build --platform linux/amd64 -t lampyrid:custom . +mkdir -p ./data/oauth +sudo chown -R 65532:65532 ./data/oauth ``` -## CI/CD and Releases - -LamPyrid uses GitHub Actions for continuous integration and deployment: +## Development -### Automated Workflows +```bash +# Install dependencies +uv sync -- **CI Workflow**: Runs on all pull requests - - Code linting and formatting validation - - Package build verification - - Docker image build test +# Format code +uv run ruff format -- **Docker Publish Workflow**: Runs on main branch and version tags - - Multi-platform image builds (amd64/arm64) - - Security scanning with Trivy - - Publishes to ghcr.io with appropriate tags +# Lint code +uv run ruff check --fix -- **Release Workflow**: Runs on version tags (e.g., `v0.2.0`) - - Generates changelog from git commits - - Creates GitHub release with installation instructions - - Links to published Docker images +# Run the server +uv run lampyrid -### Creating a Release +# Run tests +uv run pytest +``` -To create a new release: +### Project Structure -1. Merge all features to main via pull requests -2. Create a release branch and update version in `pyproject.toml` -3. Merge the version bump PR -4. Create and push a version tag (e.g., `v0.2.0`) -5. GitHub Actions automatically builds and publishes the release +``` +LamPyrid/ +├── src/lampyrid/ +│ ├── server.py # FastMCP server initialization +│ ├── config.py # Environment configuration +│ ├── clients/firefly.py # HTTP client for Firefly III API +│ ├── models/ # Pydantic models +│ ├── services/ # Business logic layer +│ └── tools/ # MCP tool definitions +├── tests/ # Unit and integration tests +├── Dockerfile # Docker image definition +└── docker-compose.yml # Docker Compose configuration +``` ## Contributing -Contributions are welcome! Please follow this workflow: - -1. **Fork the repository** -2. **Create a feature branch** from `main`: - ```bash - git checkout -b feat/your-feature-name - ``` -3. **Make your changes** following the code style guidelines below -4. **Test locally**: - ```bash - uv run ruff format - uv run ruff check --fix - uv run lampyrid # Verify the server starts - ``` -5. **Commit your changes** with clear, descriptive messages -6. **Push to your fork** and create a pull request - -### Code Style Guidelines - -- **Indentation**: Use spaces for indentation -- **Quotes**: Single quotes for strings -- **Line Length**: 100 character line limit -- **Type Safety**: Type hints required for all functions and methods -- **Async Operations**: Use async/await pattern for HTTP operations -- **Documentation**: Include docstrings for all MCP tools and complex functions - -### CI/CD Process - -The main branch is protected with the following requirements: -- All pull requests must pass CI checks (linting, formatting, Docker build) -- GitHub Actions automatically run on all PRs -- Docker images are published on version tags and main branch pushes +Contributions are welcome! Please: + +1. Fork the repository +2. Create a feature branch: `git checkout -b feat/your-feature` +3. Make changes following the code style (run `uv run ruff format && uv run ruff check --fix`) +4. Submit a pull request ## License @@ -515,4 +313,4 @@ This project is licensed under the GNU Affero General Public License v3.0 (AGPL- ## Support -For issues and feature requests, please use the GitHub issue tracker. \ No newline at end of file +For issues and feature requests, please use the [GitHub issue tracker](https://github.com/RadCod3/LamPyrid/issues).