agentic-mail-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentic_mail_mcp-0.1.0/.env.example +39 -0
- agentic_mail_mcp-0.1.0/.gitignore +28 -0
- agentic_mail_mcp-0.1.0/CHANGELOG.md +138 -0
- agentic_mail_mcp-0.1.0/LICENSE +21 -0
- agentic_mail_mcp-0.1.0/PKG-INFO +385 -0
- agentic_mail_mcp-0.1.0/README.md +334 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/Composition.py +262 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/DependencyContainer.py +78 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/Lifespan.py +31 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/Logging.py +73 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/Settings.py +127 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/__init__.py +6 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/cli.py +96 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Bootstrap/wiring.py +114 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Audit/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Audit/audit_log.py +26 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Audit/correlation.py +25 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/Events/__init__.py +73 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/Exceptions/__init__.py +26 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/Repository/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/Specifications/__init__.py +56 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/ValueObjects/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/ValueObjects/base.py +28 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/ValueObjects/uuid_id.py +26 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Domain/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Clock/__init__.py +33 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/IdGenerator/__init__.py +17 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/LLM/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Messaging/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Persistence/Migrations/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Persistence/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Persistence/audit_models.py +22 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Persistence/database.py +81 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Persistence/migrations_runner.py +24 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/Persistence/sqlite_audit_repository.py +49 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Infrastructure/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Railguards/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Railguards/config.py +68 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/Railguards/validator.py +103 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Common/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/Commands/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/Commands/commands.py +86 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/DTO/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/DTO/dtos.py +143 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/Handlers/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/Handlers/audit_log_handler.py +62 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/Queries/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/Queries/queries.py +82 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/add_label.py +44 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/archive_email.py +47 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/delete_email.py +50 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/drafts.py +42 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/forward_email.py +49 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/get_email.py +37 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/get_thread.py +19 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/list_labels.py +18 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/list_unread.py +18 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/message_builder.py +43 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/UseCases/search_emails.py +89 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Application/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Entities/__init__.py +3 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Entities/attachment.py +30 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Entities/email.py +106 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Entities/label.py +41 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Entities/thread.py +78 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Events/__init__.py +53 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Gateway/__init__.py +29 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Gateway/gmail_gateway.py +143 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Mapper/__init__.py +4 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Mapper/email_mapper.py +58 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Mapper/thread_mapper.py +22 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Repository/__init__.py +4 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Repository/email_repository.py +23 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/Repository/thread_repository.py +17 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/ValueObjects/__init__.py +13 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/ValueObjects/email_address.py +36 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/ValueObjects/gmail_message_id.py +13 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/ValueObjects/gmail_query.py +57 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/ValueObjects/history_id.py +13 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/ValueObjects/thread_id.py +13 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Domain/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/gmail_api_gateway.py +214 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/gmail_history_synchronizer.py +56 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/gmail_watcher.py +39 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/lazy_gateway.py +114 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/message_parser.py +100 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/oauth_provider.py +125 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/rate_limiter.py +36 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Google/retry.py +41 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/MCP/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/PostgreSQL/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/PostgreSQL/postgres_repositories.py +24 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/Mappers/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/Mappers/orm_mappers.py +145 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/Models/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/Models/models.py +64 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/Repositories/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/Repositories/sqlite_email_repository.py +80 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/Repositories/sqlite_thread_repository.py +44 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/SqlAlchemy/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/Persistence/cached_email_repository.py +130 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/Infrastructure/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Gmail/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/DTO/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/DTO/dtos.py +80 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/UseCases/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/UseCases/classify_email.py +81 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/UseCases/digest.py +114 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/UseCases/extract_action_items.py +67 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/UseCases/suggest_reply.py +64 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/UseCases/summarize_email.py +63 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Application/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Entities/__init__.py +5 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Entities/classification.py +32 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Entities/suggestion.py +23 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Entities/summary.py +18 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Gateway/__init__.py +3 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Gateway/llm_gateway.py +25 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Repository/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/Repository/repositories.py +22 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/ValueObjects/__init__.py +4 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/ValueObjects/model_config.py +20 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/ValueObjects/prompt_template.py +27 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Domain/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Infrastructure/InMemory/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Infrastructure/InMemory/repositories.py +36 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Infrastructure/LlamaCpp/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Infrastructure/LlamaCpp/llama_cpp_gateway.py +128 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/Infrastructure/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Intelligence/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Prompts.py +128 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Resources.py +76 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Server.py +149 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/ToolRegistry.py +132 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/arguments.py +50 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/builder.py +30 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/intelligence_tools.py +162 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/read_tools.py +152 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/search_tools.py +42 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/use_cases.py +79 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/Tools/write_tools.py +166 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/errors.py +45 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/MCP/serialization.py +30 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Application/UseCases/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Application/UseCases/notify_important_email.py +45 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Application/UseCases/publish_inbox_event.py +51 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Application/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Domain/Events/__init__.py +9 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Domain/Events/digest_ready.py +18 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Domain/Events/important_email_detected.py +18 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Domain/Events/inbox_changed.py +11 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Domain/Gateway/__init__.py +3 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Domain/Gateway/notification_gateway.py +6 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Domain/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Infrastructure/RabbitMQ/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Infrastructure/Redis/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Infrastructure/Redis/redis_notification_gateway.py +42 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Infrastructure/Webhook/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Infrastructure/Webhook/webhook_notification_gateway.py +49 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/Infrastructure/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Notification/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Application/UseCases/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Application/UseCases/dtos.py +29 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Application/UseCases/index_email.py +61 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Application/UseCases/rebuild_index.py +24 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Application/UseCases/semantic_search.py +26 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Application/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Domain/Entities/__init__.py +3 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Domain/Entities/search_document.py +48 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Domain/Gateway/__init__.py +3 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Domain/Gateway/embedding_gateway.py +9 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Domain/Repository/__init__.py +3 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Domain/Repository/vector_search_repository.py +31 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Domain/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Infrastructure/BGE/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Infrastructure/BGE/bge_embedding_gateway.py +47 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Infrastructure/PgVector/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Infrastructure/PgVector/pgvector_repository.py +100 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Infrastructure/SqliteVec/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Infrastructure/SqliteVec/sqlite_vec_repository.py +103 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/Infrastructure/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/Search/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/agentic_mail_mcp/__init__.py +0 -0
- agentic_mail_mcp-0.1.0/alembic.ini +40 -0
- agentic_mail_mcp-0.1.0/migrations/env.py +58 -0
- agentic_mail_mcp-0.1.0/migrations/script.py.mako +26 -0
- agentic_mail_mcp-0.1.0/migrations/versions/0001_initial_schema.py +82 -0
- agentic_mail_mcp-0.1.0/migrations/versions/0002_audit_log.py +39 -0
- agentic_mail_mcp-0.1.0/pyproject.toml +137 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0001-shared-primitives.md +21 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0002-ddd-vertical-slicing.md +13 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0003-persistence-strategy.md +13 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0004-railguards-write-safety.md +23 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0005-mcp-stdio-transport.md +13 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0006-caller-first-intelligence.md +19 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0007-persistence-read-through-cache.md +20 -0
- agentic_mail_mcp-0.1.0/specs/docs/adr/0008-bring-your-own-google-app.md +19 -0
- agentic_mail_mcp-0.1.0/specs/docs/api.md +222 -0
- agentic_mail_mcp-0.1.0/specs/docs/architechture.md +240 -0
- agentic_mail_mcp-0.1.0/specs/docs/configuration.md +272 -0
- agentic_mail_mcp-0.1.0/specs/docs/data-model.md +94 -0
- agentic_mail_mcp-0.1.0/specs/docs/domain-model.md +404 -0
- agentic_mail_mcp-0.1.0/specs/docs/events.md +169 -0
- agentic_mail_mcp-0.1.0/specs/docs/implementation_plan.md +607 -0
- agentic_mail_mcp-0.1.0/specs/docs/project.md +97 -0
- agentic_mail_mcp-0.1.0/specs/docs/project_brainstorming.md +18 -0
- agentic_mail_mcp-0.1.0/specs/docs/project_structure.md +254 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Bring your own Google app. Easiest: point at the credentials.json you
|
|
2
|
+
# downloaded from Google Cloud. (Or set the client id/secret below instead.)
|
|
3
|
+
AGENTIC_MAIL_MCP_GMAIL_CLIENT_SECRETS_FILE=
|
|
4
|
+
AGENTIC_MAIL_MCP_GMAIL_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
|
|
5
|
+
AGENTIC_MAIL_MCP_GMAIL_OAUTH_CLIENT_SECRET=your-client-secret
|
|
6
|
+
AGENTIC_MAIL_MCP_GMAIL_SCOPES=["https://www.googleapis.com/auth/gmail.modify"]
|
|
7
|
+
AGENTIC_MAIL_MCP_GMAIL_TOKEN_STORAGE_PATH=token.json
|
|
8
|
+
AGENTIC_MAIL_MCP_GMAIL_TOKEN_ENCRYPTION_KEY=your-encryption-key
|
|
9
|
+
AGENTIC_MAIL_MCP_DATABASE_URL=sqlite:///./agentic_mail_mcp.db
|
|
10
|
+
AGENTIC_MAIL_MCP_DATABASE_DRIVER=sqlite
|
|
11
|
+
# Read-through email cache TTL (metadata only; bodies are never persisted).
|
|
12
|
+
AGENTIC_MAIL_MCP_DATABASE_CACHE_TTL_SECONDS=900
|
|
13
|
+
AGENTIC_MAIL_MCP_RAILGUARDS_ACCESS_LEVEL=read_only
|
|
14
|
+
AGENTIC_MAIL_MCP_RAILGUARDS_ALLOWED_RECIPIENTS=[]
|
|
15
|
+
AGENTIC_MAIL_MCP_RAILGUARDS_BLOCKED_ACTIONS=[]
|
|
16
|
+
AGENTIC_MAIL_MCP_RAILGUARDS_RATE_LIMITS={}
|
|
17
|
+
AGENTIC_MAIL_MCP_RAILGUARDS_ARCHIVE_FIRST_POLICY=false
|
|
18
|
+
AGENTIC_MAIL_MCP_MCP_SERVER_NAME=Agentic-Mail-MCP
|
|
19
|
+
AGENTIC_MAIL_MCP_MCP_TRANSPORT=stdio
|
|
20
|
+
AGENTIC_MAIL_MCP_MCP_HOST=127.0.0.1
|
|
21
|
+
AGENTIC_MAIL_MCP_MCP_PORT=8080
|
|
22
|
+
AGENTIC_MAIL_MCP_LLM_PROVIDER=openai
|
|
23
|
+
AGENTIC_MAIL_MCP_LLM_MODEL=gpt-4
|
|
24
|
+
# LLM is OPTIONAL. The calling agent is itself an LLM, so per-email reasoning is
|
|
25
|
+
# exposed as MCP prompts by default. An LLM key only enables the digest tools
|
|
26
|
+
# (map-reduce over many emails). Leave empty to run without one.
|
|
27
|
+
AGENTIC_MAIL_MCP_LLM_API_KEY=
|
|
28
|
+
AGENTIC_MAIL_MCP_LLM_BASE_URL=
|
|
29
|
+
AGENTIC_MAIL_MCP_LLM_MODEL_PATH=
|
|
30
|
+
# Set true to ALSO expose per-email summarize/classify/reply/action-items as
|
|
31
|
+
# server-side tools (adds latency + needs a configured LLM). Default: caller-first.
|
|
32
|
+
AGENTIC_MAIL_MCP_LLM_INTERNAL_TOOLS=false
|
|
33
|
+
AGENTIC_MAIL_MCP_SEARCH_BACKEND=sqlite_vss
|
|
34
|
+
AGENTIC_MAIL_MCP_SEARCH_EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
|
|
35
|
+
AGENTIC_MAIL_MCP_SEARCH_EMBEDDING_DIMENSION=384
|
|
36
|
+
AGENTIC_MAIL_MCP_NOTIFICATIONS_WEBHOOK_URL=
|
|
37
|
+
AGENTIC_MAIL_MCP_NOTIFICATIONS_REDIS_URL=
|
|
38
|
+
AGENTIC_MAIL_MCP_LOGGING_LEVEL=INFO
|
|
39
|
+
AGENTIC_MAIL_MCP_LOGGING_JSON_FORMAT=true
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Secrets and OAuth credentials โ never commit these
|
|
2
|
+
/token.json
|
|
3
|
+
/credentials.json
|
|
4
|
+
# Default token_storage_path (Settings.gmail.token_storage_path)
|
|
5
|
+
token.json
|
|
6
|
+
# Encrypted token store (Settings.gmail.token_storage_path)
|
|
7
|
+
/.secrets/
|
|
8
|
+
# Build artifacts
|
|
9
|
+
/dist/
|
|
10
|
+
/build/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
# Local persistence, encrypted token store, and downloaded model artifacts
|
|
13
|
+
*.db
|
|
14
|
+
*.sqlite
|
|
15
|
+
*.sqlite3
|
|
16
|
+
/models/
|
|
17
|
+
.config/agentic-mail-mcp/
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.py[codz]
|
|
20
|
+
*$py.class
|
|
21
|
+
.env
|
|
22
|
+
.env*.local
|
|
23
|
+
.env.development
|
|
24
|
+
.env.production
|
|
25
|
+
backend/keys/
|
|
26
|
+
*.pem
|
|
27
|
+
*.log
|
|
28
|
+
/.coverage
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### โ Breaking
|
|
8
|
+
|
|
9
|
+
- **Railguards default is now read-only** (Phase 6): `railguards.access_level` defaults to `read_only` (was `owner`), so all write operations (forward/archive/delete/draft) are denied until a deployment sets `AGENTIC_MAIL_MCP_RAILGUARDS_ACCESS_LEVEL=read_write`.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Environment-variable configuration now works** (Phase 8): the `Settings`
|
|
14
|
+
sub-sections (`gmail`, `database`, `railguards`, `mcp`, `llm`, `search`,
|
|
15
|
+
`notifications`, `logging`) previously ignored their `AGENTIC_MAIL_MCP_<SECTION>_<FIELD>`
|
|
16
|
+
environment variables and always used defaults. Each section now carries its
|
|
17
|
+
own env prefix, so documented variables such as
|
|
18
|
+
`AGENTIC_MAIL_MCP_RAILGUARDS_ACCESS_LEVEL`, `AGENTIC_MAIL_MCP_MCP_TRANSPORT`, and
|
|
19
|
+
`AGENTIC_MAIL_MCP_DATABASE_URL` take effect โ required for pip/Docker deployments to
|
|
20
|
+
be configurable.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **Caller-first intelligence** ([ADR 0006](specs/docs/adr/0006-caller-first-intelligence.md)):
|
|
25
|
+
the calling agent is itself an LLM, so per-email reasoning (summarize, classify,
|
|
26
|
+
draft reply, extract action items) is now exposed as **MCP prompts** the agent
|
|
27
|
+
runs โ no server-side inference, no added latency, and **no LLM key required**
|
|
28
|
+
for the core experience. Internal LLM inference is reserved for the digest tools
|
|
29
|
+
(map-reduce over many emails), which register only when an LLM is configured;
|
|
30
|
+
set `AGENTIC_MAIL_MCP_LLM_INTERNAL_TOOLS=true` to also expose the per-email tools
|
|
31
|
+
server-side. Embeddings for semantic search remain internal.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- **Live write-path smoke test** (`tests/e2e/test_live_write_path.py`, opt-in via
|
|
36
|
+
`AGENTIC_MAIL_MCP_LIVE_WRITE_E2E=1`). Self-contained and safe: it creates its own
|
|
37
|
+
throwaway message and exercises `create_draft` โ `send_draft` โ `add_label` โ
|
|
38
|
+
`forward_email` (to self) โ `archive_email` โ `delete_email`, then trashes its
|
|
39
|
+
own artifacts. Verified green against a real account. Documented finding:
|
|
40
|
+
permanent delete needs the `https://mail.google.com/` scope (soft delete works
|
|
41
|
+
under `gmail.modify`); `add_label` uses Gmail label **ids** (system labels like
|
|
42
|
+
`STARRED`), not arbitrary user-label names.
|
|
43
|
+
- **Bring-your-own Google app** ([ADR 0008](specs/docs/adr/0008-bring-your-own-google-app.md)).
|
|
44
|
+
The server is a local, bring-your-own-credentials tool โ no central app, no
|
|
45
|
+
Google verification. Point `AGENTIC_MAIL_MCP_GMAIL_CLIENT_SECRETS_FILE` at the
|
|
46
|
+
`credentials.json` you download from your own Google Cloud project (or set the
|
|
47
|
+
client id/secret directly); credentials and token stay on your machine. Docs
|
|
48
|
+
now cover the full self-service Google setup, the unverified-app screen, and
|
|
49
|
+
avoiding the 7-day testing-token expiry.
|
|
50
|
+
- **Persistence: read-through cache** ([ADR 0007](specs/docs/adr/0007-persistence-read-through-cache.md)).
|
|
51
|
+
Gmail is the source of truth; local persistence is a `CachedEmailRepository`, not
|
|
52
|
+
a mirror: single-email reads are live (fresh, full body), the SQLite cache stores
|
|
53
|
+
**metadata only โ never bodies**, list views are served within a TTL
|
|
54
|
+
(`AGENTIC_MAIL_MCP_DATABASE_CACHE_TTL_SECONDS`, default 900s), and emails gone from the
|
|
55
|
+
server are evicted (no sync engine, no delete-propagation). Tools now identify an
|
|
56
|
+
email by its Gmail **`message_id`** end to end (write commands carry `message_id`;
|
|
57
|
+
the internal UUID is an implementation detail). The Gmailโdomain mapper extracts
|
|
58
|
+
bare addresses from display-name headers (`"Name <a@b.com>"`) instead of failing.
|
|
59
|
+
- **Runtime composition root + auth** (makes the server usable end to end)
|
|
60
|
+
- `agentic_mail_mcp/Bootstrap/Composition.py` assembles every use case from `Settings` โ
|
|
61
|
+
SQLite persistence (schema applied via Alembic), a lazy OAuth-backed Gmail
|
|
62
|
+
gateway, railguard validator, event bus, LLM gateway, and optional semantic
|
|
63
|
+
search โ into the `McpUseCases` bundle the server registers. The launched
|
|
64
|
+
`agentic-mail-mcp` now exposes its tools (previously zero).
|
|
65
|
+
- `LazyGmailGateway` builds the authenticated Gmail client on first use, so
|
|
66
|
+
tools register at startup and calls before authorization return a clear
|
|
67
|
+
"run `agentic-mail-mcp auth`" error.
|
|
68
|
+
- `agentic-mail-mcp auth` subcommand performs the one-time interactive Google
|
|
69
|
+
authorization and stores the encrypted token (`make auth`).
|
|
70
|
+
- Semantic search degrades gracefully: `semantic_search` is registered only
|
|
71
|
+
when the `search` extra (sentence-transformers + sqlite-vec) is installed.
|
|
72
|
+
- **Distribution and polish** (Phase 8)
|
|
73
|
+
- `LICENSE` (MIT); `pyproject.toml` distribution metadata (`readme`,
|
|
74
|
+
`project.urls`, `license-files`) and a scoped sdist target producing a clean
|
|
75
|
+
source distribution + wheel with the `agentic-mail-mcp` entry point
|
|
76
|
+
- `specs/docs/api.md` โ the MCP tool/resource/prompt reference with input
|
|
77
|
+
schemas, output shapes, and the structured error format
|
|
78
|
+
- Architecture ADRs `0002`โ`0005` (DDD + vertical slicing, SQLite/PostgreSQL
|
|
79
|
+
persistence, railguards write-safety, MCP stdio transport)
|
|
80
|
+
- Expanded `README.md` (tool catalog, railguards security model, stdio
|
|
81
|
+
integration example, contributing, and the automated PyPI release flow)
|
|
82
|
+
- Multi-stage `Dockerfile` (builder + slim non-root runtime, health check),
|
|
83
|
+
multi-arch build support
|
|
84
|
+
- End-to-end MCP session tests (`tests/e2e/`) covering the read/write tool
|
|
85
|
+
flow, railguard enforcement, and a container health-check smoke test
|
|
86
|
+
- Removed the superseded pre-DDD `main.py` / `server.py` skeletons from the
|
|
87
|
+
repo root (replaced by `agentic_mail_mcp/MCP/Server.py` and `agentic_mail_mcp/Bootstrap/cli.py`)
|
|
88
|
+
|
|
89
|
+
- **MCP server layer** (Phase 7)
|
|
90
|
+
- `create_server` bootstrap that assembles the server from the dependency container and integrates the application lifespan; configurable transport (`stdio` default, streamable HTTP) via `Settings.mcp.transport`; the `agentic-mail-mcp` console entry point launches it
|
|
91
|
+
- `ToolRegistry` with category-grouped tools (read/write/intelligence/search) and JSON-Schema input schemas; **defense-in-depth**: write-category tools are not registered when `railguards.access_level` is `read_only`, so they are never exposed to the agent
|
|
92
|
+
- Read tools: `search_emails`, `get_email`, `get_thread`, `list_unread`, `list_labels`
|
|
93
|
+
- Write tools (railguarded): `forward_email`, `archive_email`, `delete_email`, `create_draft`, `send_draft`, `add_label`
|
|
94
|
+
- Intelligence tools: `summarize_email`, `classify_email`, `suggest_reply`, `extract_action_items`, `daily_digest`, `weekly_digest`
|
|
95
|
+
- Search tool: `semantic_search`
|
|
96
|
+
- MCP resources (account info, watch status, index status) and prompts (search strategy, email management); structured tool-error mapping for railguard denials, missing entities, and invalid input
|
|
97
|
+
- `AddLabelUseCase` (railguarded) emitting `EmailLabeled`; digest use cases accept an optional date anchor
|
|
98
|
+
- `Settings.mcp.transport` (`stdio` default)
|
|
99
|
+
- **Railguards framework** (Phase 6)
|
|
100
|
+
- `RailguardConfig` (access level, recipient allowlist with address/domain matching, action blocklist, windowed rate limits, archive-first policy) and `RailguardValidator` raising `PermissionError` on violation
|
|
101
|
+
- `audit_log` table, `AuditLogRepository` (SQLite), and `AuditLogHandler` event subscriber recording every write with a correlation id
|
|
102
|
+
- Railguarded write use cases: `ForwardEmailUseCase`, `ArchiveEmailUseCase`, `DeleteEmailUseCase` (soft-delete default, archive-first for permanent), `CreateDraftUseCase` / `SendDraftUseCase` (draft-first sending)
|
|
103
|
+
- `GmailGateway` draft operations (`create_draft`/`send_draft`/`delete_draft`) and their `GmailApiGateway` implementation
|
|
104
|
+
- `Settings.railguards.archive_first_policy`; Alembic migration `0002`
|
|
105
|
+
- **Shared domain primitives** (Phase 2)
|
|
106
|
+
- `ValueObject` base class with structural equality, hashing, and repr
|
|
107
|
+
- `UUIDId` value object wrapping `uuid.UUID` with `generate()` factory
|
|
108
|
+
- Typed exception hierarchy: `DomainError`, `ValidationError`, `NotFoundError`, `PermissionError`, `ConcurrencyError`
|
|
109
|
+
- `EventBus` protocol and `InMemoryEventBus` implementation
|
|
110
|
+
- `Specification[T]` pattern with `And`, `Or`, `Not` composables
|
|
111
|
+
- `Clock` protocol with `SystemClock` and `FrozenClock` implementations
|
|
112
|
+
- `IdGenerator` protocol with `UuidIdGenerator` implementation
|
|
113
|
+
- Exhaustive unit test coverage for all shared primitives
|
|
114
|
+
- **Domain models for all bounded contexts** (Phase 3)
|
|
115
|
+
- Gmail: `Email`, `Thread`, `Attachment`, `Label` aggregates; `EmailAddress`, `GmailMessageId`, `ThreadId`, `HistoryId`, `GmailQuery` value objects; repository and `GmailGateway` ports; mappers; domain events
|
|
116
|
+
- Intelligence: `Summary`, `Classification`, `Suggestion` entities; `PromptTemplate`, `ModelConfig` value objects; `LlmGateway` port
|
|
117
|
+
- Search: `SearchDocument` entity; `EmbeddingGateway` and `VectorSearchRepository` ports
|
|
118
|
+
- Notification: `ImportantEmailDetected`, `InboxChanged`, `DigestReady` events; `NotificationGateway` port
|
|
119
|
+
- **Application use cases** (Phase 4)
|
|
120
|
+
- Gmail read use cases: `SearchEmailsUseCase`, `GetEmailUseCase`, `GetThreadUseCase`, `ListUnreadUseCase`, `ListLabelsUseCase`; query/command objects and read DTOs
|
|
121
|
+
- Intelligence use cases: `SummarizeEmailUseCase`, `SuggestReplyUseCase`, `ClassifyEmailUseCase`, `DailyDigestUseCase`, `WeeklyDigestUseCase`, `ExtractActionItemsUseCase`
|
|
122
|
+
- Search use cases: `SemanticSearchUseCase`, `IndexEmailUseCase`, `RebuildIndexUseCase`
|
|
123
|
+
- Notification use cases: `NotifyImportantEmailUseCase`, `PublishInboxEventUseCase` (domain-event subscribers)
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
|
|
127
|
+
- `EventBus` is now generic over concrete event types: handlers are registered and dispatched by the event's exact type, so domain events are no longer required to inherit `DomainEvent` (it remains an optional base for standard metadata).
|
|
128
|
+
- **Database default is now a synchronous SQLite driver** (`sqlite:///โฆ`) to match the synchronous repository ports (Phase 5). Set `AGENTIC_MAIL_MCP_DATABASE_URL` to a `postgresql+psycopg2://โฆ` URL for PostgreSQL.
|
|
129
|
+
|
|
130
|
+
### Added (Phase 5 โ Infrastructure Adapters)
|
|
131
|
+
|
|
132
|
+
- **Persistence**: synchronous SQLAlchemy engine/session wiring with a UTC-normalizing datetime type; ORM models and domainโORM mappers for Email/Thread/Attachment/Label; `SqliteEmailRepository` / `SqliteThreadRepository`; initial Alembic migration (`alembic.ini` + `migrations/`); PostgreSQL repository variants sharing the schema.
|
|
133
|
+
- **Gmail Google adapter**: `GmailOAuthProvider` (Fernet-encrypted token storage), `GmailApiGateway` (Gmail API with retry/backoff and rate limiting), `GmailWatcher` (push notifications + webhook parsing), `GmailHistorySynchronizer` (idempotent history sync emitting domain events).
|
|
134
|
+
- **Intelligence**: `LlamaCppGateway` implementing `LlmGateway` over an OpenAI-compatible endpoint or a local llama.cpp model.
|
|
135
|
+
- **Search**: `BgeEmbeddingGateway` (`EmbeddingGateway`); `SqliteVecRepository` (default) and `PgVectorRepository` (optional) implementing `VectorSearchRepository`, verified interchangeable by a shared contract test.
|
|
136
|
+
- **Notification**: `WebhookNotificationGateway` and `RedisNotificationGateway` implementing `NotificationGateway`.
|
|
137
|
+
- **Wiring**: `register_infrastructure()` binds the default adapter stack on the DI container.
|
|
138
|
+
- New Settings keys (`llm.base_url`, `llm.model_path`, `search.*`) and optional dependency extras (`postgresql`, `search`, `notifications`, `llm`); see `specs/docs/configuration.md` and `specs/docs/data-model.md`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Agentic Mail MCP Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentic-mail-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Model Context Protocol (MCP) server exposing Gmail operations for AI agents
|
|
5
|
+
Project-URL: Homepage, https://github.com/CoolDevGuys/agentic-mail-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/CoolDevGuys/agentic-mail-mcp
|
|
7
|
+
Project-URL: Documentation, https://github.com/CoolDevGuys/agentic-mail-mcp/tree/main/specs/docs
|
|
8
|
+
Project-URL: Changelog, https://github.com/CoolDevGuys/agentic-mail-mcp/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Agentic Mail MCP Team
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Requires-Dist: alembic
|
|
19
|
+
Requires-Dist: cryptography
|
|
20
|
+
Requires-Dist: google-api-python-client
|
|
21
|
+
Requires-Dist: google-auth-oauthlib
|
|
22
|
+
Requires-Dist: httpx
|
|
23
|
+
Requires-Dist: mcp
|
|
24
|
+
Requires-Dist: pydantic
|
|
25
|
+
Requires-Dist: pydantic-settings
|
|
26
|
+
Requires-Dist: python-dotenv
|
|
27
|
+
Requires-Dist: sqlalchemy
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: build; extra == 'dev'
|
|
30
|
+
Requires-Dist: fakeredis; extra == 'dev'
|
|
31
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-httpserver; extra == 'dev'
|
|
36
|
+
Requires-Dist: respx; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff==0.16.1; extra == 'dev'
|
|
38
|
+
Requires-Dist: setuptools>=83.0.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: twine; extra == 'dev'
|
|
40
|
+
Provides-Extra: llm
|
|
41
|
+
Requires-Dist: llama-cpp-python; extra == 'llm'
|
|
42
|
+
Provides-Extra: notifications
|
|
43
|
+
Requires-Dist: redis; extra == 'notifications'
|
|
44
|
+
Provides-Extra: postgresql
|
|
45
|
+
Requires-Dist: pgvector; extra == 'postgresql'
|
|
46
|
+
Requires-Dist: psycopg2-binary; extra == 'postgresql'
|
|
47
|
+
Provides-Extra: search
|
|
48
|
+
Requires-Dist: sentence-transformers; extra == 'search'
|
|
49
|
+
Requires-Dist: sqlite-vec; extra == 'search'
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
|
|
52
|
+
# ๐ง Agentic Mail MCP
|
|
53
|
+
|
|
54
|
+
> A [Model Context Protocol](https://modelcontextprotocol.io) server that lets AI
|
|
55
|
+
> agents work with a Gmail account **safely** โ read, search, summarize, and
|
|
56
|
+
> (opt-in) forward/archive/label โ behind a layered safety model.
|
|
57
|
+
|
|
58
|
+
> **๐ You bring your own Google app.** This is a **local tool, not a hosted
|
|
59
|
+
> service** โ you create your own OAuth client in your own Google Cloud project
|
|
60
|
+
> and authorize your own mailbox. Your credentials and token never leave your
|
|
61
|
+
> machine, and because the app only ever authorizes you, **there's no central
|
|
62
|
+
> service and no Google verification to wait for.**
|
|
63
|
+
|
|
64
|
+
> **โน๏ธ Status:** pre-release (`0.1.0`), fully functional locally. Not yet on PyPI โ
|
|
65
|
+
> install from source (below).
|
|
66
|
+
|
|
67
|
+
## โจ Features
|
|
68
|
+
|
|
69
|
+
| | |
|
|
70
|
+
|---|---|
|
|
71
|
+
| ๐ฅ **Email operations** | Search, read, forward, archive, delete, draft, and label |
|
|
72
|
+
| ๐ง **Intelligence** | Caller-first prompts (summarize, classify, reply, action items) + optional server-side digests |
|
|
73
|
+
| ๐ **Semantic search** | Natural-language vector search over your mail |
|
|
74
|
+
| ๐ **Notifications** | Webhook / Redis event fan-out |
|
|
75
|
+
| ๐ก๏ธ **Railguards** | Read-only by default, allowlists, rate limits, archive-first delete, draft-first send, audit log |
|
|
76
|
+
|
|
77
|
+
## ๐ Quick start
|
|
78
|
+
|
|
79
|
+
You need **Python 3.11+** and a Google account. Five minutes end to end.
|
|
80
|
+
|
|
81
|
+
```mermaid
|
|
82
|
+
flowchart LR
|
|
83
|
+
A[1. Install] --> B[2. Google<br/>credentials]
|
|
84
|
+
B --> C[3. Configure<br/>.env]
|
|
85
|
+
C --> D[4. Authorize<br/>agentic-mail-mcp auth]
|
|
86
|
+
D --> E[5. Connect agent<br/>or run HTTP]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**1. Install** (from source until published โ see [Installation](#-installation)):
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pip install "git+https://github.com/CoolDevGuys/agentic-mail-mcp.git"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**2. Get Google credentials** โ in *your* Google Cloud project, enable the Gmail
|
|
96
|
+
API, make a **Desktop-app OAuth client**, and **download its `credentials.json`**.
|
|
97
|
+
Full walkthrough with the exact clicks:
|
|
98
|
+
[Getting your Google credentials ๐](specs/docs/configuration.md#getting-your-google-credentials-oauth).
|
|
99
|
+
|
|
100
|
+
**3. Configure** โ copy `.env.example` to `.env` and point at your downloaded file:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Easiest: just point at the credentials.json you downloaded.
|
|
104
|
+
AGENTIC_MAIL_MCP_GMAIL_CLIENT_SECRETS_FILE=/path/to/credentials.json
|
|
105
|
+
AGENTIC_MAIL_MCP_GMAIL_TOKEN_ENCRYPTION_KEY=<any long random string>
|
|
106
|
+
# ๐ Writes are denied by default. Keep read_only until you trust the setup.
|
|
107
|
+
AGENTIC_MAIL_MCP_RAILGUARDS_ACCESS_LEVEL=read_only
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**4. Authorize** (one-time browser consent โ stores an encrypted token):
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
agentic-mail-mcp auth
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**5. Use it** โ connect an AI agent over **stdio** or run the **HTTP** server.
|
|
117
|
+
See [Usage](#-usage).
|
|
118
|
+
|
|
119
|
+
## โ
Requirements
|
|
120
|
+
|
|
121
|
+
- ๐ Python 3.11+
|
|
122
|
+
- ๐ Your own Google OAuth **`credentials.json`** (a Desktop-app client from your
|
|
123
|
+
Google Cloud project โ [how to get it](specs/docs/configuration.md#getting-your-google-credentials-oauth))
|
|
124
|
+
- ๐ค *(optional)* an LLM API key for the digest tools (OpenAI-compatible by default)
|
|
125
|
+
|
|
126
|
+
## ๐ฆ Installation
|
|
127
|
+
|
|
128
|
+
**From source (works today):**
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
pip install "git+https://github.com/CoolDevGuys/agentic-mail-mcp.git"
|
|
132
|
+
# or, from a clone:
|
|
133
|
+
pip install .
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Optional extras** (combine as needed, e.g. `".[postgresql,search]"`):
|
|
137
|
+
|
|
138
|
+
| Extra | Adds |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `postgresql` | PostgreSQL + pgvector backends |
|
|
141
|
+
| `search` | local embeddings + sqlite-vec semantic search |
|
|
142
|
+
| `notifications` | Redis pub/sub notifications |
|
|
143
|
+
| `llm` | local llama.cpp inference |
|
|
144
|
+
| `dev` | test / lint / build tooling |
|
|
145
|
+
|
|
146
|
+
**Docker:** `docker compose up --build` (see [HTTP server](#http-server-deployment)).
|
|
147
|
+
|
|
148
|
+
> ๐ก Once published to PyPI, the recommended install for MCP clients will be
|
|
149
|
+
> `uvx agentic-mail-mcp` / `pipx run agentic-mail-mcp` โ no virtualenv to manage.
|
|
150
|
+
|
|
151
|
+
## โ๏ธ Configuration
|
|
152
|
+
|
|
153
|
+
Set environment variables with the `AGENTIC_MAIL_MCP_` prefix, or use a `.env` file
|
|
154
|
+
(copy `.env.example`). The table below covers the essentials; **every** setting,
|
|
155
|
+
with defaults and purpose โ and the **Google OAuth walkthrough** โ is in
|
|
156
|
+
[`specs/docs/configuration.md`](specs/docs/configuration.md).
|
|
157
|
+
|
|
158
|
+
| Variable | Description | Default |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| `AGENTIC_MAIL_MCP_GMAIL_CLIENT_SECRETS_FILE` | Path to your downloaded `credentials.json` (recommended) | (one of these two) |
|
|
161
|
+
| `AGENTIC_MAIL_MCP_GMAIL_OAUTH_CLIENT_ID` / `_SECRET` | โฆor the OAuth client id/secret directly | (one of these two) |
|
|
162
|
+
| `AGENTIC_MAIL_MCP_GMAIL_TOKEN_ENCRYPTION_KEY` | Secret used to encrypt the stored token | (required to store tokens) |
|
|
163
|
+
| `AGENTIC_MAIL_MCP_GMAIL_TOKEN_STORAGE_PATH` | Encrypted token file path (set outside the repo in prod) | `token.json` |
|
|
164
|
+
| `AGENTIC_MAIL_MCP_DATABASE_URL` | SQLAlchemy URL (synchronous driver) | `sqlite:///./agentic_mail_mcp.db` |
|
|
165
|
+
| `AGENTIC_MAIL_MCP_RAILGUARDS_ACCESS_LEVEL` | `read_only` or `read_write` โ **writes denied by default** | `read_only` |
|
|
166
|
+
| `AGENTIC_MAIL_MCP_LLM_PROVIDER` | `openai` (HTTP) or `llamacpp` (local) | `openai` |
|
|
167
|
+
| `AGENTIC_MAIL_MCP_LLM_API_KEY` | LLM API key | (required for intelligence) |
|
|
168
|
+
| `AGENTIC_MAIL_MCP_MCP_TRANSPORT` | `stdio` (default) or `http` | `stdio` |
|
|
169
|
+
| `AGENTIC_MAIL_MCP_MCP_HOST` / `AGENTIC_MAIL_MCP_MCP_PORT` | HTTP transport bind address | `127.0.0.1` / `8080` |
|
|
170
|
+
|
|
171
|
+
## ๐ Usage
|
|
172
|
+
|
|
173
|
+
The server speaks MCP over two transports:
|
|
174
|
+
|
|
175
|
+
| Transport | Best for | How |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| **stdio** (default) | one user on a laptop (Claude Desktop, IDE agents) | agent launches the process |
|
|
178
|
+
| **HTTP** (streamable) | shared / containerized deployments | long-running server on a port |
|
|
179
|
+
|
|
180
|
+
> โ ๏ธ **Authorize first.** Run `agentic-mail-mcp auth` once (browser consent) before
|
|
181
|
+
> starting the server โ it stores the encrypted token the server reads on every
|
|
182
|
+
> start. Details:
|
|
183
|
+
> [Authorize](specs/docs/configuration.md#6-authorize-one-time-consent).
|
|
184
|
+
>
|
|
185
|
+
> **Headless server (no browser)?** `auth` needs a browser + loopback redirect,
|
|
186
|
+
> so you don't run it on the server. Authorize once on a machine that has a
|
|
187
|
+
> browser, then copy the encrypted token file across โ see
|
|
188
|
+
> [Headless / server deployment](specs/docs/configuration.md#7-headless--server-deployment-no-browser).
|
|
189
|
+
|
|
190
|
+
### ๐ป Local (stdio) โ connect an AI agent
|
|
191
|
+
|
|
192
|
+
Point your MCP client at the `agentic-mail-mcp` command. Example client config:
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"mcpServers": {
|
|
197
|
+
"gmail": {
|
|
198
|
+
"command": "agentic-mail-mcp",
|
|
199
|
+
"env": {
|
|
200
|
+
"AGENTIC_MAIL_MCP_GMAIL_OAUTH_CLIENT_ID": "...",
|
|
201
|
+
"AGENTIC_MAIL_MCP_GMAIL_OAUTH_CLIENT_SECRET": "...",
|
|
202
|
+
"AGENTIC_MAIL_MCP_GMAIL_TOKEN_ENCRYPTION_KEY": "...",
|
|
203
|
+
"AGENTIC_MAIL_MCP_RAILGUARDS_ACCESS_LEVEL": "read_only"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The agent then discovers the tools, resources, and prompts described in the
|
|
211
|
+
[MCP API reference](specs/docs/api.md). Start with `read_only` and enable
|
|
212
|
+
`read_write` deliberately once you understand the [railguards](#railguards-security-model).
|
|
213
|
+
|
|
214
|
+
### HTTP server (deployment)
|
|
215
|
+
|
|
216
|
+
Run a standalone streamable-HTTP server:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
AGENTIC_MAIL_MCP_MCP_TRANSPORT=http AGENTIC_MAIL_MCP_MCP_HOST=0.0.0.0 AGENTIC_MAIL_MCP_MCP_PORT=8080 \
|
|
220
|
+
agentic-mail-mcp
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Or with Docker (the compose file already sets HTTP transport and a health check):
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
docker compose up --build # server on http://localhost:8080
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
> ๐ **Auth on a headless host:** authorize on your laptop and mount the
|
|
230
|
+
> encrypted token into the container (e.g. `-v /etc/agentic-mail-mcp:/secrets:ro`)
|
|
231
|
+
> โ full steps under
|
|
232
|
+
> [Headless / server deployment](specs/docs/configuration.md#7-headless--server-deployment-no-browser).
|
|
233
|
+
|
|
234
|
+
Point an HTTP-capable MCP client at `http://<host>:8080`. Keep the server behind
|
|
235
|
+
your own auth/TLS if it's reachable beyond localhost.
|
|
236
|
+
|
|
237
|
+
## ๐งฐ MCP Tools
|
|
238
|
+
|
|
239
|
+
Full input/output schemas, resources, prompts, and error formats are in the
|
|
240
|
+
[MCP API reference](specs/docs/api.md).
|
|
241
|
+
|
|
242
|
+
### Read Tools (always available)
|
|
243
|
+
|
|
244
|
+
- `search_emails` โ Search emails by subject, sender, recipient, date range, labels, attachments, unread status
|
|
245
|
+
- `get_email` โ Read a specific email by ID
|
|
246
|
+
- `get_thread` โ Read a conversation thread
|
|
247
|
+
- `list_unread` โ List unread emails
|
|
248
|
+
- `list_labels` โ List labels (system, user, or all)
|
|
249
|
+
|
|
250
|
+
### Write Tools (require `read_write` access)
|
|
251
|
+
|
|
252
|
+
- `forward_email` โ Forward an email (recipient allowlist enforced)
|
|
253
|
+
- `archive_email` โ Archive an email or thread
|
|
254
|
+
- `delete_email` โ Delete an email (trash by default, archive-first policy)
|
|
255
|
+
- `create_draft` โ Create a draft for review
|
|
256
|
+
- `send_draft` โ Send a reviewed draft
|
|
257
|
+
- `add_label` โ Add a label to an email
|
|
258
|
+
|
|
259
|
+
### Intelligence โ caller-first ๐ง
|
|
260
|
+
|
|
261
|
+
The calling agent is itself an LLM, so per-email reasoning ships as **MCP prompts**
|
|
262
|
+
the agent runs on data it fetches with `get_email` โ **no server-side inference,
|
|
263
|
+
no added latency, no LLM key required**:
|
|
264
|
+
|
|
265
|
+
- prompts: `summarize_email` ยท `classify_email` ยท `draft_reply` ยท `extract_action_items`
|
|
266
|
+
|
|
267
|
+
Internal LLM inference is reserved for where it pays off (map-reduce over many
|
|
268
|
+
emails), and registers **only when an LLM is configured**:
|
|
269
|
+
|
|
270
|
+
- tools: `daily_digest` ยท `weekly_digest`
|
|
271
|
+
- *(opt-in)* set `AGENTIC_MAIL_MCP_LLM_INTERNAL_TOOLS=true` to also expose the per-email
|
|
272
|
+
ones as server-side tools. See [ADR 0006](specs/docs/adr/0006-caller-first-intelligence.md).
|
|
273
|
+
|
|
274
|
+
### Search Tools
|
|
275
|
+
|
|
276
|
+
- `semantic_search` โ natural-language vector search *(needs the `search` extra)*
|
|
277
|
+
|
|
278
|
+
## Project Structure
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
agentic_mail_mcp/
|
|
282
|
+
Bootstrap/ CLI, Settings, Logging, Lifespan, DI Container
|
|
283
|
+
Common/ Shared domain primitives
|
|
284
|
+
Gmail/ Gmail bounded context
|
|
285
|
+
Intelligence/ LLM-powered email analysis
|
|
286
|
+
Search/ Semantic/vector search
|
|
287
|
+
Notification/ Event notifications
|
|
288
|
+
MCP/ MCP server, tools, resources, prompts
|
|
289
|
+
tests/
|
|
290
|
+
unit/ Unit tests
|
|
291
|
+
integration/ Integration tests
|
|
292
|
+
fakes/ Test doubles
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Railguards (security model)
|
|
296
|
+
|
|
297
|
+
Writes are **denied by default**. Safety is layered so an AI agent cannot mutate
|
|
298
|
+
a mailbox unless a human deliberately enables it:
|
|
299
|
+
|
|
300
|
+
- **Access level** โ `read_only` (default) or `read_write`. The master switch.
|
|
301
|
+
Under `read_only`, write tools are **not even registered** with the MCP server
|
|
302
|
+
(defense in depth), so the agent never sees them โ not merely blocked at call
|
|
303
|
+
time.
|
|
304
|
+
- **Recipient allowlist** โ forwarding is restricted to configured addresses or
|
|
305
|
+
domains (`@example.com`).
|
|
306
|
+
- **Rate limits** โ per-action caps within a trailing 1-hour window
|
|
307
|
+
(e.g. `{"forward": 50}`).
|
|
308
|
+
- **Archive-first policy** โ an email must be archived before it can be
|
|
309
|
+
permanently deleted; deletes are soft (Trash) by default.
|
|
310
|
+
- **Draft-first sending** โ the agent creates a draft for human review;
|
|
311
|
+
`send_draft` is a separate, explicit step.
|
|
312
|
+
- **Audit log** โ every write is recorded (action, email id, correlation id).
|
|
313
|
+
|
|
314
|
+
A railguard denial surfaces to the agent as a structured `permission_denied`
|
|
315
|
+
error, never as an unhandled exception. See the
|
|
316
|
+
[railguards configuration](specs/docs/configuration.md#railguards) and
|
|
317
|
+
[ADR 0004](specs/docs/adr/0004-railguards-write-safety.md).
|
|
318
|
+
|
|
319
|
+
## Development
|
|
320
|
+
|
|
321
|
+
A `Makefile` wraps the common tasks (run `make` to list them):
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
make setup # first-time: create .venv, install dev deps, .env, run migrations
|
|
325
|
+
make auth # one-time Google authorization (browser consent)
|
|
326
|
+
make run # start the server (stdio); make run-http for HTTP transport
|
|
327
|
+
make test # full test suite with coverage gates (as CI runs)
|
|
328
|
+
make check # lint (ruff) + type-check (mypy) + tests
|
|
329
|
+
make format # auto-format and fix imports
|
|
330
|
+
make migrate # apply DB migrations; make migration m="..." to autogenerate
|
|
331
|
+
make build # build the sdist + wheel and validate metadata
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Prefer raw tools? They work too: `pytest`, `ruff check agentic_mail_mcp tests`, `mypy agentic_mail_mcp`,
|
|
335
|
+
`alembic upgrade head`. All `make` targets run inside a local `.venv`.
|
|
336
|
+
|
|
337
|
+
## Contributing
|
|
338
|
+
|
|
339
|
+
- The architecture (DDD + vertical slicing) and key decisions are recorded as
|
|
340
|
+
[ADRs](specs/docs/adr/); read them before adding a bounded context or changing
|
|
341
|
+
a boundary.
|
|
342
|
+
- Changes follow the OpenSpec workflow under `openspec/` โ propose a change,
|
|
343
|
+
generate its spec deltas, implement, then archive.
|
|
344
|
+
- Keep the tiered coverage floors green (โฅ90% on `Domain/`, โฅ80% overall) and
|
|
345
|
+
ensure `ruff check` and `mypy agentic_mail_mcp/` pass before opening a PR.
|
|
346
|
+
|
|
347
|
+
## ๐ค Distribution
|
|
348
|
+
|
|
349
|
+
The recommended distribution is a **PyPI package launched via `uvx` / `pipx`**,
|
|
350
|
+
not a compiled binary. MCP clients already know how to run
|
|
351
|
+
`command: "uvx"` / `"pipx run"`, so users get a one-line config with no
|
|
352
|
+
virtualenv to manage, and Python-native OAuth/optional-dependency handling stays
|
|
353
|
+
simple. A single-file binary would fight the OAuth browser flow and the optional
|
|
354
|
+
native extras (llama.cpp, sentence-transformers, sqlite-vec) for little gain. The
|
|
355
|
+
**Docker image** covers HTTP/server deployments.
|
|
356
|
+
|
|
357
|
+
### Releasing (maintainers)
|
|
358
|
+
|
|
359
|
+
Releases are **fully automated** by the `publish` job in
|
|
360
|
+
[`.github/workflows/ci.yml`](.github/workflows/ci.yml). Publishing a GitHub
|
|
361
|
+
Release is the entire flow โ it builds the sdist + wheel and uploads them to
|
|
362
|
+
PyPI via **Trusted Publishing (OIDC)**, so no API token is stored in the repo.
|
|
363
|
+
|
|
364
|
+
**One-time PyPI setup** (per project, done once in the PyPI web UI):
|
|
365
|
+
|
|
366
|
+
1. On [PyPI](https://pypi.org/manage/account/publishing/) โ *Publishing* โ add a
|
|
367
|
+
**pending trusted publisher** with:
|
|
368
|
+
- **PyPI Project Name**: `agentic-mail-mcp`
|
|
369
|
+
- **Owner**: your GitHub org/user ยท **Repository**: this repo
|
|
370
|
+
- **Workflow name**: `ci.yml` ยท **Environment name**: `pypi`
|
|
371
|
+
2. In GitHub โ *Settings โ Environments* โ create an environment named **`pypi`**
|
|
372
|
+
(optionally add required reviewers to gate publishes).
|
|
373
|
+
|
|
374
|
+
**To cut a release:**
|
|
375
|
+
|
|
376
|
+
1. Bump `project.version` in `pyproject.toml`, move the `CHANGELOG.md`
|
|
377
|
+
`[Unreleased]` section under the new version, and merge to `main`.
|
|
378
|
+
2. On GitHub โ *Releases โ Draft a new release* โ create a tag (e.g. `v0.1.0`)
|
|
379
|
+
โ **Publish release**.
|
|
380
|
+
3. CI runs lint / type-check / tests / audit, then the `publish` job builds and
|
|
381
|
+
uploads to PyPI. Done โ `uvx agentic-mail-mcp` now resolves the new version.
|
|
382
|
+
|
|
383
|
+
## License
|
|
384
|
+
|
|
385
|
+
Released under the [MIT License](LICENSE).
|