A Model Context Protocol (MCP) server providing comprehensive tools for interacting with Firefly III personal finance software. LamPyrid enables automated personal finance workflows and analysis through 18 MCP tools with support for account management, transaction operations, and budget management.
- Comprehensive Account Management: List, search, and retrieve account information across all Firefly III account types
- Transaction Operations: Full CRUD operations for transactions with support for withdrawals, deposits, and transfers
- Bulk Operations: Efficient bulk transaction creation and updates for high-volume workflows
- Budget Management: Complete budget analysis with spending tracking, allocation, and summary reporting
- 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
The fastest way to get started is using the published Docker image:
# Pull the latest image
docker pull ghcr.io/radcod3/lampyrid:latest
# 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
# Or use docker-compose
cat > docker-compose.yml <<EOF
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
volumes:
# Persist OAuth tokens if authentication is enabled
- ./data/oauth:/app/data/oauth
restart: unless-stopped
EOF
docker-compose up -dNote on Volume Permissions: If you encounter permission errors like sqlite3.OperationalError: unable to open database file when the container tries to write to the OAuth storage directory, you may need to set the correct ownership:
sudo chown -R 65532:65532 ./data/oauthThis ensures the nonroot user (UID 65532) in the container can write to the mounted volume. This is environment-dependent and may not be needed on all systems.
- Python 3.14+
- uv package manager
- Access to a Firefly III instance with API token
- Clone the repository:
git clone https://github.com/RadCod3/LamPyrid.git
cd LamPyrid- Install dependencies:
uv sync- Configure environment variables:
# Create a .env file or set environment variables
FIREFLY_BASE_URL=https://your-firefly-instance.com
FIREFLY_TOKEN=your-api-token- Run the MCP server:
uv run lampyridLamPyrid uses environment variables for configuration:
FIREFLY_BASE_URL: URL of your Firefly III instanceFIREFLY_TOKEN: Personal access token for API authentication
MCP_TRANSPORT: Transport protocol (stdio/http/sse, default: stdio)MCP_HOST: Host binding for HTTP/SSE transports (default: 0.0.0.0)MCP_PORT: Port binding for HTTP/SSE transports (default: 3000)LOGGING_LEVEL: Logging verbosity (DEBUG/INFO/WARNING/ERROR/CRITICAL, default: INFO)
For remote server deployments requiring authentication, you can enable Google OAuth:
GOOGLE_CLIENT_ID: Google OAuth 2.0 client IDGOOGLE_CLIENT_SECRET: Google OAuth 2.0 client secretSERVER_BASE_URL: Your server's public URL (e.g.,http://localhost:8000)
Note: Authentication is optional and only needed for remote server deployments. All three OAuth variables must be provided together to enable authentication.
By default, OAuth tokens are stored in memory and lost on server restarts. To enable persistent authentication across restarts, configure encrypted token storage:
JWT_SIGNING_KEY: JWT signing key for OAuth tokensOAUTH_STORAGE_ENCRYPTION_KEY: Fernet encryption key for token storageOAUTH_STORAGE_PATH: Storage path (default:~/.local/share/lampyrid/oauthfor local,/app/data/oauthfor Docker)
Generate encryption keys:
# Generate JWT signing key
python -c "import secrets; print(secrets.token_urlsafe(32))"
# Generate Fernet encryption key
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"IMPORTANT: Keep these keys secure and consistent across deployments. Changing keys will invalidate existing tokens and require users to re-authenticate.
Configuration can be provided via a .env file in the project root or as environment variables.
If you need authentication for remote server deployment:
- Go to Google Cloud Console: Visit console.cloud.google.com
- Create or select a project: Choose an existing project or create a new one
- Enable APIs:
- Navigate to "APIs & Services" → "Library"
- Search for and enable "Google+ API"
- Configure OAuth Consent Screen:
- Go to "APIs & Services" → "OAuth consent screen"
- Choose "External" user type (unless you have Google Workspace)
- Fill in required fields: app name, user support email, developer contact
- Add scopes:
openid,email,profile - Save and continue
- Create OAuth 2.0 Credentials:
- Go to "APIs & Services" → "Credentials"
- Click "Create Credentials" → "OAuth client ID"
- Application type: "Web application"
- Name: "LamPyrid MCP Server"
- Add authorized redirect URI:
{SERVER_BASE_URL}/auth/callback- For local development:
http://localhost:8000/auth/callback - For production:
https://your-domain.com/auth/callback
- For local development:
- Click "Create"
- Copy the Client ID and Client Secret
- Configure Environment: Add to your
.envfile:GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=your-client-secret SERVER_BASE_URL=http://localhost:8000
To use LamPyrid with Claude Desktop, add the following configuration to your Claude Desktop MCP settings:
- Install LamPyrid: Ensure LamPyrid is installed and configured with your Firefly III credentials
- Configure Claude Desktop: Add the server configuration to your Claude Desktop settings file
Option 1: Local Installation (stdio mode)
{
"mcpServers": {
"lampyrid": {
"command": "uv",
"args": ["run", "lampyrid"],
"cwd": "/path/to/your/LamPyrid",
"env": {
"FIREFLY_BASE_URL": "https://your-firefly-instance.com",
"FIREFLY_TOKEN": "your-personal-access-token"
}
}
}
}Option 2: Docker Container (HTTP mode)
{
"mcpServers": {
"lampyrid": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-e", "MCP_TRANSPORT=stdio",
"-e", "FIREFLY_BASE_URL=https://your-firefly-instance.com",
"-e", "FIREFLY_TOKEN=your-personal-access-token",
"ghcr.io/radcod3/lampyrid:latest"
]
}
}
}Option 3: HTTP Connection to Running Container If you have LamPyrid running in HTTP mode (e.g., via docker-compose), you can connect directly:
{
"mcpServers": {
"lampyrid": {
"url": "http://localhost:3000"
}
}
}You can also use a .env file in your LamPyrid directory instead of inline environment variables:
# .env file in LamPyrid directory
FIREFLY_BASE_URL=https://your-firefly-instance.com
FIREFLY_TOKEN=your-personal-access-tokenAfter configuration, restart Claude Desktop. LamPyrid tools will be available for account management, transaction operations, and budget analysis.
list_accounts- List accounts by type (asset, expense, revenue, etc.)search_accounts- Search accounts by name with optional type filteringget_account- Get detailed information for a single account
get_transactions- Retrieve transactions with time range and type filteringsearch_transactions- Search transactions by description or text fieldsget_transaction- Get detailed information for a single transactioncreate_withdrawal- Create withdrawal transactions with budget allocationcreate_deposit- Create deposit transactionscreate_transfer- Create transfer transactions between accountscreate_bulk_transactions- Create multiple transactions efficiently in a single operationupdate_transaction- Update existing transaction details (amount, description, accounts, budget, etc.)bulk_update_transactions- Update multiple transactions efficiently in a single operationdelete_transaction- Delete transactions by ID
list_budgets- List all budgets with optional filteringget_budget- Get detailed budget informationget_budget_spending- Analyze spending for specific budgets and periodsget_budget_summary- Comprehensive summary of all budgets with spendingget_available_budget- Check available budget amounts for periods
All tools include comprehensive error handling and return structured data optimized for MCP integration.
# Install dependencies
uv sync
# Format code
uv run ruff format
# Lint code
uv run ruff check --fix
# Build Docker image locally
docker build -t lampyrid:dev .
# Run local development server
uv run lampyridLamPyrid/
├── 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
│ └── 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)
├── .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
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/): Modular MCP tool definitions organized by domainaccounts.py: Account management tools (3 tools)transactions.py: Transaction management tools (10 tools)budgets.py: Budget management tools (5 tools)
- 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 speclampyrid_models.py: Simplified models for MCP tool interfaces
- Configuration (
config.py): Environment-based settings using pydantic-settings
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 - The
tools/__init__.pymodule providescompose_all_servers()to coordinate composition - The
server.pyusesmcp.import_server()to compose all domain servers into the main server - This leverages FastMCP's built-in server composition while keeping modular organization
The architecture enables easy extension and modification while maintaining type safety and comprehensive error handling throughout.
LamPyrid provides production-ready Docker images published to GitHub Container Registry.
- 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
# 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:latestservices:
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
volumes:
# Persist OAuth tokens across container restarts (if OAuth is enabled)
- ./data/oauth:/app/data/oauth
restart: unless-stoppedWhen using Docker with OAuth token persistence, you may encounter permission issues where the container cannot write to the mounted volume at ./data/oauth.
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.
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.
Solution: Set the correct ownership on the host directory before starting the container:
# Create the directory if it doesn't exist
mkdir -p ./data/oauth
# Set ownership to UID 65532 (nonroot user)
sudo chown -R 65532:65532 ./data/oauthNote: 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.
# Build locally
docker build -t lampyrid:custom .
# Build for specific platform
docker buildx build --platform linux/amd64 -t lampyrid:custom .LamPyrid uses GitHub Actions for continuous integration and deployment:
-
CI Workflow: Runs on all pull requests
- Code linting and formatting validation
- Package build verification
- Docker image build test
-
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
-
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
To create a new release:
- Merge all features to main via pull requests
- Create a release branch and update version in
pyproject.toml - Merge the version bump PR
- Create and push a version tag (e.g.,
v0.2.0) - GitHub Actions automatically builds and publishes the release
Contributions are welcome! Please follow this workflow:
- Fork the repository
- Create a feature branch from
main:git checkout -b feat/your-feature-name
- Make your changes following the code style guidelines below
- Test locally:
uv run ruff format uv run ruff check --fix uv run lampyrid # Verify the server starts - Commit your changes with clear, descriptive messages
- Push to your fork and create a pull request
- Indentation: Use tabs 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
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
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
For issues and feature requests, please use the GitHub issue tracker.