vikunja-mcp-ng 0.4.0
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.
- package/LICENSE +21 -0
- package/README.md +123 -0
- package/dist/auth/AuthManager.d.ts +63 -0
- package/dist/auth/AuthManager.d.ts.map +1 -0
- package/dist/auth/AuthManager.js +137 -0
- package/dist/auth/AuthManager.js.map +1 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +14 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/permissions.d.ts +60 -0
- package/dist/auth/permissions.d.ts.map +1 -0
- package/dist/auth/permissions.js +173 -0
- package/dist/auth/permissions.js.map +1 -0
- package/dist/client/VikunjaClientFactory.d.ts +41 -0
- package/dist/client/VikunjaClientFactory.d.ts.map +1 -0
- package/dist/client/VikunjaClientFactory.js +58 -0
- package/dist/client/VikunjaClientFactory.js.map +1 -0
- package/dist/client.d.ts +70 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +136 -0
- package/dist/client.js.map +1 -0
- package/dist/config/ConfigurationManager.d.ts +106 -0
- package/dist/config/ConfigurationManager.d.ts.map +1 -0
- package/dist/config/ConfigurationManager.js +509 -0
- package/dist/config/ConfigurationManager.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +36 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/secrets.d.ts +33 -0
- package/dist/config/secrets.d.ts.map +1 -0
- package/dist/config/secrets.js +90 -0
- package/dist/config/secrets.js.map +1 -0
- package/dist/config/types.d.ts +1113 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +189 -0
- package/dist/config/types.js.map +1 -0
- package/dist/formatters/BatchImportResponseFormatter.d.ts +89 -0
- package/dist/formatters/BatchImportResponseFormatter.d.ts.map +1 -0
- package/dist/formatters/BatchImportResponseFormatter.js +125 -0
- package/dist/formatters/BatchImportResponseFormatter.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +130 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/direct-middleware.d.ts +9 -0
- package/dist/middleware/direct-middleware.d.ts.map +1 -0
- package/dist/middleware/direct-middleware.js +49 -0
- package/dist/middleware/direct-middleware.js.map +1 -0
- package/dist/middleware/index.d.ts +8 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +21 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/simplified-rate-limit.d.ts +147 -0
- package/dist/middleware/simplified-rate-limit.d.ts.map +1 -0
- package/dist/middleware/simplified-rate-limit.js +533 -0
- package/dist/middleware/simplified-rate-limit.js.map +1 -0
- package/dist/parsers/CSVParser.d.ts +36 -0
- package/dist/parsers/CSVParser.d.ts.map +1 -0
- package/dist/parsers/CSVParser.js +69 -0
- package/dist/parsers/CSVParser.js.map +1 -0
- package/dist/parsers/InputParserFactory.d.ts +17 -0
- package/dist/parsers/InputParserFactory.d.ts.map +1 -0
- package/dist/parsers/InputParserFactory.js +137 -0
- package/dist/parsers/InputParserFactory.js.map +1 -0
- package/dist/parsers/JSONParser.d.ts +74 -0
- package/dist/parsers/JSONParser.d.ts.map +1 -0
- package/dist/parsers/JSONParser.js +69 -0
- package/dist/parsers/JSONParser.js.map +1 -0
- package/dist/services/EntityResolver.d.ts +92 -0
- package/dist/services/EntityResolver.d.ts.map +1 -0
- package/dist/services/EntityResolver.js +201 -0
- package/dist/services/EntityResolver.js.map +1 -0
- package/dist/services/TaskCreationService.d.ts +99 -0
- package/dist/services/TaskCreationService.d.ts.map +1 -0
- package/dist/services/TaskCreationService.js +392 -0
- package/dist/services/TaskCreationService.js.map +1 -0
- package/dist/storage/SimpleFilterStorage.d.ts +103 -0
- package/dist/storage/SimpleFilterStorage.d.ts.map +1 -0
- package/dist/storage/SimpleFilterStorage.js +350 -0
- package/dist/storage/SimpleFilterStorage.js.map +1 -0
- package/dist/storage/filtering/FilterSerializer.d.ts +45 -0
- package/dist/storage/filtering/FilterSerializer.d.ts.map +1 -0
- package/dist/storage/filtering/FilterSerializer.js +171 -0
- package/dist/storage/filtering/FilterSerializer.js.map +1 -0
- package/dist/storage/filtering/FilterValidator.d.ts +59 -0
- package/dist/storage/filtering/FilterValidator.d.ts.map +1 -0
- package/dist/storage/filtering/FilterValidator.js +183 -0
- package/dist/storage/filtering/FilterValidator.js.map +1 -0
- package/dist/storage/index.d.ts +61 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +125 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/templateFileStore.d.ts +62 -0
- package/dist/storage/templateFileStore.d.ts.map +1 -0
- package/dist/storage/templateFileStore.js +151 -0
- package/dist/storage/templateFileStore.js.map +1 -0
- package/dist/tools/admin.d.ts +51 -0
- package/dist/tools/admin.d.ts.map +1 -0
- package/dist/tools/admin.js +207 -0
- package/dist/tools/admin.js.map +1 -0
- package/dist/tools/auth.d.ts +9 -0
- package/dist/tools/auth.d.ts.map +1 -0
- package/dist/tools/auth.js +175 -0
- package/dist/tools/auth.js.map +1 -0
- package/dist/tools/batch-import.d.ts +5 -0
- package/dist/tools/batch-import.d.ts.map +1 -0
- package/dist/tools/batch-import.js +153 -0
- package/dist/tools/batch-import.js.map +1 -0
- package/dist/tools/caldav-tokens.d.ts +45 -0
- package/dist/tools/caldav-tokens.d.ts.map +1 -0
- package/dist/tools/caldav-tokens.js +93 -0
- package/dist/tools/caldav-tokens.js.map +1 -0
- package/dist/tools/export.d.ts +14 -0
- package/dist/tools/export.d.ts.map +1 -0
- package/dist/tools/export.js +252 -0
- package/dist/tools/export.js.map +1 -0
- package/dist/tools/filters.d.ts +50 -0
- package/dist/tools/filters.d.ts.map +1 -0
- package/dist/tools/filters.js +512 -0
- package/dist/tools/filters.js.map +1 -0
- package/dist/tools/index.d.ts +53 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +217 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/labels.d.ts +22 -0
- package/dist/tools/labels.d.ts.map +1 -0
- package/dist/tools/labels.js +206 -0
- package/dist/tools/labels.js.map +1 -0
- package/dist/tools/notifications.d.ts +17 -0
- package/dist/tools/notifications.d.ts.map +1 -0
- package/dist/tools/notifications.js +171 -0
- package/dist/tools/notifications.js.map +1 -0
- package/dist/tools/projects/backgrounds.d.ts +80 -0
- package/dist/tools/projects/backgrounds.d.ts.map +1 -0
- package/dist/tools/projects/backgrounds.js +154 -0
- package/dist/tools/projects/backgrounds.js.map +1 -0
- package/dist/tools/projects/buckets.d.ts +147 -0
- package/dist/tools/projects/buckets.d.ts.map +1 -0
- package/dist/tools/projects/buckets.js +291 -0
- package/dist/tools/projects/buckets.js.map +1 -0
- package/dist/tools/projects/crud.d.ts +145 -0
- package/dist/tools/projects/crud.d.ts.map +1 -0
- package/dist/tools/projects/crud.js +425 -0
- package/dist/tools/projects/crud.js.map +1 -0
- package/dist/tools/projects/duplicate.d.ts +41 -0
- package/dist/tools/projects/duplicate.d.ts.map +1 -0
- package/dist/tools/projects/duplicate.js +49 -0
- package/dist/tools/projects/duplicate.js.map +1 -0
- package/dist/tools/projects/hierarchy.d.ts +77 -0
- package/dist/tools/projects/hierarchy.d.ts.map +1 -0
- package/dist/tools/projects/hierarchy.js +300 -0
- package/dist/tools/projects/hierarchy.js.map +1 -0
- package/dist/tools/projects/index.d.ts +34 -0
- package/dist/tools/projects/index.d.ts.map +1 -0
- package/dist/tools/projects/index.js +522 -0
- package/dist/tools/projects/index.js.map +1 -0
- package/dist/tools/projects/permission.d.ts +26 -0
- package/dist/tools/projects/permission.d.ts.map +1 -0
- package/dist/tools/projects/permission.js +53 -0
- package/dist/tools/projects/permission.js.map +1 -0
- package/dist/tools/projects/response-formatter.d.ts +54 -0
- package/dist/tools/projects/response-formatter.d.ts.map +1 -0
- package/dist/tools/projects/response-formatter.js +139 -0
- package/dist/tools/projects/response-formatter.js.map +1 -0
- package/dist/tools/projects/sharing-access.d.ts +165 -0
- package/dist/tools/projects/sharing-access.d.ts.map +1 -0
- package/dist/tools/projects/sharing-access.js +450 -0
- package/dist/tools/projects/sharing-access.js.map +1 -0
- package/dist/tools/projects/sharing.d.ts +105 -0
- package/dist/tools/projects/sharing.d.ts.map +1 -0
- package/dist/tools/projects/sharing.js +258 -0
- package/dist/tools/projects/sharing.js.map +1 -0
- package/dist/tools/projects/validation.d.ts +51 -0
- package/dist/tools/projects/validation.d.ts.map +1 -0
- package/dist/tools/projects/validation.js +160 -0
- package/dist/tools/projects/validation.js.map +1 -0
- package/dist/tools/projects/views.d.ts +161 -0
- package/dist/tools/projects/views.d.ts.map +1 -0
- package/dist/tools/projects/views.js +234 -0
- package/dist/tools/projects/views.js.map +1 -0
- package/dist/tools/projects.d.ts +20 -0
- package/dist/tools/projects.d.ts.map +1 -0
- package/dist/tools/projects.js +66 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/reactions.d.ts +25 -0
- package/dist/tools/reactions.d.ts.map +1 -0
- package/dist/tools/reactions.js +108 -0
- package/dist/tools/reactions.js.map +1 -0
- package/dist/tools/subscriptions.d.ts +23 -0
- package/dist/tools/subscriptions.d.ts.map +1 -0
- package/dist/tools/subscriptions.js +111 -0
- package/dist/tools/subscriptions.js.map +1 -0
- package/dist/tools/task-assignees.d.ts +13 -0
- package/dist/tools/task-assignees.d.ts.map +1 -0
- package/dist/tools/task-assignees.js +74 -0
- package/dist/tools/task-assignees.js.map +1 -0
- package/dist/tools/task-bulk.d.ts +13 -0
- package/dist/tools/task-bulk.d.ts.map +1 -0
- package/dist/tools/task-bulk.js +117 -0
- package/dist/tools/task-bulk.js.map +1 -0
- package/dist/tools/task-comments.d.ts +12 -0
- package/dist/tools/task-comments.d.ts.map +1 -0
- package/dist/tools/task-comments.js +65 -0
- package/dist/tools/task-comments.js.map +1 -0
- package/dist/tools/task-crud.d.ts +13 -0
- package/dist/tools/task-crud.d.ts.map +1 -0
- package/dist/tools/task-crud.js +168 -0
- package/dist/tools/task-crud.js.map +1 -0
- package/dist/tools/task-labels.d.ts +13 -0
- package/dist/tools/task-labels.d.ts.map +1 -0
- package/dist/tools/task-labels.js +64 -0
- package/dist/tools/task-labels.js.map +1 -0
- package/dist/tools/task-relations.d.ts +13 -0
- package/dist/tools/task-relations.d.ts.map +1 -0
- package/dist/tools/task-relations.js +74 -0
- package/dist/tools/task-relations.js.map +1 -0
- package/dist/tools/task-reminders.d.ts +13 -0
- package/dist/tools/task-reminders.d.ts.map +1 -0
- package/dist/tools/task-reminders.js +69 -0
- package/dist/tools/task-reminders.js.map +1 -0
- package/dist/tools/tasks/assignees/AssigneeOperationsService.d.ts +63 -0
- package/dist/tools/tasks/assignees/AssigneeOperationsService.d.ts.map +1 -0
- package/dist/tools/tasks/assignees/AssigneeOperationsService.js +152 -0
- package/dist/tools/tasks/assignees/AssigneeOperationsService.js.map +1 -0
- package/dist/tools/tasks/assignees/AssigneeResponseFormatter.d.ts +28 -0
- package/dist/tools/tasks/assignees/AssigneeResponseFormatter.d.ts.map +1 -0
- package/dist/tools/tasks/assignees/AssigneeResponseFormatter.js +73 -0
- package/dist/tools/tasks/assignees/AssigneeResponseFormatter.js.map +1 -0
- package/dist/tools/tasks/assignees/AssigneeValidationService.d.ts +46 -0
- package/dist/tools/tasks/assignees/AssigneeValidationService.d.ts.map +1 -0
- package/dist/tools/tasks/assignees/AssigneeValidationService.js +70 -0
- package/dist/tools/tasks/assignees/AssigneeValidationService.js.map +1 -0
- package/dist/tools/tasks/assignees/index.d.ts +52 -0
- package/dist/tools/tasks/assignees/index.d.ts.map +1 -0
- package/dist/tools/tasks/assignees/index.js +103 -0
- package/dist/tools/tasks/assignees/index.js.map +1 -0
- package/dist/tools/tasks/attach.d.ts +39 -0
- package/dist/tools/tasks/attach.d.ts.map +1 -0
- package/dist/tools/tasks/attach.js +90 -0
- package/dist/tools/tasks/attach.js.map +1 -0
- package/dist/tools/tasks/attachments.d.ts +67 -0
- package/dist/tools/tasks/attachments.d.ts.map +1 -0
- package/dist/tools/tasks/attachments.js +153 -0
- package/dist/tools/tasks/attachments.js.map +1 -0
- package/dist/tools/tasks/buckets.d.ts +41 -0
- package/dist/tools/tasks/buckets.d.ts.map +1 -0
- package/dist/tools/tasks/buckets.js +75 -0
- package/dist/tools/tasks/buckets.js.map +1 -0
- package/dist/tools/tasks/bulk/BatchProcessorFactory.d.ts +30 -0
- package/dist/tools/tasks/bulk/BatchProcessorFactory.d.ts.map +1 -0
- package/dist/tools/tasks/bulk/BatchProcessorFactory.js +69 -0
- package/dist/tools/tasks/bulk/BatchProcessorFactory.js.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationErrorHandler.d.ts +50 -0
- package/dist/tools/tasks/bulk/BulkOperationErrorHandler.d.ts.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationErrorHandler.js +183 -0
- package/dist/tools/tasks/bulk/BulkOperationErrorHandler.js.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationProcessor.d.ts +101 -0
- package/dist/tools/tasks/bulk/BulkOperationProcessor.d.ts.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationProcessor.js +416 -0
- package/dist/tools/tasks/bulk/BulkOperationProcessor.js.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationTypes.d.ts +50 -0
- package/dist/tools/tasks/bulk/BulkOperationTypes.d.ts.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationTypes.js +6 -0
- package/dist/tools/tasks/bulk/BulkOperationTypes.js.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationValidator.d.ts +53 -0
- package/dist/tools/tasks/bulk/BulkOperationValidator.d.ts.map +1 -0
- package/dist/tools/tasks/bulk/BulkOperationValidator.js +216 -0
- package/dist/tools/tasks/bulk/BulkOperationValidator.js.map +1 -0
- package/dist/tools/tasks/bulk/index.d.ts +9 -0
- package/dist/tools/tasks/bulk/index.d.ts.map +1 -0
- package/dist/tools/tasks/bulk/index.js +15 -0
- package/dist/tools/tasks/bulk/index.js.map +1 -0
- package/dist/tools/tasks/bulk-operations-simplified.d.ts +62 -0
- package/dist/tools/tasks/bulk-operations-simplified.d.ts.map +1 -0
- package/dist/tools/tasks/bulk-operations-simplified.js +416 -0
- package/dist/tools/tasks/bulk-operations-simplified.js.map +1 -0
- package/dist/tools/tasks/bulk-operations.d.ts +8 -0
- package/dist/tools/tasks/bulk-operations.d.ts.map +1 -0
- package/dist/tools/tasks/bulk-operations.js +13 -0
- package/dist/tools/tasks/bulk-operations.js.map +1 -0
- package/dist/tools/tasks/by-index.d.ts +36 -0
- package/dist/tools/tasks/by-index.d.ts.map +1 -0
- package/dist/tools/tasks/by-index.js +52 -0
- package/dist/tools/tasks/by-index.js.map +1 -0
- package/dist/tools/tasks/comments/CommentOperationsService.d.ts +44 -0
- package/dist/tools/tasks/comments/CommentOperationsService.d.ts.map +1 -0
- package/dist/tools/tasks/comments/CommentOperationsService.js +86 -0
- package/dist/tools/tasks/comments/CommentOperationsService.js.map +1 -0
- package/dist/tools/tasks/comments/CommentResponseFormatter.d.ts +41 -0
- package/dist/tools/tasks/comments/CommentResponseFormatter.d.ts.map +1 -0
- package/dist/tools/tasks/comments/CommentResponseFormatter.js +114 -0
- package/dist/tools/tasks/comments/CommentResponseFormatter.js.map +1 -0
- package/dist/tools/tasks/comments/CommentValidationService.d.ts +62 -0
- package/dist/tools/tasks/comments/CommentValidationService.d.ts.map +1 -0
- package/dist/tools/tasks/comments/CommentValidationService.js +105 -0
- package/dist/tools/tasks/comments/CommentValidationService.js.map +1 -0
- package/dist/tools/tasks/comments/index.d.ts +66 -0
- package/dist/tools/tasks/comments/index.d.ts.map +1 -0
- package/dist/tools/tasks/comments/index.js +99 -0
- package/dist/tools/tasks/comments/index.js.map +1 -0
- package/dist/tools/tasks/constants.d.ts +19 -0
- package/dist/tools/tasks/constants.d.ts.map +1 -0
- package/dist/tools/tasks/constants.js +82 -0
- package/dist/tools/tasks/constants.js.map +1 -0
- package/dist/tools/tasks/crud/TaskCreationService.d.ts +29 -0
- package/dist/tools/tasks/crud/TaskCreationService.d.ts.map +1 -0
- package/dist/tools/tasks/crud/TaskCreationService.js +274 -0
- package/dist/tools/tasks/crud/TaskCreationService.js.map +1 -0
- package/dist/tools/tasks/crud/TaskDeletionService.d.ts +19 -0
- package/dist/tools/tasks/crud/TaskDeletionService.d.ts.map +1 -0
- package/dist/tools/tasks/crud/TaskDeletionService.js +96 -0
- package/dist/tools/tasks/crud/TaskDeletionService.js.map +1 -0
- package/dist/tools/tasks/crud/TaskReadService.d.ts +19 -0
- package/dist/tools/tasks/crud/TaskReadService.d.ts.map +1 -0
- package/dist/tools/tasks/crud/TaskReadService.js +66 -0
- package/dist/tools/tasks/crud/TaskReadService.js.map +1 -0
- package/dist/tools/tasks/crud/TaskResponseFormatter.d.ts +18 -0
- package/dist/tools/tasks/crud/TaskResponseFormatter.d.ts.map +1 -0
- package/dist/tools/tasks/crud/TaskResponseFormatter.js +248 -0
- package/dist/tools/tasks/crud/TaskResponseFormatter.js.map +1 -0
- package/dist/tools/tasks/crud/TaskUpdateService.d.ts +33 -0
- package/dist/tools/tasks/crud/TaskUpdateService.d.ts.map +1 -0
- package/dist/tools/tasks/crud/TaskUpdateService.js +294 -0
- package/dist/tools/tasks/crud/TaskUpdateService.js.map +1 -0
- package/dist/tools/tasks/crud/index.d.ts +17 -0
- package/dist/tools/tasks/crud/index.d.ts.map +1 -0
- package/dist/tools/tasks/crud/index.js +20 -0
- package/dist/tools/tasks/crud/index.js.map +1 -0
- package/dist/tools/tasks/duplicate.d.ts +28 -0
- package/dist/tools/tasks/duplicate.d.ts.map +1 -0
- package/dist/tools/tasks/duplicate.js +41 -0
- package/dist/tools/tasks/duplicate.js.map +1 -0
- package/dist/tools/tasks/filtering/FilterExecutor.d.ts +39 -0
- package/dist/tools/tasks/filtering/FilterExecutor.d.ts.map +1 -0
- package/dist/tools/tasks/filtering/FilterExecutor.js +214 -0
- package/dist/tools/tasks/filtering/FilterExecutor.js.map +1 -0
- package/dist/tools/tasks/filtering/FilterValidator.d.ts +59 -0
- package/dist/tools/tasks/filtering/FilterValidator.d.ts.map +1 -0
- package/dist/tools/tasks/filtering/FilterValidator.js +257 -0
- package/dist/tools/tasks/filtering/FilterValidator.js.map +1 -0
- package/dist/tools/tasks/filtering/TaskFilteringOrchestrator.d.ts +78 -0
- package/dist/tools/tasks/filtering/TaskFilteringOrchestrator.d.ts.map +1 -0
- package/dist/tools/tasks/filtering/TaskFilteringOrchestrator.js +195 -0
- package/dist/tools/tasks/filtering/TaskFilteringOrchestrator.js.map +1 -0
- package/dist/tools/tasks/filtering/evaluators.d.ts +41 -0
- package/dist/tools/tasks/filtering/evaluators.d.ts.map +1 -0
- package/dist/tools/tasks/filtering/evaluators.js +224 -0
- package/dist/tools/tasks/filtering/evaluators.js.map +1 -0
- package/dist/tools/tasks/filtering/index.d.ts +11 -0
- package/dist/tools/tasks/filtering/index.d.ts.map +1 -0
- package/dist/tools/tasks/filtering/index.js +26 -0
- package/dist/tools/tasks/filtering/index.js.map +1 -0
- package/dist/tools/tasks/index.d.ts +9 -0
- package/dist/tools/tasks/index.d.ts.map +1 -0
- package/dist/tools/tasks/index.js +337 -0
- package/dist/tools/tasks/index.js.map +1 -0
- package/dist/tools/tasks/labels.d.ts +49 -0
- package/dist/tools/tasks/labels.d.ts.map +1 -0
- package/dist/tools/tasks/labels.js +223 -0
- package/dist/tools/tasks/labels.js.map +1 -0
- package/dist/tools/tasks/mark-read.d.ts +27 -0
- package/dist/tools/tasks/mark-read.d.ts.map +1 -0
- package/dist/tools/tasks/mark-read.js +38 -0
- package/dist/tools/tasks/mark-read.js.map +1 -0
- package/dist/tools/tasks/position.d.ts +53 -0
- package/dist/tools/tasks/position.d.ts.map +1 -0
- package/dist/tools/tasks/position.js +83 -0
- package/dist/tools/tasks/position.js.map +1 -0
- package/dist/tools/tasks/reminders.d.ts +56 -0
- package/dist/tools/tasks/reminders.d.ts.map +1 -0
- package/dist/tools/tasks/reminders.js +213 -0
- package/dist/tools/tasks/reminders.js.map +1 -0
- package/dist/tools/tasks/subtasks.d.ts +85 -0
- package/dist/tools/tasks/subtasks.d.ts.map +1 -0
- package/dist/tools/tasks/subtasks.js +286 -0
- package/dist/tools/tasks/subtasks.js.map +1 -0
- package/dist/tools/tasks/types/filters.d.ts +136 -0
- package/dist/tools/tasks/types/filters.d.ts.map +1 -0
- package/dist/tools/tasks/types/filters.js +7 -0
- package/dist/tools/tasks/types/filters.js.map +1 -0
- package/dist/tools/tasks/validation.d.ts +47 -0
- package/dist/tools/tasks/validation.d.ts.map +1 -0
- package/dist/tools/tasks/validation.js +131 -0
- package/dist/tools/tasks/validation.js.map +1 -0
- package/dist/tools/tasks-relations.d.ts +25 -0
- package/dist/tools/tasks-relations.d.ts.map +1 -0
- package/dist/tools/tasks-relations.js +271 -0
- package/dist/tools/tasks-relations.js.map +1 -0
- package/dist/tools/tasks.d.ts +6 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +10 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/teams.d.ts +9 -0
- package/dist/tools/teams.d.ts.map +1 -0
- package/dist/tools/teams.js +255 -0
- package/dist/tools/teams.js.map +1 -0
- package/dist/tools/templates.d.ts +9 -0
- package/dist/tools/templates.d.ts.map +1 -0
- package/dist/tools/templates.js +450 -0
- package/dist/tools/templates.js.map +1 -0
- package/dist/tools/tokens.d.ts +37 -0
- package/dist/tools/tokens.d.ts.map +1 -0
- package/dist/tools/tokens.js +122 -0
- package/dist/tools/tokens.js.map +1 -0
- package/dist/tools/user-deletion.d.ts +41 -0
- package/dist/tools/user-deletion.d.ts.map +1 -0
- package/dist/tools/user-deletion.js +126 -0
- package/dist/tools/user-deletion.js.map +1 -0
- package/dist/tools/users.d.ts +9 -0
- package/dist/tools/users.d.ts.map +1 -0
- package/dist/tools/users.js +418 -0
- package/dist/tools/users.js.map +1 -0
- package/dist/tools/webhooks.d.ts +31 -0
- package/dist/tools/webhooks.d.ts.map +1 -0
- package/dist/tools/webhooks.js +414 -0
- package/dist/tools/webhooks.js.map +1 -0
- package/dist/transforms/base.d.ts +204 -0
- package/dist/transforms/base.d.ts.map +1 -0
- package/dist/transforms/base.js +175 -0
- package/dist/transforms/base.js.map +1 -0
- package/dist/transforms/field-selector.d.ts +27 -0
- package/dist/transforms/field-selector.d.ts.map +1 -0
- package/dist/transforms/field-selector.js +91 -0
- package/dist/transforms/field-selector.js.map +1 -0
- package/dist/transforms/index.d.ts +15 -0
- package/dist/transforms/index.d.ts.map +1 -0
- package/dist/transforms/index.js +50 -0
- package/dist/transforms/index.js.map +1 -0
- package/dist/transforms/size-calculator.d.ts +131 -0
- package/dist/transforms/size-calculator.d.ts.map +1 -0
- package/dist/transforms/size-calculator.js +284 -0
- package/dist/transforms/size-calculator.js.map +1 -0
- package/dist/transforms/task.d.ts +207 -0
- package/dist/transforms/task.d.ts.map +1 -0
- package/dist/transforms/task.js +259 -0
- package/dist/transforms/task.js.map +1 -0
- package/dist/types/errors.d.ts +65 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +44 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/filters.d.ts +149 -0
- package/dist/types/filters.d.ts.map +1 -0
- package/dist/types/filters.js +26 -0
- package/dist/types/filters.js.map +1 -0
- package/dist/types/index.d.ts +147 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +24 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/node-vikunja-extended.d.ts +36 -0
- package/dist/types/node-vikunja-extended.d.ts.map +1 -0
- package/dist/types/node-vikunja-extended.js +25 -0
- package/dist/types/node-vikunja-extended.js.map +1 -0
- package/dist/types/responses.d.ts +121 -0
- package/dist/types/responses.d.ts.map +1 -0
- package/dist/types/responses.js +26 -0
- package/dist/types/responses.js.map +1 -0
- package/dist/types/vikunja.d.ts +319 -0
- package/dist/types/vikunja.d.ts.map +1 -0
- package/dist/types/vikunja.js +7 -0
- package/dist/types/vikunja.js.map +1 -0
- package/dist/utils/auth-error-handler.d.ts +23 -0
- package/dist/utils/auth-error-handler.d.ts.map +1 -0
- package/dist/utils/auth-error-handler.js +162 -0
- package/dist/utils/auth-error-handler.js.map +1 -0
- package/dist/utils/composite-operation.d.ts +184 -0
- package/dist/utils/composite-operation.d.ts.map +1 -0
- package/dist/utils/composite-operation.js +293 -0
- package/dist/utils/composite-operation.js.map +1 -0
- package/dist/utils/error-handler.d.ts +39 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +336 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/filtering/ClientSideFilteringStrategy.d.ts +13 -0
- package/dist/utils/filtering/ClientSideFilteringStrategy.d.ts.map +1 -0
- package/dist/utils/filtering/ClientSideFilteringStrategy.js +129 -0
- package/dist/utils/filtering/ClientSideFilteringStrategy.js.map +1 -0
- package/dist/utils/filtering/FilteringContext.d.ts +40 -0
- package/dist/utils/filtering/FilteringContext.d.ts.map +1 -0
- package/dist/utils/filtering/FilteringContext.js +58 -0
- package/dist/utils/filtering/FilteringContext.js.map +1 -0
- package/dist/utils/filtering/HybridFilteringStrategy.d.ts +15 -0
- package/dist/utils/filtering/HybridFilteringStrategy.d.ts.map +1 -0
- package/dist/utils/filtering/HybridFilteringStrategy.js +55 -0
- package/dist/utils/filtering/HybridFilteringStrategy.js.map +1 -0
- package/dist/utils/filtering/RestCrossProjectFilteringStrategy.d.ts +42 -0
- package/dist/utils/filtering/RestCrossProjectFilteringStrategy.d.ts.map +1 -0
- package/dist/utils/filtering/RestCrossProjectFilteringStrategy.js +120 -0
- package/dist/utils/filtering/RestCrossProjectFilteringStrategy.js.map +1 -0
- package/dist/utils/filtering/ServerSideFilteringStrategy.d.ts +13 -0
- package/dist/utils/filtering/ServerSideFilteringStrategy.d.ts.map +1 -0
- package/dist/utils/filtering/ServerSideFilteringStrategy.js +88 -0
- package/dist/utils/filtering/ServerSideFilteringStrategy.js.map +1 -0
- package/dist/utils/filtering/TaskFilteringStrategy.d.ts +19 -0
- package/dist/utils/filtering/TaskFilteringStrategy.d.ts.map +1 -0
- package/dist/utils/filtering/TaskFilteringStrategy.js +10 -0
- package/dist/utils/filtering/TaskFilteringStrategy.js.map +1 -0
- package/dist/utils/filtering/index.d.ts +14 -0
- package/dist/utils/filtering/index.d.ts.map +1 -0
- package/dist/utils/filtering/index.js +22 -0
- package/dist/utils/filtering/index.js.map +1 -0
- package/dist/utils/filtering/types.d.ts +108 -0
- package/dist/utils/filtering/types.d.ts.map +1 -0
- package/dist/utils/filtering/types.js +6 -0
- package/dist/utils/filtering/types.js.map +1 -0
- package/dist/utils/filters.d.ts +70 -0
- package/dist/utils/filters.d.ts.map +1 -0
- package/dist/utils/filters.js +812 -0
- package/dist/utils/filters.js.map +1 -0
- package/dist/utils/http-error-detail.d.ts +28 -0
- package/dist/utils/http-error-detail.d.ts.map +1 -0
- package/dist/utils/http-error-detail.js +67 -0
- package/dist/utils/http-error-detail.js.map +1 -0
- package/dist/utils/label-bulk.d.ts +21 -0
- package/dist/utils/label-bulk.d.ts.map +1 -0
- package/dist/utils/label-bulk.js +51 -0
- package/dist/utils/label-bulk.js.map +1 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +66 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/memory.d.ts +73 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +194 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/performance/batch-processor.d.ts +77 -0
- package/dist/utils/performance/batch-processor.d.ts.map +1 -0
- package/dist/utils/performance/batch-processor.js +218 -0
- package/dist/utils/performance/batch-processor.js.map +1 -0
- package/dist/utils/performance/index.d.ts +42 -0
- package/dist/utils/performance/index.d.ts.map +1 -0
- package/dist/utils/performance/index.js +49 -0
- package/dist/utils/performance/index.js.map +1 -0
- package/dist/utils/performance/performance-monitor.d.ts +116 -0
- package/dist/utils/performance/performance-monitor.d.ts.map +1 -0
- package/dist/utils/performance/performance-monitor.js +307 -0
- package/dist/utils/performance/performance-monitor.js.map +1 -0
- package/dist/utils/read-only.d.ts +111 -0
- package/dist/utils/read-only.d.ts.map +1 -0
- package/dist/utils/read-only.js +503 -0
- package/dist/utils/read-only.js.map +1 -0
- package/dist/utils/response-factory.d.ts +81 -0
- package/dist/utils/response-factory.d.ts.map +1 -0
- package/dist/utils/response-factory.js +86 -0
- package/dist/utils/response-factory.js.map +1 -0
- package/dist/utils/retry.d.ts +160 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +316 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/security.d.ts +70 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +358 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/simple-response.d.ts +75 -0
- package/dist/utils/simple-response.d.ts.map +1 -0
- package/dist/utils/simple-response.js +311 -0
- package/dist/utils/simple-response.js.map +1 -0
- package/dist/utils/storage-errors.d.ts +9 -0
- package/dist/utils/storage-errors.d.ts.map +1 -0
- package/dist/utils/storage-errors.js +20 -0
- package/dist/utils/storage-errors.js.map +1 -0
- package/dist/utils/task-rest-transport.d.ts +28 -0
- package/dist/utils/task-rest-transport.d.ts.map +1 -0
- package/dist/utils/task-rest-transport.js +33 -0
- package/dist/utils/task-rest-transport.js.map +1 -0
- package/dist/utils/unicode-fix.d.ts +19 -0
- package/dist/utils/unicode-fix.d.ts.map +1 -0
- package/dist/utils/unicode-fix.js +70 -0
- package/dist/utils/unicode-fix.js.map +1 -0
- package/dist/utils/validation.d.ts +75 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +758 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/utils/vikunja-rest.d.ts +159 -0
- package/dist/utils/vikunja-rest.d.ts.map +1 -0
- package/dist/utils/vikunja-rest.js +378 -0
- package/dist/utils/vikunja-rest.js.map +1 -0
- package/docs/CONFIGURATION.md +957 -0
- package/docs/DOCKER-DESKTOP-MCP.md +207 -0
- package/docs/TOOLS.md +422 -0
- package/package.json +145 -0
|
@@ -0,0 +1,957 @@
|
|
|
1
|
+
# Configuration Management
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Vikunja MCP server uses a centralized configuration system that replaces scattered `process.env` usage with type-safe, validated configuration management. This system addresses TD-002 (Environment Variable Sprawl) by consolidating 33 environment variables into a unified architecture.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### Basic Usage
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { getConfiguration, getAuthConfig, getRateLimitConfig } from './config';
|
|
13
|
+
|
|
14
|
+
// Get complete configuration
|
|
15
|
+
const config = await getConfiguration();
|
|
16
|
+
|
|
17
|
+
// Get specific sections
|
|
18
|
+
const authConfig = await getAuthConfig();
|
|
19
|
+
const rateLimiting = await getRateLimitConfig();
|
|
20
|
+
|
|
21
|
+
// Check feature flags
|
|
22
|
+
const isEnabled = await isFeatureEnabled('enableServerSideFiltering');
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Environment Setup
|
|
26
|
+
|
|
27
|
+
1. Copy `.env.example` to `.env`
|
|
28
|
+
2. Configure your Vikunja connection:
|
|
29
|
+
```env
|
|
30
|
+
VIKUNJA_URL=https://your-vikunja-instance.com
|
|
31
|
+
VIKUNJA_API_TOKEN=your-api-token-here
|
|
32
|
+
```
|
|
33
|
+
3. Set your environment:
|
|
34
|
+
```env
|
|
35
|
+
NODE_ENV=development # or test, production
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Configuration Architecture
|
|
39
|
+
|
|
40
|
+
### Configuration Sections
|
|
41
|
+
|
|
42
|
+
The configuration is organized into four main sections:
|
|
43
|
+
|
|
44
|
+
#### 1. Authentication (`AuthConfig`)
|
|
45
|
+
```typescript
|
|
46
|
+
interface AuthConfig {
|
|
47
|
+
vikunjaUrl?: string; // Vikunja server URL
|
|
48
|
+
vikunjaToken?: string; // API or JWT token
|
|
49
|
+
mcpMode?: string; // MCP server mode
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### 2. Logging (`LoggingConfig`)
|
|
54
|
+
```typescript
|
|
55
|
+
interface LoggingConfig {
|
|
56
|
+
level: 'error' | 'warn' | 'info' | 'debug';
|
|
57
|
+
debug: boolean;
|
|
58
|
+
environment: Environment;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### 3. Rate Limiting (`RateLimitConfig`)
|
|
63
|
+
```typescript
|
|
64
|
+
interface RateLimitConfig {
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
default: RateLimitSettings; // Standard tools
|
|
67
|
+
expensive: RateLimitSettings; // Resource-intensive operations
|
|
68
|
+
bulk: RateLimitSettings; // Batch operations
|
|
69
|
+
export: RateLimitSettings; // Export operations
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface RateLimitSettings {
|
|
73
|
+
requestsPerMinute: number;
|
|
74
|
+
requestsPerHour: number;
|
|
75
|
+
maxRequestSize: number;
|
|
76
|
+
maxResponseSize: number;
|
|
77
|
+
executionTimeout: number;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### 4. Feature Flags (`FeatureFlagsConfig`)
|
|
82
|
+
```typescript
|
|
83
|
+
interface FeatureFlagsConfig {
|
|
84
|
+
enableServerSideFiltering: boolean;
|
|
85
|
+
enableAdvancedMetrics: boolean;
|
|
86
|
+
enableExperimentalFeatures: boolean;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### 5. Templates (`TemplatesConfig`)
|
|
91
|
+
```typescript
|
|
92
|
+
interface TemplatesConfig {
|
|
93
|
+
persistPath?: string; // File-backed persistence — see Templates Persistence below
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Environment Profiles
|
|
98
|
+
|
|
99
|
+
The system automatically applies environment-specific defaults:
|
|
100
|
+
|
|
101
|
+
#### Development Profile
|
|
102
|
+
- **Logging**: Debug level, verbose output
|
|
103
|
+
- **Rate Limiting**: Disabled for easier testing
|
|
104
|
+
- **Features**: Experimental features enabled
|
|
105
|
+
|
|
106
|
+
#### Test Profile
|
|
107
|
+
- **Logging**: Error level only to reduce noise
|
|
108
|
+
- **Rate Limiting**: Disabled for test performance
|
|
109
|
+
- **Features**: Conservative settings for consistent behavior
|
|
110
|
+
|
|
111
|
+
#### Production Profile
|
|
112
|
+
- **Logging**: Info level for operational visibility
|
|
113
|
+
- **Rate Limiting**: Full protection enabled
|
|
114
|
+
- **Features**: Only stable features enabled
|
|
115
|
+
|
|
116
|
+
## Configuration Priority
|
|
117
|
+
|
|
118
|
+
Configuration values are resolved in the following priority order (highest to lowest):
|
|
119
|
+
|
|
120
|
+
1. **Programmatic Sources** - Direct configuration objects (used by tests / embedders)
|
|
121
|
+
2. **Environment Variables** - System environment variables — **always win over the config file**
|
|
122
|
+
3. **Config File** - Optional `vikunja-mcp.config.json` (see [Config File](#config-file) below)
|
|
123
|
+
4. **Environment Profiles** - Dev/test/production defaults
|
|
124
|
+
5. **Schema Defaults** - Fallback values defined in schema
|
|
125
|
+
|
|
126
|
+
## Config File
|
|
127
|
+
|
|
128
|
+
Non-sensitive configuration can be layered in from an optional JSON file. It is safe to
|
|
129
|
+
commit, safe to mount read-only into a container (e.g. as a Docker `config`), and is
|
|
130
|
+
**never** the place for secrets — see [Secrets Management](#secrets-management).
|
|
131
|
+
|
|
132
|
+
- **Default path**: `vikunja-mcp.config.json` in the process's current working directory.
|
|
133
|
+
If it doesn't exist, it is silently skipped — the file is entirely optional.
|
|
134
|
+
- **Override path**: set `VIKUNJA_MCP_CONFIG=/path/to/file.json`. When this variable is
|
|
135
|
+
set explicitly, a missing or unreadable file is a **hard startup error** (fail fast) —
|
|
136
|
+
an explicit path that can't be read is assumed to be a misconfiguration, not something
|
|
137
|
+
to silently ignore.
|
|
138
|
+
- **Malformed file**: invalid JSON, or JSON whose top-level value isn't an object, is
|
|
139
|
+
always a hard startup error with a message naming the file path and the parse problem —
|
|
140
|
+
regardless of whether the path was explicit or the default.
|
|
141
|
+
- **Shape**: the file mirrors `ApplicationConfig` — any of `auth` (non-secret fields
|
|
142
|
+
only), `logging`, `rateLimiting`, `featureFlags`, `modules`, `templates` may be
|
|
143
|
+
present; anything omitted falls back to the environment profile / schema default.
|
|
144
|
+
|
|
145
|
+
Example `vikunja-mcp.config.json`:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"modules": {
|
|
150
|
+
"webhooks": false,
|
|
151
|
+
"batchImport": { "enabled": true }
|
|
152
|
+
},
|
|
153
|
+
"logging": {
|
|
154
|
+
"level": "info"
|
|
155
|
+
},
|
|
156
|
+
"readOnly": false
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Module Gating
|
|
161
|
+
|
|
162
|
+
Each Vikunja entity's tools live behind a **module** toggle, resolved once at
|
|
163
|
+
tool-registration time (`registerTools` in `src/tools/index.ts`). A disabled module's
|
|
164
|
+
tools are never registered with the MCP server — they are invisible to the client, not
|
|
165
|
+
merely rejected at call time.
|
|
166
|
+
|
|
167
|
+
### Module Config Shape
|
|
168
|
+
|
|
169
|
+
A module's value is a plain boolean today, but the object form is accepted so
|
|
170
|
+
per-subcommand granularity can be added later **without a breaking change**:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{ "modules": { "tasks": false } }
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{ "modules": { "tasks": { "enabled": true } } }
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The object form already tolerates (and ignores, for now) extra boolean keys, so a future
|
|
181
|
+
release can start honoring `{"tasks": {"enabled": true, "delete": false}}` without
|
|
182
|
+
requiring any config migration.
|
|
183
|
+
|
|
184
|
+
### Known Modules
|
|
185
|
+
|
|
186
|
+
| Module | Default | Notes |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| `tasks` | **ON** | Gates the entire task tool family (CRUD, bulk, assignees, comments, reminders, labels, relations) together |
|
|
189
|
+
| `projects` | **ON** | |
|
|
190
|
+
| `labels` | **ON** | |
|
|
191
|
+
| `teams` | **ON** | |
|
|
192
|
+
| `users` | **ON** | Also requires JWT authentication — see [Composing with Auth-Type Gating](#composing-with-auth-type-gating) |
|
|
193
|
+
| `webhooks` | **ON** | |
|
|
194
|
+
| `filters` | **ON** | |
|
|
195
|
+
| `templates` | **ON** | |
|
|
196
|
+
| `export` | **ON** | Also requires JWT authentication |
|
|
197
|
+
| `batchImport` | **ON** | |
|
|
198
|
+
| `notifications` | **ON** | Gates `vikunja_notifications` |
|
|
199
|
+
| `subscriptions` | **ON** | Gates `vikunja_subscriptions` |
|
|
200
|
+
| `reactions` | **ON** | Gates `vikunja_reactions` |
|
|
201
|
+
| `admin` | **OFF** ⚠️ | Gates `vikunja_admin` (instance-admin operations: overview, all-projects listing + owner reassignment, user list/create/delete, admin-flag + status toggles). Deny-by-default AND JWT-only — see [Composing with Auth-Type Gating](#composing-with-auth-type-gating). `delete-user` additionally requires an explicit `confirm: true` tool argument. |
|
|
202
|
+
| `userDeletion` | **OFF** ⚠️⚠️ | Gates `vikunja_user_deletion` (`request`/`confirm`/`cancel` self-deletion of the **currently authenticated account**). Deny-by-default AND JWT-only — see [Composing with Auth-Type Gating](#composing-with-auth-type-gating). `request` and `confirm` additionally require an explicit `confirm: true` tool argument; both are genuinely irreversible once the emailed confirmation token is used — do not enable this module unless you specifically want an AI assistant able to delete the connected Vikunja account. `cancel` (the safe undo) does not require `confirm: true`. |
|
|
203
|
+
| `tokenManagement` | **OFF** ⚠️ | Gates `vikunja_tokens` (API token list/create/delete for the connected account). Deny-by-default — credential-adjacent. No auth-type restriction at registration time (unlike `admin`/`users`/`export`), but the underlying `/tokens` endpoints may reject API-token sessions server-side — see `src/tools/tokens.ts`. |
|
|
204
|
+
| `caldavTokens` | **OFF** ⚠️ | Gates `vikunja_caldav_tokens` (CalDAV token list/create/delete for the connected account). Deny-by-default — credential-adjacent, and a created token's secret is shown only once. Unlike `tokenManagement`, the underlying `/user/settings/token/caldav*` endpoints ARE JWT-only per the vendored OpenAPI spec, so registration composes with the same JWT-only gate as `users`/`export`/`admin` — see [Composing with Auth-Type Gating](#composing-with-auth-type-gating) and `src/tools/caldav-tokens.ts`. |
|
|
205
|
+
| `backgrounds` | **OFF** (opt-in) | Gates three `vikunja_projects` subcommands — `remove-background`, `set-unsplash-background`, `search-unsplash` (G7, project backgrounds) — **not** a whole tool. Deny-by-default for the opposite reason to `admin`/`userDeletion`/`tokenManagement`: not dangerous, just low-value/cosmetic for a task-management assistant. See [Subcommand-Level Gating: `backgrounds`](#subcommand-level-gating-backgrounds) below. |
|
|
206
|
+
|
|
207
|
+
Ordinary modules default **ON** (matching pre-existing behavior — this system is
|
|
208
|
+
additive, not a breaking change). The four reserved "dangerous" modules default **OFF**
|
|
209
|
+
(deny-by-default): `admin`, `tokenManagement`, `caldavTokens`, and `userDeletion` now all
|
|
210
|
+
have tools wired to them and ship already gated closed until an operator opts in.
|
|
211
|
+
`userDeletion` deserves particular caution — read its row above in full before enabling
|
|
212
|
+
it. `backgrounds` is also **OFF** by default, but as an **opt-in cosmetic** module rather
|
|
213
|
+
than a dangerous one — see below.
|
|
214
|
+
|
|
215
|
+
### Subcommand-Level Gating: `backgrounds`
|
|
216
|
+
|
|
217
|
+
Every module above gates a whole standalone tool at registration time. `backgrounds` is
|
|
218
|
+
the one exception: it gates only three subcommands *within* the always-registered
|
|
219
|
+
`vikunja_projects` tool (`remove-background`, `set-unsplash-background`,
|
|
220
|
+
`search-unsplash`), because bundling low-value cosmetic operations into their own tool
|
|
221
|
+
would be worse ergonomics than adding them to the tool that already owns project state.
|
|
222
|
+
|
|
223
|
+
The same "invisible to the client, not merely rejected at call time" contract still
|
|
224
|
+
holds — it is just enforced one level down. `registerProjectsTool`
|
|
225
|
+
(`src/tools/projects/index.ts`) builds `vikunja_projects`'s subcommand **enum** itself
|
|
226
|
+
conditionally on whether `backgrounds` is enabled: when it isn't (the default), those
|
|
227
|
+
three strings are not present in the enum at all, so a call naming one of them fails
|
|
228
|
+
MCP schema validation (an unrecognized enum value) rather than reaching any handler
|
|
229
|
+
logic. Enable the module and the enum includes them; disable it and they vanish from
|
|
230
|
+
the schema again — exactly mirroring what module gating does for a whole tool.
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{ "modules": { "backgrounds": true } }
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
```env
|
|
237
|
+
VIKUNJA_MCP_MODULE_BACKGROUNDS=true
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Two of the three subcommands (`set-unsplash-background`, `search-unsplash`) only work
|
|
241
|
+
when the connected Vikunja server itself has an Unsplash provider configured
|
|
242
|
+
(an admin-side API key) — when it doesn't, the server's error is recognized and
|
|
243
|
+
rewritten into a friendly, actionable message rather than surfaced as opaque server
|
|
244
|
+
text. The binary image bytes (upload, and fetching the actual image/thumbnail) stay
|
|
245
|
+
parked — MCP has no content channel for them; see
|
|
246
|
+
[docs/ENDPOINT-TAIL-RETRIAGE.md](ENDPOINT-TAIL-RETRIAGE.md) item G7.
|
|
247
|
+
|
|
248
|
+
### Module Env Var Overrides
|
|
249
|
+
|
|
250
|
+
Each module has a matching boolean-only env var override (env vars carry the boolean
|
|
251
|
+
shorthand only — the object form with future per-subcommand keys is a config-file-only
|
|
252
|
+
feature):
|
|
253
|
+
|
|
254
|
+
```env
|
|
255
|
+
VIKUNJA_MCP_MODULE_TASKS=true
|
|
256
|
+
VIKUNJA_MCP_MODULE_PROJECTS=true
|
|
257
|
+
VIKUNJA_MCP_MODULE_LABELS=true
|
|
258
|
+
VIKUNJA_MCP_MODULE_TEAMS=true
|
|
259
|
+
VIKUNJA_MCP_MODULE_USERS=true
|
|
260
|
+
VIKUNJA_MCP_MODULE_WEBHOOKS=true
|
|
261
|
+
VIKUNJA_MCP_MODULE_FILTERS=true
|
|
262
|
+
VIKUNJA_MCP_MODULE_TEMPLATES=true
|
|
263
|
+
VIKUNJA_MCP_MODULE_EXPORT=true
|
|
264
|
+
VIKUNJA_MCP_MODULE_BATCH_IMPORT=true
|
|
265
|
+
VIKUNJA_MCP_MODULE_NOTIFICATIONS=true
|
|
266
|
+
VIKUNJA_MCP_MODULE_SUBSCRIPTIONS=true
|
|
267
|
+
VIKUNJA_MCP_MODULE_REACTIONS=true
|
|
268
|
+
|
|
269
|
+
# Reserved / dangerous — deny-by-default
|
|
270
|
+
VIKUNJA_MCP_MODULE_ADMIN=false
|
|
271
|
+
VIKUNJA_MCP_MODULE_USER_DELETION=false
|
|
272
|
+
VIKUNJA_MCP_MODULE_TOKEN_MANAGEMENT=false
|
|
273
|
+
VIKUNJA_MCP_MODULE_CALDAV_TOKENS=false
|
|
274
|
+
|
|
275
|
+
# Opt-in cosmetic — deny-by-default (not dangerous, just low-value)
|
|
276
|
+
VIKUNJA_MCP_MODULE_BACKGROUNDS=false
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
As with every other setting, these env vars always win over the config file.
|
|
280
|
+
|
|
281
|
+
### Composing with Auth-Type Gating
|
|
282
|
+
|
|
283
|
+
Module config can only **narrow** what authentication already allows — it can never
|
|
284
|
+
**expand** it. The `users` and `export` tools have always required JWT authentication
|
|
285
|
+
(API-token auth excludes them for backward compatibility); `admin` composes with the
|
|
286
|
+
same JWT-only gate. Module gating is applied *in addition to*, never instead of, that
|
|
287
|
+
check:
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
const jwtAuthenticated = authManager.isAuthenticated() && authManager.getAuthType() === 'jwt';
|
|
291
|
+
if (jwtAuthenticated && isModuleEnabled(modules.users)) {
|
|
292
|
+
registerUsersTool(server, authManager, clientFactory);
|
|
293
|
+
}
|
|
294
|
+
// ... and further down:
|
|
295
|
+
if (jwtAuthenticated && isModuleEnabled(modules.admin)) {
|
|
296
|
+
registerAdminTool(server, authManager, clientFactory);
|
|
297
|
+
}
|
|
298
|
+
if (jwtAuthenticated && isModuleEnabled(modules.userDeletion)) {
|
|
299
|
+
registerUserDeletionTool(server, authManager, clientFactory);
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Setting `VIKUNJA_MCP_MODULE_USERS=true` while authenticated with an API token does
|
|
304
|
+
**not** register the users tool — there is no config setting that can grant access auth
|
|
305
|
+
doesn't already permit. The same is true of `VIKUNJA_MCP_MODULE_ADMIN=true` and
|
|
306
|
+
`VIKUNJA_MCP_MODULE_USER_DELETION=true`: with an API-token session, `vikunja_admin` and
|
|
307
|
+
`vikunja_user_deletion` both stay unregistered regardless of the config value — per
|
|
308
|
+
docs/VIKUNJA_API_ISSUES.md, every `/user/*` endpoint (including `/user/deletion/*`)
|
|
309
|
+
rejects `tk_*` API tokens server-side, so this JWT-only gate is not just a local policy
|
|
310
|
+
choice here. `tokenManagement` is the one deny-by-default module that does **not**
|
|
311
|
+
compose with the JWT-only gate — `vikunja_tokens` registers for either session type once
|
|
312
|
+
its module key is enabled, since the underlying endpoints' auth requirement is a runtime
|
|
313
|
+
server behavior rather than something this server enforces at registration time.
|
|
314
|
+
|
|
315
|
+
`caldavTokens`, by contrast, DOES compose with the JWT-only gate, the same way
|
|
316
|
+
`admin` does — `vikunja_caldav_tokens` registers only when both
|
|
317
|
+
`VIKUNJA_MCP_MODULE_CALDAV_TOKENS=true` (or the config-file equivalent) AND the
|
|
318
|
+
session is JWT-authenticated, because the vendored OpenAPI spec scopes every
|
|
319
|
+
`/user/settings/token/caldav*` operation to `JWTKeyAuth` only (no `APIKeyAuth` entry) —
|
|
320
|
+
unlike `/tokens`, this is enforced at registration time, not left for the server to
|
|
321
|
+
reject at runtime.
|
|
322
|
+
|
|
323
|
+
## Global Read-Only Safety Mode
|
|
324
|
+
|
|
325
|
+
A separate, orthogonal safety layer from module gating: instead of hiding a tool from the
|
|
326
|
+
MCP client entirely (module gating), read-only mode keeps every tool **visible and
|
|
327
|
+
registered**, but rejects any subcommand that writes or destroys data on the connected
|
|
328
|
+
Vikunja instance — read subcommands (`list`, `get`, `status`, ...) keep working normally.
|
|
329
|
+
This is useful for a read-only "explore my tasks" session, a demo environment, or any
|
|
330
|
+
deployment where an operator wants to guarantee an AI assistant cannot mutate data no
|
|
331
|
+
matter what a tool call asks for.
|
|
332
|
+
|
|
333
|
+
- **Config file key**: `readOnly` (boolean, default `false`) at the top level of
|
|
334
|
+
`vikunja-mcp.config.json` — a peer of `modules`/`logging`/etc., not nested under either.
|
|
335
|
+
- **Env override**: `VIKUNJA_MCP_READ_ONLY` (boolean shorthand, `true`/`false`) — as with
|
|
336
|
+
every other setting, the env var always wins over the config file.
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
{ "readOnly": true }
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
```env
|
|
343
|
+
VIKUNJA_MCP_READ_ONLY=true
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### What gets rejected
|
|
347
|
+
|
|
348
|
+
Rejection happens at dispatch, inside each tool's handler, via a single shared guard
|
|
349
|
+
(`assertWriteAllowed` in `src/utils/read-only.ts`) that every tool dispatcher calls once,
|
|
350
|
+
right after its existing auth check — not 24 copy-pasted `if (readOnly)` checks. The guard
|
|
351
|
+
consults one classification table per tool (`subcommand -> read | write | destructive`),
|
|
352
|
+
built from the actual Vikunja API semantics of each subcommand (see the module's doc
|
|
353
|
+
comment for the full rubric and the rationale behind edge cases like the dual-purpose
|
|
354
|
+
`comment` subcommand, `vikunja_batch_import`'s `dryRun`, and the fully-exempt
|
|
355
|
+
`vikunja_auth` tool). A rejected call fails with a consistent, clearly-worded error:
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
server is in read-only mode: 'vikunja_tasks' subcommand 'delete' is a destructive
|
|
359
|
+
operation and is rejected. Set 'readOnly' to false in vikunja-mcp.config.json
|
|
360
|
+
(or unset VIKUNJA_MCP_READ_ONLY) to allow writes.
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Notes on scope:
|
|
364
|
+
|
|
365
|
+
- **`vikunja_auth`** (`connect`/`status`/`refresh`/`disconnect`/`info`) is entirely exempt
|
|
366
|
+
— those subcommands only manage the MCP server's local session, never a Vikunja
|
|
367
|
+
resource, so read-only mode never blocks them.
|
|
368
|
+
- **Dynamic classification**: a small number of subcommands classify themselves based on
|
|
369
|
+
the actual call arguments rather than a fixed table entry — `vikunja_tasks`'/
|
|
370
|
+
`vikunja_task_comments`' dual-purpose `comment` subcommand (creates when text is
|
|
371
|
+
supplied, otherwise lists — classified `read` only when no comment text is given) and
|
|
372
|
+
`vikunja_batch_import` (classified `read` only when `dryRun: true`, since a dry run
|
|
373
|
+
never writes).
|
|
374
|
+
- Module gating and read-only mode compose independently: a module disabled entirely
|
|
375
|
+
(§ Module Gating above) is invisible regardless of `readOnly`; a module left enabled
|
|
376
|
+
under `readOnly: true` stays visible but write/destructive calls into it are rejected.
|
|
377
|
+
|
|
378
|
+
### MCP Tool Annotations
|
|
379
|
+
|
|
380
|
+
The same per-tool classification tables drive the MCP SDK's `ToolAnnotations`
|
|
381
|
+
(`readOnlyHint` / `destructiveHint` / `idempotentHint`), registered alongside every tool's
|
|
382
|
+
schema so MCP clients can render tool cards accurately and apply their own consent/
|
|
383
|
+
confirmation UX for destructive calls. Because a single MCP tool name here fans out to
|
|
384
|
+
several subcommands with different semantics, the tool-level hints are derived
|
|
385
|
+
conservatively:
|
|
386
|
+
|
|
387
|
+
- `readOnlyHint` is `true` only when **every** subcommand on that tool is classified
|
|
388
|
+
`read` (today: `vikunja_auth` and `vikunja_export_project`).
|
|
389
|
+
- `destructiveHint` is `true` when **any** subcommand is classified `destructive` (true
|
|
390
|
+
for nearly every CRUD-shaped tool, since almost all of them expose a `delete`-shaped
|
|
391
|
+
operation).
|
|
392
|
+
- `idempotentHint` is set `true` only for tools on an explicit, hand-reviewed allowlist
|
|
393
|
+
where every non-read subcommand is genuinely idempotent — currently just
|
|
394
|
+
`vikunja_notifications` (`mark-read`/`mark-all-read` are ensure-semantics: marking an
|
|
395
|
+
already-read notification as read again is a no-op). It is intentionally *not* inferred
|
|
396
|
+
automatically from the read/write/destructive table, since idempotency is a semantic
|
|
397
|
+
judgment call the three-way classification doesn't capture (e.g. `vikunja_teams`'
|
|
398
|
+
`members:toggleAdmin` is a `write`, not a `delete`, but explicitly is **not**
|
|
399
|
+
idempotent — it flips a flag rather than setting it).
|
|
400
|
+
|
|
401
|
+
## Templates Persistence
|
|
402
|
+
|
|
403
|
+
`vikunja_templates` templates are **session-only by default**: they live in the same
|
|
404
|
+
in-memory `SimpleFilterStorage` as saved filters, scoped to the connected session, and
|
|
405
|
+
are lost when the server process restarts. Set a persist path to make them durable
|
|
406
|
+
across restarts.
|
|
407
|
+
|
|
408
|
+
- **Config key**: `templates.persistPath` in `vikunja-mcp.config.json`.
|
|
409
|
+
- **Env var**: `VIKUNJA_MCP_TEMPLATES_FILE=/path/to/templates.json` — **wins over the
|
|
410
|
+
config file**, same precedence as every other setting (see
|
|
411
|
+
[Configuration Priority](#configuration-priority)).
|
|
412
|
+
- **Unset (default)**: templates stay in-memory only — behavior is byte-identical to
|
|
413
|
+
before this feature existed.
|
|
414
|
+
- **Set**: the file is loaded once, tolerantly, the first time `vikunja_templates` is
|
|
415
|
+
used after startup — a missing file (first run / fresh volume) or a corrupt/malformed
|
|
416
|
+
file both fall back to an empty template set (logged as a warning for the corrupt
|
|
417
|
+
case), **never** a crash. Every `create` / `update` / `delete` mutation then
|
|
418
|
+
write-throughs the full current template set back to the file, **atomically**: written
|
|
419
|
+
to a temp file in the same directory, then renamed over the target, so a reader never
|
|
420
|
+
observes a half-written file and a crash mid-write can't corrupt the previous good
|
|
421
|
+
state. The parent directory is created automatically if it doesn't exist yet.
|
|
422
|
+
|
|
423
|
+
This is intentionally a plain JSON file, not a database — SQLite was evaluated for this
|
|
424
|
+
work item and parked (native-dependency cost outweighs the need for a single opt-in
|
|
425
|
+
file; see `docs/ROADMAP.md`). The path is a single file, which makes it trivial to mount
|
|
426
|
+
as a Docker volume:
|
|
427
|
+
|
|
428
|
+
```yaml
|
|
429
|
+
services:
|
|
430
|
+
vikunja-mcp:
|
|
431
|
+
image: ghcr.io/netadvanced/vikunja-mcp-ng:latest
|
|
432
|
+
environment:
|
|
433
|
+
VIKUNJA_URL: "https://vikunja.example.com/api/v1"
|
|
434
|
+
VIKUNJA_API_TOKEN_FILE: /run/secrets/vikunja_api_token
|
|
435
|
+
VIKUNJA_MCP_TEMPLATES_FILE: /data/templates.json
|
|
436
|
+
volumes:
|
|
437
|
+
- vikunja-mcp-templates:/data
|
|
438
|
+
secrets:
|
|
439
|
+
- source: vikunja_api_token
|
|
440
|
+
target: vikunja_api_token
|
|
441
|
+
mode: 0400
|
|
442
|
+
|
|
443
|
+
volumes:
|
|
444
|
+
vikunja-mcp-templates:
|
|
445
|
+
|
|
446
|
+
secrets:
|
|
447
|
+
vikunja_api_token:
|
|
448
|
+
file: ./secrets/vikunja_api_token.txt
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Or via the config file instead of the env var:
|
|
452
|
+
|
|
453
|
+
```json
|
|
454
|
+
{
|
|
455
|
+
"templates": {
|
|
456
|
+
"persistPath": "/data/templates.json"
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
The template file contains no credentials — it's a plain JSON array of template
|
|
462
|
+
definitions (project/task shape, no auth data) — so, like the rest of the config file, it
|
|
463
|
+
doesn't need Docker-secrets treatment; only the volume itself needs to persist across
|
|
464
|
+
container recreations.
|
|
465
|
+
|
|
466
|
+
## Secrets Management
|
|
467
|
+
|
|
468
|
+
**The config file is for non-sensitive settings only.** It's designed to be safe to
|
|
469
|
+
commit to source control and safe to mount as a read-only Docker/Swarm `config` — so
|
|
470
|
+
credentials must never be written into it. Secrets belong in environment variables.
|
|
471
|
+
|
|
472
|
+
### The `*_FILE` Convention
|
|
473
|
+
|
|
474
|
+
Every sensitive environment variable also accepts a `<NAME>_FILE` variant that names a
|
|
475
|
+
file whose contents are read at startup and used in place of the plain variable — the
|
|
476
|
+
same convention the official `postgres`/`mysql` Docker images use
|
|
477
|
+
(`POSTGRES_PASSWORD_FILE`, etc.), which plugs directly into Docker/Swarm/Kubernetes
|
|
478
|
+
secrets mounted as files.
|
|
479
|
+
|
|
480
|
+
Currently sensitive variables (audited against every `process.env.*` read under `src/`):
|
|
481
|
+
|
|
482
|
+
| Variable | `_FILE` variant |
|
|
483
|
+
|---|---|
|
|
484
|
+
| `VIKUNJA_API_TOKEN` | `VIKUNJA_API_TOKEN_FILE` |
|
|
485
|
+
|
|
486
|
+
Behavior:
|
|
487
|
+
|
|
488
|
+
- File contents are read once at startup and **trimmed of surrounding whitespace**
|
|
489
|
+
(trailing newlines from `echo`/`printf`-created secret files are common and would
|
|
490
|
+
otherwise silently corrupt the token).
|
|
491
|
+
- Setting **both** the plain variable and its `_FILE` variant is a **hard startup
|
|
492
|
+
error** — never a silent precedence choice. This matches the postgres-image
|
|
493
|
+
convention and avoids a class of bug where an operator believes they've moved a
|
|
494
|
+
secret into a file but the plain env var (e.g. left over in a `.env` file) is still
|
|
495
|
+
silently taking priority.
|
|
496
|
+
- Neither set: the plain variable's absence is handled exactly as before (e.g. no
|
|
497
|
+
auto-authentication).
|
|
498
|
+
|
|
499
|
+
```env
|
|
500
|
+
# Use a file-mounted secret instead of the plain token
|
|
501
|
+
VIKUNJA_API_TOKEN_FILE=/run/secrets/vikunja_token
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
```env
|
|
505
|
+
# Hard error at startup — remove one of these
|
|
506
|
+
VIKUNJA_API_TOKEN=tk_xxx
|
|
507
|
+
VIKUNJA_API_TOKEN_FILE=/run/secrets/vikunja_token
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Docker Swarm Example
|
|
511
|
+
|
|
512
|
+
Config file mounted as a `config` (non-sensitive), token mounted as a `secret`:
|
|
513
|
+
|
|
514
|
+
```yaml
|
|
515
|
+
version: "3.8"
|
|
516
|
+
|
|
517
|
+
services:
|
|
518
|
+
vikunja-mcp:
|
|
519
|
+
image: ghcr.io/netadvanced/vikunja-mcp-ng:latest
|
|
520
|
+
environment:
|
|
521
|
+
VIKUNJA_URL: "https://vikunja.example.com/api/v1"
|
|
522
|
+
VIKUNJA_API_TOKEN_FILE: /run/secrets/vikunja_api_token
|
|
523
|
+
VIKUNJA_MCP_CONFIG: /etc/vikunja-mcp/vikunja-mcp.config.json
|
|
524
|
+
configs:
|
|
525
|
+
- source: vikunja_mcp_config
|
|
526
|
+
target: /etc/vikunja-mcp/vikunja-mcp.config.json
|
|
527
|
+
mode: 0444
|
|
528
|
+
secrets:
|
|
529
|
+
- source: vikunja_api_token
|
|
530
|
+
target: vikunja_api_token
|
|
531
|
+
mode: 0400
|
|
532
|
+
|
|
533
|
+
configs:
|
|
534
|
+
vikunja_mcp_config:
|
|
535
|
+
file: ./vikunja-mcp.config.json
|
|
536
|
+
|
|
537
|
+
secrets:
|
|
538
|
+
vikunja_api_token:
|
|
539
|
+
file: ./secrets/vikunja_api_token.txt
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Deploy with:
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
docker swarm init # if not already a swarm manager
|
|
546
|
+
docker stack deploy -c docker-compose.yml vikunja-mcp
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
The token file (`./secrets/vikunja_api_token.txt`) should contain only the token,
|
|
550
|
+
optionally with a trailing newline — it will be trimmed automatically. It should never
|
|
551
|
+
be committed to source control; the config file (`./vikunja-mcp.config.json`) is safe to
|
|
552
|
+
commit since it contains no credentials.
|
|
553
|
+
|
|
554
|
+
## Environment Variables Reference
|
|
555
|
+
|
|
556
|
+
### Authentication Variables
|
|
557
|
+
```env
|
|
558
|
+
VIKUNJA_URL=https://vikunja.example.com
|
|
559
|
+
VIKUNJA_API_TOKEN=tk_your_token_here # or VIKUNJA_API_TOKEN_FILE=/path/to/token — see Secrets Management
|
|
560
|
+
MCP_MODE=server
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Config File Variable
|
|
564
|
+
```env
|
|
565
|
+
VIKUNJA_MCP_CONFIG=/path/to/vikunja-mcp.config.json # optional; see Config File
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Module Gating Variables
|
|
569
|
+
```env
|
|
570
|
+
VIKUNJA_MCP_MODULE_TASKS=true # see Module Gating for the full list and defaults
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Global Read-Only Mode Variable
|
|
574
|
+
```env
|
|
575
|
+
VIKUNJA_MCP_READ_ONLY=true # optional, default false; see Global Read-Only Safety Mode
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### Templates Persistence Variable
|
|
579
|
+
```env
|
|
580
|
+
VIKUNJA_MCP_TEMPLATES_FILE=/path/to/templates.json # optional; see Templates Persistence
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Logging Variables
|
|
584
|
+
```env
|
|
585
|
+
LOG_LEVEL=info # error, warn, info, debug
|
|
586
|
+
DEBUG=false # true/false
|
|
587
|
+
NODE_ENV=production # development, test, production
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Rate Limiting Variables
|
|
591
|
+
```env
|
|
592
|
+
# Global control
|
|
593
|
+
RATE_LIMIT_ENABLED=true
|
|
594
|
+
|
|
595
|
+
# Default tool limits
|
|
596
|
+
RATE_LIMIT_PER_MINUTE=60
|
|
597
|
+
RATE_LIMIT_PER_HOUR=1000
|
|
598
|
+
MAX_REQUEST_SIZE=1048576 # 1MB in bytes
|
|
599
|
+
MAX_RESPONSE_SIZE=10485760 # 10MB in bytes
|
|
600
|
+
TOOL_TIMEOUT=30000 # 30 seconds in milliseconds
|
|
601
|
+
|
|
602
|
+
# Expensive tool limits
|
|
603
|
+
EXPENSIVE_RATE_LIMIT_PER_MINUTE=10
|
|
604
|
+
EXPENSIVE_RATE_LIMIT_PER_HOUR=100
|
|
605
|
+
EXPENSIVE_MAX_REQUEST_SIZE=2097152
|
|
606
|
+
EXPENSIVE_MAX_RESPONSE_SIZE=52428800
|
|
607
|
+
EXPENSIVE_TOOL_TIMEOUT=120000
|
|
608
|
+
|
|
609
|
+
# Bulk operation limits
|
|
610
|
+
BULK_RATE_LIMIT_PER_MINUTE=5
|
|
611
|
+
BULK_RATE_LIMIT_PER_HOUR=50
|
|
612
|
+
BULK_MAX_REQUEST_SIZE=5242880
|
|
613
|
+
BULK_MAX_RESPONSE_SIZE=104857600
|
|
614
|
+
BULK_TOOL_TIMEOUT=300000
|
|
615
|
+
|
|
616
|
+
# Export operation limits
|
|
617
|
+
EXPORT_RATE_LIMIT_PER_MINUTE=2
|
|
618
|
+
EXPORT_RATE_LIMIT_PER_HOUR=10
|
|
619
|
+
EXPORT_MAX_REQUEST_SIZE=1048576
|
|
620
|
+
EXPORT_MAX_RESPONSE_SIZE=1073741824
|
|
621
|
+
EXPORT_TOOL_TIMEOUT=600000
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Feature Flag Variables
|
|
625
|
+
```env
|
|
626
|
+
VIKUNJA_ENABLE_SERVER_SIDE_FILTERING=true
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
## Usage Patterns
|
|
630
|
+
|
|
631
|
+
### Application Initialization
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import { ConfigurationManager, getConfiguration } from './config';
|
|
635
|
+
|
|
636
|
+
async function initializeApplication() {
|
|
637
|
+
try {
|
|
638
|
+
// Load and validate configuration early
|
|
639
|
+
const config = await getConfiguration();
|
|
640
|
+
|
|
641
|
+
// Use validated configuration
|
|
642
|
+
if (config.auth.vikunjaUrl && config.auth.vikunjaToken) {
|
|
643
|
+
await connectToVikunja(config.auth.vikunjaUrl, config.auth.vikunjaToken);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Configure components
|
|
647
|
+
const logger = await createLogger(config.logging);
|
|
648
|
+
const rateLimiter = await createRateLimiter(config.rateLimiting);
|
|
649
|
+
|
|
650
|
+
} catch (error) {
|
|
651
|
+
console.error('Configuration error:', error);
|
|
652
|
+
process.exit(1);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### Component Configuration
|
|
658
|
+
|
|
659
|
+
```typescript
|
|
660
|
+
// Before: Direct environment usage
|
|
661
|
+
export class RateLimitingMiddleware {
|
|
662
|
+
constructor() {
|
|
663
|
+
this.requestsPerMinute = parseInt(process.env.RATE_LIMIT_PER_MINUTE || '60', 10);
|
|
664
|
+
this.enabled = process.env.RATE_LIMIT_ENABLED !== 'false';
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// After: Configuration injection
|
|
669
|
+
export class RateLimitingMiddleware {
|
|
670
|
+
constructor(private config: RateLimitConfig) {
|
|
671
|
+
// Configuration already validated and typed
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
static async create(): Promise<RateLimitingMiddleware> {
|
|
675
|
+
const config = await getRateLimitConfig();
|
|
676
|
+
return new RateLimitingMiddleware(config);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Feature Flag Checks
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
// Simple boolean check
|
|
685
|
+
if (await isFeatureEnabled('enableServerSideFiltering')) {
|
|
686
|
+
return useServerSideStrategy();
|
|
687
|
+
} else {
|
|
688
|
+
return useClientSideStrategy();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Configuration-dependent logic
|
|
692
|
+
const featureFlags = await getFeatureFlagsConfig();
|
|
693
|
+
const strategy = featureFlags.enableServerSideFiltering ?
|
|
694
|
+
'server-side' : 'client-side';
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
## Testing with Configuration
|
|
698
|
+
|
|
699
|
+
### Test Configuration Injection
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
import { ConfigurationManager } from '../src/config';
|
|
703
|
+
|
|
704
|
+
describe('RateLimitingMiddleware', () => {
|
|
705
|
+
beforeEach(() => {
|
|
706
|
+
// Reset singleton for clean test state
|
|
707
|
+
ConfigurationManager.reset();
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
it('should respect custom rate limits', async () => {
|
|
711
|
+
// Inject test configuration
|
|
712
|
+
const manager = ConfigurationManager.getInstance({
|
|
713
|
+
sources: {
|
|
714
|
+
rateLimiting: {
|
|
715
|
+
enabled: true,
|
|
716
|
+
default: {
|
|
717
|
+
requestsPerMinute: 5, // Very low for testing
|
|
718
|
+
requestsPerHour: 50,
|
|
719
|
+
maxRequestSize: 1000,
|
|
720
|
+
maxResponseSize: 10000,
|
|
721
|
+
executionTimeout: 5000,
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
const config = await manager.getRateLimitConfig();
|
|
728
|
+
expect(config.default.requestsPerMinute).toBe(5);
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
### Environment-Specific Testing
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
// Test development profile behavior
|
|
737
|
+
it('should disable rate limiting in development', async () => {
|
|
738
|
+
const manager = ConfigurationManager.getInstance({
|
|
739
|
+
environment: Environment.DEVELOPMENT
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
const config = await manager.getRateLimitConfig();
|
|
743
|
+
expect(config.enabled).toBe(false);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
// Test validation errors
|
|
747
|
+
it('should reject invalid configuration', async () => {
|
|
748
|
+
const manager = ConfigurationManager.getInstance({
|
|
749
|
+
sources: {
|
|
750
|
+
rateLimiting: {
|
|
751
|
+
default: {
|
|
752
|
+
requestsPerMinute: -1 // Invalid negative value
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
await expect(manager.getConfiguration()).rejects.toThrow(ConfigurationError);
|
|
759
|
+
});
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
## Error Handling
|
|
763
|
+
|
|
764
|
+
### Configuration Errors
|
|
765
|
+
|
|
766
|
+
The system provides detailed validation errors:
|
|
767
|
+
|
|
768
|
+
```typescript
|
|
769
|
+
try {
|
|
770
|
+
const config = await getConfiguration();
|
|
771
|
+
} catch (error) {
|
|
772
|
+
if (error instanceof ConfigurationError) {
|
|
773
|
+
console.error('Configuration validation failed:');
|
|
774
|
+
console.error(`Field: ${error.field}`);
|
|
775
|
+
console.error(`Message: ${error.message}`);
|
|
776
|
+
console.error(`Value: ${error.value}`);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### Common Error Scenarios
|
|
782
|
+
|
|
783
|
+
1. **Invalid URL Format**
|
|
784
|
+
```
|
|
785
|
+
Configuration error in validation: Configuration validation failed:
|
|
786
|
+
- auth.vikunjaUrl: Invalid url
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
2. **Negative Rate Limits**
|
|
790
|
+
```
|
|
791
|
+
Configuration error in validation: Configuration validation failed:
|
|
792
|
+
- rateLimiting.default.requestsPerMinute: Number must be greater than 0
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
3. **Invalid Log Level**
|
|
796
|
+
```
|
|
797
|
+
Configuration error in validation: Configuration validation failed:
|
|
798
|
+
- logging.level: Invalid enum value. Expected 'error' | 'warn' | 'info' | 'debug', received 'verbose'
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
## Migration from Legacy Configuration
|
|
802
|
+
|
|
803
|
+
### Step 1: Update Imports
|
|
804
|
+
```typescript
|
|
805
|
+
// Before
|
|
806
|
+
const maxSize = parseInt(process.env.MAX_REQUEST_SIZE || '1048576', 10);
|
|
807
|
+
|
|
808
|
+
// After
|
|
809
|
+
import { getRateLimitConfig } from './config';
|
|
810
|
+
const config = await getRateLimitConfig();
|
|
811
|
+
const maxSize = config.default.maxRequestSize;
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
### Step 2: Handle Async Configuration
|
|
815
|
+
```typescript
|
|
816
|
+
// Before: Synchronous constructor
|
|
817
|
+
class Logger {
|
|
818
|
+
constructor() {
|
|
819
|
+
this.level = process.env.LOG_LEVEL || 'info';
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// After: Async factory
|
|
824
|
+
class Logger {
|
|
825
|
+
constructor(private config: LoggingConfig) {}
|
|
826
|
+
|
|
827
|
+
static async create(): Promise<Logger> {
|
|
828
|
+
const config = await getLoggingConfig();
|
|
829
|
+
return new Logger(config);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
### Step 3: Update Tests
|
|
835
|
+
```typescript
|
|
836
|
+
// Before: Environment manipulation
|
|
837
|
+
beforeEach(() => {
|
|
838
|
+
process.env.RATE_LIMIT_PER_MINUTE = '30';
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
// After: Configuration injection
|
|
842
|
+
beforeEach(() => {
|
|
843
|
+
ConfigurationManager.reset();
|
|
844
|
+
ConfigurationManager.getInstance({
|
|
845
|
+
sources: { rateLimiting: { default: { requestsPerMinute: 30 } } }
|
|
846
|
+
});
|
|
847
|
+
});
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
## Performance Considerations
|
|
851
|
+
|
|
852
|
+
### Configuration Caching
|
|
853
|
+
- Configuration is loaded once and cached per ConfigurationManager instance
|
|
854
|
+
- Subsequent calls to `getConfiguration()` return cached values
|
|
855
|
+
- Use `ConfigurationManager.reset()` to clear cache (testing only)
|
|
856
|
+
|
|
857
|
+
### Memory Usage
|
|
858
|
+
- Configuration schemas use minimal memory overhead
|
|
859
|
+
- Zod validation occurs only during initial load
|
|
860
|
+
- No performance impact on application runtime
|
|
861
|
+
|
|
862
|
+
### Startup Performance
|
|
863
|
+
- Configuration loading adds ~1-5ms to application startup
|
|
864
|
+
- All validation errors are caught early in startup process
|
|
865
|
+
- Async loading prevents blocking main application logic
|
|
866
|
+
|
|
867
|
+
## Best Practices
|
|
868
|
+
|
|
869
|
+
### 1. Load Configuration Early
|
|
870
|
+
```typescript
|
|
871
|
+
// Good: Load configuration at application startup
|
|
872
|
+
async function main() {
|
|
873
|
+
const config = await getConfiguration();
|
|
874
|
+
// Initialize components with configuration
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Avoid: Loading configuration in hot paths
|
|
878
|
+
async function handleRequest() {
|
|
879
|
+
const config = await getConfiguration(); // Cache hit, but still async
|
|
880
|
+
// Handle request
|
|
881
|
+
}
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
### 2. Use Type-Safe Configuration
|
|
885
|
+
```typescript
|
|
886
|
+
// Good: Use typed configuration sections
|
|
887
|
+
const rateLimits = await getRateLimitConfig();
|
|
888
|
+
const limit = rateLimits.default.requestsPerMinute; // TypeScript knows this is number
|
|
889
|
+
|
|
890
|
+
// Avoid: Accessing nested properties without types
|
|
891
|
+
const config = await getConfiguration();
|
|
892
|
+
const limit = (config as any).rateLimiting.default.requestsPerMinute;
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
### 3. Handle Configuration Errors Gracefully
|
|
896
|
+
```typescript
|
|
897
|
+
// Good: Specific error handling
|
|
898
|
+
try {
|
|
899
|
+
const config = await getConfiguration();
|
|
900
|
+
} catch (error) {
|
|
901
|
+
if (error instanceof ConfigurationError) {
|
|
902
|
+
logger.error('Configuration validation failed', { error: error.message });
|
|
903
|
+
process.exit(1);
|
|
904
|
+
}
|
|
905
|
+
throw error; // Re-throw unexpected errors
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// Avoid: Generic error handling
|
|
909
|
+
try {
|
|
910
|
+
const config = await getConfiguration();
|
|
911
|
+
} catch (error) {
|
|
912
|
+
console.error('Something went wrong:', error);
|
|
913
|
+
}
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
### 4. Test with Configuration Injection
|
|
917
|
+
```typescript
|
|
918
|
+
// Good: Inject test configuration
|
|
919
|
+
const testManager = ConfigurationManager.getInstance({
|
|
920
|
+
sources: { /* test configuration */ }
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// Avoid: Manipulating process.env in tests
|
|
924
|
+
process.env.RATE_LIMIT_PER_MINUTE = '30';
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
## Troubleshooting
|
|
928
|
+
|
|
929
|
+
### Common Issues
|
|
930
|
+
|
|
931
|
+
1. **Configuration Not Loading**
|
|
932
|
+
- Check that `getConfiguration()` is awaited
|
|
933
|
+
- Verify environment variables are set correctly
|
|
934
|
+
- Check for validation errors in logs
|
|
935
|
+
|
|
936
|
+
2. **Environment Variables Not Recognized**
|
|
937
|
+
- Verify variable names match `.env.example`
|
|
938
|
+
- Check for typos in environment variable names
|
|
939
|
+
- Ensure values are in correct format (numbers, booleans)
|
|
940
|
+
|
|
941
|
+
3. **Test Failures After Migration**
|
|
942
|
+
- Reset ConfigurationManager in test setup
|
|
943
|
+
- Replace environment manipulation with configuration injection
|
|
944
|
+
- Update mocks to use new configuration patterns
|
|
945
|
+
|
|
946
|
+
### Debug Configuration Loading
|
|
947
|
+
|
|
948
|
+
```typescript
|
|
949
|
+
// Enable detailed configuration logging
|
|
950
|
+
const config = await ConfigurationManager.getInstance({
|
|
951
|
+
sources: { logging: { level: 'debug' } }
|
|
952
|
+
}).getConfiguration();
|
|
953
|
+
|
|
954
|
+
// Configuration loading details will be logged
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
This centralized configuration system eliminates the 57 hours of technical debt from environment variable sprawl while providing type safety, better testing capabilities, and improved developer experience.
|