memory-journal-mcp 8.0.1 → 9.1.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/README.md +278 -353
- package/dist/audit/audit-logger.d.ts +89 -0
- package/dist/audit/audit-logger.d.ts.map +1 -0
- package/dist/audit/audit-resource.d.ts +28 -0
- package/dist/audit/audit-resource.d.ts.map +1 -0
- package/dist/audit/index.d.ts +12 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/interceptor.d.ts +44 -0
- package/dist/audit/interceptor.d.ts.map +1 -0
- package/dist/audit/types.d.ts +68 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/auth/auth-context.d.ts +42 -0
- package/dist/auth/auth-context.d.ts.map +1 -0
- package/dist/auth/authorization-server-discovery.d.ts +90 -0
- package/dist/auth/authorization-server-discovery.d.ts.map +1 -0
- package/dist/auth/errors.d.ts +90 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/index.d.ts +16 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/middleware.d.ts +77 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/oauth-resource-server.d.ts +73 -0
- package/dist/auth/oauth-resource-server.d.ts.map +1 -0
- package/dist/auth/scope-map.d.ts +14 -0
- package/dist/auth/scope-map.d.ts.map +1 -0
- package/dist/auth/scopes.d.ts +112 -0
- package/dist/auth/scopes.d.ts.map +1 -0
- package/dist/auth/token-validator.d.ts +64 -0
- package/dist/auth/token-validator.d.ts.map +1 -0
- package/dist/auth/transport-agnostic.d.ts +47 -0
- package/dist/auth/transport-agnostic.d.ts.map +1 -0
- package/dist/auth/types.d.ts +256 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/validation.d.ts +15 -0
- package/dist/auth/validation.d.ts.map +1 -0
- package/dist/chunk-4FZCHFB5.js +216 -0
- package/dist/chunk-D2FY6XS5.js +313 -0
- package/dist/chunk-E6IQP6PE.js +252 -0
- package/dist/chunk-FZLB6NAV.js +746 -0
- package/dist/chunk-LE6ZWUPK.js +2667 -0
- package/dist/chunk-SGJU2DHU.js +2102 -0
- package/dist/chunk-T7SROBBV.js +34066 -0
- package/dist/chunk-Y6MMKR2Z.js +3766 -0
- package/dist/cli/commands/admin.d.ts +123 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/analytics.d.ts +21 -0
- package/dist/cli/commands/analytics.d.ts.map +1 -0
- package/dist/cli/commands/entry-payload.d.ts +38 -0
- package/dist/cli/commands/entry-payload.d.ts.map +1 -0
- package/dist/cli/commands/entry.d.ts +130 -0
- package/dist/cli/commands/entry.d.ts.map +1 -0
- package/dist/cli/commands/exec.d.ts +31 -0
- package/dist/cli/commands/exec.d.ts.map +1 -0
- package/dist/cli/commands/io.d.ts +76 -0
- package/dist/cli/commands/io.d.ts.map +1 -0
- package/dist/cli/commands/project.d.ts +6 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/search.d.ts +30 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/serve.d.ts +84 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/visualize.d.ts +20 -0
- package/dist/cli/commands/visualize.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +9 -0
- package/dist/cli/option-groups.d.ts +18 -0
- package/dist/cli/option-groups.d.ts.map +1 -0
- package/dist/cli/program.d.ts +7 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/schemas.d.ts +648 -0
- package/dist/cli/schemas.d.ts.map +1 -0
- package/dist/cli/server-options-builder.d.ts +13 -0
- package/dist/cli/server-options-builder.d.ts.map +1 -0
- package/dist/cli.js +9 -433
- package/dist/codemode/api/git-api.d.ts +9 -0
- package/dist/codemode/api/git-api.d.ts.map +1 -0
- package/dist/codemode/api/group-factory.d.ts +30 -0
- package/dist/codemode/api/group-factory.d.ts.map +1 -0
- package/dist/codemode/api/index.d.ts +10 -0
- package/dist/codemode/api/index.d.ts.map +1 -0
- package/dist/codemode/api/journal-api.d.ts +39 -0
- package/dist/codemode/api/journal-api.d.ts.map +1 -0
- package/dist/codemode/api/key-normalizer.d.ts +8 -0
- package/dist/codemode/api/key-normalizer.d.ts.map +1 -0
- package/dist/codemode/api/param-normalizer.d.ts +15 -0
- package/dist/codemode/api/param-normalizer.d.ts.map +1 -0
- package/dist/codemode/api/project-registry-ops.d.ts +26 -0
- package/dist/codemode/api/project-registry-ops.d.ts.map +1 -0
- package/dist/codemode/api/sandbox-bindings.d.ts +25 -0
- package/dist/codemode/api/sandbox-bindings.d.ts.map +1 -0
- package/dist/codemode/api/types.d.ts +21 -0
- package/dist/codemode/api/types.d.ts.map +1 -0
- package/dist/codemode/api-constants.d.ts +6 -0
- package/dist/codemode/api-constants.d.ts.map +1 -0
- package/dist/codemode/auto-return.d.ts +25 -0
- package/dist/codemode/auto-return.d.ts.map +1 -0
- package/dist/codemode/constants/examples-and-params.d.ts +31 -0
- package/dist/codemode/constants/examples-and-params.d.ts.map +1 -0
- package/dist/codemode/constants/method-aliases.d.ts +8 -0
- package/dist/codemode/constants/method-aliases.d.ts.map +1 -0
- package/dist/codemode/index.d.ts +12 -0
- package/dist/codemode/index.d.ts.map +1 -0
- package/dist/codemode/normalizers/domain-tool-interceptions.d.ts +6 -0
- package/dist/codemode/normalizers/domain-tool-interceptions.d.ts.map +1 -0
- package/dist/codemode/normalizers/entry-and-search-interceptions.d.ts +6 -0
- package/dist/codemode/normalizers/entry-and-search-interceptions.d.ts.map +1 -0
- package/dist/codemode/normalizers/generic-interceptions.d.ts +6 -0
- package/dist/codemode/normalizers/generic-interceptions.d.ts.map +1 -0
- package/dist/codemode/normalizers/github-and-backup-interceptions.d.ts +6 -0
- package/dist/codemode/normalizers/github-and-backup-interceptions.d.ts.map +1 -0
- package/dist/codemode/normalizers/shared-utils.d.ts +31 -0
- package/dist/codemode/normalizers/shared-utils.d.ts.map +1 -0
- package/dist/codemode/param-normalizer.d.ts +11 -0
- package/dist/codemode/param-normalizer.d.ts.map +1 -0
- package/dist/codemode/proxy-helpers.d.ts +34 -0
- package/dist/codemode/proxy-helpers.d.ts.map +1 -0
- package/dist/codemode/proxy-namespaces.d.ts +30 -0
- package/dist/codemode/proxy-namespaces.d.ts.map +1 -0
- package/dist/codemode/sandbox-factory.d.ts +52 -0
- package/dist/codemode/sandbox-factory.d.ts.map +1 -0
- package/dist/codemode/security.d.ts +54 -0
- package/dist/codemode/security.d.ts.map +1 -0
- package/dist/codemode/type-generator.d.ts +11 -0
- package/dist/codemode/type-generator.d.ts.map +1 -0
- package/dist/codemode/types.d.ts +165 -0
- package/dist/codemode/types.d.ts.map +1 -0
- package/dist/codemode/worker/mj-shim-domains.d.ts +15 -0
- package/dist/codemode/worker/mj-shim-domains.d.ts.map +1 -0
- package/dist/codemode/worker/mj-shim-proxy.d.ts +18 -0
- package/dist/codemode/worker/mj-shim-proxy.d.ts.map +1 -0
- package/dist/codemode/worker/namespace-shims.d.ts +32 -0
- package/dist/codemode/worker/namespace-shims.d.ts.map +1 -0
- package/dist/codemode/worker/node-shims.d.ts +65 -0
- package/dist/codemode/worker/node-shims.d.ts.map +1 -0
- package/dist/codemode/worker/prototype-hardening.d.ts +18 -0
- package/dist/codemode/worker/prototype-hardening.d.ts.map +1 -0
- package/dist/codemode/worker/result-compactor.d.ts +20 -0
- package/dist/codemode/worker/result-compactor.d.ts.map +1 -0
- package/dist/codemode/worker/sandbox-globals.d.ts +19 -0
- package/dist/codemode/worker/sandbox-globals.d.ts.map +1 -0
- package/dist/codemode/worker-api-proxy.d.ts +12 -0
- package/dist/codemode/worker-api-proxy.d.ts.map +1 -0
- package/dist/codemode/worker-result-proxy.d.ts +12 -0
- package/dist/codemode/worker-result-proxy.d.ts.map +1 -0
- package/dist/codemode/worker-sandbox.d.ts +58 -0
- package/dist/codemode/worker-sandbox.d.ts.map +1 -0
- package/dist/codemode/worker-script.d.ts +9 -0
- package/dist/codemode/worker-script.d.ts.map +1 -0
- package/dist/constants/icons.d.ts +58 -0
- package/dist/constants/icons.d.ts.map +1 -0
- package/dist/constants/instructions/admin.d.ts +2 -0
- package/dist/constants/instructions/admin.d.ts.map +1 -0
- package/dist/constants/instructions/analytics.d.ts +2 -0
- package/dist/constants/instructions/analytics.d.ts.map +1 -0
- package/dist/constants/instructions/backup.d.ts +2 -0
- package/dist/constants/instructions/backup.d.ts.map +1 -0
- package/dist/constants/instructions/base.d.ts +3 -0
- package/dist/constants/instructions/base.d.ts.map +1 -0
- package/dist/constants/instructions/codemode.d.ts +2 -0
- package/dist/constants/instructions/codemode.d.ts.map +1 -0
- package/dist/constants/instructions/core.d.ts +2 -0
- package/dist/constants/instructions/core.d.ts.map +1 -0
- package/dist/constants/instructions/git.d.ts +2 -0
- package/dist/constants/instructions/git.d.ts.map +1 -0
- package/dist/constants/instructions/github.d.ts +2 -0
- package/dist/constants/instructions/github.d.ts.map +1 -0
- package/dist/constants/instructions/gotchas.d.ts +2 -0
- package/dist/constants/instructions/gotchas.d.ts.map +1 -0
- package/dist/constants/instructions/io.d.ts +2 -0
- package/dist/constants/instructions/io.d.ts.map +1 -0
- package/dist/constants/instructions/relationships.d.ts +2 -0
- package/dist/constants/instructions/relationships.d.ts.map +1 -0
- package/dist/constants/instructions/search.d.ts +2 -0
- package/dist/constants/instructions/search.d.ts.map +1 -0
- package/dist/constants/instructions/team.d.ts +2 -0
- package/dist/constants/instructions/team.d.ts.map +1 -0
- package/dist/constants/instructions/templates.d.ts +2 -0
- package/dist/constants/instructions/templates.d.ts.map +1 -0
- package/dist/constants/server-instructions.d.ts +64 -0
- package/dist/constants/server-instructions.d.ts.map +1 -0
- package/dist/database/adapter-factory.d.ts +9 -0
- package/dist/database/adapter-factory.d.ts.map +1 -0
- package/dist/database/core/DatabaseAdapterProxy.d.ts +5 -0
- package/dist/database/core/DatabaseAdapterProxy.d.ts.map +1 -0
- package/dist/database/core/interfaces.d.ts +455 -0
- package/dist/database/core/interfaces.d.ts.map +1 -0
- package/dist/database/migrations/001-init.d.ts +3 -0
- package/dist/database/migrations/001-init.d.ts.map +1 -0
- package/dist/database/migrations/002-add-significance-and-context.d.ts +3 -0
- package/dist/database/migrations/002-add-significance-and-context.d.ts.map +1 -0
- package/dist/database/migrations/003-add-deleted-and-archived.d.ts +3 -0
- package/dist/database/migrations/003-add-deleted-and-archived.d.ts.map +1 -0
- package/dist/database/migrations/004-add-github-and-workflow-integration.d.ts +3 -0
- package/dist/database/migrations/004-add-github-and-workflow-integration.d.ts.map +1 -0
- package/dist/database/migrations/005-add-entry-revisions.d.ts +3 -0
- package/dist/database/migrations/005-add-entry-revisions.d.ts.map +1 -0
- package/dist/database/migrations/006-add-analytics-snapshots.d.ts +3 -0
- package/dist/database/migrations/006-add-analytics-snapshots.d.ts.map +1 -0
- package/dist/database/migrations/007-add-team-author.d.ts +3 -0
- package/dist/database/migrations/007-add-team-author.d.ts.map +1 -0
- package/dist/database/migrations/008-add-team-members.d.ts +3 -0
- package/dist/database/migrations/008-add-team-members.d.ts.map +1 -0
- package/dist/database/migrations/009-add-entry-version.d.ts +3 -0
- package/dist/database/migrations/009-add-entry-version.d.ts.map +1 -0
- package/dist/database/migrations/010-add-author-aliases.d.ts +3 -0
- package/dist/database/migrations/010-add-author-aliases.d.ts.map +1 -0
- package/dist/database/migrations/011-add-workspace-id.d.ts +3 -0
- package/dist/database/migrations/011-add-workspace-id.d.ts.map +1 -0
- package/dist/database/migrations/012-add-trust-and-anchors.d.ts +3 -0
- package/dist/database/migrations/012-add-trust-and-anchors.d.ts.map +1 -0
- package/dist/database/migrations/013-add-session-id.d.ts +3 -0
- package/dist/database/migrations/013-add-session-id.d.ts.map +1 -0
- package/dist/database/migrations/migration-list.d.ts +3 -0
- package/dist/database/migrations/migration-list.d.ts.map +1 -0
- package/dist/database/migrations/migration-manager.d.ts +14 -0
- package/dist/database/migrations/migration-manager.d.ts.map +1 -0
- package/dist/database/migrations/migration.d.ts +23 -0
- package/dist/database/migrations/migration.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/adapter-delegates.d.ts +161 -0
- package/dist/database/sqlite-adapter/adapter-delegates.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/aliases.d.ts +14 -0
- package/dist/database/sqlite-adapter/aliases.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/backup.d.ts +27 -0
- package/dist/database/sqlite-adapter/backup.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/database-adapter.d.ts +192 -0
- package/dist/database/sqlite-adapter/database-adapter.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/anchors.d.ts +9 -0
- package/dist/database/sqlite-adapter/entries/anchors.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/crud-read.d.ts +16 -0
- package/dist/database/sqlite-adapter/entries/crud-read.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/crud-write.d.ts +62 -0
- package/dist/database/sqlite-adapter/entries/crud-write.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/crud.d.ts +4 -0
- package/dist/database/sqlite-adapter/entries/crud.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/digest.d.ts +60 -0
- package/dist/database/sqlite-adapter/entries/digest.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/fuzzy-matcher.d.ts +27 -0
- package/dist/database/sqlite-adapter/entries/fuzzy-matcher.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/importance.d.ts +38 -0
- package/dist/database/sqlite-adapter/entries/importance.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/index.d.ts +186 -0
- package/dist/database/sqlite-adapter/entries/index.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/revisions.d.ts +16 -0
- package/dist/database/sqlite-adapter/entries/revisions.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/search/cursor.d.ts +15 -0
- package/dist/database/sqlite-adapter/entries/search/cursor.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/search/date-and-pagination.d.ts +37 -0
- package/dist/database/sqlite-adapter/entries/search/date-and-pagination.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/search/entity-lookups.d.ts +31 -0
- package/dist/database/sqlite-adapter/entries/search/entity-lookups.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/search/fts-and-hybrid.d.ts +44 -0
- package/dist/database/sqlite-adapter/entries/search/fts-and-hybrid.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/search/fts-sanitizer.d.ts +15 -0
- package/dist/database/sqlite-adapter/entries/search/fts-sanitizer.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/search/index.d.ts +8 -0
- package/dist/database/sqlite-adapter/entries/search/index.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/search/query.d.ts +4 -0
- package/dist/database/sqlite-adapter/entries/search/query.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/shared.d.ts +39 -0
- package/dist/database/sqlite-adapter/entries/shared.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/entries/statistics.d.ts +3 -0
- package/dist/database/sqlite-adapter/entries/statistics.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/health-operations.d.ts +10 -0
- package/dist/database/sqlite-adapter/health-operations.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/index.d.ts +2 -0
- package/dist/database/sqlite-adapter/index.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/insights/cross-project.d.ts +42 -0
- package/dist/database/sqlite-adapter/insights/cross-project.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/insights/entry-digest-queries.d.ts +17 -0
- package/dist/database/sqlite-adapter/insights/entry-digest-queries.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/insights/team-collaboration.d.ts +29 -0
- package/dist/database/sqlite-adapter/insights/team-collaboration.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/insights-operations.d.ts +47 -0
- package/dist/database/sqlite-adapter/insights-operations.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/lifecycle-operations.d.ts +32 -0
- package/dist/database/sqlite-adapter/lifecycle-operations.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/members.d.ts +23 -0
- package/dist/database/sqlite-adapter/members.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/native-connection.d.ts +46 -0
- package/dist/database/sqlite-adapter/native-connection.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/relationships.d.ts +26 -0
- package/dist/database/sqlite-adapter/relationships.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/tags.d.ts +16 -0
- package/dist/database/sqlite-adapter/tags.d.ts.map +1 -0
- package/dist/database/sqlite-adapter/vector-operations.d.ts +24 -0
- package/dist/database/sqlite-adapter/vector-operations.d.ts.map +1 -0
- package/dist/errors-MHAM6AKR.js +1 -0
- package/dist/filtering/tool-constants.d.ts +33 -0
- package/dist/filtering/tool-constants.d.ts.map +1 -0
- package/dist/filtering/tool-filter.d.ts +65 -0
- package/dist/filtering/tool-filter.d.ts.map +1 -0
- package/dist/fts-YHUVPPYF.js +2 -0
- package/dist/github/commit-references/enricher.d.ts +12 -0
- package/dist/github/commit-references/enricher.d.ts.map +1 -0
- package/dist/github/commit-references/index.d.ts +4 -0
- package/dist/github/commit-references/index.d.ts.map +1 -0
- package/dist/github/commit-references/parser.d.ts +10 -0
- package/dist/github/commit-references/parser.d.ts.map +1 -0
- package/dist/github/commit-references/resolver.d.ts +14 -0
- package/dist/github/commit-references/resolver.d.ts.map +1 -0
- package/dist/github/github-integration/client.d.ts +29 -0
- package/dist/github/github-integration/client.d.ts.map +1 -0
- package/dist/github/github-integration/index.d.ts +83 -0
- package/dist/github/github-integration/index.d.ts.map +1 -0
- package/dist/github/github-integration/insights.d.ts +11 -0
- package/dist/github/github-integration/insights.d.ts.map +1 -0
- package/dist/github/github-integration/issues.d.ts +25 -0
- package/dist/github/github-integration/issues.d.ts.map +1 -0
- package/dist/github/github-integration/milestones.d.ts +20 -0
- package/dist/github/github-integration/milestones.d.ts.map +1 -0
- package/dist/github/github-integration/projects.d.ts +21 -0
- package/dist/github/github-integration/projects.d.ts.map +1 -0
- package/dist/github/github-integration/pull-requests.d.ts +16 -0
- package/dist/github/github-integration/pull-requests.d.ts.map +1 -0
- package/dist/github/github-integration/repository.d.ts +14 -0
- package/dist/github/github-integration/repository.d.ts.map +1 -0
- package/dist/github/github-integration/types.d.ts +77 -0
- package/dist/github/github-integration/types.d.ts.map +1 -0
- package/dist/handlers/prompts/adversarial-helpers.d.ts +75 -0
- package/dist/handlers/prompts/adversarial-helpers.d.ts.map +1 -0
- package/dist/handlers/prompts/adversarial.d.ts +13 -0
- package/dist/handlers/prompts/adversarial.d.ts.map +1 -0
- package/dist/handlers/prompts/analytics.d.ts +12 -0
- package/dist/handlers/prompts/analytics.d.ts.map +1 -0
- package/dist/handlers/prompts/cms-supervisor.d.ts +8 -0
- package/dist/handlers/prompts/cms-supervisor.d.ts.map +1 -0
- package/dist/handlers/prompts/git.d.ts +8 -0
- package/dist/handlers/prompts/git.d.ts.map +1 -0
- package/dist/handlers/prompts/github.d.ts +12 -0
- package/dist/handlers/prompts/github.d.ts.map +1 -0
- package/dist/handlers/prompts/index.d.ts +53 -0
- package/dist/handlers/prompts/index.d.ts.map +1 -0
- package/dist/handlers/prompts/load-briefing.d.ts +3 -0
- package/dist/handlers/prompts/load-briefing.d.ts.map +1 -0
- package/dist/handlers/prompts/optimizer.d.ts +8 -0
- package/dist/handlers/prompts/optimizer.d.ts.map +1 -0
- package/dist/handlers/prompts/workflow.d.ts +15 -0
- package/dist/handlers/prompts/workflow.d.ts.map +1 -0
- package/dist/handlers/resources/core/agent-context.d.ts +4 -0
- package/dist/handlers/resources/core/agent-context.d.ts.map +1 -0
- package/dist/handlers/resources/core/briefing/context-section.d.ts +57 -0
- package/dist/handlers/resources/core/briefing/context-section.d.ts.map +1 -0
- package/dist/handlers/resources/core/briefing/github-repo-and-kanban.d.ts +57 -0
- package/dist/handlers/resources/core/briefing/github-repo-and-kanban.d.ts.map +1 -0
- package/dist/handlers/resources/core/briefing/github-section.d.ts +88 -0
- package/dist/handlers/resources/core/briefing/github-section.d.ts.map +1 -0
- package/dist/handlers/resources/core/briefing/index.d.ts +11 -0
- package/dist/handlers/resources/core/briefing/index.d.ts.map +1 -0
- package/dist/handlers/resources/core/briefing/insights-section.d.ts +35 -0
- package/dist/handlers/resources/core/briefing/insights-section.d.ts.map +1 -0
- package/dist/handlers/resources/core/briefing/system-section.d.ts +85 -0
- package/dist/handlers/resources/core/briefing/system-section.d.ts.map +1 -0
- package/dist/handlers/resources/core/briefing/user-message.d.ts +46 -0
- package/dist/handlers/resources/core/briefing/user-message.d.ts.map +1 -0
- package/dist/handlers/resources/core/health.d.ts +3 -0
- package/dist/handlers/resources/core/health.d.ts.map +1 -0
- package/dist/handlers/resources/core/index.d.ts +6 -0
- package/dist/handlers/resources/core/index.d.ts.map +1 -0
- package/dist/handlers/resources/core/instructions.d.ts +3 -0
- package/dist/handlers/resources/core/instructions.d.ts.map +1 -0
- package/dist/handlers/resources/core/metrics-resource.d.ts +23 -0
- package/dist/handlers/resources/core/metrics-resource.d.ts.map +1 -0
- package/dist/handlers/resources/core/utilities.d.ts +7 -0
- package/dist/handlers/resources/core/utilities.d.ts.map +1 -0
- package/dist/handlers/resources/github.d.ts +11 -0
- package/dist/handlers/resources/github.d.ts.map +1 -0
- package/dist/handlers/resources/graph.d.ts +12 -0
- package/dist/handlers/resources/graph.d.ts.map +1 -0
- package/dist/handlers/resources/help.d.ts +39 -0
- package/dist/handlers/resources/help.d.ts.map +1 -0
- package/dist/handlers/resources/index.d.ts +37 -0
- package/dist/handlers/resources/index.d.ts.map +1 -0
- package/dist/handlers/resources/insights.d.ts +16 -0
- package/dist/handlers/resources/insights.d.ts.map +1 -0
- package/dist/handlers/resources/shared.d.ts +136 -0
- package/dist/handlers/resources/shared.d.ts.map +1 -0
- package/dist/handlers/resources/staleness.d.ts +3 -0
- package/dist/handlers/resources/staleness.d.ts.map +1 -0
- package/dist/handlers/resources/team.d.ts +6 -0
- package/dist/handlers/resources/team.d.ts.map +1 -0
- package/dist/handlers/resources/templates.d.ts +13 -0
- package/dist/handlers/resources/templates.d.ts.map +1 -0
- package/dist/handlers/resources/tools-catalog.d.ts +3 -0
- package/dist/handlers/resources/tools-catalog.d.ts.map +1 -0
- package/dist/handlers/tools/admin/batch-tools.d.ts +3 -0
- package/dist/handlers/tools/admin/batch-tools.d.ts.map +1 -0
- package/dist/handlers/tools/admin/core-tools.d.ts +3 -0
- package/dist/handlers/tools/admin/core-tools.d.ts.map +1 -0
- package/dist/handlers/tools/admin/index.d.ts +3 -0
- package/dist/handlers/tools/admin/index.d.ts.map +1 -0
- package/dist/handlers/tools/admin/lifecycle-tools.d.ts +3 -0
- package/dist/handlers/tools/admin/lifecycle-tools.d.ts.map +1 -0
- package/dist/handlers/tools/admin/misc-tools.d.ts +3 -0
- package/dist/handlers/tools/admin/misc-tools.d.ts.map +1 -0
- package/dist/handlers/tools/admin/project-tools.d.ts +3 -0
- package/dist/handlers/tools/admin/project-tools.d.ts.map +1 -0
- package/dist/handlers/tools/admin/schemas/crud-batch-schemas.d.ts +609 -0
- package/dist/handlers/tools/admin/schemas/crud-batch-schemas.d.ts.map +1 -0
- package/dist/handlers/tools/admin/schemas/project-and-ops-schemas.d.ts +136 -0
- package/dist/handlers/tools/admin/schemas/project-and-ops-schemas.d.ts.map +1 -0
- package/dist/handlers/tools/admin/schemas.d.ts +3 -0
- package/dist/handlers/tools/admin/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/admin/update_configuration.d.ts +36 -0
- package/dist/handlers/tools/admin/update_configuration.d.ts.map +1 -0
- package/dist/handlers/tools/admin/vector-tools.d.ts +3 -0
- package/dist/handlers/tools/admin/vector-tools.d.ts.map +1 -0
- package/dist/handlers/tools/analytics.d.ts +8 -0
- package/dist/handlers/tools/analytics.d.ts.map +1 -0
- package/dist/handlers/tools/arg-interceptions.d.ts +51 -0
- package/dist/handlers/tools/arg-interceptions.d.ts.map +1 -0
- package/dist/handlers/tools/backup.d.ts +8 -0
- package/dist/handlers/tools/backup.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/code-healer.d.ts +11 -0
- package/dist/handlers/tools/codemode/code-healer.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/handler.d.ts +7 -0
- package/dist/handlers/tools/codemode/handler.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/index.d.ts +2 -0
- package/dist/handlers/tools/codemode/index.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/json-entry-recovery.d.ts +13 -0
- package/dist/handlers/tools/codemode/json-entry-recovery.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/payload-synthesizer.d.ts +17 -0
- package/dist/handlers/tools/codemode/payload-synthesizer.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/schemas.d.ts +77 -0
- package/dist/handlers/tools/codemode/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/secure-dispatcher.d.ts +25 -0
- package/dist/handlers/tools/codemode/secure-dispatcher.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/singleton-state.d.ts +11 -0
- package/dist/handlers/tools/codemode/singleton-state.d.ts.map +1 -0
- package/dist/handlers/tools/codemode/sql-recovery.d.ts +14 -0
- package/dist/handlers/tools/codemode/sql-recovery.d.ts.map +1 -0
- package/dist/handlers/tools/core/dummy-healing/alias-catalog.d.ts +21 -0
- package/dist/handlers/tools/core/dummy-healing/alias-catalog.d.ts.map +1 -0
- package/dist/handlers/tools/core/dummy-healing/entry-fallbacks.d.ts +4 -0
- package/dist/handlers/tools/core/dummy-healing/entry-fallbacks.d.ts.map +1 -0
- package/dist/handlers/tools/core/dummy-healing/fs-fallbacks.d.ts +19 -0
- package/dist/handlers/tools/core/dummy-healing/fs-fallbacks.d.ts.map +1 -0
- package/dist/handlers/tools/core/dummy-healing/index.d.ts +7 -0
- package/dist/handlers/tools/core/dummy-healing/index.d.ts.map +1 -0
- package/dist/handlers/tools/core/dummy-healing/mcp-fallbacks.d.ts +12 -0
- package/dist/handlers/tools/core/dummy-healing/mcp-fallbacks.d.ts.map +1 -0
- package/dist/handlers/tools/core/dummy-healing.d.ts +2 -0
- package/dist/handlers/tools/core/dummy-healing.d.ts.map +1 -0
- package/dist/handlers/tools/core/index.d.ts +5 -0
- package/dist/handlers/tools/core/index.d.ts.map +1 -0
- package/dist/handlers/tools/core/schemas.d.ts +417 -0
- package/dist/handlers/tools/core/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/core/staleness-tools.d.ts +33 -0
- package/dist/handlers/tools/core/staleness-tools.d.ts.map +1 -0
- package/dist/handlers/tools/core/tools.d.ts +3 -0
- package/dist/handlers/tools/core/tools.d.ts.map +1 -0
- package/dist/handlers/tools/error-fields-mixin.d.ts +10 -0
- package/dist/handlers/tools/error-fields-mixin.d.ts.map +1 -0
- package/dist/handlers/tools/git.d.ts +62 -0
- package/dist/handlers/tools/git.d.ts.map +1 -0
- package/dist/handlers/tools/github/close-issue-tool.d.ts +6 -0
- package/dist/handlers/tools/github/close-issue-tool.d.ts.map +1 -0
- package/dist/handlers/tools/github/copilot-tools.d.ts +8 -0
- package/dist/handlers/tools/github/copilot-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/create-issue-tool.d.ts +6 -0
- package/dist/handlers/tools/github/create-issue-tool.d.ts.map +1 -0
- package/dist/handlers/tools/github/helpers.d.ts +38 -0
- package/dist/handlers/tools/github/helpers.d.ts.map +1 -0
- package/dist/handlers/tools/github/insights-tools.d.ts +8 -0
- package/dist/handlers/tools/github/insights-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/issue-tools.d.ts +11 -0
- package/dist/handlers/tools/github/issue-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/kanban-tools.d.ts +8 -0
- package/dist/handlers/tools/github/kanban-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/milestone-tools.d.ts +9 -0
- package/dist/handlers/tools/github/milestone-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/mutation-tools.d.ts +12 -0
- package/dist/handlers/tools/github/mutation-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/read-tools.d.ts +8 -0
- package/dist/handlers/tools/github/read-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/schemas.d.ts +823 -0
- package/dist/handlers/tools/github/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/github.d.ts +15 -0
- package/dist/handlers/tools/github.d.ts.map +1 -0
- package/dist/handlers/tools/index.d.ts +29 -0
- package/dist/handlers/tools/index.d.ts.map +1 -0
- package/dist/handlers/tools/io/index.d.ts +2 -0
- package/dist/handlers/tools/io/index.d.ts.map +1 -0
- package/dist/handlers/tools/io/schemas.d.ts +291 -0
- package/dist/handlers/tools/io/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/io/tools.d.ts +3 -0
- package/dist/handlers/tools/io/tools.d.ts.map +1 -0
- package/dist/handlers/tools/relationships.d.ts +8 -0
- package/dist/handlers/tools/relationships.d.ts.map +1 -0
- package/dist/handlers/tools/schemas/constants-and-primitives.d.ts +53 -0
- package/dist/handlers/tools/schemas/constants-and-primitives.d.ts.map +1 -0
- package/dist/handlers/tools/schemas/hallucination-healer.d.ts +8 -0
- package/dist/handlers/tools/schemas/hallucination-healer.d.ts.map +1 -0
- package/dist/handlers/tools/schemas/output-schemas.d.ts +247 -0
- package/dist/handlers/tools/schemas/output-schemas.d.ts.map +1 -0
- package/dist/handlers/tools/schemas.d.ts +7 -0
- package/dist/handlers/tools/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/search/auto.d.ts +38 -0
- package/dist/handlers/tools/search/auto.d.ts.map +1 -0
- package/dist/handlers/tools/search/cross-team.d.ts +132 -0
- package/dist/handlers/tools/search/cross-team.d.ts.map +1 -0
- package/dist/handlers/tools/search/date-range-search.d.ts +3 -0
- package/dist/handlers/tools/search/date-range-search.d.ts.map +1 -0
- package/dist/handlers/tools/search/fts.d.ts +50 -0
- package/dist/handlers/tools/search/fts.d.ts.map +1 -0
- package/dist/handlers/tools/search/helpers.d.ts +52 -0
- package/dist/handlers/tools/search/helpers.d.ts.map +1 -0
- package/dist/handlers/tools/search/hybrid.d.ts +45 -0
- package/dist/handlers/tools/search/hybrid.d.ts.map +1 -0
- package/dist/handlers/tools/search/index.d.ts +3 -0
- package/dist/handlers/tools/search/index.d.ts.map +1 -0
- package/dist/handlers/tools/search/misc-tools.d.ts +3 -0
- package/dist/handlers/tools/search/misc-tools.d.ts.map +1 -0
- package/dist/handlers/tools/search/schemas.d.ts +352 -0
- package/dist/handlers/tools/search/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/search/search-entries.d.ts +3 -0
- package/dist/handlers/tools/search/search-entries.d.ts.map +1 -0
- package/dist/handlers/tools/search/semantic-search.d.ts +3 -0
- package/dist/handlers/tools/search/semantic-search.d.ts.map +1 -0
- package/dist/handlers/tools/team/admin-tools/batch.d.ts +8 -0
- package/dist/handlers/tools/team/admin-tools/batch.d.ts.map +1 -0
- package/dist/handlers/tools/team/admin-tools/crud.d.ts +8 -0
- package/dist/handlers/tools/team/admin-tools/crud.d.ts.map +1 -0
- package/dist/handlers/tools/team/admin-tools/index.d.ts +9 -0
- package/dist/handlers/tools/team/admin-tools/index.d.ts.map +1 -0
- package/dist/handlers/tools/team/alias-tools.d.ts +3 -0
- package/dist/handlers/tools/team/alias-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/analytics-tools.d.ts +8 -0
- package/dist/handlers/tools/team/analytics-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/backup-tools.d.ts +8 -0
- package/dist/handlers/tools/team/backup-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/core-tools.d.ts +8 -0
- package/dist/handlers/tools/team/core-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/export-tools.d.ts +8 -0
- package/dist/handlers/tools/team/export-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/helpers.d.ts +30 -0
- package/dist/handlers/tools/team/helpers.d.ts.map +1 -0
- package/dist/handlers/tools/team/index.d.ts +31 -0
- package/dist/handlers/tools/team/index.d.ts.map +1 -0
- package/dist/handlers/tools/team/io-tools.d.ts +11 -0
- package/dist/handlers/tools/team/io-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/member-tools.d.ts +8 -0
- package/dist/handlers/tools/team/member-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/rbac.d.ts +28 -0
- package/dist/handlers/tools/team/rbac.d.ts.map +1 -0
- package/dist/handlers/tools/team/relationship-tools.d.ts +8 -0
- package/dist/handlers/tools/team/relationship-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/schemas/admin-batch-schemas.d.ts +618 -0
- package/dist/handlers/tools/team/schemas/admin-batch-schemas.d.ts.map +1 -0
- package/dist/handlers/tools/team/schemas/analytics-vector-schemas.d.ts +464 -0
- package/dist/handlers/tools/team/schemas/analytics-vector-schemas.d.ts.map +1 -0
- package/dist/handlers/tools/team/schemas/core-search-schemas.d.ts +525 -0
- package/dist/handlers/tools/team/schemas/core-search-schemas.d.ts.map +1 -0
- package/dist/handlers/tools/team/schemas/io-backup-schemas.d.ts +419 -0
- package/dist/handlers/tools/team/schemas/io-backup-schemas.d.ts.map +1 -0
- package/dist/handlers/tools/team/schemas.d.ts +8 -0
- package/dist/handlers/tools/team/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/team/search-tools.d.ts +8 -0
- package/dist/handlers/tools/team/search-tools.d.ts.map +1 -0
- package/dist/handlers/tools/team/vector-tools.d.ts +9 -0
- package/dist/handlers/tools/team/vector-tools.d.ts.map +1 -0
- package/dist/index.d.ts +10 -823
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -13
- package/dist/markdown/converters/index.d.ts +26 -0
- package/dist/markdown/converters/index.d.ts.map +1 -0
- package/dist/markdown/converters/logseq.d.ts +14 -0
- package/dist/markdown/converters/logseq.d.ts.map +1 -0
- package/dist/markdown/converters/notion.d.ts +14 -0
- package/dist/markdown/converters/notion.d.ts.map +1 -0
- package/dist/markdown/converters/obsidian.d.ts +14 -0
- package/dist/markdown/converters/obsidian.d.ts.map +1 -0
- package/dist/markdown/converters/utils.d.ts +4 -0
- package/dist/markdown/converters/utils.d.ts.map +1 -0
- package/dist/markdown/converters/yaml-parser.d.ts +32 -0
- package/dist/markdown/converters/yaml-parser.d.ts.map +1 -0
- package/dist/markdown/exporter.d.ts +54 -0
- package/dist/markdown/exporter.d.ts.map +1 -0
- package/dist/markdown/frontmatter.d.ts +47 -0
- package/dist/markdown/frontmatter.d.ts.map +1 -0
- package/dist/markdown/importer.d.ts +81 -0
- package/dist/markdown/importer.d.ts.map +1 -0
- package/dist/markdown/index.d.ts +14 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/observability/index.d.ts +19 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/interceptor.d.ts +27 -0
- package/dist/observability/interceptor.d.ts.map +1 -0
- package/dist/observability/latency-tracker.d.ts +47 -0
- package/dist/observability/latency-tracker.d.ts.map +1 -0
- package/dist/observability/metrics-server.d.ts +3 -0
- package/dist/observability/metrics-server.d.ts.map +1 -0
- package/dist/observability/metrics.d.ts +138 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/prometheus-formatter.d.ts +14 -0
- package/dist/observability/prometheus-formatter.d.ts.map +1 -0
- package/dist/observability/token-estimator.d.ts +44 -0
- package/dist/observability/token-estimator.d.ts.map +1 -0
- package/dist/security-utils-P4P6A2DG.js +2 -0
- package/dist/server/auto-prune.d.ts +48 -0
- package/dist/server/auto-prune.d.ts.map +1 -0
- package/dist/server/digest-reporter.d.ts +16 -0
- package/dist/server/digest-reporter.d.ts.map +1 -0
- package/dist/server/mcp-server/core.d.ts +3 -0
- package/dist/server/mcp-server/core.d.ts.map +1 -0
- package/dist/server/mcp-server/index.d.ts +4 -0
- package/dist/server/mcp-server/index.d.ts.map +1 -0
- package/dist/server/mcp-server/initialization.d.ts +13 -0
- package/dist/server/mcp-server/initialization.d.ts.map +1 -0
- package/dist/server/mcp-server/tool-registration/call-interceptor.d.ts +6 -0
- package/dist/server/mcp-server/tool-registration/call-interceptor.d.ts.map +1 -0
- package/dist/server/mcp-server/tool-registration/index.d.ts +4 -0
- package/dist/server/mcp-server/tool-registration/index.d.ts.map +1 -0
- package/dist/server/mcp-server/tool-registration/list-interceptor.d.ts +4 -0
- package/dist/server/mcp-server/tool-registration/list-interceptor.d.ts.map +1 -0
- package/dist/server/mcp-server/tool-registration/register-tools.d.ts +18 -0
- package/dist/server/mcp-server/tool-registration/register-tools.d.ts.map +1 -0
- package/dist/server/mcp-server/tool-registration.d.ts +2 -0
- package/dist/server/mcp-server/tool-registration.d.ts.map +1 -0
- package/dist/server/mcp-server/types.d.ts +78 -0
- package/dist/server/mcp-server/types.d.ts.map +1 -0
- package/dist/server/registration.d.ts +73 -0
- package/dist/server/registration.d.ts.map +1 -0
- package/dist/server/scheduler.d.ts +129 -0
- package/dist/server/scheduler.d.ts.map +1 -0
- package/dist/server/subscription-manager.d.ts +46 -0
- package/dist/server/subscription-manager.d.ts.map +1 -0
- package/dist/tools-BOQV7QD3.js +6 -0
- package/dist/transports/http/handlers.d.ts +25 -0
- package/dist/transports/http/handlers.d.ts.map +1 -0
- package/dist/transports/http/index.d.ts +8 -0
- package/dist/transports/http/index.d.ts.map +1 -0
- package/dist/transports/http/security.d.ts +43 -0
- package/dist/transports/http/security.d.ts.map +1 -0
- package/dist/transports/http/server/http-transport.d.ts +25 -0
- package/dist/transports/http/server/http-transport.d.ts.map +1 -0
- package/dist/transports/http/server/index.d.ts +4 -0
- package/dist/transports/http/server/index.d.ts.map +1 -0
- package/dist/transports/http/server/legacy-sse.d.ts +30 -0
- package/dist/transports/http/server/legacy-sse.d.ts.map +1 -0
- package/dist/transports/http/server/protocol-handlers.d.ts +9 -0
- package/dist/transports/http/server/protocol-handlers.d.ts.map +1 -0
- package/dist/transports/http/types.d.ts +95 -0
- package/dist/transports/http/types.d.ts.map +1 -0
- package/dist/types/auto-context.d.ts +44 -0
- package/dist/types/auto-context.d.ts.map +1 -0
- package/dist/types/entities.d.ts +180 -0
- package/dist/types/entities.d.ts.map +1 -0
- package/dist/types/error-types.d.ts +48 -0
- package/dist/types/error-types.d.ts.map +1 -0
- package/dist/types/errors.d.ts +108 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/filtering.d.ts +34 -0
- package/dist/types/filtering.d.ts.map +1 -0
- package/dist/types/github.d.ts +202 -0
- package/dist/types/github.d.ts.map +1 -0
- package/dist/types/index.d.ts +326 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/config-manager.d.ts +24 -0
- package/dist/utils/config-manager.d.ts.map +1 -0
- package/dist/utils/config-resolver.d.ts +41 -0
- package/dist/utils/config-resolver.d.ts.map +1 -0
- package/dist/utils/error-helpers.d.ts +38 -0
- package/dist/utils/error-helpers.d.ts.map +1 -0
- package/dist/utils/errors/error-response-fields.d.ts +28 -0
- package/dist/utils/errors/error-response-fields.d.ts.map +1 -0
- package/dist/utils/errors/suggestions.d.ts +29 -0
- package/dist/utils/errors/suggestions.d.ts.map +1 -0
- package/dist/utils/github-helpers.d.ts +12 -0
- package/dist/utils/github-helpers.d.ts.map +1 -0
- package/dist/utils/issue-logger.d.ts +10 -0
- package/dist/utils/issue-logger.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +30 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/maintenance-lock.d.ts +34 -0
- package/dist/utils/maintenance-lock.d.ts.map +1 -0
- package/dist/utils/mcp-logger.d.ts +73 -0
- package/dist/utils/mcp-logger.d.ts.map +1 -0
- package/dist/utils/progress-utils.d.ts +53 -0
- package/dist/utils/progress-utils.d.ts.map +1 -0
- package/dist/utils/query-helpers.d.ts +43 -0
- package/dist/utils/query-helpers.d.ts.map +1 -0
- package/dist/utils/request-context.d.ts +9 -0
- package/dist/utils/request-context.d.ts.map +1 -0
- package/dist/utils/resource-annotations.d.ts +36 -0
- package/dist/utils/resource-annotations.d.ts.map +1 -0
- package/dist/utils/security-utils.d.ts +113 -0
- package/dist/utils/security-utils.d.ts.map +1 -0
- package/dist/utils/vector-index-helpers.d.ts +14 -0
- package/dist/utils/vector-index-helpers.d.ts.map +1 -0
- package/dist/utils/workspace-resolver.d.ts +40 -0
- package/dist/utils/workspace-resolver.d.ts.map +1 -0
- package/dist/vector/vector-search-manager/VectorSearchManagerProxy.d.ts +5 -0
- package/dist/vector/vector-search-manager/VectorSearchManagerProxy.d.ts.map +1 -0
- package/dist/vector/vector-search-manager/index.d.ts +3 -0
- package/dist/vector/vector-search-manager/index.d.ts.map +1 -0
- package/dist/vector/vector-search-manager/manager.d.ts +75 -0
- package/dist/vector/vector-search-manager/manager.d.ts.map +1 -0
- package/dist/vector/vector-search-manager/rebuild.d.ts +20 -0
- package/dist/vector/vector-search-manager/rebuild.d.ts.map +1 -0
- package/dist/vector/vector-search-manager/types.d.ts +12 -0
- package/dist/vector/vector-search-manager/types.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/agent-exec.d.ts +2 -0
- package/dist/vendor/lib-agent-exec/agent-exec.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/command-builder.d.ts +11 -0
- package/dist/vendor/lib-agent-exec/command-builder.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/command-utils.d.ts +29 -0
- package/dist/vendor/lib-agent-exec/command-utils.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/environment.d.ts +4 -0
- package/dist/vendor/lib-agent-exec/environment.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/eval-healer.d.ts +15 -0
- package/dist/vendor/lib-agent-exec/eval-healer.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/execution-engine.d.ts +4 -0
- package/dist/vendor/lib-agent-exec/execution-engine.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/help.d.ts +3 -0
- package/dist/vendor/lib-agent-exec/help.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/cloud-cli-interceptor.d.ts +3 -0
- package/dist/vendor/lib-agent-exec/interceptors/cloud-cli-interceptor.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/docker-interceptor.d.ts +3 -0
- package/dist/vendor/lib-agent-exec/interceptors/docker-interceptor.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/git-interceptor.d.ts +3 -0
- package/dist/vendor/lib-agent-exec/interceptors/git-interceptor.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/index.d.ts +9 -0
- package/dist/vendor/lib-agent-exec/interceptors/index.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/mutating-interceptors.d.ts +7 -0
- package/dist/vendor/lib-agent-exec/interceptors/mutating-interceptors.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/package-manager-interceptor.d.ts +3 -0
- package/dist/vendor/lib-agent-exec/interceptors/package-manager-interceptor.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/repl-tui-interceptor.d.ts +3 -0
- package/dist/vendor/lib-agent-exec/interceptors/repl-tui-interceptor.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/search-interceptor.d.ts +15 -0
- package/dist/vendor/lib-agent-exec/interceptors/search-interceptor.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/structural-interceptors.d.ts +15 -0
- package/dist/vendor/lib-agent-exec/interceptors/structural-interceptors.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/system-interceptor.d.ts +3 -0
- package/dist/vendor/lib-agent-exec/interceptors/system-interceptor.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/types.d.ts +11 -0
- package/dist/vendor/lib-agent-exec/interceptors/types.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/interceptors/utils.d.ts +5 -0
- package/dist/vendor/lib-agent-exec/interceptors/utils.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/io-controller.d.ts +48 -0
- package/dist/vendor/lib-agent-exec/io-controller.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/io-utils.d.ts +12 -0
- package/dist/vendor/lib-agent-exec/io-utils.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/path-healer.d.ts +15 -0
- package/dist/vendor/lib-agent-exec/path-healer.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/process-controller.d.ts +38 -0
- package/dist/vendor/lib-agent-exec/process-controller.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/process-manager.d.ts +6 -0
- package/dist/vendor/lib-agent-exec/process-manager.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/prompt-detector.d.ts +2 -0
- package/dist/vendor/lib-agent-exec/prompt-detector.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/schema.d.ts +182 -0
- package/dist/vendor/lib-agent-exec/schema.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/stream-manager.d.ts +20 -0
- package/dist/vendor/lib-agent-exec/stream-manager.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/utils.d.ts +17 -0
- package/dist/vendor/lib-agent-exec/utils.d.ts.map +1 -0
- package/dist/vendor/lib-agent-exec/webhook-template.d.ts +2 -0
- package/dist/vendor/lib-agent-exec/webhook-template.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/cache.d.ts +56 -0
- package/dist/vendor/lib-git-history/cache.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/cli.d.ts +147 -0
- package/dist/vendor/lib-git-history/cli.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/constants.d.ts +36 -0
- package/dist/vendor/lib-git-history/constants.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/git-numstat.d.ts +7 -0
- package/dist/vendor/lib-git-history/git-numstat.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/git-patch.d.ts +3 -0
- package/dist/vendor/lib-git-history/git-patch.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/git-runner.d.ts +25 -0
- package/dist/vendor/lib-git-history/git-runner.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/parser-batch.d.ts +5 -0
- package/dist/vendor/lib-git-history/parser-batch.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/parser-metadata.d.ts +3 -0
- package/dist/vendor/lib-git-history/parser-metadata.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/parser-record.d.ts +37 -0
- package/dist/vendor/lib-git-history/parser-record.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/parser-utils.d.ts +22 -0
- package/dist/vendor/lib-git-history/parser-utils.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/parser.d.ts +4 -0
- package/dist/vendor/lib-git-history/parser.d.ts.map +1 -0
- package/dist/vendor/lib-git-history/schema.d.ts +131 -0
- package/dist/vendor/lib-git-history/schema.d.ts.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/worker-script.js +2937 -342
- package/package.json +130 -106
- package/skills/memory-journal-mcp/SKILL.md +41 -0
- package/dist/chunk-6OHRCNYW.js +0 -3231
- package/dist/chunk-JFMITANR.js +0 -5168
- package/dist/chunk-UHSO65A4.js +0 -8937
- package/dist/chunk-V3UTFQQK.js +0 -5538
- package/dist/cli.d.ts +0 -2
- package/dist/resources-IJVKDFGS.js +0 -2
- package/dist/tools-44DGXE3V.js +0 -2
- package/dist/worker-script.d.ts +0 -2
- package/skills/README.md +0 -121
- package/skills/adversarial-performance/SKILL.md +0 -139
- package/skills/adversarial-performance/references/audit-categories.md +0 -462
- package/skills/adversarial-performance/references/copilot-performance-prompts.md +0 -44
- package/skills/adversarial-performance/references/copilot-usage.md +0 -16
- package/skills/adversarial-performance/references/feedback-loop.md +0 -177
- package/skills/adversarial-performance/references/multi-pass-performance-protocol.md +0 -398
- package/skills/adversarial-planner/SKILL.md +0 -89
- package/skills/adversarial-planner/references/copilot-integration.md +0 -83
- package/skills/adversarial-planner/references/copilot-usage.md +0 -16
- package/skills/adversarial-planner/references/feedback-loop.md +0 -148
- package/skills/adversarial-planner/references/multi-pass-protocol.md +0 -229
- package/skills/adversarial-security/SKILL.md +0 -149
- package/skills/adversarial-security/references/adversarial-base-protocol.md +0 -44
- package/skills/adversarial-security/references/audit-categories.md +0 -723
- package/skills/adversarial-security/references/copilot-security-prompts.md +0 -142
- package/skills/adversarial-security/references/copilot-usage.md +0 -16
- package/skills/adversarial-security/references/feedback-loop.md +0 -206
- package/skills/adversarial-security/references/journal-opt-out.md +0 -7
- package/skills/adversarial-security/references/multi-pass-security-protocol.md +0 -403
- package/skills/adversarial-skill-audit/SKILL.md +0 -118
- package/skills/adversarial-skill-audit/references/audit-categories.md +0 -308
- package/skills/adversarial-skill-audit/references/copilot-skill-prompts.md +0 -68
- package/skills/adversarial-skill-audit/references/copilot-usage.md +0 -16
- package/skills/adversarial-skill-audit/references/feedback-loop.md +0 -155
- package/skills/adversarial-skill-audit/references/multi-pass-skill-protocol.md +0 -367
- package/skills/adversarial-skill-audit/scripts/check-skills.ps1 +0 -48
- package/skills/adversarial-skill-audit/scripts/run-copilot.ps1 +0 -52
- package/skills/adversarial-workflow-audit/SKILL.md +0 -82
- package/skills/adversarial-workflow-audit/references/audit-categories.md +0 -28
- package/skills/adversarial-workflow-audit/references/copilot-usage.md +0 -16
- package/skills/adversarial-workflow-audit/scripts/check-workflows.ps1 +0 -24
- package/skills/agents-sdk/SKILL.md +0 -220
- package/skills/agents-sdk/references/callable.md +0 -92
- package/skills/agents-sdk/references/codemode.md +0 -209
- package/skills/agents-sdk/references/email.md +0 -144
- package/skills/agents-sdk/references/mcp/SKILL.md +0 -65
- package/skills/agents-sdk/references/mcp/code-mode-reference.md +0 -245
- package/skills/agents-sdk/references/mcp/oauth-reference.md +0 -359
- package/skills/agents-sdk/references/mcp/references/architecture-reference.md +0 -208
- package/skills/agents-sdk/references/mcp/references/cloudflare-quickstart.md +0 -156
- package/skills/agents-sdk/references/mcp/references/error-handling.md +0 -343
- package/skills/agents-sdk/references/mcp/references/http-security.md +0 -164
- package/skills/agents-sdk/references/mcp/references/implementation-guide.md +0 -507
- package/skills/agents-sdk/references/mcp/references/testing-reference.md +0 -171
- package/skills/agents-sdk/references/mcp.md +0 -157
- package/skills/agents-sdk/references/state-scheduling.md +0 -164
- package/skills/agents-sdk/references/streaming-chat.md +0 -168
- package/skills/agents-sdk/references/workflows.md +0 -136
- package/skills/auth-identity/SKILL.md +0 -48
- package/skills/autonomous-dev/SKILL.md +0 -79
- package/skills/autonomous-dev/references/workflow_orchestration.md +0 -22
- package/skills/aws/SKILL.md +0 -39
- package/skills/azure/SKILL.md +0 -38
- package/skills/bin/sync.js +0 -56
- package/skills/biome/SKILL.md +0 -59
- package/skills/bun/SKILL.md +0 -162
- package/skills/cloudflare/SKILL.md +0 -37
- package/skills/cloudflare/references/agents-sdk/README.md +0 -95
- package/skills/cloudflare/references/agents-sdk/api.md +0 -195
- package/skills/cloudflare/references/agents-sdk/configuration.md +0 -178
- package/skills/cloudflare/references/agents-sdk/gotchas.md +0 -173
- package/skills/cloudflare/references/agents-sdk/patterns.md +0 -215
- package/skills/cloudflare/references/ai-gateway/README.md +0 -176
- package/skills/cloudflare/references/ai-gateway/configuration.md +0 -117
- package/skills/cloudflare/references/ai-gateway/dynamic-routing.md +0 -88
- package/skills/cloudflare/references/ai-gateway/features.md +0 -96
- package/skills/cloudflare/references/ai-gateway/sdk-integration.md +0 -110
- package/skills/cloudflare/references/ai-gateway/troubleshooting.md +0 -90
- package/skills/cloudflare/references/ai-search/README.md +0 -145
- package/skills/cloudflare/references/ai-search/api.md +0 -87
- package/skills/cloudflare/references/ai-search/configuration.md +0 -91
- package/skills/cloudflare/references/ai-search/gotchas.md +0 -92
- package/skills/cloudflare/references/ai-search/patterns.md +0 -87
- package/skills/cloudflare/references/analytics-engine/README.md +0 -96
- package/skills/cloudflare/references/analytics-engine/api.md +0 -112
- package/skills/cloudflare/references/analytics-engine/configuration.md +0 -107
- package/skills/cloudflare/references/analytics-engine/gotchas.md +0 -87
- package/skills/cloudflare/references/analytics-engine/patterns.md +0 -83
- package/skills/cloudflare/references/api/README.md +0 -66
- package/skills/cloudflare/references/api/api.md +0 -205
- package/skills/cloudflare/references/api/configuration.md +0 -158
- package/skills/cloudflare/references/api/gotchas.md +0 -231
- package/skills/cloudflare/references/api/patterns.md +0 -208
- package/skills/cloudflare/references/api-shield/README.md +0 -44
- package/skills/cloudflare/references/api-shield/api.md +0 -153
- package/skills/cloudflare/references/api-shield/configuration.md +0 -210
- package/skills/cloudflare/references/api-shield/gotchas.md +0 -132
- package/skills/cloudflare/references/api-shield/patterns.md +0 -185
- package/skills/cloudflare/references/argo-smart-routing/README.md +0 -96
- package/skills/cloudflare/references/argo-smart-routing/api.md +0 -253
- package/skills/cloudflare/references/argo-smart-routing/configuration.md +0 -205
- package/skills/cloudflare/references/argo-smart-routing/gotchas.md +0 -115
- package/skills/cloudflare/references/argo-smart-routing/patterns.md +0 -107
- package/skills/cloudflare/references/bindings/README.md +0 -127
- package/skills/cloudflare/references/bindings/api.md +0 -214
- package/skills/cloudflare/references/bindings/configuration.md +0 -200
- package/skills/cloudflare/references/bindings/gotchas.md +0 -210
- package/skills/cloudflare/references/bindings/patterns.md +0 -205
- package/skills/cloudflare/references/bot-management/README.md +0 -95
- package/skills/cloudflare/references/bot-management/api.md +0 -175
- package/skills/cloudflare/references/bot-management/configuration.md +0 -175
- package/skills/cloudflare/references/bot-management/gotchas.md +0 -116
- package/skills/cloudflare/references/bot-management/patterns.md +0 -181
- package/skills/cloudflare/references/browser-rendering/README.md +0 -84
- package/skills/cloudflare/references/browser-rendering/api.md +0 -108
- package/skills/cloudflare/references/browser-rendering/configuration.md +0 -78
- package/skills/cloudflare/references/browser-rendering/gotchas.md +0 -91
- package/skills/cloudflare/references/browser-rendering/patterns.md +0 -93
- package/skills/cloudflare/references/c3/README.md +0 -111
- package/skills/cloudflare/references/c3/api.md +0 -71
- package/skills/cloudflare/references/c3/configuration.md +0 -85
- package/skills/cloudflare/references/c3/gotchas.md +0 -97
- package/skills/cloudflare/references/c3/patterns.md +0 -84
- package/skills/cloudflare/references/cache-reserve/README.md +0 -150
- package/skills/cloudflare/references/cache-reserve/api.md +0 -184
- package/skills/cloudflare/references/cache-reserve/configuration.md +0 -170
- package/skills/cloudflare/references/cache-reserve/gotchas.md +0 -136
- package/skills/cloudflare/references/cache-reserve/patterns.md +0 -197
- package/skills/cloudflare/references/containers/README.md +0 -87
- package/skills/cloudflare/references/containers/api.md +0 -197
- package/skills/cloudflare/references/containers/configuration.md +0 -191
- package/skills/cloudflare/references/containers/gotchas.md +0 -182
- package/skills/cloudflare/references/containers/patterns.md +0 -204
- package/skills/cloudflare/references/cron-triggers/README.md +0 -101
- package/skills/cloudflare/references/cron-triggers/api.md +0 -224
- package/skills/cloudflare/references/cron-triggers/configuration.md +0 -190
- package/skills/cloudflare/references/cron-triggers/gotchas.md +0 -207
- package/skills/cloudflare/references/cron-triggers/patterns.md +0 -274
- package/skills/cloudflare/references/d1/README.md +0 -137
- package/skills/cloudflare/references/d1/api.md +0 -213
- package/skills/cloudflare/references/d1/configuration.md +0 -198
- package/skills/cloudflare/references/d1/gotchas.md +0 -98
- package/skills/cloudflare/references/d1/patterns.md +0 -240
- package/skills/cloudflare/references/ddos/README.md +0 -42
- package/skills/cloudflare/references/ddos/api.md +0 -158
- package/skills/cloudflare/references/ddos/configuration.md +0 -94
- package/skills/cloudflare/references/ddos/gotchas.md +0 -114
- package/skills/cloudflare/references/ddos/patterns.md +0 -220
- package/skills/cloudflare/references/decision-trees.md +0 -95
- package/skills/cloudflare/references/do-storage/README.md +0 -79
- package/skills/cloudflare/references/do-storage/api.md +0 -107
- package/skills/cloudflare/references/do-storage/configuration.md +0 -114
- package/skills/cloudflare/references/do-storage/gotchas.md +0 -153
- package/skills/cloudflare/references/do-storage/patterns.md +0 -210
- package/skills/cloudflare/references/do-storage/testing.md +0 -186
- package/skills/cloudflare/references/durable-objects/README.md +0 -194
- package/skills/cloudflare/references/durable-objects/api.md +0 -205
- package/skills/cloudflare/references/durable-objects/configuration.md +0 -160
- package/skills/cloudflare/references/durable-objects/gotchas.md +0 -200
- package/skills/cloudflare/references/durable-objects/patterns.md +0 -205
- package/skills/cloudflare/references/email-routing/README.md +0 -89
- package/skills/cloudflare/references/email-routing/api.md +0 -192
- package/skills/cloudflare/references/email-routing/configuration.md +0 -187
- package/skills/cloudflare/references/email-routing/gotchas.md +0 -203
- package/skills/cloudflare/references/email-routing/patterns.md +0 -241
- package/skills/cloudflare/references/email-workers/README.md +0 -153
- package/skills/cloudflare/references/email-workers/api.md +0 -227
- package/skills/cloudflare/references/email-workers/configuration.md +0 -115
- package/skills/cloudflare/references/email-workers/gotchas.md +0 -133
- package/skills/cloudflare/references/email-workers/patterns.md +0 -108
- package/skills/cloudflare/references/graphql-api/README.md +0 -147
- package/skills/cloudflare/references/graphql-api/api.md +0 -175
- package/skills/cloudflare/references/graphql-api/configuration.md +0 -151
- package/skills/cloudflare/references/graphql-api/gotchas.md +0 -111
- package/skills/cloudflare/references/graphql-api/patterns.md +0 -276
- package/skills/cloudflare/references/hyperdrive/README.md +0 -84
- package/skills/cloudflare/references/hyperdrive/api.md +0 -149
- package/skills/cloudflare/references/hyperdrive/configuration.md +0 -166
- package/skills/cloudflare/references/hyperdrive/gotchas.md +0 -77
- package/skills/cloudflare/references/hyperdrive/patterns.md +0 -203
- package/skills/cloudflare/references/images/README.md +0 -65
- package/skills/cloudflare/references/images/api.md +0 -101
- package/skills/cloudflare/references/images/configuration.md +0 -206
- package/skills/cloudflare/references/images/gotchas.md +0 -106
- package/skills/cloudflare/references/images/patterns.md +0 -126
- package/skills/cloudflare/references/kv/README.md +0 -90
- package/skills/cloudflare/references/kv/api.md +0 -163
- package/skills/cloudflare/references/kv/configuration.md +0 -148
- package/skills/cloudflare/references/kv/gotchas.md +0 -133
- package/skills/cloudflare/references/kv/patterns.md +0 -195
- package/skills/cloudflare/references/miniflare/README.md +0 -113
- package/skills/cloudflare/references/miniflare/api.md +0 -204
- package/skills/cloudflare/references/miniflare/configuration.md +0 -174
- package/skills/cloudflare/references/miniflare/gotchas.md +0 -179
- package/skills/cloudflare/references/miniflare/patterns.md +0 -187
- package/skills/cloudflare/references/network-interconnect/README.md +0 -104
- package/skills/cloudflare/references/network-interconnect/api.md +0 -220
- package/skills/cloudflare/references/network-interconnect/configuration.md +0 -123
- package/skills/cloudflare/references/network-interconnect/gotchas.md +0 -175
- package/skills/cloudflare/references/network-interconnect/patterns.md +0 -174
- package/skills/cloudflare/references/observability/README.md +0 -93
- package/skills/cloudflare/references/observability/api.md +0 -168
- package/skills/cloudflare/references/observability/configuration.md +0 -178
- package/skills/cloudflare/references/observability/gotchas.md +0 -125
- package/skills/cloudflare/references/observability/patterns.md +0 -105
- package/skills/cloudflare/references/pages/README.md +0 -92
- package/skills/cloudflare/references/pages/api.md +0 -205
- package/skills/cloudflare/references/pages/configuration.md +0 -216
- package/skills/cloudflare/references/pages/gotchas.md +0 -218
- package/skills/cloudflare/references/pages/patterns.md +0 -215
- package/skills/cloudflare/references/pages-functions/README.md +0 -104
- package/skills/cloudflare/references/pages-functions/api.md +0 -159
- package/skills/cloudflare/references/pages-functions/configuration.md +0 -130
- package/skills/cloudflare/references/pages-functions/gotchas.md +0 -102
- package/skills/cloudflare/references/pages-functions/patterns.md +0 -148
- package/skills/cloudflare/references/pipelines/README.md +0 -109
- package/skills/cloudflare/references/pipelines/api.md +0 -214
- package/skills/cloudflare/references/pipelines/configuration.md +0 -98
- package/skills/cloudflare/references/pipelines/gotchas.md +0 -84
- package/skills/cloudflare/references/pipelines/patterns.md +0 -87
- package/skills/cloudflare/references/product-index.md +0 -112
- package/skills/cloudflare/references/pulumi/README.md +0 -113
- package/skills/cloudflare/references/pulumi/api.md +0 -230
- package/skills/cloudflare/references/pulumi/configuration.md +0 -213
- package/skills/cloudflare/references/pulumi/gotchas.md +0 -205
- package/skills/cloudflare/references/pulumi/patterns.md +0 -260
- package/skills/cloudflare/references/queues/README.md +0 -99
- package/skills/cloudflare/references/queues/api.md +0 -211
- package/skills/cloudflare/references/queues/configuration.md +0 -151
- package/skills/cloudflare/references/queues/gotchas.md +0 -210
- package/skills/cloudflare/references/queues/patterns.md +0 -220
- package/skills/cloudflare/references/r2/README.md +0 -97
- package/skills/cloudflare/references/r2/api.md +0 -235
- package/skills/cloudflare/references/r2/configuration.md +0 -176
- package/skills/cloudflare/references/r2/gotchas.md +0 -190
- package/skills/cloudflare/references/r2/patterns.md +0 -203
- package/skills/cloudflare/references/r2-data-catalog/README.md +0 -157
- package/skills/cloudflare/references/r2-data-catalog/api.md +0 -199
- package/skills/cloudflare/references/r2-data-catalog/configuration.md +0 -205
- package/skills/cloudflare/references/r2-data-catalog/gotchas.md +0 -170
- package/skills/cloudflare/references/r2-data-catalog/patterns.md +0 -191
- package/skills/cloudflare/references/r2-sql/README.md +0 -138
- package/skills/cloudflare/references/r2-sql/SKILL.md.backup +0 -512
- package/skills/cloudflare/references/r2-sql/api.md +0 -159
- package/skills/cloudflare/references/r2-sql/configuration.md +0 -152
- package/skills/cloudflare/references/r2-sql/gotchas.md +0 -228
- package/skills/cloudflare/references/r2-sql/patterns.md +0 -230
- package/skills/cloudflare/references/realtime-sfu/README.md +0 -66
- package/skills/cloudflare/references/realtime-sfu/api.md +0 -164
- package/skills/cloudflare/references/realtime-sfu/configuration.md +0 -141
- package/skills/cloudflare/references/realtime-sfu/gotchas.md +0 -138
- package/skills/cloudflare/references/realtime-sfu/patterns.md +0 -187
- package/skills/cloudflare/references/realtimekit/README.md +0 -118
- package/skills/cloudflare/references/realtimekit/api.md +0 -234
- package/skills/cloudflare/references/realtimekit/configuration.md +0 -226
- package/skills/cloudflare/references/realtimekit/gotchas.md +0 -206
- package/skills/cloudflare/references/realtimekit/patterns.md +0 -240
- package/skills/cloudflare/references/sandbox/README.md +0 -104
- package/skills/cloudflare/references/sandbox/api.md +0 -200
- package/skills/cloudflare/references/sandbox/configuration.md +0 -154
- package/skills/cloudflare/references/sandbox/gotchas.md +0 -201
- package/skills/cloudflare/references/sandbox/patterns.md +0 -195
- package/skills/cloudflare/references/secrets-store/README.md +0 -77
- package/skills/cloudflare/references/secrets-store/api.md +0 -199
- package/skills/cloudflare/references/secrets-store/configuration.md +0 -187
- package/skills/cloudflare/references/secrets-store/gotchas.md +0 -97
- package/skills/cloudflare/references/secrets-store/patterns.md +0 -218
- package/skills/cloudflare/references/smart-placement/README.md +0 -143
- package/skills/cloudflare/references/smart-placement/api.md +0 -192
- package/skills/cloudflare/references/smart-placement/configuration.md +0 -202
- package/skills/cloudflare/references/smart-placement/gotchas.md +0 -180
- package/skills/cloudflare/references/smart-placement/patterns.md +0 -190
- package/skills/cloudflare/references/snippets/README.md +0 -74
- package/skills/cloudflare/references/snippets/api.md +0 -214
- package/skills/cloudflare/references/snippets/configuration.md +0 -239
- package/skills/cloudflare/references/snippets/gotchas.md +0 -104
- package/skills/cloudflare/references/snippets/patterns.md +0 -135
- package/skills/cloudflare/references/spectrum/README.md +0 -52
- package/skills/cloudflare/references/spectrum/api.md +0 -184
- package/skills/cloudflare/references/spectrum/configuration.md +0 -203
- package/skills/cloudflare/references/spectrum/gotchas.md +0 -155
- package/skills/cloudflare/references/spectrum/patterns.md +0 -206
- package/skills/cloudflare/references/static-assets/README.md +0 -65
- package/skills/cloudflare/references/static-assets/api.md +0 -201
- package/skills/cloudflare/references/static-assets/configuration.md +0 -186
- package/skills/cloudflare/references/static-assets/gotchas.md +0 -164
- package/skills/cloudflare/references/static-assets/patterns.md +0 -189
- package/skills/cloudflare/references/stream/README.md +0 -123
- package/skills/cloudflare/references/stream/api-live.md +0 -202
- package/skills/cloudflare/references/stream/api.md +0 -206
- package/skills/cloudflare/references/stream/configuration.md +0 -151
- package/skills/cloudflare/references/stream/gotchas.md +0 -139
- package/skills/cloudflare/references/stream/patterns.md +0 -217
- package/skills/cloudflare/references/tail-workers/README.md +0 -92
- package/skills/cloudflare/references/tail-workers/api.md +0 -203
- package/skills/cloudflare/references/tail-workers/configuration.md +0 -178
- package/skills/cloudflare/references/tail-workers/gotchas.md +0 -206
- package/skills/cloudflare/references/tail-workers/patterns.md +0 -190
- package/skills/cloudflare/references/terraform/README.md +0 -100
- package/skills/cloudflare/references/terraform/api.md +0 -178
- package/skills/cloudflare/references/terraform/configuration.md +0 -197
- package/skills/cloudflare/references/terraform/gotchas.md +0 -150
- package/skills/cloudflare/references/terraform/patterns.md +0 -174
- package/skills/cloudflare/references/tunnel/README.md +0 -137
- package/skills/cloudflare/references/tunnel/api.md +0 -205
- package/skills/cloudflare/references/tunnel/configuration.md +0 -163
- package/skills/cloudflare/references/tunnel/gotchas.md +0 -159
- package/skills/cloudflare/references/tunnel/networking.md +0 -174
- package/skills/cloudflare/references/tunnel/patterns.md +0 -199
- package/skills/cloudflare/references/turn/README.md +0 -86
- package/skills/cloudflare/references/turn/api.md +0 -236
- package/skills/cloudflare/references/turn/configuration.md +0 -181
- package/skills/cloudflare/references/turn/gotchas.md +0 -236
- package/skills/cloudflare/references/turn/patterns.md +0 -228
- package/skills/cloudflare/references/turnstile/README.md +0 -102
- package/skills/cloudflare/references/turnstile/api.md +0 -253
- package/skills/cloudflare/references/turnstile/configuration.md +0 -242
- package/skills/cloudflare/references/turnstile/gotchas.md +0 -253
- package/skills/cloudflare/references/turnstile/patterns.md +0 -195
- package/skills/cloudflare/references/vectorize/README.md +0 -133
- package/skills/cloudflare/references/vectorize/api.md +0 -89
- package/skills/cloudflare/references/vectorize/configuration.md +0 -91
- package/skills/cloudflare/references/vectorize/gotchas.md +0 -83
- package/skills/cloudflare/references/vectorize/patterns.md +0 -92
- package/skills/cloudflare/references/waf/README.md +0 -125
- package/skills/cloudflare/references/waf/api.md +0 -203
- package/skills/cloudflare/references/waf/configuration.md +0 -215
- package/skills/cloudflare/references/waf/gotchas.md +0 -208
- package/skills/cloudflare/references/waf/patterns.md +0 -236
- package/skills/cloudflare/references/web-analytics/README.md +0 -149
- package/skills/cloudflare/references/web-analytics/configuration.md +0 -81
- package/skills/cloudflare/references/web-analytics/gotchas.md +0 -86
- package/skills/cloudflare/references/web-analytics/integration.md +0 -63
- package/skills/cloudflare/references/web-analytics/patterns.md +0 -98
- package/skills/cloudflare/references/workerd/README.md +0 -85
- package/skills/cloudflare/references/workerd/api.md +0 -219
- package/skills/cloudflare/references/workerd/configuration.md +0 -200
- package/skills/cloudflare/references/workerd/gotchas.md +0 -151
- package/skills/cloudflare/references/workerd/patterns.md +0 -205
- package/skills/cloudflare/references/workers/README.md +0 -110
- package/skills/cloudflare/references/workers/api.md +0 -197
- package/skills/cloudflare/references/workers/configuration.md +0 -184
- package/skills/cloudflare/references/workers/frameworks.md +0 -200
- package/skills/cloudflare/references/workers/gotchas.md +0 -145
- package/skills/cloudflare/references/workers/patterns.md +0 -220
- package/skills/cloudflare/references/workers-ai/README.md +0 -206
- package/skills/cloudflare/references/workers-ai/api.md +0 -115
- package/skills/cloudflare/references/workers-ai/configuration.md +0 -98
- package/skills/cloudflare/references/workers-ai/gotchas.md +0 -130
- package/skills/cloudflare/references/workers-ai/patterns.md +0 -122
- package/skills/cloudflare/references/workers-for-platforms/README.md +0 -95
- package/skills/cloudflare/references/workers-for-platforms/api.md +0 -212
- package/skills/cloudflare/references/workers-for-platforms/configuration.md +0 -178
- package/skills/cloudflare/references/workers-for-platforms/gotchas.md +0 -134
- package/skills/cloudflare/references/workers-for-platforms/patterns.md +0 -210
- package/skills/cloudflare/references/workers-playground/README.md +0 -131
- package/skills/cloudflare/references/workers-playground/api.md +0 -101
- package/skills/cloudflare/references/workers-playground/configuration.md +0 -169
- package/skills/cloudflare/references/workers-playground/gotchas.md +0 -88
- package/skills/cloudflare/references/workers-playground/patterns.md +0 -134
- package/skills/cloudflare/references/workers-vpc/README.md +0 -130
- package/skills/cloudflare/references/workers-vpc/api.md +0 -196
- package/skills/cloudflare/references/workers-vpc/configuration.md +0 -151
- package/skills/cloudflare/references/workers-vpc/gotchas.md +0 -171
- package/skills/cloudflare/references/workers-vpc/patterns.md +0 -235
- package/skills/cloudflare/references/workflows/README.md +0 -72
- package/skills/cloudflare/references/workflows/api.md +0 -237
- package/skills/cloudflare/references/workflows/configuration.md +0 -158
- package/skills/cloudflare/references/workflows/gotchas.md +0 -97
- package/skills/cloudflare/references/workflows/patterns.md +0 -245
- package/skills/cloudflare/references/wrangler/README.md +0 -143
- package/skills/cloudflare/references/wrangler/api.md +0 -188
- package/skills/cloudflare/references/wrangler/configuration.md +0 -198
- package/skills/cloudflare/references/wrangler/gotchas.md +0 -212
- package/skills/cloudflare/references/wrangler/patterns.md +0 -211
- package/skills/cloudflare/references/zaraz/IMPLEMENTATION_SUMMARY.md +0 -131
- package/skills/cloudflare/references/zaraz/README.md +0 -114
- package/skills/cloudflare/references/zaraz/api.md +0 -118
- package/skills/cloudflare/references/zaraz/configuration.md +0 -94
- package/skills/cloudflare/references/zaraz/gotchas.md +0 -88
- package/skills/cloudflare/references/zaraz/patterns.md +0 -77
- package/skills/docker/SKILL.md +0 -168
- package/skills/docker/references/advanced-examples.md +0 -71
- package/skills/docker/references/templates.md +0 -34
- package/skills/docs-marketer/SKILL.md +0 -178
- package/skills/docs-marketer/references/audit-categories.md +0 -328
- package/skills/docs-marketer/references/copilot-docs-prompts.md +0 -88
- package/skills/docs-marketer/references/copilot-usage.md +0 -16
- package/skills/docs-marketer/references/feedback-loop.md +0 -155
- package/skills/docs-marketer/references/multi-pass-docs-protocol.md +0 -410
- package/skills/drizzle-orm/SKILL.md +0 -82
- package/skills/durable-objects/SKILL.md +0 -167
- package/skills/durable-objects/references/advanced_features.md +0 -29
- package/skills/durable-objects/references/rules.md +0 -300
- package/skills/durable-objects/references/testing.md +0 -261
- package/skills/durable-objects/references/workers.md +0 -336
- package/skills/gcp/SKILL.md +0 -37
- package/skills/github-actions/SKILL.md +0 -262
- package/skills/github-actions/references/templates.md +0 -65
- package/skills/github-commander/SKILL.md +0 -144
- package/skills/github-commander/config/project-config.example.md +0 -125
- package/skills/github-commander/workflows/code-quality-audit.md +0 -82
- package/skills/github-commander/workflows/copilot-audit.md +0 -50
- package/skills/github-commander/workflows/issue-triage.md +0 -248
- package/skills/github-commander/workflows/milestone-sprint.md +0 -89
- package/skills/github-commander/workflows/perf-audit.md +0 -144
- package/skills/github-commander/workflows/pr-review.md +0 -129
- package/skills/github-commander/workflows/roadmap-kickoff.md +0 -79
- package/skills/github-commander/workflows/security-audit.md +0 -170
- package/skills/github-commander/workflows/update-deps.md +0 -109
- package/skills/github-copilot-cli/SKILL.md +0 -59
- package/skills/github-repo-setup/SKILL.md +0 -136
- package/skills/github-repo-setup/references/community-standards.md +0 -136
- package/skills/github-repo-setup/references/github-automation.md +0 -490
- package/skills/github-repo-setup/references/inline-templates.md +0 -205
- package/skills/github-repo-setup/references/project-config.md +0 -320
- package/skills/gitlab/SKILL.md +0 -120
- package/skills/gitlab/package-lock.json +0 -392
- package/skills/gitlab/package.json +0 -14
- package/skills/gitlab/scripts/gitlab-client.ts +0 -125
- package/skills/gitlab/scripts/gitlab-helper.ts +0 -80
- package/skills/golang/SKILL.md +0 -61
- package/skills/graphql/SKILL.md +0 -30
- package/skills/hono/SKILL.md +0 -82
- package/skills/journal-optimizer/SKILL.md +0 -206
- package/skills/journal-optimizer/references/optimizer-scripts.md +0 -169
- package/skills/llm-app-engineering/SKILL.md +0 -18
- package/skills/monorepo/SKILL.md +0 -56
- package/skills/multi-agent-orchestration/SKILL.md +0 -14
- package/skills/mysql/SKILL.md +0 -34
- package/skills/next-best-practices/README.md +0 -127
- package/skills/next-best-practices/SKILL.md +0 -86
- package/skills/next-best-practices/metadata.json +0 -17
- package/skills/next-best-practices/references/cache-components-examples.md +0 -234
- package/skills/next-best-practices/references/cache-components.md +0 -210
- package/skills/next-best-practices/references/upgrade-decision-tree.md +0 -33
- package/skills/next-best-practices/references/upgrade.md +0 -43
- package/skills/next-best-practices/rules/_sections.md +0 -46
- package/skills/next-best-practices/rules/_template.md +0 -28
- package/skills/next-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/skills/next-best-practices/rules/advanced-init-once.md +0 -42
- package/skills/next-best-practices/rules/advanced-use-latest.md +0 -39
- package/skills/next-best-practices/rules/async-api-routes.md +0 -35
- package/skills/next-best-practices/rules/async-defer-await.md +0 -80
- package/skills/next-best-practices/rules/async-dependencies.md +0 -48
- package/skills/next-best-practices/rules/async-parallel.md +0 -24
- package/skills/next-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/skills/next-best-practices/rules/bundle-barrel-imports.md +0 -59
- package/skills/next-best-practices/rules/bundle-conditional.md +0 -37
- package/skills/next-best-practices/rules/bundle-defer-third-party.md +0 -48
- package/skills/next-best-practices/rules/bundle-dynamic-imports.md +0 -34
- package/skills/next-best-practices/rules/bundle-preload.md +0 -44
- package/skills/next-best-practices/rules/client-event-listeners.md +0 -78
- package/skills/next-best-practices/rules/client-localstorage-schema.md +0 -74
- package/skills/next-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/skills/next-best-practices/rules/client-swr-dedup.md +0 -56
- package/skills/next-best-practices/rules/js-batch-dom-css.md +0 -110
- package/skills/next-best-practices/rules/js-cache-function-results.md +0 -80
- package/skills/next-best-practices/rules/js-cache-property-access.md +0 -28
- package/skills/next-best-practices/rules/js-cache-storage.md +0 -68
- package/skills/next-best-practices/rules/js-combine-iterations.md +0 -32
- package/skills/next-best-practices/rules/js-early-exit.md +0 -50
- package/skills/next-best-practices/rules/js-hoist-regexp.md +0 -45
- package/skills/next-best-practices/rules/js-index-maps.md +0 -37
- package/skills/next-best-practices/rules/js-length-check-first.md +0 -50
- package/skills/next-best-practices/rules/js-min-max-loop.md +0 -82
- package/skills/next-best-practices/rules/js-set-map-lookups.md +0 -24
- package/skills/next-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/skills/next-best-practices/rules/rendering-activity.md +0 -24
- package/skills/next-best-practices/rules/rendering-animate-svg-wrapper.md +0 -38
- package/skills/next-best-practices/rules/rendering-conditional-render.md +0 -32
- package/skills/next-best-practices/rules/rendering-content-visibility.md +0 -38
- package/skills/next-best-practices/rules/rendering-hoist-jsx.md +0 -36
- package/skills/next-best-practices/rules/rendering-hydration-no-flicker.md +0 -72
- package/skills/next-best-practices/rules/rendering-hydration-suppress-warning.md +0 -26
- package/skills/next-best-practices/rules/rendering-svg-precision.md +0 -28
- package/skills/next-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/skills/next-best-practices/rules/rerender-defer-reads.md +0 -39
- package/skills/next-best-practices/rules/rerender-dependencies.md +0 -45
- package/skills/next-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/skills/next-best-practices/rules/rerender-derived-state.md +0 -29
- package/skills/next-best-practices/rules/rerender-functional-setstate.md +0 -77
- package/skills/next-best-practices/rules/rerender-lazy-state-init.md +0 -56
- package/skills/next-best-practices/rules/rerender-memo-with-default-value.md +0 -36
- package/skills/next-best-practices/rules/rerender-memo.md +0 -44
- package/skills/next-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/skills/next-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/skills/next-best-practices/rules/rerender-transitions.md +0 -40
- package/skills/next-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/skills/next-best-practices/rules/server-after-nonblocking.md +0 -73
- package/skills/next-best-practices/rules/server-auth-actions.md +0 -96
- package/skills/next-best-practices/rules/server-cache-lru.md +0 -41
- package/skills/next-best-practices/rules/server-cache-react.md +0 -76
- package/skills/next-best-practices/rules/server-dedup-props.md +0 -65
- package/skills/next-best-practices/rules/server-parallel-fetching.md +0 -83
- package/skills/next-best-practices/rules/server-serialization.md +0 -38
- package/skills/next-cache-components/SKILL.md +0 -441
- package/skills/next-upgrade/SKILL.md +0 -43
- package/skills/next-upgrade/references/decision-tree.md +0 -33
- package/skills/nodejs/SKILL.md +0 -46
- package/skills/opentelemetry/SKILL.md +0 -62
- package/skills/package.json +0 -89
- package/skills/playwright-standard/SKILL.md +0 -53
- package/skills/playwright-standard/examples/fixtures.ts +0 -66
- package/skills/playwright-standard/examples/type-stubs.d.ts +0 -10
- package/skills/playwright-standard/references/advanced-scenarios.md +0 -59
- package/skills/playwright-standard/references/infrastructure.md +0 -43
- package/skills/playwright-standard/references/locators.md +0 -7
- package/skills/postgres/SKILL.md +0 -38
- package/skills/python/SKILL.md +0 -195
- package/skills/python/references/advanced-patterns.md +0 -37
- package/skills/python/references/config-templates.md +0 -48
- package/skills/rag-pipelines/SKILL.md +0 -14
- package/skills/redis/SKILL.md +0 -31
- package/skills/render/SKILL.md +0 -35
- package/skills/rust/SKILL.md +0 -76
- package/skills/rust/references/borrow-checker.md +0 -13
- package/skills/rust/references/ecosystem.md +0 -11
- package/skills/sandbox-sdk/SKILL.md +0 -186
- package/skills/sandbox-sdk/references/api-quick-ref.md +0 -113
- package/skills/sandbox-sdk/references/examples.md +0 -52
- package/skills/shadcn-ui/SKILL.md +0 -37
- package/skills/skill-builder/SKILL.md +0 -56
- package/skills/skill-builder/checklist.md +0 -65
- package/skills/skill-builder/references/tutorial.md +0 -457
- package/skills/sqlite/SKILL.md +0 -49
- package/skills/table.md +0 -59
- package/skills/tailwind-css/SKILL.md +0 -219
- package/skills/tailwind-css/references/component-patterns.md +0 -52
- package/skills/trpc/SKILL.md +0 -56
- package/skills/typescript/SKILL.md +0 -50
- package/skills/typescript/assets/eslint-template.js +0 -102
- package/skills/typescript/assets/tsconfig-template.json +0 -45
- package/skills/typescript/references/enterprise-patterns.md +0 -531
- package/skills/typescript/references/generics.md +0 -493
- package/skills/typescript/references/nestjs-integration.md +0 -579
- package/skills/typescript/references/react-integration.md +0 -616
- package/skills/typescript/references/toolchain.md +0 -547
- package/skills/typescript/references/tutorial.md +0 -453
- package/skills/typescript/references/type-system.md +0 -481
- package/skills/vercel-ai-sdk/SKILL.md +0 -48
- package/skills/vitest-standard/SKILL.md +0 -76
- package/skills/vitest-standard/examples/service-mock.ts +0 -60
- package/skills/vitest-standard/examples/tdd-calculator.ts +0 -41
- package/skills/vitest-standard/examples/type-stubs.d.ts +0 -18
- package/skills/vitest-standard/references/assertions.md +0 -11
- package/skills/vitest-standard/references/async-and-errors.md +0 -58
- package/skills/vitest-standard/references/coverage-and-config.md +0 -53
- package/skills/vitest-standard/references/mocking.md +0 -61
- package/skills/vitest-standard/references/tdd-patterns.md +0 -60
- package/skills/web-perf/SKILL.md +0 -207
- package/skills/workers-best-practices/SKILL.md +0 -120
- package/skills/workers-best-practices/references/anti-patterns.md +0 -18
- package/skills/workers-best-practices/references/review.md +0 -174
- package/skills/workers-best-practices/references/rules.md +0 -485
- package/skills/wrangler/SKILL.md +0 -43
- package/skills/wrangler/references/cli-commands.md +0 -861
- package/skills/zod/SKILL.md +0 -48
|
@@ -0,0 +1,3766 @@
|
|
|
1
|
+
import { DUMMY_GREP_SEARCH_TOOL_NAMES, DUMMY_FILE_VIEW_TOOL_NAMES, DUMMY_DIR_LIST_TOOL_NAMES, TOOL_GROUPS, logger, DatabaseAdapterFactory, runAutoPrune, AuditLogger, createAuditInterceptor, getGitHubIntegration, parseToolFilter, getFilterSummary, getToolFilterFromEnv, getAllToolNames, DEFAULT_BRIEFING_CONFIG, getTools, globalSubscriptionManager, getRequiredScope, getResources, getPrompts, callTool, sendProgress, requestContextStorage, MetricsAccumulator, formatPrometheusMetrics, SUPPORTED_SCOPES, logAgentIssue, validateResourceSubscription, isValidScope, getEnabledGroups, generateCodeModeInstructions, generateStandardInstructions, enforceAccessBoundary, auditOperation, parseScopes, BASE_SCOPES, getPrompt, handlePrompt, handleReadResource, handleListResources, handleListPrompts, handleGetPrompt, DUMMY_SERVER_INFO_TOOL_NAMES, handleServerInfo, handleListAdapters, handleGrepSearch, handleViewFile, handleListDir, DUMMY_RESOURCE_TOOL_NAMES, DUMMY_LIST_RESOURCE_TOOL_NAMES, DUMMY_LIST_PROMPT_TOOL_NAMES, DUMMY_LIST_TOOL_NAMES, DUMMY_GET_PROMPT_TOOL_NAMES, DUMMY_PROJECT_TOOL_NAMES, DUMMY_ADAPTER_TOOL_NAMES, readResource } from './chunk-T7SROBBV.js';
|
|
2
|
+
import { VERSION, applyArgInterceptions } from './chunk-SGJU2DHU.js';
|
|
3
|
+
import { runWithAuthContext, getAuthContext } from './chunk-4FZCHFB5.js';
|
|
4
|
+
import { MemoryJournalMcpError, ConfigurationError } from './chunk-E6IQP6PE.js';
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
|
|
6
|
+
import express from 'express';
|
|
7
|
+
import { createHash, timingSafeEqual, randomUUID } from 'crypto';
|
|
8
|
+
import 'https';
|
|
9
|
+
import * as jose from 'jose';
|
|
10
|
+
import { localhostHostValidation, hostHeaderValidation } from '@modelcontextprotocol/express';
|
|
11
|
+
import { toNodeHandler, NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
|
|
12
|
+
import { McpServer, createMcpHandler, ResourceTemplate } from '@modelcontextprotocol/server';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { loadSkills } from '@modelcontextprotocol/server/ext/skills/node';
|
|
16
|
+
import * as dns from 'dns';
|
|
17
|
+
import { EventEmitter } from 'events';
|
|
18
|
+
import { parse, stringify } from 'yaml';
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
import * as http from 'http';
|
|
21
|
+
|
|
22
|
+
// src/transports/http/types.ts
|
|
23
|
+
var HTTP_REQUEST_TIMEOUT_MS = 12e4;
|
|
24
|
+
var HTTP_KEEP_ALIVE_TIMEOUT_MS = 65e3;
|
|
25
|
+
var HTTP_HEADERS_TIMEOUT_MS = 66e3;
|
|
26
|
+
var DEFAULT_RATE_LIMIT_WINDOW_MS = 6e4;
|
|
27
|
+
var DEFAULT_RATE_LIMIT_MAX_REQUESTS = 100;
|
|
28
|
+
var DEFAULT_MAX_BODY_BYTES = 1048576;
|
|
29
|
+
var DEFAULT_HSTS_MAX_AGE = 31536e3;
|
|
30
|
+
var CORS_PREFLIGHT_MAX_AGE_SECONDS = 86400;
|
|
31
|
+
var SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
32
|
+
var SESSION_SWEEP_INTERVAL_MS = 1 * 60 * 1e3;
|
|
33
|
+
function getClientIp(req) {
|
|
34
|
+
return req.ip ?? req.socket.remoteAddress ?? "unknown";
|
|
35
|
+
}
|
|
36
|
+
function checkRateLimit(req, config, rateLimitMap) {
|
|
37
|
+
if (config.enableRateLimit === false) {
|
|
38
|
+
return { allowed: true };
|
|
39
|
+
}
|
|
40
|
+
const authReq = req;
|
|
41
|
+
const subject = authReq.tokenClaims?.sub ?? authReq.tokenClaims?.client_id ?? authReq.auth?.sub ?? authReq.auth?.subject ?? authReq.auth?.clientId;
|
|
42
|
+
const ip = getClientIp(req);
|
|
43
|
+
const rawIdentity = typeof subject === "string" && subject ? subject : ip;
|
|
44
|
+
const clientIdentity = createHash("sha256").update(rawIdentity).digest("hex");
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
const windowMs = config.rateLimitWindowMs ?? DEFAULT_RATE_LIMIT_WINDOW_MS;
|
|
47
|
+
let envMaxRequests = process.env["MCP_RATE_LIMIT_MAX"] ? parseInt(process.env["MCP_RATE_LIMIT_MAX"], 10) : NaN;
|
|
48
|
+
if (Number.isNaN(envMaxRequests) || envMaxRequests <= 0) {
|
|
49
|
+
envMaxRequests = DEFAULT_RATE_LIMIT_MAX_REQUESTS;
|
|
50
|
+
}
|
|
51
|
+
const maxRequests = config.rateLimitMaxRequests ?? envMaxRequests;
|
|
52
|
+
const entry = rateLimitMap.get(clientIdentity);
|
|
53
|
+
if (!entry || now > entry.resetTime) {
|
|
54
|
+
if (rateLimitMap.size >= 1e4 && !rateLimitMap.has(clientIdentity)) {
|
|
55
|
+
for (const [key, val] of rateLimitMap.entries()) {
|
|
56
|
+
if (now > val.resetTime) {
|
|
57
|
+
rateLimitMap.delete(key);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (rateLimitMap.size >= 1e4) {
|
|
61
|
+
const firstKey = rateLimitMap.keys().next().value;
|
|
62
|
+
if (firstKey !== void 0) {
|
|
63
|
+
rateLimitMap.delete(firstKey);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
rateLimitMap.set(clientIdentity, { count: 1, resetTime: now + windowMs, lastSeen: now });
|
|
68
|
+
return { allowed: true };
|
|
69
|
+
}
|
|
70
|
+
entry.lastSeen = now;
|
|
71
|
+
rateLimitMap.delete(clientIdentity);
|
|
72
|
+
rateLimitMap.set(clientIdentity, entry);
|
|
73
|
+
if (entry.count >= maxRequests) {
|
|
74
|
+
const retryAfterSeconds = Math.ceil((entry.resetTime - now) / 1e3);
|
|
75
|
+
return { allowed: false, retryAfterSeconds };
|
|
76
|
+
}
|
|
77
|
+
entry.count++;
|
|
78
|
+
return { allowed: true };
|
|
79
|
+
}
|
|
80
|
+
function setSecurityHeaders(res, config) {
|
|
81
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
82
|
+
res.setHeader("X-Frame-Options", "DENY");
|
|
83
|
+
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
84
|
+
res.setHeader("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'");
|
|
85
|
+
res.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
|
|
86
|
+
res.setHeader("Referrer-Policy", "no-referrer");
|
|
87
|
+
if (config.enableHSTS) {
|
|
88
|
+
const maxAge = config.hstsMaxAge ?? DEFAULT_HSTS_MAX_AGE;
|
|
89
|
+
res.setHeader("Strict-Transport-Security", `max-age=${String(maxAge)}; includeSubDomains`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function setCorsHeaders(req, res, config) {
|
|
93
|
+
let corsOrigins = config.corsOrigins ?? [];
|
|
94
|
+
const isLocalhost = config.host === "localhost" || config.host === "127.0.0.1" || config.host === "::1";
|
|
95
|
+
const hasAuth = Boolean(config.authToken) || config.oauthEnabled === true;
|
|
96
|
+
if (isLocalhost && !hasAuth && corsOrigins.includes("*")) {
|
|
97
|
+
corsOrigins = corsOrigins.filter((o) => o !== "*");
|
|
98
|
+
}
|
|
99
|
+
const isWildcard = corsOrigins.includes("*");
|
|
100
|
+
const origin = req.headers.origin;
|
|
101
|
+
if (isWildcard) {
|
|
102
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
103
|
+
} else if (origin) {
|
|
104
|
+
const whitelist = /* @__PURE__ */ Object.create(null);
|
|
105
|
+
for (const allowed of corsOrigins) {
|
|
106
|
+
whitelist[allowed] = true;
|
|
107
|
+
}
|
|
108
|
+
if (origin in whitelist) {
|
|
109
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
110
|
+
res.setHeader("Vary", "Origin");
|
|
111
|
+
if (config.corsAllowCredentials) {
|
|
112
|
+
res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
117
|
+
res.setHeader(
|
|
118
|
+
"Access-Control-Allow-Headers",
|
|
119
|
+
"Content-Type, Accept, Authorization, mcp-session-id, Last-Event-ID, mcp-protocol-version"
|
|
120
|
+
);
|
|
121
|
+
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id");
|
|
122
|
+
res.setHeader("Access-Control-Max-Age", String(CORS_PREFLIGHT_MAX_AGE_SECONDS));
|
|
123
|
+
if (origin && !isWildcard) {
|
|
124
|
+
const whitelist = /* @__PURE__ */ Object.create(null);
|
|
125
|
+
for (const allowed of corsOrigins) whitelist[allowed] = true;
|
|
126
|
+
if (!(origin in whitelist)) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
function handleHealthCheck(_req, res) {
|
|
133
|
+
res.status(200).json({
|
|
134
|
+
status: "healthy",
|
|
135
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function handlePrometheusMetrics(runtime) {
|
|
139
|
+
return (_req, res) => {
|
|
140
|
+
if (runtime?.metrics === void 0) {
|
|
141
|
+
res.status(503).send("Metrics not available");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const metricsText = formatPrometheusMetrics(runtime.metrics);
|
|
146
|
+
res.set("Content-Type", "text/plain; version=0.0.4; charset=utf-8");
|
|
147
|
+
res.status(200).send(metricsText);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
logger.error("Failed to format Prometheus metrics", { module: "HTTP", error });
|
|
150
|
+
res.status(500).send("Internal Server Error");
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function handleRootInfo(_req, res) {
|
|
155
|
+
res.status(200).json({
|
|
156
|
+
name: "memory-journal-mcp",
|
|
157
|
+
version: VERSION,
|
|
158
|
+
description: "Project context management for AI-assisted development",
|
|
159
|
+
endpoints: {
|
|
160
|
+
"POST /mcp": "JSON-RPC requests (Streamable HTTP, MCP 2025-03-26)",
|
|
161
|
+
"GET /mcp": "SSE stream for server-to-client notifications",
|
|
162
|
+
"DELETE /mcp": "Session termination",
|
|
163
|
+
"GET /sse": "Legacy SSE connection (MCP 2024-11-05)",
|
|
164
|
+
"POST /messages": "Legacy SSE message endpoint",
|
|
165
|
+
"GET /health": "Health check",
|
|
166
|
+
"GET /metrics": "Prometheus metrics export (if enabled)"
|
|
167
|
+
},
|
|
168
|
+
documentation: "https://github.com/neverinfamous/memory-journal-mcp"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function createAuthMiddleware(authToken) {
|
|
172
|
+
logger.info("Bearer token authentication enabled", { module: "HTTP" });
|
|
173
|
+
return (req, res, next) => {
|
|
174
|
+
if (req.path === "/health" || req.path === "/metrics") {
|
|
175
|
+
next();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const header = req.headers.authorization;
|
|
179
|
+
const expected = Buffer.from(`Bearer ${authToken}`);
|
|
180
|
+
const received = Buffer.from(header ?? "");
|
|
181
|
+
if (expected.length !== received.length || !timingSafeEqual(expected, received)) {
|
|
182
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const envScopes = process.env["MCP_AUTH_SCOPES"];
|
|
186
|
+
let defaultScopes = envScopes ? envScopes.split(",").map((s) => s.trim()) : ["read"];
|
|
187
|
+
const invalidScopes = defaultScopes.filter((s) => !isValidScope(s));
|
|
188
|
+
if (invalidScopes.length > 0) {
|
|
189
|
+
logger.warning(
|
|
190
|
+
`Invalid MCP_AUTH_SCOPES detected: ${invalidScopes.join(", ")}. Falling back to safe defaults.`,
|
|
191
|
+
{ module: "HTTP" }
|
|
192
|
+
);
|
|
193
|
+
defaultScopes = ["read"];
|
|
194
|
+
}
|
|
195
|
+
const clientIp = getClientIp(req);
|
|
196
|
+
const hashInput = `${authToken}:${clientIp}`;
|
|
197
|
+
const identityHash = createHash("sha256").update(hashInput).digest("hex").substring(0, 12);
|
|
198
|
+
const identity = `bearer-${identityHash}`;
|
|
199
|
+
req.auth = {
|
|
200
|
+
sub: identity,
|
|
201
|
+
subject: identity,
|
|
202
|
+
scopes: defaultScopes
|
|
203
|
+
};
|
|
204
|
+
next();
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/auth/errors.ts
|
|
209
|
+
var AUTH_ERROR_CODES = {
|
|
210
|
+
TOKEN_MISSING: "AUTH_TOKEN_MISSING",
|
|
211
|
+
TOKEN_INVALID: "AUTH_TOKEN_INVALID",
|
|
212
|
+
TOKEN_EXPIRED: "AUTH_TOKEN_EXPIRED",
|
|
213
|
+
SIGNATURE_INVALID: "AUTH_SIGNATURE_INVALID",
|
|
214
|
+
JWKS_FETCH_FAILED: "AUTH_JWKS_FETCH_FAILED"};
|
|
215
|
+
var OAuthError = class extends MemoryJournalMcpError {
|
|
216
|
+
/** HTTP status code for this error */
|
|
217
|
+
httpStatus;
|
|
218
|
+
/** WWW-Authenticate header value */
|
|
219
|
+
wwwAuthenticate;
|
|
220
|
+
constructor(message, code, httpStatus, details, wwwAuthenticate) {
|
|
221
|
+
const category = httpStatus === 403 ? "authorization" : "authentication";
|
|
222
|
+
super(message, code, category, {
|
|
223
|
+
suggestion: httpStatus === 403 ? "Request a token with the required scopes" : "Provide a valid OAuth 2.0 bearer token",
|
|
224
|
+
recoverable: httpStatus !== 500,
|
|
225
|
+
details
|
|
226
|
+
});
|
|
227
|
+
this.name = "OAuthError";
|
|
228
|
+
this.httpStatus = httpStatus;
|
|
229
|
+
this.wwwAuthenticate = wwwAuthenticate;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
var TokenMissingError = class extends OAuthError {
|
|
233
|
+
constructor(realm = "memory-journal-mcp") {
|
|
234
|
+
super(
|
|
235
|
+
"No access token provided",
|
|
236
|
+
AUTH_ERROR_CODES.TOKEN_MISSING,
|
|
237
|
+
401,
|
|
238
|
+
void 0,
|
|
239
|
+
`Bearer realm="${realm}"`
|
|
240
|
+
);
|
|
241
|
+
this.name = "TokenMissingError";
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
var InvalidTokenError = class extends OAuthError {
|
|
245
|
+
constructor(message = "Invalid access token", details) {
|
|
246
|
+
super(message, AUTH_ERROR_CODES.TOKEN_INVALID, 401, details, 'Bearer error="invalid_token"');
|
|
247
|
+
this.name = "InvalidTokenError";
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
var TokenExpiredError = class extends OAuthError {
|
|
251
|
+
constructor(expiredAt) {
|
|
252
|
+
super(
|
|
253
|
+
"Access token has expired",
|
|
254
|
+
AUTH_ERROR_CODES.TOKEN_EXPIRED,
|
|
255
|
+
401,
|
|
256
|
+
expiredAt ? { expiredAt: expiredAt.toISOString() } : void 0,
|
|
257
|
+
'Bearer error="invalid_token", error_description="Token has expired"'
|
|
258
|
+
);
|
|
259
|
+
this.name = "TokenExpiredError";
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
var InvalidSignatureError = class extends OAuthError {
|
|
263
|
+
constructor(message = "Token signature verification failed") {
|
|
264
|
+
super(
|
|
265
|
+
message,
|
|
266
|
+
AUTH_ERROR_CODES.SIGNATURE_INVALID,
|
|
267
|
+
401,
|
|
268
|
+
void 0,
|
|
269
|
+
'Bearer error="invalid_token", error_description="Signature verification failed"'
|
|
270
|
+
);
|
|
271
|
+
this.name = "InvalidSignatureError";
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
var JwksFetchError = class extends OAuthError {
|
|
275
|
+
constructor(jwksUri, cause) {
|
|
276
|
+
super("Failed to fetch JWKS: " + jwksUri, AUTH_ERROR_CODES.JWKS_FETCH_FAILED, 500, {
|
|
277
|
+
jwksUri,
|
|
278
|
+
cause: cause?.message
|
|
279
|
+
});
|
|
280
|
+
this.name = "JwksFetchError";
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
function isOAuthError(error) {
|
|
284
|
+
return error instanceof OAuthError;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// src/auth/oauth-resource-server.ts
|
|
288
|
+
var OAuthResourceServer = class {
|
|
289
|
+
config;
|
|
290
|
+
metadata = null;
|
|
291
|
+
constructor(config) {
|
|
292
|
+
this.config = {
|
|
293
|
+
resource: config.resource,
|
|
294
|
+
authorizationServers: config.authorizationServers,
|
|
295
|
+
scopesSupported: config.scopesSupported.length > 0 ? config.scopesSupported : [...SUPPORTED_SCOPES],
|
|
296
|
+
bearerMethodsSupported: config.bearerMethodsSupported ?? ["header"]
|
|
297
|
+
};
|
|
298
|
+
logger.info(`OAuth Resource Server initialized for: ${this.config.resource}`, {
|
|
299
|
+
module: "AUTH",
|
|
300
|
+
operation: "init"
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get the Protected Resource Metadata document
|
|
305
|
+
*
|
|
306
|
+
* @returns RFC 9728 compliant metadata
|
|
307
|
+
*/
|
|
308
|
+
getMetadata() {
|
|
309
|
+
this.metadata ??= this.buildMetadata();
|
|
310
|
+
return this.metadata;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Build the Protected Resource Metadata document
|
|
314
|
+
*/
|
|
315
|
+
buildMetadata() {
|
|
316
|
+
return {
|
|
317
|
+
resource: this.config.resource,
|
|
318
|
+
authorization_servers: this.config.authorizationServers,
|
|
319
|
+
scopes_supported: this.config.scopesSupported,
|
|
320
|
+
bearer_methods_supported: this.config.bearerMethodsSupported,
|
|
321
|
+
resource_documentation: `${this.config.resource}/docs`,
|
|
322
|
+
resource_signing_alg_values_supported: ["RS256", "ES256"]
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get Express request handler for the metadata endpoint
|
|
327
|
+
*
|
|
328
|
+
* Serves: GET /.well-known/oauth-protected-resource
|
|
329
|
+
*/
|
|
330
|
+
getMetadataHandler() {
|
|
331
|
+
return (_req, res) => {
|
|
332
|
+
const metadata = this.getMetadata();
|
|
333
|
+
res.setHeader("Content-Type", "application/oauth-protected-resource-metadata+json");
|
|
334
|
+
res.setHeader("Cache-Control", "public, max-age=3600");
|
|
335
|
+
res.json(metadata);
|
|
336
|
+
logger.info("Protected Resource Metadata served", {
|
|
337
|
+
module: "AUTH",
|
|
338
|
+
operation: "metadata-served"
|
|
339
|
+
});
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Generate WWW-Authenticate header for 401 responses
|
|
344
|
+
*
|
|
345
|
+
* @param error - Error type for the header
|
|
346
|
+
* @param errorDescription - Human-readable error description
|
|
347
|
+
* @returns WWW-Authenticate header value
|
|
348
|
+
*/
|
|
349
|
+
getWWWAuthenticateHeader(error, errorDescription) {
|
|
350
|
+
const escapeHeaderValue = (str) => str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/[\r\n]/g, " ");
|
|
351
|
+
const parts = [`Bearer realm="${escapeHeaderValue(this.config.resource)}"`];
|
|
352
|
+
if (error) {
|
|
353
|
+
parts.push(`error="${escapeHeaderValue(error)}"`);
|
|
354
|
+
}
|
|
355
|
+
if (errorDescription) {
|
|
356
|
+
parts.push(`error_description="${escapeHeaderValue(errorDescription)}"`);
|
|
357
|
+
}
|
|
358
|
+
return parts.join(", ");
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Get the resource URI
|
|
362
|
+
*/
|
|
363
|
+
getResourceUri() {
|
|
364
|
+
return this.config.resource;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Get the authorization servers
|
|
368
|
+
*/
|
|
369
|
+
getAuthorizationServers() {
|
|
370
|
+
return [...this.config.authorizationServers];
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Get supported scopes
|
|
374
|
+
*/
|
|
375
|
+
getSupportedScopes() {
|
|
376
|
+
return [...this.config.scopesSupported];
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Check if a scope is supported by this resource server.
|
|
380
|
+
*/
|
|
381
|
+
isScopeSupported(scope) {
|
|
382
|
+
if (BASE_SCOPES.includes(scope)) {
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
if (this.config.scopesSupported.includes(scope)) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Get the well-known metadata endpoint path
|
|
392
|
+
*/
|
|
393
|
+
getWellKnownPath() {
|
|
394
|
+
return "/.well-known/oauth-protected-resource";
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Clear cached metadata (useful when configuration changes)
|
|
398
|
+
*/
|
|
399
|
+
clearCache() {
|
|
400
|
+
this.metadata = null;
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
function createOAuthResourceServer(config) {
|
|
404
|
+
return new OAuthResourceServer(config);
|
|
405
|
+
}
|
|
406
|
+
var TokenValidator = class {
|
|
407
|
+
/** Resolved configuration with all defaults applied */
|
|
408
|
+
jwksUri;
|
|
409
|
+
issuer;
|
|
410
|
+
audience;
|
|
411
|
+
clockTolerance;
|
|
412
|
+
jwksCacheTtl;
|
|
413
|
+
jwks = null;
|
|
414
|
+
jwksExpiry = 0;
|
|
415
|
+
constructor(config) {
|
|
416
|
+
this.jwksUri = config.jwksUri;
|
|
417
|
+
this.issuer = config.issuer;
|
|
418
|
+
this.audience = config.audience;
|
|
419
|
+
this.clockTolerance = config.clockTolerance ?? 60;
|
|
420
|
+
this.jwksCacheTtl = config.jwksCacheTtl ?? 3600;
|
|
421
|
+
const issuerUrl = new URL(this.issuer);
|
|
422
|
+
const jwksUrl = new URL(this.jwksUri);
|
|
423
|
+
const isLoopback = (host) => host === "localhost" || host === "127.0.0.1" || host === "[::1]";
|
|
424
|
+
if (issuerUrl.protocol !== "https:" && !isLoopback(issuerUrl.hostname)) {
|
|
425
|
+
throw new Error(
|
|
426
|
+
`Security Violation: Issuer must use HTTPS protocol (got ${this.issuer})`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
if (jwksUrl.protocol !== "https:" && !isLoopback(jwksUrl.hostname)) {
|
|
430
|
+
throw new Error(
|
|
431
|
+
`Security Violation: JWKS URI must use HTTPS protocol (got ${this.jwksUri})`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
if (issuerUrl.origin !== jwksUrl.origin) {
|
|
435
|
+
throw new Error(
|
|
436
|
+
`Security Violation: JWKS URI origin (${jwksUrl.origin}) does not match Issuer origin (${issuerUrl.origin})`
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
const issuerHost = new URL(this.issuer).hostname;
|
|
440
|
+
logger.info(`Token Validator initialized for issuer: ${issuerHost}`, {
|
|
441
|
+
module: "AUTH",
|
|
442
|
+
operation: "init"
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Validate an access token
|
|
447
|
+
*
|
|
448
|
+
* @param token - The JWT access token
|
|
449
|
+
* @returns Validation result with claims or error
|
|
450
|
+
*/
|
|
451
|
+
async validate(token) {
|
|
452
|
+
try {
|
|
453
|
+
const jwks = this.getJwks();
|
|
454
|
+
const { payload } = await jose.jwtVerify(token, jwks, {
|
|
455
|
+
issuer: this.issuer,
|
|
456
|
+
audience: this.audience,
|
|
457
|
+
clockTolerance: this.clockTolerance,
|
|
458
|
+
algorithms: ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"],
|
|
459
|
+
// jose only checks `exp` when it is present. Require it so a validly signed token
|
|
460
|
+
// without an expiry cannot become a permanent credential.
|
|
461
|
+
requiredClaims: ["exp"]
|
|
462
|
+
});
|
|
463
|
+
const claims = this.extractClaims(payload);
|
|
464
|
+
logger.info(`Token validated for subject: ${claims.sub}`, {
|
|
465
|
+
module: "AUTH",
|
|
466
|
+
operation: "validate",
|
|
467
|
+
entityId: claims.sub
|
|
468
|
+
});
|
|
469
|
+
return {
|
|
470
|
+
valid: true,
|
|
471
|
+
claims
|
|
472
|
+
};
|
|
473
|
+
} catch (error) {
|
|
474
|
+
return this.handleValidationError(error);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get or refresh the JWKS
|
|
479
|
+
*/
|
|
480
|
+
getJwks() {
|
|
481
|
+
if (this.jwks && Date.now() < this.jwksExpiry) {
|
|
482
|
+
return this.jwks;
|
|
483
|
+
}
|
|
484
|
+
const jwksHost = (() => {
|
|
485
|
+
try {
|
|
486
|
+
return new URL(this.jwksUri).hostname;
|
|
487
|
+
} catch {
|
|
488
|
+
return "[configured]";
|
|
489
|
+
}
|
|
490
|
+
})();
|
|
491
|
+
logger.info(`Fetching JWKS from: ${jwksHost}`, {
|
|
492
|
+
module: "AUTH",
|
|
493
|
+
operation: "jwks-fetch"
|
|
494
|
+
});
|
|
495
|
+
try {
|
|
496
|
+
this.jwks = jose.createRemoteJWKSet(new URL(this.jwksUri), {
|
|
497
|
+
cooldownDuration: 3e4,
|
|
498
|
+
// 30 seconds between retries
|
|
499
|
+
cacheMaxAge: this.jwksCacheTtl * 1e3,
|
|
500
|
+
timeoutDuration: 5e3
|
|
501
|
+
// Explicit 5s timeout to prevent socket hangs
|
|
502
|
+
});
|
|
503
|
+
this.jwksExpiry = Date.now() + this.jwksCacheTtl * 1e3;
|
|
504
|
+
logger.info(`JWKS cached for ${String(this.jwksCacheTtl)}s`, {
|
|
505
|
+
module: "AUTH",
|
|
506
|
+
operation: "jwks-cache"
|
|
507
|
+
});
|
|
508
|
+
return this.jwks;
|
|
509
|
+
} catch (error) {
|
|
510
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
511
|
+
logger.error("Failed to fetch JWKS", {
|
|
512
|
+
module: "AUTH",
|
|
513
|
+
operation: "jwks-fetch",
|
|
514
|
+
error: cause.message
|
|
515
|
+
});
|
|
516
|
+
throw new JwksFetchError(this.jwksUri, cause);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Extract and normalize token claims
|
|
521
|
+
*/
|
|
522
|
+
extractClaims(payload) {
|
|
523
|
+
let scopes = [];
|
|
524
|
+
if (typeof payload["scope"] === "string") {
|
|
525
|
+
scopes = parseScopes(payload["scope"]);
|
|
526
|
+
} else if (Array.isArray(payload["scopes"])) {
|
|
527
|
+
scopes = payload["scopes"].filter((s) => typeof s === "string");
|
|
528
|
+
} else if (Array.isArray(payload["scope"])) {
|
|
529
|
+
scopes = payload["scope"].filter((s) => typeof s === "string");
|
|
530
|
+
}
|
|
531
|
+
const { exp } = payload;
|
|
532
|
+
if (exp === void 0) {
|
|
533
|
+
throw new jose.errors.JWTClaimValidationFailed(
|
|
534
|
+
'missing required "exp" claim',
|
|
535
|
+
payload,
|
|
536
|
+
"exp",
|
|
537
|
+
"missing"
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
return {
|
|
541
|
+
sub: payload.sub ?? "unknown",
|
|
542
|
+
scopes,
|
|
543
|
+
exp,
|
|
544
|
+
iat: payload.iat ?? 0,
|
|
545
|
+
iss: payload.iss,
|
|
546
|
+
aud: payload.aud,
|
|
547
|
+
nbf: payload.nbf ?? void 0,
|
|
548
|
+
jti: payload.jti,
|
|
549
|
+
client_id: payload["client_id"],
|
|
550
|
+
// Include all other claims
|
|
551
|
+
...payload
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Handle validation errors and convert to TokenValidationResult
|
|
556
|
+
*/
|
|
557
|
+
handleValidationError(error) {
|
|
558
|
+
if (error instanceof jose.errors.JWTExpired) {
|
|
559
|
+
logger.warning("Token has expired", {
|
|
560
|
+
module: "AUTH",
|
|
561
|
+
operation: "validate"
|
|
562
|
+
});
|
|
563
|
+
return {
|
|
564
|
+
valid: false,
|
|
565
|
+
error: "Invalid or expired token",
|
|
566
|
+
errorCode: AUTH_ERROR_CODES.TOKEN_EXPIRED
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
if (error instanceof jose.errors.JWTClaimValidationFailed) {
|
|
570
|
+
logger.warning(`Token claim validation failed: ${error.message}`, {
|
|
571
|
+
module: "AUTH",
|
|
572
|
+
operation: "validate"
|
|
573
|
+
});
|
|
574
|
+
return {
|
|
575
|
+
valid: false,
|
|
576
|
+
error: "Invalid or expired token",
|
|
577
|
+
errorCode: AUTH_ERROR_CODES.TOKEN_INVALID
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
if (error instanceof jose.errors.JWSSignatureVerificationFailed) {
|
|
581
|
+
logger.warning("Token signature verification failed", {
|
|
582
|
+
module: "AUTH",
|
|
583
|
+
operation: "validate"
|
|
584
|
+
});
|
|
585
|
+
return {
|
|
586
|
+
valid: false,
|
|
587
|
+
error: "Invalid or expired token",
|
|
588
|
+
errorCode: AUTH_ERROR_CODES.SIGNATURE_INVALID
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
if (error instanceof jose.errors.JWKSNoMatchingKey) {
|
|
592
|
+
logger.warning("No matching key found in JWKS", {
|
|
593
|
+
module: "AUTH",
|
|
594
|
+
operation: "validate"
|
|
595
|
+
});
|
|
596
|
+
return {
|
|
597
|
+
valid: false,
|
|
598
|
+
error: "Invalid or expired token",
|
|
599
|
+
errorCode: AUTH_ERROR_CODES.TOKEN_INVALID
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
603
|
+
logger.error(`Token validation failed: ${message}`, {
|
|
604
|
+
module: "AUTH",
|
|
605
|
+
operation: "validate"
|
|
606
|
+
});
|
|
607
|
+
return {
|
|
608
|
+
valid: false,
|
|
609
|
+
error: "Invalid or expired token",
|
|
610
|
+
errorCode: AUTH_ERROR_CODES.TOKEN_INVALID
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Refresh the JWKS cache
|
|
615
|
+
*/
|
|
616
|
+
refreshJwks() {
|
|
617
|
+
this.jwks = null;
|
|
618
|
+
this.jwksExpiry = 0;
|
|
619
|
+
this.getJwks();
|
|
620
|
+
logger.info("JWKS cache refreshed", { module: "AUTH", operation: "jwks-refresh" });
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Clear the JWKS cache
|
|
624
|
+
*/
|
|
625
|
+
clearCache() {
|
|
626
|
+
this.jwks = null;
|
|
627
|
+
this.jwksExpiry = 0;
|
|
628
|
+
logger.info("Token validator cache cleared", { module: "AUTH", operation: "cache-clear" });
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Convert a validation error to the appropriate OAuth error class
|
|
632
|
+
*/
|
|
633
|
+
static toOAuthError(result) {
|
|
634
|
+
if (result.errorCode === AUTH_ERROR_CODES.TOKEN_EXPIRED) {
|
|
635
|
+
return new TokenExpiredError();
|
|
636
|
+
}
|
|
637
|
+
if (result.errorCode === AUTH_ERROR_CODES.SIGNATURE_INVALID) {
|
|
638
|
+
return new InvalidSignatureError();
|
|
639
|
+
}
|
|
640
|
+
return new InvalidTokenError(result.error);
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Preload JWKS to validate availability at startup
|
|
644
|
+
*/
|
|
645
|
+
async preload() {
|
|
646
|
+
const jwksHost = (() => {
|
|
647
|
+
try {
|
|
648
|
+
return new URL(this.jwksUri).hostname;
|
|
649
|
+
} catch {
|
|
650
|
+
return "[configured]";
|
|
651
|
+
}
|
|
652
|
+
})();
|
|
653
|
+
logger.info(`Pre-fetching JWKS from: ${jwksHost}`, {
|
|
654
|
+
module: "AUTH",
|
|
655
|
+
operation: "jwks-preload"
|
|
656
|
+
});
|
|
657
|
+
try {
|
|
658
|
+
const response = await fetch(this.jwksUri, {
|
|
659
|
+
method: "GET",
|
|
660
|
+
signal: AbortSignal.timeout(1e4),
|
|
661
|
+
redirect: "error"
|
|
662
|
+
});
|
|
663
|
+
if (!response.ok) {
|
|
664
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
665
|
+
}
|
|
666
|
+
} catch (error) {
|
|
667
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
668
|
+
logger.error("Failed to pre-fetch JWKS at startup", {
|
|
669
|
+
module: "AUTH",
|
|
670
|
+
operation: "jwks-preload",
|
|
671
|
+
error: cause.message
|
|
672
|
+
});
|
|
673
|
+
throw new JwksFetchError(this.jwksUri, cause);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
function createTokenValidator(config) {
|
|
678
|
+
return new TokenValidator(config);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/auth/transport-agnostic.ts
|
|
682
|
+
function extractBearerToken(authHeader) {
|
|
683
|
+
if (!authHeader) return null;
|
|
684
|
+
const parts = authHeader.split(" ");
|
|
685
|
+
const scheme = parts[0];
|
|
686
|
+
const tokenPart = parts[1];
|
|
687
|
+
if (parts.length !== 2 || scheme?.toLowerCase() !== "bearer") return null;
|
|
688
|
+
if (tokenPart === void 0) return null;
|
|
689
|
+
const token = tokenPart.trim();
|
|
690
|
+
return token.length > 0 ? token : null;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// src/auth/middleware.ts
|
|
694
|
+
function isPublicPath(path2, publicPaths) {
|
|
695
|
+
if (path2 === "/.well-known/oauth-authorization-server" || path2 === "/.well-known/jwks.json") {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
for (const pattern of publicPaths) {
|
|
699
|
+
if (pattern === path2) {
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
if (pattern.endsWith("/*")) {
|
|
703
|
+
const prefix = pattern.slice(0, -2);
|
|
704
|
+
if (path2 === prefix || path2.startsWith(prefix + "/")) {
|
|
705
|
+
return true;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
function createAuthMiddleware2(config) {
|
|
712
|
+
const { tokenValidator, resourceServer, publicPaths = [] } = config;
|
|
713
|
+
return async (req, res, next) => {
|
|
714
|
+
const authReq = req;
|
|
715
|
+
const requestId = crypto.randomUUID();
|
|
716
|
+
authReq.requestId = requestId;
|
|
717
|
+
if (isPublicPath(req.path, publicPaths)) {
|
|
718
|
+
logger.info(`Public path accessed: ${req.path}`, {
|
|
719
|
+
module: "AUTH",
|
|
720
|
+
operation: "public-path"
|
|
721
|
+
});
|
|
722
|
+
next();
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
const token = extractBearerToken(req.headers.authorization);
|
|
726
|
+
if (!token) {
|
|
727
|
+
const error = new TokenMissingError(resourceServer.getResourceUri());
|
|
728
|
+
logger.warning("No access token provided", {
|
|
729
|
+
module: "AUTH",
|
|
730
|
+
operation: "authenticate"
|
|
731
|
+
});
|
|
732
|
+
res.status(error.httpStatus);
|
|
733
|
+
res.setHeader("WWW-Authenticate", error.wwwAuthenticate ?? "");
|
|
734
|
+
res.json({
|
|
735
|
+
error: "unauthorized",
|
|
736
|
+
error_description: error.message
|
|
737
|
+
});
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const result = await tokenValidator.validate(token);
|
|
741
|
+
if (!result.valid) {
|
|
742
|
+
logger.warning(`Token validation failed: ${result.error ?? "Unknown error"}`, {
|
|
743
|
+
module: "AUTH",
|
|
744
|
+
operation: "authenticate"
|
|
745
|
+
});
|
|
746
|
+
res.status(401);
|
|
747
|
+
res.setHeader(
|
|
748
|
+
"WWW-Authenticate",
|
|
749
|
+
resourceServer.getWWWAuthenticateHeader("invalid_token", result.error)
|
|
750
|
+
);
|
|
751
|
+
res.json({
|
|
752
|
+
error: "invalid_token",
|
|
753
|
+
error_description: result.error
|
|
754
|
+
});
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
const claims = result.claims;
|
|
758
|
+
if (!claims) {
|
|
759
|
+
res.status(500).json({ error: "internal_error" });
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
const authInfo = {
|
|
763
|
+
token,
|
|
764
|
+
clientId: claims.client_id || claims.sub,
|
|
765
|
+
scopes: claims.scopes,
|
|
766
|
+
expiresAt: claims.exp * 1e3
|
|
767
|
+
};
|
|
768
|
+
authReq.auth = authInfo;
|
|
769
|
+
authReq.tokenClaims = claims;
|
|
770
|
+
authReq.accessToken = token;
|
|
771
|
+
logger.info(`Request authenticated: ${claims.sub}`, {
|
|
772
|
+
module: "AUTH",
|
|
773
|
+
operation: "authenticate",
|
|
774
|
+
entityId: claims.sub
|
|
775
|
+
});
|
|
776
|
+
next();
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
function oauthErrorHandler(error, _req, res, next) {
|
|
780
|
+
if (isOAuthError(error)) {
|
|
781
|
+
res.status(error.httpStatus);
|
|
782
|
+
if (error.wwwAuthenticate) {
|
|
783
|
+
res.setHeader("WWW-Authenticate", error.wwwAuthenticate);
|
|
784
|
+
}
|
|
785
|
+
res.json({
|
|
786
|
+
error: error.code,
|
|
787
|
+
error_description: error.message
|
|
788
|
+
});
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
next(error);
|
|
792
|
+
}
|
|
793
|
+
var LegacySSEServerTransport = class {
|
|
794
|
+
constructor(messagesEndpoint, sessionId) {
|
|
795
|
+
this.messagesEndpoint = messagesEndpoint;
|
|
796
|
+
this.sessionId = sessionId ?? randomUUID();
|
|
797
|
+
}
|
|
798
|
+
messagesEndpoint;
|
|
799
|
+
res = null;
|
|
800
|
+
sessionId;
|
|
801
|
+
onclose;
|
|
802
|
+
onerror;
|
|
803
|
+
onmessage;
|
|
804
|
+
async start() {
|
|
805
|
+
}
|
|
806
|
+
close() {
|
|
807
|
+
if (this.res) {
|
|
808
|
+
this.res.end();
|
|
809
|
+
this.res = null;
|
|
810
|
+
}
|
|
811
|
+
const onclose = this.onclose;
|
|
812
|
+
this.onclose = void 0;
|
|
813
|
+
onclose?.();
|
|
814
|
+
return Promise.resolve();
|
|
815
|
+
}
|
|
816
|
+
send(message) {
|
|
817
|
+
if (!this.res) {
|
|
818
|
+
return Promise.reject(new Error("Not connected"));
|
|
819
|
+
}
|
|
820
|
+
this.res.write(`event: message
|
|
821
|
+
data: ${JSON.stringify(message)}
|
|
822
|
+
|
|
823
|
+
`);
|
|
824
|
+
return Promise.resolve();
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Handles the initial GET request to establish the SSE stream.
|
|
828
|
+
*/
|
|
829
|
+
handleSseRequest(req, res) {
|
|
830
|
+
if (this.res !== null) {
|
|
831
|
+
res.status(409).json({ error: { message: "SSE stream already connected for this session" } });
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
this.res = res;
|
|
835
|
+
res.writeHead(200, {
|
|
836
|
+
"Content-Type": "text/event-stream",
|
|
837
|
+
"Cache-Control": "no-cache, no-transform",
|
|
838
|
+
"Connection": "keep-alive",
|
|
839
|
+
"X-Accel-Buffering": "no",
|
|
840
|
+
"mcp-session-id": this.sessionId
|
|
841
|
+
});
|
|
842
|
+
const endpointUrl = `${this.messagesEndpoint}?sessionId=${this.sessionId}`;
|
|
843
|
+
res.write(`event: endpoint
|
|
844
|
+
data: ${endpointUrl}
|
|
845
|
+
|
|
846
|
+
`);
|
|
847
|
+
req.on("close", () => {
|
|
848
|
+
this.close().catch((err) => {
|
|
849
|
+
logger.error("Error closing Legacy SSE transport", { error: String(err) });
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Handles incoming POST requests containing JSON-RPC messages.
|
|
855
|
+
*/
|
|
856
|
+
handlePostMessage(req, res) {
|
|
857
|
+
const body = req.body;
|
|
858
|
+
if (body === void 0 || body === null || typeof body !== "object") {
|
|
859
|
+
res.status(400).json({ error: "Invalid JSON body" });
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
if (this.onmessage) {
|
|
863
|
+
this.onmessage(req.body);
|
|
864
|
+
}
|
|
865
|
+
res.status(202).end();
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
// src/transports/http/server/protocol-handlers.ts
|
|
870
|
+
var MAX_ACTIVE_SESSIONS = 100;
|
|
871
|
+
function resolveRequestSubject() {
|
|
872
|
+
const claims = getAuthContext()?.claims;
|
|
873
|
+
const sub = claims?.sub ?? claims?.email ?? claims?.client_id ?? claims?.subject ?? claims?.clientId;
|
|
874
|
+
return typeof sub === "string" && sub.length > 0 ? sub : void 0;
|
|
875
|
+
}
|
|
876
|
+
function registerMcpProtocolRoutes(app, config, serverFactory, activeServers, sseTransports) {
|
|
877
|
+
const statelessMcpHandler = toNodeHandler(
|
|
878
|
+
createMcpHandler(
|
|
879
|
+
() => {
|
|
880
|
+
const server = serverFactory();
|
|
881
|
+
activeServers.add(server);
|
|
882
|
+
const originalClose = server.close.bind(server);
|
|
883
|
+
server.close = async () => {
|
|
884
|
+
activeServers.delete(server);
|
|
885
|
+
return originalClose();
|
|
886
|
+
};
|
|
887
|
+
return server;
|
|
888
|
+
},
|
|
889
|
+
{ legacy: "reject" }
|
|
890
|
+
)
|
|
891
|
+
);
|
|
892
|
+
const sessionOwners = /* @__PURE__ */ new Map();
|
|
893
|
+
const sessionLastActivity = /* @__PURE__ */ new Map();
|
|
894
|
+
const sweepTimer = setInterval(() => {
|
|
895
|
+
const now = Date.now();
|
|
896
|
+
for (const [sid, lastActive] of sessionLastActivity.entries()) {
|
|
897
|
+
if (now - lastActive > SESSION_TIMEOUT_MS) {
|
|
898
|
+
const transport = sseTransports.get(sid);
|
|
899
|
+
if (transport !== void 0) {
|
|
900
|
+
void transport.close();
|
|
901
|
+
sseTransports.delete(sid);
|
|
902
|
+
}
|
|
903
|
+
sessionOwners.delete(sid);
|
|
904
|
+
sessionLastActivity.delete(sid);
|
|
905
|
+
globalSubscriptionManager.unregisterServer(sid);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}, SESSION_SWEEP_INTERVAL_MS);
|
|
909
|
+
sweepTimer.unref();
|
|
910
|
+
const verifySessionOwner = (res, sid) => {
|
|
911
|
+
const expectedOwner = sessionOwners.get(sid);
|
|
912
|
+
const callerSubject = resolveRequestSubject();
|
|
913
|
+
if (expectedOwner !== void 0 && expectedOwner !== callerSubject) {
|
|
914
|
+
res.status(403).json({ error: { message: "Forbidden: Session belongs to another principal" } });
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
sessionLastActivity.set(sid, Date.now());
|
|
918
|
+
return true;
|
|
919
|
+
};
|
|
920
|
+
const createSessionAndHandle = (req, res, next, _sid, isLegacySse = false) => {
|
|
921
|
+
if (sseTransports.size >= MAX_ACTIVE_SESSIONS) {
|
|
922
|
+
res.status(503).json({
|
|
923
|
+
error: { message: "Service Unavailable: Maximum active stateful sessions reached" }
|
|
924
|
+
});
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const sid = _sid ?? randomUUID();
|
|
928
|
+
const transport = isLegacySse ? new LegacySSEServerTransport("/messages", sid) : new NodeStreamableHTTPServerTransport({
|
|
929
|
+
sessionIdGenerator: () => sid
|
|
930
|
+
});
|
|
931
|
+
const sessionId = sid;
|
|
932
|
+
const server = serverFactory();
|
|
933
|
+
const callerSubject = resolveRequestSubject();
|
|
934
|
+
if (callerSubject !== void 0) {
|
|
935
|
+
sessionOwners.set(sessionId, callerSubject);
|
|
936
|
+
}
|
|
937
|
+
sessionLastActivity.set(sessionId, Date.now());
|
|
938
|
+
const authLog = callerSubject !== void 0 ? ` as ${callerSubject}` : "";
|
|
939
|
+
logger.info(`New MCP stateful session initialized${authLog}`, {
|
|
940
|
+
module: "HTTP",
|
|
941
|
+
sessionId,
|
|
942
|
+
...callerSubject !== void 0 ? { subject: callerSubject } : {}
|
|
943
|
+
});
|
|
944
|
+
activeServers.add(server);
|
|
945
|
+
globalSubscriptionManager.registerServer(sessionId, server);
|
|
946
|
+
const originalClose = server.close.bind(server);
|
|
947
|
+
server.close = async () => {
|
|
948
|
+
activeServers.delete(server);
|
|
949
|
+
sseTransports.delete(sessionId);
|
|
950
|
+
sessionOwners.delete(sessionId);
|
|
951
|
+
sessionLastActivity.delete(sessionId);
|
|
952
|
+
globalSubscriptionManager.unregisterServer(sessionId);
|
|
953
|
+
return originalClose();
|
|
954
|
+
};
|
|
955
|
+
sseTransports.set(sessionId, transport);
|
|
956
|
+
transport.onclose = () => {
|
|
957
|
+
server.close().catch(
|
|
958
|
+
(err) => logger.error("Error closing server on transport close", {
|
|
959
|
+
error: String(err)
|
|
960
|
+
})
|
|
961
|
+
);
|
|
962
|
+
};
|
|
963
|
+
server.connect(transport).catch(
|
|
964
|
+
(err) => logger.error("Error connecting server to transport", {
|
|
965
|
+
error: String(err)
|
|
966
|
+
})
|
|
967
|
+
);
|
|
968
|
+
if (transport instanceof LegacySSEServerTransport) {
|
|
969
|
+
transport.handleSseRequest(req, res);
|
|
970
|
+
} else {
|
|
971
|
+
transport.handleRequest(req, res, req.body).catch((err) => {
|
|
972
|
+
logger.error("Error handling transport request", {
|
|
973
|
+
error: String(err),
|
|
974
|
+
...err instanceof Error && err.stack !== void 0 ? { stack: err.stack } : {}
|
|
975
|
+
});
|
|
976
|
+
next(err);
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
const handleStatefulGet = (req, res, next) => {
|
|
981
|
+
if (config.stateless) {
|
|
982
|
+
if (req.path === "/sse" || req.path === "/sse/") {
|
|
983
|
+
next();
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
res.status(405).json({
|
|
987
|
+
error: { message: "SSE streaming not available in stateless mode" }
|
|
988
|
+
});
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
|
|
992
|
+
if (sid !== void 0 && sid !== "") {
|
|
993
|
+
const transport = sseTransports.get(sid);
|
|
994
|
+
if (transport === void 0) {
|
|
995
|
+
res.status(400).json({ error: { message: "Session not found" } });
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
if (!verifySessionOwner(res, sid)) return;
|
|
999
|
+
if (transport instanceof LegacySSEServerTransport) {
|
|
1000
|
+
transport.handleSseRequest(req, res);
|
|
1001
|
+
} else {
|
|
1002
|
+
transport.handleRequest(req, res).catch((err) => {
|
|
1003
|
+
next(err);
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
} else {
|
|
1007
|
+
if (req.path === "/sse" || req.path === "/sse/") {
|
|
1008
|
+
createSessionAndHandle(req, res, next, randomUUID(), true);
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
res.status(405).json({
|
|
1012
|
+
error: "Method Not Allowed (Streamable HTTP requires POST initialization)"
|
|
1013
|
+
});
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
app.get("/mcp", handleStatefulGet);
|
|
1018
|
+
app.get("/sse", handleStatefulGet);
|
|
1019
|
+
const handlePost = (req, res, next) => {
|
|
1020
|
+
const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
|
|
1021
|
+
if (sid !== void 0 && sid !== "") {
|
|
1022
|
+
const transport = sseTransports.get(sid);
|
|
1023
|
+
if (transport === void 0) {
|
|
1024
|
+
res.status(400).json({ error: { message: "Session not found" } });
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
if (!verifySessionOwner(res, sid)) return;
|
|
1028
|
+
if (transport instanceof LegacySSEServerTransport) {
|
|
1029
|
+
transport.handlePostMessage(req, res);
|
|
1030
|
+
} else {
|
|
1031
|
+
transport.handleRequest(req, res, req.body).catch((err) => {
|
|
1032
|
+
next(err);
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
} else {
|
|
1036
|
+
const acceptsSse = req.headers.accept?.includes("text/event-stream") ?? false;
|
|
1037
|
+
const isLegacyMessages = req.path === "/messages" || req.path === "/messages/";
|
|
1038
|
+
if (isLegacyMessages) {
|
|
1039
|
+
res.status(400).json({ error: { message: "Missing sessionId parameter" } });
|
|
1040
|
+
} else if (acceptsSse && !config.stateless) {
|
|
1041
|
+
createSessionAndHandle(req, res, next, randomUUID(), false);
|
|
1042
|
+
} else {
|
|
1043
|
+
logger.debug("Routing to statelessMcpHandler", {
|
|
1044
|
+
method: req.method,
|
|
1045
|
+
path: req.path
|
|
1046
|
+
});
|
|
1047
|
+
statelessMcpHandler(req, res, req.body).catch((err) => {
|
|
1048
|
+
next(err);
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
app.post("/mcp", handlePost);
|
|
1054
|
+
app.post("/sse", handlePost);
|
|
1055
|
+
app.post("/messages", handlePost);
|
|
1056
|
+
app.delete("/mcp", (req, res) => {
|
|
1057
|
+
if (config.stateless) {
|
|
1058
|
+
res.status(204).end();
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
const sid = req.query?.["sessionId"] ?? req.headers?.["mcp-session-id"];
|
|
1062
|
+
if (sid === void 0 || sid === "") {
|
|
1063
|
+
res.status(400).json({ error: { message: "Missing sessionId parameter" } });
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
const transport = sseTransports.get(sid);
|
|
1067
|
+
if (transport !== void 0) {
|
|
1068
|
+
if (!verifySessionOwner(res, sid)) return;
|
|
1069
|
+
void transport.close();
|
|
1070
|
+
sseTransports.delete(sid);
|
|
1071
|
+
sessionOwners.delete(sid);
|
|
1072
|
+
sessionLastActivity.delete(sid);
|
|
1073
|
+
globalSubscriptionManager.unregisterServer(sid);
|
|
1074
|
+
}
|
|
1075
|
+
res.status(204).end();
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// src/transports/http/server/http-transport.ts
|
|
1080
|
+
var HttpTransport = class {
|
|
1081
|
+
app;
|
|
1082
|
+
config;
|
|
1083
|
+
activeServers = /* @__PURE__ */ new Set();
|
|
1084
|
+
httpServer = null;
|
|
1085
|
+
sseTransports = /* @__PURE__ */ new Map();
|
|
1086
|
+
rateLimitMap = /* @__PURE__ */ new Map();
|
|
1087
|
+
rateLimitCleanupTimer = null;
|
|
1088
|
+
constructor(config) {
|
|
1089
|
+
this.config = {
|
|
1090
|
+
...config,
|
|
1091
|
+
enableRateLimit: config.enableRateLimit ?? true
|
|
1092
|
+
};
|
|
1093
|
+
this.app = express();
|
|
1094
|
+
if (this.config.trustProxy === true) {
|
|
1095
|
+
this.app.set("trust proxy", "loopback");
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
async start(serverFactory, scheduler, runtime) {
|
|
1099
|
+
const { port, host, authToken, corsOrigins } = this.config;
|
|
1100
|
+
const isLocalhost = host === "localhost" || host === "127.0.0.1" || host === "::1";
|
|
1101
|
+
const hasCorsOpen = corsOrigins?.includes("*") ?? false;
|
|
1102
|
+
const hasAuth = Boolean(authToken) || this.config.oauthEnabled === true;
|
|
1103
|
+
if (!hasAuth && hasCorsOpen) {
|
|
1104
|
+
const errorMsg = `FATAL: Refusing to bind HTTP with open wildcard CORS ('*') without explicit authentication. You MUST specify --auth-token (or OAuth) or restrict --cors-origin to specific trusted origins.`;
|
|
1105
|
+
logger.error(errorMsg, { module: "HTTP" });
|
|
1106
|
+
throw new Error(errorMsg);
|
|
1107
|
+
}
|
|
1108
|
+
if (authToken === "change_this_to_a_secure_token_for_production") {
|
|
1109
|
+
const errorMsg = `FATAL: Default auth token detected. You MUST change MCP_AUTH_TOKEN to a secure, cryptographically random value for production.`;
|
|
1110
|
+
logger.error(errorMsg, { module: "HTTP" });
|
|
1111
|
+
throw new Error(errorMsg);
|
|
1112
|
+
}
|
|
1113
|
+
if (!isLocalhost && !hasAuth) {
|
|
1114
|
+
const errorMsg = `FATAL: Refusing to bind public HTTP on '${host}' without explicit authentication. You MUST specify --auth-token (or OAuth).`;
|
|
1115
|
+
logger.error(errorMsg, { module: "HTTP" });
|
|
1116
|
+
throw new Error(errorMsg);
|
|
1117
|
+
}
|
|
1118
|
+
if (hasCorsOpen) {
|
|
1119
|
+
logger.warning(
|
|
1120
|
+
'CORS origin is set to "*" (all origins). Set --cors-origin or MCP_CORS_ORIGIN for production deployments.',
|
|
1121
|
+
{ module: "HTTP" }
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
if (!hasAuth) {
|
|
1125
|
+
logger.warning(
|
|
1126
|
+
"No authentication configured for HTTP transport. Set --auth-token or MCP_AUTH_TOKEN for production deployments.",
|
|
1127
|
+
{ module: "HTTP" }
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
const isLocalHostHeader = host === "localhost" || host === "127.0.0.1" || host === "::1";
|
|
1131
|
+
this.app.use(
|
|
1132
|
+
isLocalHostHeader ? localhostHostValidation() : hostHeaderValidation([host, "localhost", "127.0.0.1", "[::1]"])
|
|
1133
|
+
);
|
|
1134
|
+
logger.info("DNS rebinding protection enabled (host header validation)", {
|
|
1135
|
+
module: "HTTP",
|
|
1136
|
+
allowedHosts: isLocalHostHeader ? ["localhost", "127.0.0.1", "[::1]"] : [host]
|
|
1137
|
+
});
|
|
1138
|
+
this.app.use((req, res, next) => {
|
|
1139
|
+
setSecurityHeaders(res, this.config);
|
|
1140
|
+
const allowed = setCorsHeaders(req, res, this.config);
|
|
1141
|
+
if (!allowed) {
|
|
1142
|
+
res.status(403).json({ error: "CORS policy violation" });
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
next();
|
|
1146
|
+
});
|
|
1147
|
+
this.app.use((req, res, next) => {
|
|
1148
|
+
if (req.method === "OPTIONS") {
|
|
1149
|
+
res.status(204).end();
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
next();
|
|
1153
|
+
});
|
|
1154
|
+
const maxBody = this.config.maxBodySize ?? DEFAULT_MAX_BODY_BYTES;
|
|
1155
|
+
const jsonParser = express.json({ limit: maxBody });
|
|
1156
|
+
this.app.use((req, res, next) => {
|
|
1157
|
+
const contentLength = parseInt(req.headers["content-length"] ?? "0", 10);
|
|
1158
|
+
if (contentLength > maxBody) {
|
|
1159
|
+
res.status(413).json({
|
|
1160
|
+
jsonrpc: "2.0",
|
|
1161
|
+
error: {
|
|
1162
|
+
code: -32e3,
|
|
1163
|
+
message: "Payload Too Large: Maximum request body size exceeded"
|
|
1164
|
+
},
|
|
1165
|
+
id: null
|
|
1166
|
+
});
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
jsonParser(req, res, next);
|
|
1170
|
+
});
|
|
1171
|
+
this.app.use((err, _req, res, next) => {
|
|
1172
|
+
if (err !== null && typeof err === "object" && "type" in err) {
|
|
1173
|
+
const errRecord = err;
|
|
1174
|
+
if (typeof errRecord["type"] === "string") {
|
|
1175
|
+
const errType = errRecord["type"];
|
|
1176
|
+
if (errType === "entity.too.large") {
|
|
1177
|
+
res.status(413).json({
|
|
1178
|
+
jsonrpc: "2.0",
|
|
1179
|
+
error: {
|
|
1180
|
+
code: -32e3,
|
|
1181
|
+
message: "Payload Too Large: Maximum request body size exceeded"
|
|
1182
|
+
},
|
|
1183
|
+
id: null
|
|
1184
|
+
});
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
if (errType === "entity.parse.failed") {
|
|
1188
|
+
res.status(400).json({
|
|
1189
|
+
jsonrpc: "2.0",
|
|
1190
|
+
error: {
|
|
1191
|
+
code: -32700,
|
|
1192
|
+
message: "Parse error: Invalid JSON"
|
|
1193
|
+
},
|
|
1194
|
+
id: null
|
|
1195
|
+
});
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
next(err);
|
|
1201
|
+
});
|
|
1202
|
+
if (this.config.enableRateLimit !== false) {
|
|
1203
|
+
this.app.use((req, res, next) => {
|
|
1204
|
+
const result = checkRateLimit(req, this.config, this.rateLimitMap);
|
|
1205
|
+
if (!result.allowed) {
|
|
1206
|
+
if (result.retryAfterSeconds !== void 0) {
|
|
1207
|
+
res.setHeader("Retry-After", String(result.retryAfterSeconds));
|
|
1208
|
+
}
|
|
1209
|
+
res.status(429).json({
|
|
1210
|
+
error: "Too Many Requests",
|
|
1211
|
+
retryAfter: result.retryAfterSeconds
|
|
1212
|
+
});
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
next();
|
|
1216
|
+
});
|
|
1217
|
+
this.rateLimitCleanupTimer = setInterval(() => {
|
|
1218
|
+
const now = Date.now();
|
|
1219
|
+
for (const [key, entry] of this.rateLimitMap) {
|
|
1220
|
+
if (now > entry.resetTime) {
|
|
1221
|
+
this.rateLimitMap.delete(key);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}, 6e4);
|
|
1225
|
+
this.rateLimitCleanupTimer.unref();
|
|
1226
|
+
logger.info("Rate limiting enabled (using IP)", { module: "HTTP" });
|
|
1227
|
+
}
|
|
1228
|
+
if (this.config.oauthEnabled === true && this.config.oauthIssuer !== void 0 && this.config.oauthAudience !== void 0) {
|
|
1229
|
+
if (this.config.oauthIssuer.startsWith("http://")) {
|
|
1230
|
+
if (this.config.allowPlaintextLoopbackOAuth !== true) {
|
|
1231
|
+
const errorMsg = `FATAL: OAuth issuer targets a plaintext protocol. You MUST deliberately set 'allowPlaintextLoopbackOAuth: true' in config to bypass strict discovery bound.`;
|
|
1232
|
+
logger.error(errorMsg, { module: "HTTP", operation: "oauth-config" });
|
|
1233
|
+
throw new Error(errorMsg);
|
|
1234
|
+
}
|
|
1235
|
+
try {
|
|
1236
|
+
const url = new URL(this.config.oauthIssuer);
|
|
1237
|
+
if (url.hostname !== "localhost" && url.hostname !== "127.0.0.1" && url.hostname !== "[::1]") {
|
|
1238
|
+
throw new Error();
|
|
1239
|
+
}
|
|
1240
|
+
} catch {
|
|
1241
|
+
const errorMsg = `FATAL: Plaintext OAuth bypass is ONLY permitted for loopback hosts (localhost, 127.0.0.1, [::1]). The configured issuer is not allowed.`;
|
|
1242
|
+
logger.error(errorMsg, { module: "HTTP", operation: "oauth-config" });
|
|
1243
|
+
throw new Error(errorMsg);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (!isLocalhost && (this.config.publicOrigin === void 0 || this.config.publicOrigin === "")) {
|
|
1247
|
+
const errorMsg = `FATAL: OAuth is enabled on a non-loopback interface ('${host}'), but no 'publicOrigin' was provided. You MUST specify an explicit public origin (e.g. 'https://api.example.com') for secure OAuth token audience binding.`;
|
|
1248
|
+
logger.error(errorMsg, { module: "HTTP" });
|
|
1249
|
+
throw new Error(errorMsg);
|
|
1250
|
+
}
|
|
1251
|
+
const jwksUri = this.config.oauthJwksUri ?? `${this.config.oauthIssuer}/.well-known/jwks.json`;
|
|
1252
|
+
const tokenValidator = createTokenValidator({
|
|
1253
|
+
jwksUri,
|
|
1254
|
+
issuer: this.config.oauthIssuer,
|
|
1255
|
+
audience: this.config.oauthAudience,
|
|
1256
|
+
clockTolerance: this.config.oauthClockTolerance ?? 60
|
|
1257
|
+
});
|
|
1258
|
+
await tokenValidator.preload();
|
|
1259
|
+
const resourceServer = createOAuthResourceServer({
|
|
1260
|
+
resource: this.config.publicOrigin ?? `http://${host}:${String(port)}`,
|
|
1261
|
+
authorizationServers: [this.config.oauthIssuer],
|
|
1262
|
+
scopesSupported: [...SUPPORTED_SCOPES]
|
|
1263
|
+
});
|
|
1264
|
+
this.app.get(resourceServer.getWellKnownPath(), resourceServer.getMetadataHandler());
|
|
1265
|
+
this.app.use(
|
|
1266
|
+
createAuthMiddleware2({
|
|
1267
|
+
tokenValidator,
|
|
1268
|
+
resourceServer,
|
|
1269
|
+
publicPaths: ["/health", "/", "/.well-known/*"]
|
|
1270
|
+
})
|
|
1271
|
+
);
|
|
1272
|
+
this.app.use(oauthErrorHandler);
|
|
1273
|
+
logger.info("OAuth 2.1 authentication enabled", {
|
|
1274
|
+
module: "HTTP",
|
|
1275
|
+
resource: resourceServer.getResourceUri(),
|
|
1276
|
+
audience: this.config.oauthAudience
|
|
1277
|
+
});
|
|
1278
|
+
} else if (authToken !== void 0 && authToken !== "") {
|
|
1279
|
+
this.app.use(createAuthMiddleware(authToken));
|
|
1280
|
+
}
|
|
1281
|
+
const propagateContextMiddleware = (req, _res, next) => {
|
|
1282
|
+
const reqRecord = req;
|
|
1283
|
+
const tokenClaims = reqRecord["tokenClaims"];
|
|
1284
|
+
const authInfo = reqRecord["auth"];
|
|
1285
|
+
if (tokenClaims !== void 0 && tokenClaims !== null) {
|
|
1286
|
+
runWithAuthContext(
|
|
1287
|
+
{ authenticated: true, claims: tokenClaims, scopes: tokenClaims.scopes },
|
|
1288
|
+
next
|
|
1289
|
+
);
|
|
1290
|
+
} else if (authInfo !== void 0 && authInfo !== null) {
|
|
1291
|
+
const sub = authInfo.sub ?? (typeof authInfo["subject"] === "string" ? authInfo["subject"] : void 0) ?? authInfo.clientId ?? "unknown";
|
|
1292
|
+
const normalizedClaims = {
|
|
1293
|
+
...authInfo,
|
|
1294
|
+
sub,
|
|
1295
|
+
scopes: Array.isArray(authInfo.scopes) ? authInfo.scopes : []
|
|
1296
|
+
};
|
|
1297
|
+
runWithAuthContext(
|
|
1298
|
+
{ authenticated: true, claims: normalizedClaims, scopes: normalizedClaims.scopes },
|
|
1299
|
+
next
|
|
1300
|
+
);
|
|
1301
|
+
} else {
|
|
1302
|
+
next();
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
this.app.use(propagateContextMiddleware);
|
|
1306
|
+
this.app.get("/health", handleHealthCheck);
|
|
1307
|
+
if (this.config.metricsExport === "prometheus") {
|
|
1308
|
+
this.app.get("/metrics", handlePrometheusMetrics(runtime));
|
|
1309
|
+
logger.info("Prometheus metrics export enabled on /metrics", { module: "HTTP" });
|
|
1310
|
+
}
|
|
1311
|
+
this.app.get("/", handleRootInfo);
|
|
1312
|
+
registerMcpProtocolRoutes(
|
|
1313
|
+
this.app,
|
|
1314
|
+
this.config,
|
|
1315
|
+
serverFactory,
|
|
1316
|
+
this.activeServers,
|
|
1317
|
+
this.sseTransports
|
|
1318
|
+
);
|
|
1319
|
+
this.app.use((req, res) => {
|
|
1320
|
+
logger.debug("404 Not Found", {
|
|
1321
|
+
method: req.method,
|
|
1322
|
+
path: req.path
|
|
1323
|
+
});
|
|
1324
|
+
res.status(404).json({ error: "Not found" });
|
|
1325
|
+
});
|
|
1326
|
+
this.httpServer = this.app.listen(port, host, () => {
|
|
1327
|
+
if (this.httpServer !== null) {
|
|
1328
|
+
this.httpServer.setTimeout(HTTP_REQUEST_TIMEOUT_MS);
|
|
1329
|
+
this.httpServer.keepAliveTimeout = HTTP_KEEP_ALIVE_TIMEOUT_MS;
|
|
1330
|
+
this.httpServer.headersTimeout = HTTP_HEADERS_TIMEOUT_MS;
|
|
1331
|
+
}
|
|
1332
|
+
logger.info(
|
|
1333
|
+
`MCP server started on HTTP (${this.config.stateless ? "stateless" : "stateful"})`,
|
|
1334
|
+
{
|
|
1335
|
+
module: "HTTP",
|
|
1336
|
+
port,
|
|
1337
|
+
host,
|
|
1338
|
+
endpoint: `http://${host}:${String(port)}/mcp`
|
|
1339
|
+
}
|
|
1340
|
+
);
|
|
1341
|
+
});
|
|
1342
|
+
scheduler?.start();
|
|
1343
|
+
this.httpServer.on("close", () => {
|
|
1344
|
+
logger.info("HTTP server closed", { module: "HTTP" });
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
async stop(scheduler) {
|
|
1348
|
+
logger.info("Shutting down HTTP server...", { module: "HTTP" });
|
|
1349
|
+
scheduler?.stop();
|
|
1350
|
+
if (this.rateLimitCleanupTimer !== null) {
|
|
1351
|
+
clearInterval(this.rateLimitCleanupTimer);
|
|
1352
|
+
this.rateLimitCleanupTimer = null;
|
|
1353
|
+
}
|
|
1354
|
+
for (const server of this.activeServers) {
|
|
1355
|
+
try {
|
|
1356
|
+
await server.close();
|
|
1357
|
+
} catch (error) {
|
|
1358
|
+
logger.error("Error closing active server", {
|
|
1359
|
+
module: "HTTP",
|
|
1360
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
this.activeServers.clear();
|
|
1365
|
+
if (this.httpServer !== null) {
|
|
1366
|
+
this.httpServer.close();
|
|
1367
|
+
}
|
|
1368
|
+
logger.info("Shutdown complete", { module: "HTTP" });
|
|
1369
|
+
}
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
// src/database/core/DatabaseAdapterProxy.ts
|
|
1373
|
+
var DatabaseAdapterProxy = {
|
|
1374
|
+
create(primary, testDb) {
|
|
1375
|
+
return new Proxy(primary, {
|
|
1376
|
+
get(target, prop, _receiver) {
|
|
1377
|
+
const context = requestContextStorage.getStore();
|
|
1378
|
+
const activeTarget = context?.useTestDb && testDb ? testDb : target;
|
|
1379
|
+
const value = Reflect.get(activeTarget, prop, activeTarget);
|
|
1380
|
+
if (typeof value === "function") {
|
|
1381
|
+
return value.bind(activeTarget);
|
|
1382
|
+
}
|
|
1383
|
+
return value;
|
|
1384
|
+
}
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
|
|
1389
|
+
// src/vector/vector-search-manager/types.ts
|
|
1390
|
+
var DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
1391
|
+
var REBUILD_BATCH_SIZE = 50;
|
|
1392
|
+
var REBUILD_PAGE_SIZE = 200;
|
|
1393
|
+
|
|
1394
|
+
// src/vector/vector-search-manager/rebuild.ts
|
|
1395
|
+
var setTimeoutFn = globalThis.setTimeout;
|
|
1396
|
+
async function rebuildIndex(manager, dbAdapter, progress, options) {
|
|
1397
|
+
const force = options?.force ?? false;
|
|
1398
|
+
const batchSize = options?.batchSize ?? REBUILD_BATCH_SIZE;
|
|
1399
|
+
const pageSize = options?.pageSize ?? REBUILD_PAGE_SIZE;
|
|
1400
|
+
let indexed = 0;
|
|
1401
|
+
let skipped = 0;
|
|
1402
|
+
let errorsCount = 0;
|
|
1403
|
+
let firstError = null;
|
|
1404
|
+
let totalEntries;
|
|
1405
|
+
try {
|
|
1406
|
+
totalEntries = dbAdapter.getActiveEntryCount();
|
|
1407
|
+
} catch (err) {
|
|
1408
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1409
|
+
logger.error("Failed to count entries for vector indexing", { error: err });
|
|
1410
|
+
return { success: false, indexed: 0, failed: 1, firstError: errorMessage };
|
|
1411
|
+
}
|
|
1412
|
+
if (totalEntries === 0) {
|
|
1413
|
+
return { success: true, indexed: 0, failed: 0, firstError: null };
|
|
1414
|
+
}
|
|
1415
|
+
await sendProgress(progress, 0, totalEntries, "Starting vector index rebuild");
|
|
1416
|
+
let offset = 0;
|
|
1417
|
+
while (offset < totalEntries) {
|
|
1418
|
+
const result = dbAdapter.getEntriesPage(offset, pageSize);
|
|
1419
|
+
const entries = result.entries;
|
|
1420
|
+
if (entries.length === 0) break;
|
|
1421
|
+
for (let i = 0; i < entries.length; i += batchSize) {
|
|
1422
|
+
const batch = entries.slice(i, i + batchSize);
|
|
1423
|
+
const vectorsToUpsert = [];
|
|
1424
|
+
for (const entry of batch) {
|
|
1425
|
+
if (!force) {
|
|
1426
|
+
try {
|
|
1427
|
+
const exists = dbAdapter.getVector(entry.id);
|
|
1428
|
+
if (exists) {
|
|
1429
|
+
skipped++;
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
} catch {
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
try {
|
|
1436
|
+
const tagsText = entry.tags !== void 0 && entry.tags !== null && entry.tags.length > 0 ? ` [Tags: ${entry.tags.join(", ")}]` : "";
|
|
1437
|
+
const text = `[${entry.entryType}]${tagsText} ${entry.content}`;
|
|
1438
|
+
const embedding = await manager.generateEmbedding(text);
|
|
1439
|
+
vectorsToUpsert.push({ entryId: entry.id, embedding });
|
|
1440
|
+
} catch (err) {
|
|
1441
|
+
errorsCount++;
|
|
1442
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1443
|
+
firstError ??= errorMessage;
|
|
1444
|
+
logger.error(`Failed to generate embedding for entry ${entry.id}`, {
|
|
1445
|
+
error: errorMessage
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
if (vectorsToUpsert.length > 0) {
|
|
1450
|
+
try {
|
|
1451
|
+
dbAdapter.upsertVectors(vectorsToUpsert);
|
|
1452
|
+
indexed += vectorsToUpsert.length;
|
|
1453
|
+
} catch (err) {
|
|
1454
|
+
errorsCount += vectorsToUpsert.length;
|
|
1455
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1456
|
+
firstError ??= errorMessage;
|
|
1457
|
+
logger.error("Failed to upsert vector batch", {
|
|
1458
|
+
error: errorMessage,
|
|
1459
|
+
batchSize: vectorsToUpsert.length
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
await new Promise((resolve) => setTimeoutFn(resolve, 0));
|
|
1464
|
+
await sendProgress(
|
|
1465
|
+
progress,
|
|
1466
|
+
offset + i + batch.length,
|
|
1467
|
+
totalEntries,
|
|
1468
|
+
`Indexing... (${indexed} indexed, ${skipped} skipped)`
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1471
|
+
offset += pageSize;
|
|
1472
|
+
}
|
|
1473
|
+
if (errorsCount === 0) {
|
|
1474
|
+
try {
|
|
1475
|
+
dbAdapter.cleanupStaleVectors();
|
|
1476
|
+
} catch (err) {
|
|
1477
|
+
logger.warning("Failed to cleanup stale vectors after rebuild", { error: err });
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return {
|
|
1481
|
+
success: errorsCount === 0,
|
|
1482
|
+
indexed,
|
|
1483
|
+
failed: errorsCount,
|
|
1484
|
+
firstError
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// src/vector/vector-search-manager/manager.ts
|
|
1489
|
+
var VectorSearchManager = class _VectorSearchManager {
|
|
1490
|
+
dbAdapter;
|
|
1491
|
+
modelName;
|
|
1492
|
+
dimensions = null;
|
|
1493
|
+
// Lazy-loaded dependencies
|
|
1494
|
+
pipeline = null;
|
|
1495
|
+
transformers = null;
|
|
1496
|
+
initializationPromise = null;
|
|
1497
|
+
constructor(dbAdapter, options) {
|
|
1498
|
+
this.dbAdapter = dbAdapter;
|
|
1499
|
+
this.modelName = options?.modelName || DEFAULT_MODEL;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Get the active model name
|
|
1503
|
+
*/
|
|
1504
|
+
getModelName() {
|
|
1505
|
+
return this.modelName;
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Get the detected dimensions for the current model
|
|
1509
|
+
*/
|
|
1510
|
+
getDimensions() {
|
|
1511
|
+
return this.dimensions;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Check if the vector search manager is initialized
|
|
1515
|
+
*/
|
|
1516
|
+
isInitialized() {
|
|
1517
|
+
return this.initializationPromise !== null && (this.pipeline !== null || this.dimensions !== null);
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Initialize the vector search manager.
|
|
1521
|
+
* This loads the huggingface transformer model and creates the virtual table.
|
|
1522
|
+
*/
|
|
1523
|
+
async initialize() {
|
|
1524
|
+
if (this.dbAdapter == null) {
|
|
1525
|
+
throw new Error("Vector database not available");
|
|
1526
|
+
}
|
|
1527
|
+
if (this.initializationPromise) {
|
|
1528
|
+
return this.initializationPromise;
|
|
1529
|
+
}
|
|
1530
|
+
this.initializationPromise = this._initialize().catch((error) => {
|
|
1531
|
+
this.initializationPromise = null;
|
|
1532
|
+
throw error;
|
|
1533
|
+
});
|
|
1534
|
+
return this.initializationPromise;
|
|
1535
|
+
}
|
|
1536
|
+
async _initialize() {
|
|
1537
|
+
try {
|
|
1538
|
+
logger.info("Initializing vector search...");
|
|
1539
|
+
const hasCustomEmbeddingFn = this.generateEmbedding !== _VectorSearchManager.prototype.generateEmbedding;
|
|
1540
|
+
if (hasCustomEmbeddingFn) {
|
|
1541
|
+
logger.info("Detecting embedding dimensions via custom embedding generator...");
|
|
1542
|
+
const testEmbedding = await this.generateEmbedding("test");
|
|
1543
|
+
this.dimensions = testEmbedding.length;
|
|
1544
|
+
this.pipeline = true;
|
|
1545
|
+
logger.info(`Detected ${this.dimensions} dimensions for ${this.modelName}`);
|
|
1546
|
+
} else {
|
|
1547
|
+
if (this.transformers === null) {
|
|
1548
|
+
const transformersModule2 = await import('@huggingface/transformers');
|
|
1549
|
+
this.transformers = transformersModule2;
|
|
1550
|
+
transformersModule2.env.allowRemoteModels = true;
|
|
1551
|
+
transformersModule2.env.localModelPath = ".cache/huggingface";
|
|
1552
|
+
}
|
|
1553
|
+
logger.info(`Loading embedding model: ${this.modelName}`);
|
|
1554
|
+
const transformersModule = this.transformers;
|
|
1555
|
+
this.pipeline = await transformersModule.pipeline(
|
|
1556
|
+
"feature-extraction",
|
|
1557
|
+
this.modelName,
|
|
1558
|
+
{
|
|
1559
|
+
dtype: "fp32"
|
|
1560
|
+
}
|
|
1561
|
+
);
|
|
1562
|
+
logger.info("Embedding model loaded");
|
|
1563
|
+
logger.info("Detecting embedding dimensions...");
|
|
1564
|
+
const pipelineFunc = this.pipeline;
|
|
1565
|
+
const testResult = await pipelineFunc("test", { pooling: "mean", normalize: true });
|
|
1566
|
+
this.dimensions = testResult.data.length;
|
|
1567
|
+
logger.info(`Detected ${this.dimensions} dimensions for ${this.modelName}`);
|
|
1568
|
+
}
|
|
1569
|
+
this.verifyAndCreateVecTable();
|
|
1570
|
+
logger.info("Vector search initialized successfully");
|
|
1571
|
+
} catch (error) {
|
|
1572
|
+
logger.error("Failed to initialize vector search", {
|
|
1573
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1574
|
+
});
|
|
1575
|
+
throw error;
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Verify the vec_journal_entries table exists and has the correct dimensions.
|
|
1580
|
+
* If the model or dimensions changed, drops the old table and creates a new one.
|
|
1581
|
+
*/
|
|
1582
|
+
verifyAndCreateVecTable() {
|
|
1583
|
+
const dimensions = this.dimensions;
|
|
1584
|
+
if (dimensions === null) {
|
|
1585
|
+
throw new Error("Dimensions not detected. Cannot create vector table.");
|
|
1586
|
+
}
|
|
1587
|
+
let needsRecreation = false;
|
|
1588
|
+
try {
|
|
1589
|
+
const existingDimStr = this.dbAdapter.getVectorMetadata("dimensions");
|
|
1590
|
+
if (existingDimStr) {
|
|
1591
|
+
const existingDim = parseInt(existingDimStr, 10);
|
|
1592
|
+
if (existingDim !== this.dimensions) {
|
|
1593
|
+
needsRecreation = true;
|
|
1594
|
+
logger.info(`Vector model or dimensions changed, dropping old index`, {
|
|
1595
|
+
oldModel: this.dbAdapter.getVectorMetadata("model_name") || "unknown",
|
|
1596
|
+
newModel: this.modelName,
|
|
1597
|
+
oldDimensions: existingDim,
|
|
1598
|
+
newDimensions: this.dimensions
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
} else {
|
|
1602
|
+
needsRecreation = true;
|
|
1603
|
+
}
|
|
1604
|
+
} catch (err) {
|
|
1605
|
+
needsRecreation = true;
|
|
1606
|
+
logger.warning("Failed to verify vector table dimensions, recreating", { error: err });
|
|
1607
|
+
}
|
|
1608
|
+
if (needsRecreation) {
|
|
1609
|
+
try {
|
|
1610
|
+
this.dbAdapter.executeInTransaction(() => {
|
|
1611
|
+
this.dbAdapter.dropVecTable();
|
|
1612
|
+
this.dbAdapter.createVecTable(dimensions);
|
|
1613
|
+
this.dbAdapter.setVectorMetadata("model_name", this.modelName);
|
|
1614
|
+
this.dbAdapter.setVectorMetadata("dimensions", dimensions.toString());
|
|
1615
|
+
});
|
|
1616
|
+
logger.info(`Created new vec_journal_entries table with ${this.dimensions} dimensions`);
|
|
1617
|
+
} catch (err) {
|
|
1618
|
+
logger.error("Failed to recreate vector table", { error: err });
|
|
1619
|
+
throw err;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Generate an embedding for text
|
|
1625
|
+
*/
|
|
1626
|
+
async generateEmbedding(text) {
|
|
1627
|
+
await this.initialize();
|
|
1628
|
+
if (this.getDimensions() === null) {
|
|
1629
|
+
throw new Error("Vector search not initialized properly. Cannot rebuild index.");
|
|
1630
|
+
}
|
|
1631
|
+
const pipelineFunc = this.pipeline;
|
|
1632
|
+
const result = await pipelineFunc(text, { pooling: "mean", normalize: true });
|
|
1633
|
+
return new Float32Array(result.data);
|
|
1634
|
+
}
|
|
1635
|
+
async addEntry(entry) {
|
|
1636
|
+
await this.initialize();
|
|
1637
|
+
try {
|
|
1638
|
+
const tagsText = entry.tags !== void 0 && entry.tags !== null && entry.tags.length > 0 ? ` [Tags: ${entry.tags.join(", ")}]` : "";
|
|
1639
|
+
const text = `[${entry.entryType}]${tagsText} ${entry.content}`;
|
|
1640
|
+
const embedding = await this.generateEmbedding(text);
|
|
1641
|
+
this.dbAdapter.upsertVector(entry.id, embedding);
|
|
1642
|
+
} catch (error) {
|
|
1643
|
+
logger.error(`Failed to add entry ${entry.id} to vector index`, {
|
|
1644
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1645
|
+
});
|
|
1646
|
+
throw error;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
/**
|
|
1650
|
+
* Remove an entry from the vector index
|
|
1651
|
+
*/
|
|
1652
|
+
removeEntry(entryId) {
|
|
1653
|
+
if (this.dbAdapter == null) return false;
|
|
1654
|
+
try {
|
|
1655
|
+
this.dbAdapter.deleteVector(entryId);
|
|
1656
|
+
return true;
|
|
1657
|
+
} catch (error) {
|
|
1658
|
+
logger.warning(`Failed to remove entry ${entryId} from vector index`, { error });
|
|
1659
|
+
return false;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* Search for similar entries by text query
|
|
1664
|
+
*/
|
|
1665
|
+
async search(query, limit = 10, threshold = 0, workspaceId) {
|
|
1666
|
+
await this.initialize();
|
|
1667
|
+
try {
|
|
1668
|
+
const queryEmbedding = await this.generateEmbedding(query);
|
|
1669
|
+
const results = this.dbAdapter.searchVectors(queryEmbedding, limit);
|
|
1670
|
+
const candidates = [];
|
|
1671
|
+
for (const result of results) {
|
|
1672
|
+
const similarityScore = Math.max(-1, 1 - result.distance * result.distance / 2);
|
|
1673
|
+
if (similarityScore >= threshold) {
|
|
1674
|
+
candidates.push({
|
|
1675
|
+
entryId: result.entry_id,
|
|
1676
|
+
distance: result.distance,
|
|
1677
|
+
similarityScore
|
|
1678
|
+
});
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
if (candidates.length === 0) {
|
|
1682
|
+
return [];
|
|
1683
|
+
}
|
|
1684
|
+
const targetWs = workspaceId ?? "*";
|
|
1685
|
+
const entriesMap = typeof this.dbAdapter.getEntriesByIds === "function" ? this.dbAdapter.getEntriesByIds(candidates.map((c) => c.entryId)) : null;
|
|
1686
|
+
const searchResults = [];
|
|
1687
|
+
for (const candidate of candidates) {
|
|
1688
|
+
const entry = entriesMap ? entriesMap.get(candidate.entryId) ?? null : this.dbAdapter.getEntryById(candidate.entryId, targetWs);
|
|
1689
|
+
if (entry && (targetWs === "*" || entry.workspaceId === void 0 || entry.workspaceId === targetWs)) {
|
|
1690
|
+
searchResults.push({
|
|
1691
|
+
entryId: candidate.entryId,
|
|
1692
|
+
entry,
|
|
1693
|
+
distance: candidate.distance,
|
|
1694
|
+
score: candidate.similarityScore,
|
|
1695
|
+
similarityScore: candidate.similarityScore
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
if (searchResults.length >= limit) break;
|
|
1699
|
+
}
|
|
1700
|
+
return searchResults;
|
|
1701
|
+
} catch (error) {
|
|
1702
|
+
logger.error("Semantic search failed", {
|
|
1703
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1704
|
+
query
|
|
1705
|
+
});
|
|
1706
|
+
throw error;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Search for similar entries using an existing entry as the query
|
|
1711
|
+
*/
|
|
1712
|
+
async searchByEntryId(entryId, limit = 10, threshold = 0, workspaceId) {
|
|
1713
|
+
await this.initialize();
|
|
1714
|
+
try {
|
|
1715
|
+
const sourceEntry = this.dbAdapter.getEntryById(entryId, workspaceId ?? "*");
|
|
1716
|
+
if (!sourceEntry) {
|
|
1717
|
+
throw new Error(`Entry ${entryId} not found`);
|
|
1718
|
+
}
|
|
1719
|
+
let queryEmbedding = this.dbAdapter.getVector(entryId);
|
|
1720
|
+
if (!queryEmbedding) {
|
|
1721
|
+
const tagsText = sourceEntry.tags !== void 0 && sourceEntry.tags !== null && sourceEntry.tags.length > 0 ? ` [Tags: ${sourceEntry.tags.join(", ")}]` : "";
|
|
1722
|
+
const text = `[${sourceEntry.entryType}]${tagsText} ${sourceEntry.content}`;
|
|
1723
|
+
queryEmbedding = await this.generateEmbedding(text);
|
|
1724
|
+
this.dbAdapter.upsertVector(entryId, queryEmbedding);
|
|
1725
|
+
}
|
|
1726
|
+
const results = this.dbAdapter.searchVectors(queryEmbedding, limit + 1);
|
|
1727
|
+
const candidates = [];
|
|
1728
|
+
for (const result of results) {
|
|
1729
|
+
const candidateId = result.entry_id;
|
|
1730
|
+
if (candidateId === entryId) continue;
|
|
1731
|
+
const similarityScore = Math.max(-1, 1 - result.distance * result.distance / 2);
|
|
1732
|
+
if (similarityScore >= threshold) {
|
|
1733
|
+
candidates.push({
|
|
1734
|
+
entryId: candidateId,
|
|
1735
|
+
distance: result.distance,
|
|
1736
|
+
similarityScore
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
if (candidates.length === 0) {
|
|
1741
|
+
return [];
|
|
1742
|
+
}
|
|
1743
|
+
const targetWs = workspaceId ?? "*";
|
|
1744
|
+
const entriesMap = typeof this.dbAdapter.getEntriesByIds === "function" ? this.dbAdapter.getEntriesByIds(candidates.map((c) => c.entryId)) : null;
|
|
1745
|
+
const searchResults = [];
|
|
1746
|
+
for (const candidate of candidates) {
|
|
1747
|
+
const entry = entriesMap ? entriesMap.get(candidate.entryId) ?? null : this.dbAdapter.getEntryById(candidate.entryId, targetWs);
|
|
1748
|
+
if (entry && (targetWs === "*" || entry.workspaceId === void 0 || entry.workspaceId === targetWs)) {
|
|
1749
|
+
searchResults.push({
|
|
1750
|
+
entryId: candidate.entryId,
|
|
1751
|
+
entry,
|
|
1752
|
+
distance: candidate.distance,
|
|
1753
|
+
score: candidate.similarityScore,
|
|
1754
|
+
similarityScore: candidate.similarityScore
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
if (searchResults.length >= limit) break;
|
|
1758
|
+
}
|
|
1759
|
+
return searchResults;
|
|
1760
|
+
} catch (error) {
|
|
1761
|
+
logger.error(`Semantic search by entry ID ${entryId} failed`, {
|
|
1762
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1763
|
+
});
|
|
1764
|
+
throw error;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Helper to get vector search statistics
|
|
1769
|
+
*/
|
|
1770
|
+
getStats() {
|
|
1771
|
+
let itemCount = 0;
|
|
1772
|
+
let isReady = false;
|
|
1773
|
+
try {
|
|
1774
|
+
itemCount = this.dbAdapter.getVectorCount();
|
|
1775
|
+
isReady = this.pipeline !== null;
|
|
1776
|
+
} catch (error) {
|
|
1777
|
+
logger.warning("Failed to get vector search stats", { error });
|
|
1778
|
+
}
|
|
1779
|
+
return {
|
|
1780
|
+
itemCount,
|
|
1781
|
+
dimensions: this.dimensions ?? 0,
|
|
1782
|
+
modelName: this.modelName,
|
|
1783
|
+
isReady
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
async rebuildIndex(progress, options) {
|
|
1787
|
+
await this.initialize();
|
|
1788
|
+
return rebuildIndex(this, this.dbAdapter, progress, options);
|
|
1789
|
+
}
|
|
1790
|
+
};
|
|
1791
|
+
|
|
1792
|
+
// src/vector/vector-search-manager/VectorSearchManagerProxy.ts
|
|
1793
|
+
var VectorSearchManagerProxy = {
|
|
1794
|
+
create(primary, testManager) {
|
|
1795
|
+
return new Proxy(primary, {
|
|
1796
|
+
get(target, prop, _receiver) {
|
|
1797
|
+
const context = requestContextStorage.getStore();
|
|
1798
|
+
const activeTarget = context?.useTestDb && testManager ? testManager : target;
|
|
1799
|
+
const value = Reflect.get(activeTarget, prop, activeTarget);
|
|
1800
|
+
if (typeof value === "function") {
|
|
1801
|
+
return value.bind(activeTarget);
|
|
1802
|
+
}
|
|
1803
|
+
return value;
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
};
|
|
1808
|
+
function isBlockedWebhookIp(ip) {
|
|
1809
|
+
const normalized = ip.toLowerCase();
|
|
1810
|
+
if (normalized === "localhost" || normalized === "::1" || normalized === "0.0.0.0" || normalized === "::" || normalized.startsWith("127.") || normalized.startsWith("10.") || normalized.startsWith("192.168.") || normalized.startsWith("169.254.") || normalized.startsWith("fe80:") || normalized.startsWith("fc00:") || normalized.startsWith("fd00:") || normalized.startsWith("::ffff:")) {
|
|
1811
|
+
return true;
|
|
1812
|
+
}
|
|
1813
|
+
const octets = normalized.split(".");
|
|
1814
|
+
if (octets.length === 4 && octets[0] === "172") {
|
|
1815
|
+
const second = Number(octets[1]);
|
|
1816
|
+
if (second >= 16 && second <= 31) {
|
|
1817
|
+
return true;
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
return false;
|
|
1821
|
+
}
|
|
1822
|
+
async function validateWebhookUrl(webhookUrl) {
|
|
1823
|
+
let parsed;
|
|
1824
|
+
try {
|
|
1825
|
+
parsed = new URL(webhookUrl);
|
|
1826
|
+
} catch {
|
|
1827
|
+
throw new Error("Invalid webhook URL format");
|
|
1828
|
+
}
|
|
1829
|
+
const allowInsecureHttp = process.env["ALLOW_INSECURE_WEBHOOK_HTTP"] === "true";
|
|
1830
|
+
if (parsed.protocol !== "https:" && !(allowInsecureHttp && parsed.protocol === "http:")) {
|
|
1831
|
+
throw new Error(`Disallowed webhook protocol: ${parsed.protocol} (https: required)`);
|
|
1832
|
+
}
|
|
1833
|
+
const hostname = parsed.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
1834
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname.endsWith(".internal") || isBlockedWebhookIp(hostname)) {
|
|
1835
|
+
throw new Error(`Webhook hostname resolves to restricted network address: ${hostname}`);
|
|
1836
|
+
}
|
|
1837
|
+
if (!process.env["VITEST"]) {
|
|
1838
|
+
const records = await dns.promises.lookup(hostname, { all: true });
|
|
1839
|
+
for (const rec of records) {
|
|
1840
|
+
if (isBlockedWebhookIp(rec.address)) {
|
|
1841
|
+
throw new Error(`Webhook DNS resolved to private/loopback IP: ${rec.address}`);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
function formatDigestReport(snapshot, serverVersion) {
|
|
1847
|
+
const lines = [];
|
|
1848
|
+
lines.push(`# Memory Journal Digest`);
|
|
1849
|
+
lines.push(`_Computed at: ${snapshot.computedAt} (v${serverVersion})_`);
|
|
1850
|
+
lines.push("");
|
|
1851
|
+
lines.push(`## Activity Trend`);
|
|
1852
|
+
const currentActivity = snapshot.currentPeriodEntries;
|
|
1853
|
+
const growth = snapshot.activityGrowthPercent;
|
|
1854
|
+
const growthStr = growth !== null ? `(${growth >= 0 ? "+" : ""}${String(growth)}% vs last period)` : "(baseline period)";
|
|
1855
|
+
lines.push(`- **Entries this period**: ${String(currentActivity)} ${growthStr}`);
|
|
1856
|
+
lines.push("");
|
|
1857
|
+
if (snapshot.currentPeriodSignificant > 0) {
|
|
1858
|
+
lines.push(`## Significance Highlights`);
|
|
1859
|
+
const mult = snapshot.significanceMultiplier;
|
|
1860
|
+
const multStr = mult !== null ? `(${String(mult)}\xD7 historical average)` : "";
|
|
1861
|
+
lines.push(`- **Significant entries**: ${String(snapshot.currentPeriodSignificant)} ${multStr}`);
|
|
1862
|
+
lines.push("");
|
|
1863
|
+
}
|
|
1864
|
+
if (snapshot.staleProjects.length > 0) {
|
|
1865
|
+
lines.push(`## \u26A0 Stale Projects`);
|
|
1866
|
+
for (const stale of snapshot.staleProjects) {
|
|
1867
|
+
lines.push(`- Project P${String(stale.projectNumber)}: ${String(stale.daysSilent)} days silent (Last entry: ${stale.lastEntryDate.split("T")[0]})`);
|
|
1868
|
+
}
|
|
1869
|
+
lines.push("");
|
|
1870
|
+
}
|
|
1871
|
+
if (snapshot.topImportanceEntries.length > 0) {
|
|
1872
|
+
lines.push(`## Top Importance Entries`);
|
|
1873
|
+
for (const entry of snapshot.topImportanceEntries) {
|
|
1874
|
+
const preview = entry.preview.replace(/\n/g, " ").trim();
|
|
1875
|
+
lines.push(`- **#${String(entry.id)}** [Score: ${String(entry.score)}]: ${preview}...`);
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
return lines.join("\n");
|
|
1879
|
+
}
|
|
1880
|
+
async function deliverReport(report, snapshot, options) {
|
|
1881
|
+
const { webhookUrl, webhookAuth, contentType = "slack" } = options;
|
|
1882
|
+
try {
|
|
1883
|
+
await validateWebhookUrl(webhookUrl);
|
|
1884
|
+
} catch (err) {
|
|
1885
|
+
logger.error("Refusing to deliver digest report to unsafe webhook URL", {
|
|
1886
|
+
module: "DigestReporter",
|
|
1887
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1888
|
+
});
|
|
1889
|
+
return false;
|
|
1890
|
+
}
|
|
1891
|
+
let bodyPayload;
|
|
1892
|
+
if (contentType === "discord") {
|
|
1893
|
+
bodyPayload = JSON.stringify({ content: report });
|
|
1894
|
+
} else if (contentType === "json") {
|
|
1895
|
+
bodyPayload = JSON.stringify(snapshot);
|
|
1896
|
+
} else {
|
|
1897
|
+
bodyPayload = JSON.stringify({ text: report });
|
|
1898
|
+
}
|
|
1899
|
+
const headers = {
|
|
1900
|
+
"Content-Type": "application/json"
|
|
1901
|
+
};
|
|
1902
|
+
if (webhookAuth) {
|
|
1903
|
+
headers["Authorization"] = webhookAuth;
|
|
1904
|
+
}
|
|
1905
|
+
const MAX_RETRIES = 1;
|
|
1906
|
+
const RETRY_DELAY_MS = 3e3;
|
|
1907
|
+
const TIMEOUT_MS = 1e4;
|
|
1908
|
+
for (let attempt = 1; attempt <= MAX_RETRIES + 1; attempt++) {
|
|
1909
|
+
try {
|
|
1910
|
+
const controller = new AbortController();
|
|
1911
|
+
const timeoutId = setTimeout(() => {
|
|
1912
|
+
controller.abort();
|
|
1913
|
+
}, TIMEOUT_MS);
|
|
1914
|
+
const response = await fetch(webhookUrl, {
|
|
1915
|
+
method: "POST",
|
|
1916
|
+
headers,
|
|
1917
|
+
body: bodyPayload,
|
|
1918
|
+
signal: controller.signal,
|
|
1919
|
+
redirect: "error"
|
|
1920
|
+
});
|
|
1921
|
+
clearTimeout(timeoutId);
|
|
1922
|
+
if (response.ok) {
|
|
1923
|
+
logger.info("Digest report delivered successfully", {
|
|
1924
|
+
module: "DigestReporter",
|
|
1925
|
+
attempt,
|
|
1926
|
+
contentType
|
|
1927
|
+
});
|
|
1928
|
+
return true;
|
|
1929
|
+
}
|
|
1930
|
+
if (response.status >= 400 && response.status < 500) {
|
|
1931
|
+
logger.error("Failed to deliver digest report (client error)", {
|
|
1932
|
+
module: "DigestReporter",
|
|
1933
|
+
status: response.status,
|
|
1934
|
+
statusText: response.statusText,
|
|
1935
|
+
contentType
|
|
1936
|
+
});
|
|
1937
|
+
return false;
|
|
1938
|
+
}
|
|
1939
|
+
throw new Error(`HTTP ${String(response.status)}: ${response.statusText}`);
|
|
1940
|
+
} catch (error) {
|
|
1941
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1942
|
+
const isAbortError = error instanceof Error && error.name === "AbortError";
|
|
1943
|
+
if (attempt <= MAX_RETRIES) {
|
|
1944
|
+
logger.warning("Failed to deliver digest report, retrying...", {
|
|
1945
|
+
module: "DigestReporter",
|
|
1946
|
+
attempt,
|
|
1947
|
+
error: isAbortError ? "Timeout" : errorMessage
|
|
1948
|
+
});
|
|
1949
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
1950
|
+
} else {
|
|
1951
|
+
logger.error("Failed to deliver digest report after all attempts", {
|
|
1952
|
+
module: "DigestReporter",
|
|
1953
|
+
error: isAbortError ? "Timeout" : errorMessage
|
|
1954
|
+
});
|
|
1955
|
+
return false;
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
return false;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/server/scheduler.ts
|
|
1963
|
+
var Scheduler = class {
|
|
1964
|
+
options;
|
|
1965
|
+
db;
|
|
1966
|
+
vectorManager;
|
|
1967
|
+
timers = [];
|
|
1968
|
+
started = false;
|
|
1969
|
+
sigtermHandler = null;
|
|
1970
|
+
runtime;
|
|
1971
|
+
constructor(options, db, vectorManager, runtime) {
|
|
1972
|
+
this.options = options;
|
|
1973
|
+
this.db = db;
|
|
1974
|
+
this.vectorManager = vectorManager ?? null;
|
|
1975
|
+
this.runtime = runtime;
|
|
1976
|
+
}
|
|
1977
|
+
/**
|
|
1978
|
+
* Start all enabled scheduled jobs.
|
|
1979
|
+
* Each job runs on its own interval and failures are isolated.
|
|
1980
|
+
*/
|
|
1981
|
+
start() {
|
|
1982
|
+
if (this.started) {
|
|
1983
|
+
logger.warning("Scheduler already started, ignoring duplicate start()", {
|
|
1984
|
+
module: "Scheduler"
|
|
1985
|
+
});
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
this.started = true;
|
|
1989
|
+
this.sigtermHandler = () => {
|
|
1990
|
+
this.stop();
|
|
1991
|
+
};
|
|
1992
|
+
process.on("SIGTERM", this.sigtermHandler);
|
|
1993
|
+
const { backupIntervalMinutes, vacuumIntervalMinutes, rebuildIndexIntervalMinutes } = this.options;
|
|
1994
|
+
if (backupIntervalMinutes > 0) {
|
|
1995
|
+
this.scheduleJob("backup", backupIntervalMinutes, () => this.runBackup());
|
|
1996
|
+
}
|
|
1997
|
+
if (vacuumIntervalMinutes > 0) {
|
|
1998
|
+
this.scheduleJob("vacuum", vacuumIntervalMinutes, () => {
|
|
1999
|
+
this.runVacuumOptimize();
|
|
2000
|
+
return Promise.resolve();
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
if (this.options.pruneIntervalMinutes > 0) {
|
|
2004
|
+
this.scheduleJob("prune", this.options.pruneIntervalMinutes, () => this.runPrune());
|
|
2005
|
+
}
|
|
2006
|
+
if (rebuildIndexIntervalMinutes > 0) {
|
|
2007
|
+
if (this.vectorManager) {
|
|
2008
|
+
this.scheduleJob(
|
|
2009
|
+
"rebuild-index",
|
|
2010
|
+
rebuildIndexIntervalMinutes,
|
|
2011
|
+
() => this.runRebuildIndex()
|
|
2012
|
+
);
|
|
2013
|
+
} else {
|
|
2014
|
+
logger.warning(
|
|
2015
|
+
"rebuild-index-interval specified but vector manager not available, skipping",
|
|
2016
|
+
{ module: "Scheduler" }
|
|
2017
|
+
);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
if (this.options.digestIntervalMinutes > 0) {
|
|
2021
|
+
this.scheduleJob("digest", this.options.digestIntervalMinutes, () => {
|
|
2022
|
+
this.runDigest();
|
|
2023
|
+
return Promise.resolve();
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
if (this.options.reportIntervalMinutes > 0) {
|
|
2027
|
+
this.scheduleJob("report", this.options.reportIntervalMinutes, () => {
|
|
2028
|
+
this.runReport();
|
|
2029
|
+
return Promise.resolve();
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
if (this.timers.length > 0) {
|
|
2033
|
+
const summary = this.timers.map(
|
|
2034
|
+
(t) => `${t.name} (${String(t.intervalMinutes)}min)`
|
|
2035
|
+
);
|
|
2036
|
+
logger.info(`Scheduler started: ${summary.join(", ")}`, { module: "Scheduler" });
|
|
2037
|
+
} else {
|
|
2038
|
+
logger.info("Scheduler started with no jobs enabled", { module: "Scheduler" });
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Stop all scheduled jobs and clear timers.
|
|
2043
|
+
* Safe to call multiple times.
|
|
2044
|
+
*/
|
|
2045
|
+
stop() {
|
|
2046
|
+
for (const job of this.timers) {
|
|
2047
|
+
clearInterval(job.timer);
|
|
2048
|
+
}
|
|
2049
|
+
if (this.timers.length > 0) {
|
|
2050
|
+
logger.info(`Scheduler stopped, cleared ${String(this.timers.length)} job(s)`, {
|
|
2051
|
+
module: "Scheduler"
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
if (this.sigtermHandler !== null) {
|
|
2055
|
+
process.off("SIGTERM", this.sigtermHandler);
|
|
2056
|
+
this.sigtermHandler = null;
|
|
2057
|
+
}
|
|
2058
|
+
this.timers.length = 0;
|
|
2059
|
+
this.started = false;
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Get the current status of all scheduled jobs.
|
|
2063
|
+
*/
|
|
2064
|
+
getStatus() {
|
|
2065
|
+
return {
|
|
2066
|
+
active: this.started,
|
|
2067
|
+
jobs: this.timers.map((t) => ({
|
|
2068
|
+
name: t.name,
|
|
2069
|
+
enabled: true,
|
|
2070
|
+
intervalMinutes: t.intervalMinutes,
|
|
2071
|
+
lastRun: t.lastRun?.toISOString() ?? null,
|
|
2072
|
+
lastResult: t.lastResult,
|
|
2073
|
+
lastError: t.lastError,
|
|
2074
|
+
nextRun: t.lastRun ? new Date(t.lastRun.getTime() + t.intervalMinutes * 6e4).toISOString() : new Date(Date.now() + t.intervalMinutes * 6e4).toISOString(),
|
|
2075
|
+
runCount: t.runCount
|
|
2076
|
+
}))
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2079
|
+
// ========================================================================
|
|
2080
|
+
// Private — Job scheduling
|
|
2081
|
+
// ========================================================================
|
|
2082
|
+
/**
|
|
2083
|
+
* Schedule a recurring job.
|
|
2084
|
+
*/
|
|
2085
|
+
scheduleJob(name, intervalMinutes, fn) {
|
|
2086
|
+
const intervalMs = intervalMinutes * 6e4;
|
|
2087
|
+
const jobTimer = {
|
|
2088
|
+
name,
|
|
2089
|
+
intervalMinutes,
|
|
2090
|
+
timer: setInterval(() => {
|
|
2091
|
+
void this.executeJob(jobTimer, fn);
|
|
2092
|
+
}, intervalMs),
|
|
2093
|
+
lastRun: null,
|
|
2094
|
+
lastResult: null,
|
|
2095
|
+
lastError: null,
|
|
2096
|
+
runCount: 0
|
|
2097
|
+
};
|
|
2098
|
+
jobTimer.timer.unref();
|
|
2099
|
+
this.timers.push(jobTimer);
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Execute a job with error isolation and status tracking.
|
|
2103
|
+
*/
|
|
2104
|
+
async executeJob(job, fn) {
|
|
2105
|
+
if (job.isRunning) {
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
let inMaintenance = false;
|
|
2109
|
+
if (!this.runtime) {
|
|
2110
|
+
logger.error(
|
|
2111
|
+
"ServerRuntime is required to schedule jobs safely. Bypassing maintenance check.",
|
|
2112
|
+
{ module: "Scheduler" }
|
|
2113
|
+
);
|
|
2114
|
+
} else {
|
|
2115
|
+
inMaintenance = this.runtime.maintenanceManager.isMaintenanceModeActive();
|
|
2116
|
+
}
|
|
2117
|
+
if (inMaintenance) {
|
|
2118
|
+
logger.info(`Skipping scheduled job '${job.name}' due to active maintenance mode`, {
|
|
2119
|
+
module: "Scheduler",
|
|
2120
|
+
operation: job.name
|
|
2121
|
+
});
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
job.isRunning = true;
|
|
2125
|
+
const startTime = Date.now();
|
|
2126
|
+
try {
|
|
2127
|
+
if (this.runtime) {
|
|
2128
|
+
await this.runtime.maintenanceManager.withActiveJob(fn);
|
|
2129
|
+
} else {
|
|
2130
|
+
await fn();
|
|
2131
|
+
}
|
|
2132
|
+
job.lastRun = new Date(startTime);
|
|
2133
|
+
job.lastResult = "success";
|
|
2134
|
+
job.lastError = null;
|
|
2135
|
+
job.runCount++;
|
|
2136
|
+
} catch (error) {
|
|
2137
|
+
job.lastRun = new Date(startTime);
|
|
2138
|
+
job.lastResult = "error";
|
|
2139
|
+
job.lastError = error instanceof Error ? error.message : String(error);
|
|
2140
|
+
job.runCount++;
|
|
2141
|
+
logger.error(`Scheduled job '${job.name}' failed`, {
|
|
2142
|
+
module: "Scheduler",
|
|
2143
|
+
operation: job.name,
|
|
2144
|
+
error: job.lastError
|
|
2145
|
+
});
|
|
2146
|
+
} finally {
|
|
2147
|
+
job.isRunning = false;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
// ========================================================================
|
|
2151
|
+
// Private — Job implementations
|
|
2152
|
+
// ========================================================================
|
|
2153
|
+
/**
|
|
2154
|
+
* Backup job: export database to file, then cleanup old backups.
|
|
2155
|
+
*/
|
|
2156
|
+
async runBackup() {
|
|
2157
|
+
const result = await this.db.exportToFile();
|
|
2158
|
+
logger.info("Scheduled backup created", {
|
|
2159
|
+
module: "Scheduler",
|
|
2160
|
+
operation: "backup",
|
|
2161
|
+
context: { filename: result.filename, sizeBytes: result.sizeBytes }
|
|
2162
|
+
});
|
|
2163
|
+
const cleanup = this.db.deleteOldBackups(this.options.keepBackups);
|
|
2164
|
+
if (cleanup.deleted.length > 0) {
|
|
2165
|
+
logger.info(
|
|
2166
|
+
`Backup cleanup: deleted ${String(cleanup.deleted.length)}, kept ${String(cleanup.kept)}`,
|
|
2167
|
+
{
|
|
2168
|
+
module: "Scheduler",
|
|
2169
|
+
operation: "backup-cleanup"
|
|
2170
|
+
}
|
|
2171
|
+
);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
/**
|
|
2175
|
+
* Vacuum/optimize job: run PRAGMA optimize and flush to disk.
|
|
2176
|
+
*
|
|
2177
|
+
* PRAGMA optimize updates internal query planner statistics based on
|
|
2178
|
+
* recent query patterns. For the native better-sqlite3 driver, disk
|
|
2179
|
+
* writes happen automatically via WAL mode.
|
|
2180
|
+
*/
|
|
2181
|
+
runVacuumOptimize() {
|
|
2182
|
+
this.db.pragma("optimize");
|
|
2183
|
+
this.db.flushSave();
|
|
2184
|
+
logger.info("Scheduled database optimize completed", {
|
|
2185
|
+
module: "Scheduler",
|
|
2186
|
+
operation: "vacuum"
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
/**
|
|
2190
|
+
* Rebuild index job: full vector index rebuild from database entries.
|
|
2191
|
+
*/
|
|
2192
|
+
async runRebuildIndex() {
|
|
2193
|
+
if (!this.vectorManager) {
|
|
2194
|
+
return;
|
|
2195
|
+
}
|
|
2196
|
+
const { indexed: count } = await this.vectorManager.rebuildIndex();
|
|
2197
|
+
logger.info(`Scheduled vector index rebuild: ${String(count)} entries indexed`, {
|
|
2198
|
+
module: "Scheduler",
|
|
2199
|
+
operation: "rebuild-index",
|
|
2200
|
+
context: { entriesIndexed: count }
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
2203
|
+
// ========================================================================
|
|
2204
|
+
// Private — Prune job
|
|
2205
|
+
// ========================================================================
|
|
2206
|
+
/**
|
|
2207
|
+
* Prune job: auto-prune low-importance old entries.
|
|
2208
|
+
*/
|
|
2209
|
+
async runPrune() {
|
|
2210
|
+
const pruneResult = await runAutoPrune(this.db, {
|
|
2211
|
+
archiveOlderThanDays: this.options.archiveOlderThanDays ?? 0,
|
|
2212
|
+
pruneOlderThanDays: this.options.pruneOlderThanDays ?? 0,
|
|
2213
|
+
hardDeleteOlderThanDays: this.options.hardDeleteOlderThanDays ?? 0,
|
|
2214
|
+
importanceThreshold: this.options.pruneImportanceThreshold ?? 0.15,
|
|
2215
|
+
dryRun: this.options.pruneDryRun,
|
|
2216
|
+
excludeTags: this.options.pruneExcludeTags
|
|
2217
|
+
});
|
|
2218
|
+
logger.info("Scheduled auto-prune completed", {
|
|
2219
|
+
module: "Scheduler",
|
|
2220
|
+
operation: "prune",
|
|
2221
|
+
archivedCount: pruneResult.archivedCount,
|
|
2222
|
+
prunedCount: pruneResult.prunedCount,
|
|
2223
|
+
hardDeletedCount: pruneResult.hardDeletedCount
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
// ========================================================================
|
|
2227
|
+
// Private — Digest job
|
|
2228
|
+
// ========================================================================
|
|
2229
|
+
/**
|
|
2230
|
+
* Digest job: compute analytics snapshot and persist to database.
|
|
2231
|
+
*/
|
|
2232
|
+
runDigest() {
|
|
2233
|
+
const snapshot = this.db.computeDigest();
|
|
2234
|
+
this.db.saveAnalyticsSnapshot("digest", snapshot);
|
|
2235
|
+
logger.info("Scheduled analytics digest computed", {
|
|
2236
|
+
module: "Scheduler",
|
|
2237
|
+
operation: "digest",
|
|
2238
|
+
context: {
|
|
2239
|
+
currentPeriodEntries: snapshot.currentPeriodEntries,
|
|
2240
|
+
activityGrowthPercent: snapshot.activityGrowthPercent,
|
|
2241
|
+
topImportanceCount: snapshot.topImportanceEntries.length
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
// ========================================================================
|
|
2246
|
+
// Private — Report job
|
|
2247
|
+
// ========================================================================
|
|
2248
|
+
/**
|
|
2249
|
+
* Report job: compute analytics snapshot, persist, and deliver via webhook.
|
|
2250
|
+
*/
|
|
2251
|
+
runReport() {
|
|
2252
|
+
const snapshot = this.db.computeDigest();
|
|
2253
|
+
this.db.saveAnalyticsSnapshot("report", snapshot);
|
|
2254
|
+
logger.info("Scheduled analytics report computed", {
|
|
2255
|
+
module: "Scheduler",
|
|
2256
|
+
operation: "report",
|
|
2257
|
+
context: {
|
|
2258
|
+
currentPeriodEntries: snapshot.currentPeriodEntries
|
|
2259
|
+
}
|
|
2260
|
+
});
|
|
2261
|
+
if (this.options.reportDeliveryOptions?.webhookUrl) {
|
|
2262
|
+
const report = formatDigestReport(snapshot, VERSION);
|
|
2263
|
+
void deliverReport(report, snapshot, this.options.reportDeliveryOptions);
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
// ========================================================================
|
|
2267
|
+
// Public — Digest accessor
|
|
2268
|
+
// ========================================================================
|
|
2269
|
+
/**
|
|
2270
|
+
* Get the latest digest snapshot from the database.
|
|
2271
|
+
* Returns null if no digest has been computed yet.
|
|
2272
|
+
*/
|
|
2273
|
+
getLatestDigest() {
|
|
2274
|
+
const snapshot = this.db.getLatestAnalyticsSnapshot("digest");
|
|
2275
|
+
if (!snapshot) return null;
|
|
2276
|
+
return snapshot.data;
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
|
|
2280
|
+
// src/utils/maintenance-lock.ts
|
|
2281
|
+
var MaintenanceManager = class {
|
|
2282
|
+
activeJobs = 0;
|
|
2283
|
+
maintenanceWaitPromise = null;
|
|
2284
|
+
inMaintenanceMode = false;
|
|
2285
|
+
async withActiveJob(fn, bypass = false) {
|
|
2286
|
+
if (this.inMaintenanceMode && !bypass) {
|
|
2287
|
+
throw new MemoryJournalMcpError(
|
|
2288
|
+
"Maintenance Mode: The server is experiencing downtime for an internal maintenance operation. Please try again later.",
|
|
2289
|
+
"MAINTENANCE_MODE",
|
|
2290
|
+
"resource",
|
|
2291
|
+
{ recoverable: true }
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
this.activeJobs++;
|
|
2295
|
+
try {
|
|
2296
|
+
return await fn();
|
|
2297
|
+
} finally {
|
|
2298
|
+
this.activeJobs--;
|
|
2299
|
+
if (this.maintenanceWaitPromise !== null && this.activeJobs <= (this.inMaintenanceMode ? 1 : 0)) {
|
|
2300
|
+
this.maintenanceWaitPromise.resolve();
|
|
2301
|
+
this.maintenanceWaitPromise = null;
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
yieldJob() {
|
|
2306
|
+
this.activeJobs--;
|
|
2307
|
+
if (this.maintenanceWaitPromise !== null && this.activeJobs <= (this.inMaintenanceMode ? 1 : 0)) {
|
|
2308
|
+
this.maintenanceWaitPromise.resolve();
|
|
2309
|
+
this.maintenanceWaitPromise = null;
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
resumeJob() {
|
|
2313
|
+
this.activeJobs++;
|
|
2314
|
+
}
|
|
2315
|
+
async acquireMaintenanceLock() {
|
|
2316
|
+
if (this.inMaintenanceMode) {
|
|
2317
|
+
throw new MemoryJournalMcpError("Maintenance lock is already acquired.", "LOCK_ACQUIRED", "internal");
|
|
2318
|
+
}
|
|
2319
|
+
this.inMaintenanceMode = true;
|
|
2320
|
+
if (this.activeJobs > 1) {
|
|
2321
|
+
if (this.maintenanceWaitPromise === null) {
|
|
2322
|
+
let resolver;
|
|
2323
|
+
const promise = new Promise((resolve) => {
|
|
2324
|
+
resolver = resolve;
|
|
2325
|
+
});
|
|
2326
|
+
if (resolver) {
|
|
2327
|
+
this.maintenanceWaitPromise = { promise, resolve: resolver };
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
if (this.maintenanceWaitPromise !== null) {
|
|
2331
|
+
await this.maintenanceWaitPromise.promise;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
releaseMaintenanceLock() {
|
|
2336
|
+
this.inMaintenanceMode = false;
|
|
2337
|
+
if (this.maintenanceWaitPromise !== null) {
|
|
2338
|
+
this.maintenanceWaitPromise.resolve();
|
|
2339
|
+
this.maintenanceWaitPromise = null;
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
assertNotInMaintenanceMode() {
|
|
2343
|
+
if (this.inMaintenanceMode) {
|
|
2344
|
+
throw new MemoryJournalMcpError(
|
|
2345
|
+
"Maintenance Mode: The server is experiencing downtime for an internal maintenance operation. Please try again later.",
|
|
2346
|
+
"MAINTENANCE_MODE",
|
|
2347
|
+
"resource",
|
|
2348
|
+
{ recoverable: true }
|
|
2349
|
+
);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
isMaintenanceModeActive() {
|
|
2353
|
+
return this.inMaintenanceMode;
|
|
2354
|
+
}
|
|
2355
|
+
};
|
|
2356
|
+
var ServerRuntime = class {
|
|
2357
|
+
maintenanceManager = new MaintenanceManager();
|
|
2358
|
+
metrics = new MetricsAccumulator();
|
|
2359
|
+
auditLogger = null;
|
|
2360
|
+
auditInterceptor = null;
|
|
2361
|
+
toolMapCache = null;
|
|
2362
|
+
mappedToolsCache = null;
|
|
2363
|
+
cachedContextRefs = null;
|
|
2364
|
+
githubClientPool = null;
|
|
2365
|
+
configManager = null;
|
|
2366
|
+
};
|
|
2367
|
+
var ConfigManager = class extends EventEmitter {
|
|
2368
|
+
config;
|
|
2369
|
+
initialCodemodeFullAccess;
|
|
2370
|
+
configFilePath;
|
|
2371
|
+
watcher;
|
|
2372
|
+
isWriting = false;
|
|
2373
|
+
constructor(initialConfig, configFilePath) {
|
|
2374
|
+
super();
|
|
2375
|
+
this.config = { ...initialConfig };
|
|
2376
|
+
this.initialCodemodeFullAccess = Boolean(initialConfig.codemodeInternalFullAccess);
|
|
2377
|
+
this.configFilePath = configFilePath;
|
|
2378
|
+
if (this.configFilePath && fs.existsSync(this.configFilePath)) {
|
|
2379
|
+
this.watchFile();
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
getConfig() {
|
|
2383
|
+
return this.config;
|
|
2384
|
+
}
|
|
2385
|
+
updateConfig(newConfig, persist = false) {
|
|
2386
|
+
this.config = { ...this.config, ...newConfig };
|
|
2387
|
+
if (newConfig.rawToolFilter !== void 0) {
|
|
2388
|
+
this.config.toolFilterConfig = newConfig.rawToolFilter ? parseToolFilter(newConfig.rawToolFilter) : null;
|
|
2389
|
+
}
|
|
2390
|
+
if (persist && this.configFilePath) {
|
|
2391
|
+
this.persistToFile();
|
|
2392
|
+
}
|
|
2393
|
+
this.emit("changed", this.config);
|
|
2394
|
+
}
|
|
2395
|
+
close() {
|
|
2396
|
+
this.watcher?.close();
|
|
2397
|
+
}
|
|
2398
|
+
persistToFile() {
|
|
2399
|
+
if (!this.configFilePath) return;
|
|
2400
|
+
this.isWriting = true;
|
|
2401
|
+
try {
|
|
2402
|
+
const content = fs.readFileSync(this.configFilePath, "utf-8");
|
|
2403
|
+
let parsed = {};
|
|
2404
|
+
if (this.configFilePath.endsWith(".json")) {
|
|
2405
|
+
parsed = JSON.parse(content);
|
|
2406
|
+
} else {
|
|
2407
|
+
parsed = parse(content) ?? {};
|
|
2408
|
+
}
|
|
2409
|
+
if (this.config.rawToolFilter !== void 0) {
|
|
2410
|
+
parsed["toolFilter"] = this.config.rawToolFilter;
|
|
2411
|
+
}
|
|
2412
|
+
if (this.config.codemodeInternalFullAccess !== void 0) {
|
|
2413
|
+
parsed["codemodeInternalFullAccess"] = this.config.codemodeInternalFullAccess;
|
|
2414
|
+
}
|
|
2415
|
+
if (this.config.briefingConfig.entryCount !== void 0) parsed["briefingEntries"] = this.config.briefingConfig.entryCount;
|
|
2416
|
+
if (this.config.briefingConfig.summaryCount !== void 0) parsed["briefingSummaries"] = this.config.briefingConfig.summaryCount;
|
|
2417
|
+
if (this.config.briefingConfig.includeTeam !== void 0) parsed["briefingIncludeTeam"] = this.config.briefingConfig.includeTeam;
|
|
2418
|
+
if (this.config.briefingConfig.issueCount !== void 0) parsed["briefingIssues"] = this.config.briefingConfig.issueCount;
|
|
2419
|
+
if (this.config.briefingConfig.prCount !== void 0) parsed["briefingPrs"] = this.config.briefingConfig.prCount;
|
|
2420
|
+
if (this.config.briefingConfig.prStatusBreakdown !== void 0) parsed["briefingPrStatus"] = this.config.briefingConfig.prStatusBreakdown;
|
|
2421
|
+
if (this.config.briefingConfig.milestoneCount !== void 0) parsed["briefingMilestones"] = this.config.briefingConfig.milestoneCount;
|
|
2422
|
+
if (this.config.briefingConfig.workflowCount !== void 0) parsed["briefingWorkflows"] = this.config.briefingConfig.workflowCount;
|
|
2423
|
+
if (this.config.briefingConfig.workflowStatusBreakdown !== void 0) parsed["briefingWorkflowStatus"] = this.config.briefingConfig.workflowStatusBreakdown;
|
|
2424
|
+
if (this.config.briefingConfig.copilotReviews !== void 0) parsed["briefingCopilot"] = this.config.briefingConfig.copilotReviews;
|
|
2425
|
+
if (this.configFilePath.endsWith(".json")) {
|
|
2426
|
+
fs.writeFileSync(this.configFilePath, JSON.stringify(parsed, null, 2), "utf-8");
|
|
2427
|
+
} else {
|
|
2428
|
+
logger.warning("YAML file updates from update_configuration tool will drop comments.", { module: "ConfigManager" });
|
|
2429
|
+
const yamlStr = stringify(parsed);
|
|
2430
|
+
fs.writeFileSync(this.configFilePath, yamlStr, "utf-8");
|
|
2431
|
+
}
|
|
2432
|
+
} catch (e) {
|
|
2433
|
+
logger.error("Failed to persist configuration to file", { module: "ConfigManager", error: e instanceof Error ? e.message : String(e) });
|
|
2434
|
+
} finally {
|
|
2435
|
+
this.isWriting = false;
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
watchFile() {
|
|
2439
|
+
if (!this.configFilePath) return;
|
|
2440
|
+
let debounceTimer;
|
|
2441
|
+
try {
|
|
2442
|
+
this.watcher = fs.watch(this.configFilePath, (eventType) => {
|
|
2443
|
+
if (eventType === "change" && !this.isWriting) {
|
|
2444
|
+
clearTimeout(debounceTimer);
|
|
2445
|
+
debounceTimer = setTimeout(() => {
|
|
2446
|
+
try {
|
|
2447
|
+
this.reloadFromFile();
|
|
2448
|
+
} catch (err) {
|
|
2449
|
+
logger.error("Failed to reload config file", { module: "ConfigManager", error: err instanceof Error ? err.message : String(err) });
|
|
2450
|
+
}
|
|
2451
|
+
}, 500);
|
|
2452
|
+
}
|
|
2453
|
+
});
|
|
2454
|
+
this.watcher.on("error", (err) => {
|
|
2455
|
+
logger.warning("Config file watcher error", {
|
|
2456
|
+
module: "ConfigManager",
|
|
2457
|
+
path: this.configFilePath,
|
|
2458
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2459
|
+
});
|
|
2460
|
+
});
|
|
2461
|
+
logger.info("Watching configuration file for changes", { module: "ConfigManager", path: this.configFilePath });
|
|
2462
|
+
} catch (error) {
|
|
2463
|
+
logger.warning("Failed to start configuration file watcher", { module: "ConfigManager", error: error instanceof Error ? error.message : String(error) });
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
reloadFromFile() {
|
|
2467
|
+
if (!this.configFilePath || !fs.existsSync(this.configFilePath)) return;
|
|
2468
|
+
try {
|
|
2469
|
+
const content = fs.readFileSync(this.configFilePath, "utf-8");
|
|
2470
|
+
let parsed = {};
|
|
2471
|
+
if (this.configFilePath.endsWith(".json")) {
|
|
2472
|
+
parsed = JSON.parse(content);
|
|
2473
|
+
} else {
|
|
2474
|
+
parsed = parse(content) ?? {};
|
|
2475
|
+
}
|
|
2476
|
+
const updates = {};
|
|
2477
|
+
if ("toolFilter" in parsed) {
|
|
2478
|
+
updates.rawToolFilter = typeof parsed["toolFilter"] === "string" ? parsed["toolFilter"] : void 0;
|
|
2479
|
+
}
|
|
2480
|
+
if ("codemodeInternalFullAccess" in parsed) {
|
|
2481
|
+
const requested = typeof parsed["codemodeInternalFullAccess"] === "boolean" ? parsed["codemodeInternalFullAccess"] : void 0;
|
|
2482
|
+
if (requested === false || requested === true && this.initialCodemodeFullAccess) {
|
|
2483
|
+
updates.codemodeInternalFullAccess = requested;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
const bc = { ...this.config.briefingConfig };
|
|
2487
|
+
let bcChanged = false;
|
|
2488
|
+
const bcKeys = ["briefingEntries", "briefingSummaries", "briefingIncludeTeam", "briefingIssues", "briefingPrs", "briefingPrStatus", "briefingMilestones", "briefingWorkflows", "briefingWorkflowStatus", "briefingCopilot"];
|
|
2489
|
+
for (const key of bcKeys) {
|
|
2490
|
+
if (key in parsed) {
|
|
2491
|
+
const mappedKey = key === "briefingEntries" ? "entryCount" : key === "briefingSummaries" ? "summaryCount" : key === "briefingIncludeTeam" ? "includeTeam" : key === "briefingIssues" ? "issueCount" : key === "briefingPrs" ? "prCount" : key === "briefingPrStatus" ? "prStatusBreakdown" : key === "briefingMilestones" ? "milestoneCount" : key === "briefingWorkflows" ? "workflowCount" : key === "briefingWorkflowStatus" ? "workflowStatusBreakdown" : key === "briefingCopilot" ? "copilotReviews" : void 0;
|
|
2492
|
+
if (mappedKey) {
|
|
2493
|
+
bc[mappedKey] = parsed[key];
|
|
2494
|
+
bcChanged = true;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
if (bcChanged) {
|
|
2499
|
+
updates.briefingConfig = bc;
|
|
2500
|
+
}
|
|
2501
|
+
if (Object.keys(updates).length > 0) {
|
|
2502
|
+
this.updateConfig(updates, false);
|
|
2503
|
+
logger.info("Hot-reloaded dynamic configuration from file", { module: "ConfigManager" });
|
|
2504
|
+
}
|
|
2505
|
+
} catch (e) {
|
|
2506
|
+
logger.error("Error hot-reloading config file", { module: "ConfigManager", error: e instanceof Error ? e.message : String(e) });
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
};
|
|
2510
|
+
|
|
2511
|
+
// src/server/mcp-server/initialization.ts
|
|
2512
|
+
function resolveBundledSkillsDir() {
|
|
2513
|
+
let dir = import.meta.dirname;
|
|
2514
|
+
for (let i = 0; i < 5; i++) {
|
|
2515
|
+
const candidate = path.join(dir, "skills");
|
|
2516
|
+
if (fs.existsSync(path.join(candidate, "memory-journal-mcp", "SKILL.md"))) {
|
|
2517
|
+
return candidate;
|
|
2518
|
+
}
|
|
2519
|
+
const parent = path.dirname(dir);
|
|
2520
|
+
if (parent === dir) break;
|
|
2521
|
+
dir = parent;
|
|
2522
|
+
}
|
|
2523
|
+
return void 0;
|
|
2524
|
+
}
|
|
2525
|
+
async function loadBundledSkillCatalog(skillsDirOverride) {
|
|
2526
|
+
const skillsDir = resolveBundledSkillsDir();
|
|
2527
|
+
if (!skillsDir) {
|
|
2528
|
+
return void 0;
|
|
2529
|
+
}
|
|
2530
|
+
try {
|
|
2531
|
+
return await loadSkills(skillsDir, {
|
|
2532
|
+
onWarning: (warning) => {
|
|
2533
|
+
logger.warning(`Bundled skill catalog warning (${warning.path}): ${warning.message}`, {
|
|
2534
|
+
module: "McpServer"
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
});
|
|
2538
|
+
} catch (error) {
|
|
2539
|
+
logger.warning("Failed to load bundled skill catalog", {
|
|
2540
|
+
module: "McpServer",
|
|
2541
|
+
path: skillsDir,
|
|
2542
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2543
|
+
});
|
|
2544
|
+
return void 0;
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
async function initializeDependencies(options) {
|
|
2548
|
+
const { transport, dbPath, teamDbPath, testDbPath, testTeamDbPath } = options;
|
|
2549
|
+
const primaryDb = await DatabaseAdapterFactory.create(dbPath, options);
|
|
2550
|
+
await primaryDb.initialize();
|
|
2551
|
+
logger.info("Database initialized", { module: "McpServer", dbPath });
|
|
2552
|
+
let testDb;
|
|
2553
|
+
if (testDbPath) {
|
|
2554
|
+
testDb = await DatabaseAdapterFactory.create(testDbPath, options);
|
|
2555
|
+
await testDb.initialize();
|
|
2556
|
+
logger.info("Test database initialized", { module: "McpServer", testDbPath });
|
|
2557
|
+
}
|
|
2558
|
+
const db = DatabaseAdapterProxy.create(primaryDb, testDb);
|
|
2559
|
+
const hasAutoPrune = (options.archiveOlderThanDays ?? 0) > 0 || (options.pruneOlderThanDays ?? 0) > 0 || (options.hardDeleteOlderThanDays ?? 0) > 0;
|
|
2560
|
+
if (hasAutoPrune) {
|
|
2561
|
+
const pruneResult = await runAutoPrune(db, {
|
|
2562
|
+
archiveOlderThanDays: options.archiveOlderThanDays ?? 0,
|
|
2563
|
+
pruneOlderThanDays: options.pruneOlderThanDays ?? 0,
|
|
2564
|
+
hardDeleteOlderThanDays: options.hardDeleteOlderThanDays ?? 0,
|
|
2565
|
+
importanceThreshold: options.pruneImportanceThreshold ?? 0.15,
|
|
2566
|
+
dryRun: options.pruneDryRun,
|
|
2567
|
+
excludeTags: options.pruneExcludeTags
|
|
2568
|
+
});
|
|
2569
|
+
logger.info("Auto-prune completed", {
|
|
2570
|
+
module: "McpServer",
|
|
2571
|
+
archivedCount: pruneResult.archivedCount,
|
|
2572
|
+
prunedCount: pruneResult.prunedCount,
|
|
2573
|
+
hardDeletedCount: pruneResult.hardDeletedCount,
|
|
2574
|
+
backupFile: pruneResult.backupFile
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
const runtime = new ServerRuntime();
|
|
2578
|
+
if (options.auditConfig?.enabled) {
|
|
2579
|
+
runtime.auditLogger = new AuditLogger(options.auditConfig);
|
|
2580
|
+
runtime.auditInterceptor = createAuditInterceptor(runtime.auditLogger);
|
|
2581
|
+
logger.info("Audit logging enabled", {
|
|
2582
|
+
module: "McpServer",
|
|
2583
|
+
path: options.auditConfig.logPath,
|
|
2584
|
+
redact: options.auditConfig.redact,
|
|
2585
|
+
auditReads: options.auditConfig.auditReads
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
let activeMetricsPath;
|
|
2589
|
+
if (options.persistMetrics) {
|
|
2590
|
+
const configuredPath = options.metricsPath ?? dbPath.replace(/\.db$/, "") + "_metrics.json";
|
|
2591
|
+
activeMetricsPath = configuredPath;
|
|
2592
|
+
await runtime.metrics.loadFromFile(configuredPath);
|
|
2593
|
+
setInterval(() => {
|
|
2594
|
+
void runtime.metrics.saveToFile(configuredPath);
|
|
2595
|
+
}, 5 * 60 * 1e3).unref();
|
|
2596
|
+
}
|
|
2597
|
+
let primaryTeamDb;
|
|
2598
|
+
let testTeamDb;
|
|
2599
|
+
let teamDb;
|
|
2600
|
+
if (teamDbPath) {
|
|
2601
|
+
primaryTeamDb = await DatabaseAdapterFactory.create(teamDbPath, options);
|
|
2602
|
+
await primaryTeamDb.initialize();
|
|
2603
|
+
primaryTeamDb.applyTeamSchema();
|
|
2604
|
+
logger.info("Team database initialized", { module: "McpServer", teamDbPath });
|
|
2605
|
+
if (testTeamDbPath) {
|
|
2606
|
+
testTeamDb = await DatabaseAdapterFactory.create(testTeamDbPath, options);
|
|
2607
|
+
await testTeamDb.initialize();
|
|
2608
|
+
testTeamDb.applyTeamSchema();
|
|
2609
|
+
logger.info("Test team database initialized", { module: "McpServer", testTeamDbPath });
|
|
2610
|
+
}
|
|
2611
|
+
teamDb = DatabaseAdapterProxy.create(primaryTeamDb, testTeamDb);
|
|
2612
|
+
if (options.teamAdmin && teamDb.getTeamMemberCount !== void 0 && teamDb.addTeamMember !== void 0) {
|
|
2613
|
+
if (!teamDb.isTeamRbacActive?.()) {
|
|
2614
|
+
teamDb.addTeamMember(options.teamAdmin, "admin", "system", "Bootstrap Admin");
|
|
2615
|
+
logger.info("Bootstrapped initial team admin", { module: "McpServer", admin: options.teamAdmin });
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
const primaryVectorManager = new VectorSearchManager(primaryDb, { modelName: options.embeddingModel });
|
|
2620
|
+
let testVectorManager;
|
|
2621
|
+
if (testDb) {
|
|
2622
|
+
testVectorManager = new VectorSearchManager(testDb, { modelName: options.embeddingModel });
|
|
2623
|
+
}
|
|
2624
|
+
const vectorManager = VectorSearchManagerProxy.create(primaryVectorManager, testVectorManager);
|
|
2625
|
+
let primaryTeamVectorManager;
|
|
2626
|
+
let testTeamVectorManager;
|
|
2627
|
+
let teamVectorManager;
|
|
2628
|
+
if (primaryTeamDb) {
|
|
2629
|
+
primaryTeamVectorManager = new VectorSearchManager(primaryTeamDb, { modelName: options.embeddingModel });
|
|
2630
|
+
if (testTeamDb) {
|
|
2631
|
+
testTeamVectorManager = new VectorSearchManager(testTeamDb, { modelName: options.embeddingModel });
|
|
2632
|
+
}
|
|
2633
|
+
teamVectorManager = VectorSearchManagerProxy.create(primaryTeamVectorManager, testTeamVectorManager);
|
|
2634
|
+
logger.info("Team vector search manager created", { module: "McpServer" });
|
|
2635
|
+
}
|
|
2636
|
+
if (options.autoRebuildIndex) {
|
|
2637
|
+
logger.info("Auto-rebuilding vector index in background...", { module: "McpServer" });
|
|
2638
|
+
primaryVectorManager.initialize().then(async () => {
|
|
2639
|
+
const { indexed: count } = await primaryVectorManager.rebuildIndex();
|
|
2640
|
+
logger.info("Vector index rebuilt in background", {
|
|
2641
|
+
module: "McpServer",
|
|
2642
|
+
entriesIndexed: count
|
|
2643
|
+
});
|
|
2644
|
+
}).catch((err) => {
|
|
2645
|
+
logger.error("Background vector init/rebuild failed", {
|
|
2646
|
+
module: "McpServer",
|
|
2647
|
+
error: err
|
|
2648
|
+
});
|
|
2649
|
+
});
|
|
2650
|
+
if (testVectorManager) {
|
|
2651
|
+
testVectorManager.initialize().catch((err) => {
|
|
2652
|
+
logger.error("Background test vector init failed", { module: "McpServer", error: err });
|
|
2653
|
+
});
|
|
2654
|
+
}
|
|
2655
|
+
if (primaryTeamVectorManager) {
|
|
2656
|
+
primaryTeamVectorManager.initialize().catch((err) => {
|
|
2657
|
+
logger.error("Background team vector init failed", {
|
|
2658
|
+
module: "McpServer",
|
|
2659
|
+
error: err
|
|
2660
|
+
});
|
|
2661
|
+
});
|
|
2662
|
+
if (testTeamVectorManager) {
|
|
2663
|
+
testTeamVectorManager.initialize().catch((err) => {
|
|
2664
|
+
logger.error("Background test team vector init failed", { module: "McpServer", error: err });
|
|
2665
|
+
});
|
|
2666
|
+
}
|
|
2667
|
+
logger.info("Team vector search manager eager initialization started in background", {
|
|
2668
|
+
module: "McpServer"
|
|
2669
|
+
});
|
|
2670
|
+
}
|
|
2671
|
+
} else {
|
|
2672
|
+
logger.info("Vector search manager eager initialization started in background", {
|
|
2673
|
+
module: "McpServer"
|
|
2674
|
+
});
|
|
2675
|
+
primaryVectorManager.initialize().then(async () => {
|
|
2676
|
+
if (testVectorManager) await testVectorManager.initialize();
|
|
2677
|
+
if (primaryTeamVectorManager) {
|
|
2678
|
+
logger.info(
|
|
2679
|
+
"Team vector search manager eager initialization started in background",
|
|
2680
|
+
{ module: "McpServer" }
|
|
2681
|
+
);
|
|
2682
|
+
await primaryTeamVectorManager.initialize();
|
|
2683
|
+
if (testTeamVectorManager) await testTeamVectorManager.initialize();
|
|
2684
|
+
}
|
|
2685
|
+
}).catch((err) => {
|
|
2686
|
+
logger.error("Background vector init failed", { module: "McpServer", error: err });
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
let githubPath = ".";
|
|
2690
|
+
if (options.projectRegistry && Object.keys(options.projectRegistry).length > 0) {
|
|
2691
|
+
if (options.defaultProjectNumber !== void 0) {
|
|
2692
|
+
const defaultEntry = Object.values(options.projectRegistry).find(
|
|
2693
|
+
(r) => r.project_number === options.defaultProjectNumber
|
|
2694
|
+
);
|
|
2695
|
+
if (defaultEntry?.path) {
|
|
2696
|
+
githubPath = defaultEntry.path;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
const github = getGitHubIntegration(githubPath, runtime);
|
|
2701
|
+
try {
|
|
2702
|
+
await github.getRepoInfo();
|
|
2703
|
+
} catch (error) {
|
|
2704
|
+
logger.warning("Failed to pre-populate GitHub repository cache", {
|
|
2705
|
+
module: "McpServer",
|
|
2706
|
+
path: githubPath,
|
|
2707
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
logger.info("GitHub integration initialized", {
|
|
2711
|
+
module: "McpServer",
|
|
2712
|
+
hasToken: github.isApiAvailable()
|
|
2713
|
+
});
|
|
2714
|
+
let filterConfig;
|
|
2715
|
+
if (options.toolFilter) {
|
|
2716
|
+
filterConfig = parseToolFilter(options.toolFilter);
|
|
2717
|
+
logger.info("Tool filter applied", {
|
|
2718
|
+
module: "McpServer",
|
|
2719
|
+
summary: getFilterSummary(filterConfig)
|
|
2720
|
+
});
|
|
2721
|
+
} else {
|
|
2722
|
+
filterConfig = getToolFilterFromEnv();
|
|
2723
|
+
if (filterConfig) {
|
|
2724
|
+
logger.info("Tool filter from env", {
|
|
2725
|
+
module: "McpServer",
|
|
2726
|
+
summary: getFilterSummary(filterConfig)
|
|
2727
|
+
});
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
if (!filterConfig) {
|
|
2731
|
+
const totalTools = getAllToolNames().length;
|
|
2732
|
+
if (totalTools > 50) {
|
|
2733
|
+
logger.warning(`CONTEXT BLOAT WARNING: ${totalTools} tools are being registered without a tool filter.`);
|
|
2734
|
+
logger.warning(` This may consume excessive context window in the LLM. Consider using '--tool-filter codemode' or '--tool-filter starter' to save tokens.`);
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
const rawToolFilter = options.toolFilter ?? process.env["MEMORY_JOURNAL_MCP_TOOL_FILTER"] ?? process.env["TOOL_FILTER"];
|
|
2738
|
+
const configManager = new ConfigManager({
|
|
2739
|
+
rawToolFilter,
|
|
2740
|
+
toolFilterConfig: filterConfig,
|
|
2741
|
+
briefingConfig: options.briefingConfig ?? DEFAULT_BRIEFING_CONFIG,
|
|
2742
|
+
codemodeInternalFullAccess: options.codemodeInternalFullAccess
|
|
2743
|
+
}, options.configFilePath);
|
|
2744
|
+
runtime.configManager = configManager;
|
|
2745
|
+
let scheduler = null;
|
|
2746
|
+
if (options.scheduler) {
|
|
2747
|
+
const hasAnyJob = options.scheduler.backupIntervalMinutes > 0 || options.scheduler.vacuumIntervalMinutes > 0 || options.scheduler.rebuildIndexIntervalMinutes > 0 || options.scheduler.digestIntervalMinutes > 0 || options.scheduler.pruneIntervalMinutes > 0 || options.scheduler.reportIntervalMinutes > 0;
|
|
2748
|
+
if (hasAnyJob && transport === "stdio") {
|
|
2749
|
+
logger.warning(
|
|
2750
|
+
"Scheduler options ignored for stdio transport (session is ephemeral). Use HTTP/SSE transport for automated scheduling.",
|
|
2751
|
+
{ module: "Scheduler" }
|
|
2752
|
+
);
|
|
2753
|
+
} else if (hasAnyJob) {
|
|
2754
|
+
options.scheduler.archiveOlderThanDays = options.archiveOlderThanDays;
|
|
2755
|
+
options.scheduler.pruneOlderThanDays = options.pruneOlderThanDays;
|
|
2756
|
+
options.scheduler.hardDeleteOlderThanDays = options.hardDeleteOlderThanDays;
|
|
2757
|
+
options.scheduler.pruneImportanceThreshold = options.pruneImportanceThreshold;
|
|
2758
|
+
options.scheduler.pruneDryRun = options.pruneDryRun;
|
|
2759
|
+
options.scheduler.pruneExcludeTags = options.pruneExcludeTags;
|
|
2760
|
+
scheduler = new Scheduler(options.scheduler, db, vectorManager, runtime);
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
try {
|
|
2764
|
+
const existingSnapshot = db.getLatestAnalyticsSnapshot("digest");
|
|
2765
|
+
if (!existingSnapshot) {
|
|
2766
|
+
const digest = db.computeDigest();
|
|
2767
|
+
db.saveAnalyticsSnapshot("digest", digest);
|
|
2768
|
+
logger.info("Initial analytics digest seeded", { module: "McpServer" });
|
|
2769
|
+
}
|
|
2770
|
+
} catch (error) {
|
|
2771
|
+
logger.debug("Failed to seed initial digest (non-critical)", {
|
|
2772
|
+
module: "McpServer",
|
|
2773
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2774
|
+
});
|
|
2775
|
+
}
|
|
2776
|
+
let finalAllowedIoRoots = options.allowedIoRoots;
|
|
2777
|
+
if (!finalAllowedIoRoots) {
|
|
2778
|
+
if (options.transport === "http") {
|
|
2779
|
+
const errorMsg = `FATAL: Refusing to bind HTTP transport without explicit ALLOWED_IO_ROOTS. You MUST specify --allowed-io-roots (or ALLOWED_IO_ROOTS env var) to prevent ambient filesystem authority.`;
|
|
2780
|
+
logger.error(errorMsg, { module: "HTTP" });
|
|
2781
|
+
throw new Error(errorMsg);
|
|
2782
|
+
}
|
|
2783
|
+
finalAllowedIoRoots = [];
|
|
2784
|
+
logger.warning(
|
|
2785
|
+
"\u26A0\uFE0F SECURITY WARNING: ALLOWED_IO_ROOTS not explicitly provided. Defaulting to empty array (NO filesystem access). You MUST specify --allowed-io-roots (or ALLOWED_IO_ROOTS env var) to enable filesystem tools.",
|
|
2786
|
+
{
|
|
2787
|
+
module: "McpServer"
|
|
2788
|
+
}
|
|
2789
|
+
);
|
|
2790
|
+
}
|
|
2791
|
+
logger.info("IO sandbox configured", {
|
|
2792
|
+
module: "McpServer",
|
|
2793
|
+
allowedRoots: finalAllowedIoRoots
|
|
2794
|
+
});
|
|
2795
|
+
const skillCatalog = await loadBundledSkillCatalog();
|
|
2796
|
+
return {
|
|
2797
|
+
db,
|
|
2798
|
+
testDb,
|
|
2799
|
+
teamDb,
|
|
2800
|
+
testTeamDb,
|
|
2801
|
+
runtime,
|
|
2802
|
+
vectorManager,
|
|
2803
|
+
teamVectorManager,
|
|
2804
|
+
github,
|
|
2805
|
+
configManager,
|
|
2806
|
+
scheduler,
|
|
2807
|
+
allowedIoRoots: finalAllowedIoRoots,
|
|
2808
|
+
activeMetricsPath,
|
|
2809
|
+
...skillCatalog ? { skillCatalog } : {}
|
|
2810
|
+
};
|
|
2811
|
+
}
|
|
2812
|
+
function registerResources(server, resources, handleResourceRead, runtime) {
|
|
2813
|
+
for (const resDef of resources) {
|
|
2814
|
+
const mimeType = resDef.mimeType ?? "application/json";
|
|
2815
|
+
const meta = {
|
|
2816
|
+
description: resDef.description ?? "",
|
|
2817
|
+
mimeType,
|
|
2818
|
+
...resDef.icons ? { icons: resDef.icons } : {}
|
|
2819
|
+
};
|
|
2820
|
+
const isTemplate = resDef.uri.includes("{");
|
|
2821
|
+
if (isTemplate) {
|
|
2822
|
+
const template = new ResourceTemplate(resDef.uri, { list: void 0 });
|
|
2823
|
+
server.registerResource(
|
|
2824
|
+
resDef.name,
|
|
2825
|
+
template,
|
|
2826
|
+
meta,
|
|
2827
|
+
async (uri, _variables) => {
|
|
2828
|
+
if (!runtime) {
|
|
2829
|
+
throw new ConfigurationError(
|
|
2830
|
+
"ServerRuntime is logically required for secure resource execution."
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2833
|
+
const auditLog = runtime.auditLogger;
|
|
2834
|
+
enforceAccessBoundary(uri.href, "resource", resDef.capabilities, auditLog);
|
|
2835
|
+
return auditOperation(auditLog, "resource", resDef.name, async () => {
|
|
2836
|
+
return runtime.maintenanceManager.withActiveJob(
|
|
2837
|
+
() => handleResourceRead(uri, mimeType)
|
|
2838
|
+
);
|
|
2839
|
+
});
|
|
2840
|
+
}
|
|
2841
|
+
);
|
|
2842
|
+
} else {
|
|
2843
|
+
server.registerResource(resDef.name, resDef.uri, meta, async (uri) => {
|
|
2844
|
+
if (!runtime) {
|
|
2845
|
+
throw new ConfigurationError(
|
|
2846
|
+
"ServerRuntime is logically required for secure resource execution."
|
|
2847
|
+
);
|
|
2848
|
+
}
|
|
2849
|
+
const auditLog = runtime.auditLogger;
|
|
2850
|
+
enforceAccessBoundary(uri.href, "resource", resDef.capabilities, auditLog);
|
|
2851
|
+
return auditOperation(auditLog, "resource", resDef.name, async () => {
|
|
2852
|
+
return runtime.maintenanceManager.withActiveJob(
|
|
2853
|
+
() => handleResourceRead(uri, mimeType)
|
|
2854
|
+
);
|
|
2855
|
+
});
|
|
2856
|
+
});
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
function registerPrompts(server, prompts, db, teamDb, runtime, github, briefingConfig) {
|
|
2861
|
+
for (const promptDef of prompts) {
|
|
2862
|
+
let argsSchema;
|
|
2863
|
+
if (promptDef.arguments && promptDef.arguments.length > 0) {
|
|
2864
|
+
const hasRequired = promptDef.arguments.some((a) => a.required);
|
|
2865
|
+
if (hasRequired) {
|
|
2866
|
+
argsSchema = {};
|
|
2867
|
+
for (const arg of promptDef.arguments) {
|
|
2868
|
+
argsSchema[arg.name] = arg.required === true ? z.string().describe(arg.description) : z.string().optional().describe(arg.description);
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
server.registerPrompt(
|
|
2873
|
+
promptDef.name,
|
|
2874
|
+
{
|
|
2875
|
+
description: promptDef.description ?? "",
|
|
2876
|
+
...argsSchema ? { argsSchema: z.object(argsSchema) } : {},
|
|
2877
|
+
...promptDef.icons ? { icons: promptDef.icons } : {}
|
|
2878
|
+
},
|
|
2879
|
+
(providedArgs) => {
|
|
2880
|
+
if (!runtime) {
|
|
2881
|
+
throw new ConfigurationError(
|
|
2882
|
+
"ServerRuntime is logically required for secure prompt execution."
|
|
2883
|
+
);
|
|
2884
|
+
}
|
|
2885
|
+
const auditLog = runtime.auditLogger;
|
|
2886
|
+
enforceAccessBoundary(promptDef.name, "prompt", promptDef.capabilities, auditLog);
|
|
2887
|
+
return auditOperation(auditLog, "prompt", promptDef.name, async () => {
|
|
2888
|
+
const executePrompt = async () => {
|
|
2889
|
+
const args = providedArgs;
|
|
2890
|
+
const promptResult = await getPrompt(promptDef.name, args, db, teamDb, github, briefingConfig);
|
|
2891
|
+
return {
|
|
2892
|
+
messages: promptResult.messages.map((m) => ({
|
|
2893
|
+
role: m.role,
|
|
2894
|
+
content: m.content
|
|
2895
|
+
}))
|
|
2896
|
+
};
|
|
2897
|
+
};
|
|
2898
|
+
return await runtime.maintenanceManager.withActiveJob(executePrompt);
|
|
2899
|
+
});
|
|
2900
|
+
}
|
|
2901
|
+
);
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
// src/server/mcp-server/tool-registration/list-interceptor.ts
|
|
2906
|
+
function attachListToolsInterceptor(requestHandlers, configManager, allToolNames) {
|
|
2907
|
+
const listToolsHandler = requestHandlers?.get("tools/list");
|
|
2908
|
+
if (listToolsHandler === void 0 || requestHandlers === void 0) {
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
requestHandlers.set("tools/list", async (request2, extra) => {
|
|
2912
|
+
const currentConfig = configManager.getConfig();
|
|
2913
|
+
const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
|
|
2914
|
+
const result = await listToolsHandler(request2, extra);
|
|
2915
|
+
const res = result;
|
|
2916
|
+
if (Array.isArray(res?.tools)) {
|
|
2917
|
+
res.tools = res.tools.filter((t) => enabledSet.has(t.name));
|
|
2918
|
+
}
|
|
2919
|
+
return result;
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2923
|
+
// src/server/mcp-server/tool-registration/call-interceptor.ts
|
|
2924
|
+
var ALIASED_EXECUTE_CODE_NAMES = /* @__PURE__ */ new Set([
|
|
2925
|
+
"mysql_execute_code",
|
|
2926
|
+
"mysqlExecuteCode",
|
|
2927
|
+
"execute_code",
|
|
2928
|
+
"executeCode",
|
|
2929
|
+
"mjExecuteCode",
|
|
2930
|
+
"mj_eval",
|
|
2931
|
+
"eval_code",
|
|
2932
|
+
"run_code",
|
|
2933
|
+
"exec_code",
|
|
2934
|
+
"code_execute"
|
|
2935
|
+
]);
|
|
2936
|
+
var ALIASED_LIST_PROJECTS_NAMES = /* @__PURE__ */ new Set([
|
|
2937
|
+
"listProjects",
|
|
2938
|
+
"list-projects",
|
|
2939
|
+
"get_projects",
|
|
2940
|
+
"getProjects",
|
|
2941
|
+
"get-projects",
|
|
2942
|
+
"mj_list_projects",
|
|
2943
|
+
"mjListProjects",
|
|
2944
|
+
"mj_get_projects",
|
|
2945
|
+
"mjGetProjects",
|
|
2946
|
+
"mj_admin_list_projects",
|
|
2947
|
+
"mj_admin_get_projects"
|
|
2948
|
+
]);
|
|
2949
|
+
var ALIASED_GET_PROJECT_NAMES = /* @__PURE__ */ new Set([
|
|
2950
|
+
"getProject",
|
|
2951
|
+
"get-project",
|
|
2952
|
+
"mj_get_project",
|
|
2953
|
+
"mjGetProject",
|
|
2954
|
+
"mj_admin_get_project"
|
|
2955
|
+
]);
|
|
2956
|
+
var ALIASED_GREP_SEARCH_NAMES = new Set(DUMMY_GREP_SEARCH_TOOL_NAMES);
|
|
2957
|
+
var ALIASED_VIEW_FILE_NAMES = new Set(
|
|
2958
|
+
DUMMY_FILE_VIEW_TOOL_NAMES.filter((name) => name !== "cat")
|
|
2959
|
+
);
|
|
2960
|
+
var ALIASED_LIST_DIR_NAMES = new Set(
|
|
2961
|
+
DUMMY_DIR_LIST_TOOL_NAMES.filter((name) => name !== "ls" && name !== "dir")
|
|
2962
|
+
);
|
|
2963
|
+
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2964
|
+
var ALL_KNOWN_GROUP_TOOLS = new Set(Object.values(TOOL_GROUPS).flat());
|
|
2965
|
+
var UPPERCASE_RE = /[A-Z]/;
|
|
2966
|
+
function deepCamelToSnake(obj, depth = 0) {
|
|
2967
|
+
if (depth > 12) return obj;
|
|
2968
|
+
if (Array.isArray(obj)) return obj.map((item) => deepCamelToSnake(item, depth + 1));
|
|
2969
|
+
if (obj !== null && typeof obj === "object") {
|
|
2970
|
+
const newObj = {};
|
|
2971
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
2972
|
+
if (FORBIDDEN_KEYS.has(k)) continue;
|
|
2973
|
+
const snakeKey = UPPERCASE_RE.test(k) ? k.replace(/^[A-Z]/, (letter) => letter.toLowerCase()).replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`) : k;
|
|
2974
|
+
if (FORBIDDEN_KEYS.has(snakeKey)) continue;
|
|
2975
|
+
newObj[snakeKey] = deepCamelToSnake(v, depth + 1);
|
|
2976
|
+
}
|
|
2977
|
+
return newObj;
|
|
2978
|
+
}
|
|
2979
|
+
return obj;
|
|
2980
|
+
}
|
|
2981
|
+
function formatSuccessPayload(payload) {
|
|
2982
|
+
const enriched = JSON.stringify(payload, null, 2);
|
|
2983
|
+
return {
|
|
2984
|
+
content: [{ type: "text", text: enriched }],
|
|
2985
|
+
structuredContent: payload
|
|
2986
|
+
};
|
|
2987
|
+
}
|
|
2988
|
+
function formatTokenEstimatedError(errorResult, isError) {
|
|
2989
|
+
const enriched = JSON.stringify({ ...errorResult, _meta: { tokenEstimate: 0 } });
|
|
2990
|
+
const tokenEstimate = Math.ceil(Buffer.byteLength(enriched, "utf8") / 4);
|
|
2991
|
+
const finalText = enriched.replace('"tokenEstimate":0', `"tokenEstimate":${tokenEstimate}`);
|
|
2992
|
+
return {
|
|
2993
|
+
content: [{ type: "text", text: finalText }],
|
|
2994
|
+
structuredContent: errorResult,
|
|
2995
|
+
...isError ? { isError: true } : {}
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
function parseZodErrorsFromMessage(rawText, prefixToRemove) {
|
|
2999
|
+
let errorMessage = prefixToRemove !== void 0 ? rawText.replace(prefixToRemove, "") : rawText;
|
|
3000
|
+
try {
|
|
3001
|
+
const parts = rawText.split(": [");
|
|
3002
|
+
if (parts.length > 1) {
|
|
3003
|
+
const zodErrors = JSON.parse("[" + parts[1]);
|
|
3004
|
+
errorMessage = zodErrors.map((e) => `${e.path && e.path.length > 0 ? e.path.join(".") : "unknown"}: ${e.message ?? "invalid"}`).join("; ");
|
|
3005
|
+
}
|
|
3006
|
+
} catch {
|
|
3007
|
+
}
|
|
3008
|
+
return errorMessage;
|
|
3009
|
+
}
|
|
3010
|
+
function isSuccessObject(res) {
|
|
3011
|
+
return typeof res === "object" && res !== null && res["success"] === true;
|
|
3012
|
+
}
|
|
3013
|
+
function matchesSuffixes(name, list, suffixes) {
|
|
3014
|
+
return list.includes(name) || suffixes.some((s) => name.endsWith(s));
|
|
3015
|
+
}
|
|
3016
|
+
async function tryAutonomousUnknownToolFallback(requestedTool, toolArgs, matchingPrompt, context, allTools, allToolNames, customToolHandlerConfig) {
|
|
3017
|
+
const { configManager, db, teamDb, vectorManager, teamVectorManager, github, runtime } = context;
|
|
3018
|
+
const currentConfig = configManager.getConfig();
|
|
3019
|
+
const toolContext = {
|
|
3020
|
+
db,
|
|
3021
|
+
...teamDb !== void 0 ? { teamDb } : {},
|
|
3022
|
+
vectorManager,
|
|
3023
|
+
...teamVectorManager !== void 0 ? { teamVectorManager } : {},
|
|
3024
|
+
github,
|
|
3025
|
+
config: {
|
|
3026
|
+
...customToolHandlerConfig,
|
|
3027
|
+
filterConfig: currentConfig.toolFilterConfig,
|
|
3028
|
+
briefingConfig: currentConfig.briefingConfig,
|
|
3029
|
+
runtime
|
|
3030
|
+
}
|
|
3031
|
+
};
|
|
3032
|
+
if (matchingPrompt !== void 0) {
|
|
3033
|
+
enforceAccessBoundary(matchingPrompt.name, "prompt", void 0, runtime.auditLogger);
|
|
3034
|
+
const res = await handlePrompt(toolArgs, requestedTool, toolContext);
|
|
3035
|
+
if (isSuccessObject(res)) return formatSuccessPayload(res);
|
|
3036
|
+
}
|
|
3037
|
+
if (matchesSuffixes(requestedTool, DUMMY_RESOURCE_TOOL_NAMES, ["_read_resource", "ReadResource"]) || requestedTool === "mjReadResource" || requestedTool.startsWith("memory://")) {
|
|
3038
|
+
enforceAccessBoundary("read_resource", "tool", void 0, runtime.auditLogger);
|
|
3039
|
+
const res = await handleReadResource(toolArgs, requestedTool, toolContext);
|
|
3040
|
+
if (isSuccessObject(res)) return formatSuccessPayload(res);
|
|
3041
|
+
}
|
|
3042
|
+
if (matchesSuffixes(requestedTool, DUMMY_LIST_RESOURCE_TOOL_NAMES, ["_list_resources", "ListResources"])) {
|
|
3043
|
+
enforceAccessBoundary("list_resources", "tool", void 0, runtime.auditLogger);
|
|
3044
|
+
return formatSuccessPayload(handleListResources(requestedTool));
|
|
3045
|
+
}
|
|
3046
|
+
if (matchesSuffixes(requestedTool, DUMMY_LIST_PROMPT_TOOL_NAMES, ["_list_prompts", "ListPrompts"])) {
|
|
3047
|
+
enforceAccessBoundary("list_prompts", "tool", void 0, runtime.auditLogger);
|
|
3048
|
+
return formatSuccessPayload(handleListPrompts(requestedTool));
|
|
3049
|
+
}
|
|
3050
|
+
if (matchesSuffixes(requestedTool, DUMMY_LIST_TOOL_NAMES, ["_list_tools", "ListTools"])) {
|
|
3051
|
+
enforceAccessBoundary("list_tools", "tool", void 0, runtime.auditLogger);
|
|
3052
|
+
const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
|
|
3053
|
+
const toolsList = allTools.filter((t) => enabledSet.has(t.name)).map((t) => ({ name: t.name, title: t.title, description: t.description, annotations: t.annotations }));
|
|
3054
|
+
return formatSuccessPayload({
|
|
3055
|
+
success: true,
|
|
3056
|
+
tools: toolsList,
|
|
3057
|
+
_healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool instead of an MCP protocol request (tools/list). The available tools were returned successfully.`
|
|
3058
|
+
});
|
|
3059
|
+
}
|
|
3060
|
+
if (matchesSuffixes(requestedTool, DUMMY_GET_PROMPT_TOOL_NAMES, ["_get_prompt", "GetPrompt"])) {
|
|
3061
|
+
enforceAccessBoundary("get_prompt", "tool", void 0, runtime.auditLogger);
|
|
3062
|
+
const res = await handleGetPrompt(toolArgs, requestedTool, toolContext);
|
|
3063
|
+
if (isSuccessObject(res)) return formatSuccessPayload(res);
|
|
3064
|
+
}
|
|
3065
|
+
if (DUMMY_SERVER_INFO_TOOL_NAMES.includes(requestedTool)) {
|
|
3066
|
+
enforceAccessBoundary("server_info", "tool", void 0, runtime.auditLogger);
|
|
3067
|
+
return formatSuccessPayload(await handleServerInfo(toolArgs, requestedTool, toolContext));
|
|
3068
|
+
}
|
|
3069
|
+
if (matchesSuffixes(requestedTool, DUMMY_PROJECT_TOOL_NAMES, ["list_projects", "listProjects", "ListProjects"]) || requestedTool === "projects") {
|
|
3070
|
+
enforceAccessBoundary("list_projects", "tool", void 0, runtime.auditLogger);
|
|
3071
|
+
const cfg = currentConfig;
|
|
3072
|
+
return formatSuccessPayload({
|
|
3073
|
+
success: true,
|
|
3074
|
+
projects: cfg.projectRegistry ?? {},
|
|
3075
|
+
_healing_note: `\u{1F6E0}\uFE0F AUTONOMOUS HEALING: '${requestedTool}' was called as an MCP tool. Returned registered projects from projectRegistry successfully.`
|
|
3076
|
+
});
|
|
3077
|
+
}
|
|
3078
|
+
if (matchesSuffixes(requestedTool, DUMMY_ADAPTER_TOOL_NAMES, ["list_adapters", "listAdapters", "ListAdapters"])) {
|
|
3079
|
+
enforceAccessBoundary("list_adapters", "tool", void 0, runtime.auditLogger);
|
|
3080
|
+
return formatSuccessPayload(handleListAdapters(requestedTool, toolContext));
|
|
3081
|
+
}
|
|
3082
|
+
if (matchesSuffixes(requestedTool, DUMMY_GREP_SEARCH_TOOL_NAMES, ["grep_search", "grepSearch"])) {
|
|
3083
|
+
enforceAccessBoundary("grep_search", "tool", void 0, runtime.auditLogger);
|
|
3084
|
+
return formatSuccessPayload(await handleGrepSearch(toolArgs, requestedTool, toolContext));
|
|
3085
|
+
}
|
|
3086
|
+
if (DUMMY_FILE_VIEW_TOOL_NAMES.includes(requestedTool)) {
|
|
3087
|
+
enforceAccessBoundary("view_file", "tool", void 0, runtime.auditLogger);
|
|
3088
|
+
return formatSuccessPayload(await handleViewFile(toolArgs, requestedTool, toolContext));
|
|
3089
|
+
}
|
|
3090
|
+
if (DUMMY_DIR_LIST_TOOL_NAMES.includes(requestedTool)) {
|
|
3091
|
+
enforceAccessBoundary("list_dir", "tool", void 0, runtime.auditLogger);
|
|
3092
|
+
return formatSuccessPayload(await handleListDir(toolArgs, requestedTool, toolContext));
|
|
3093
|
+
}
|
|
3094
|
+
return void 0;
|
|
3095
|
+
}
|
|
3096
|
+
function normalizeAndAliasToolCall(reqParams, options) {
|
|
3097
|
+
reqParams.arguments = deepCamelToSnake(reqParams.arguments);
|
|
3098
|
+
const toolArgs = reqParams.arguments;
|
|
3099
|
+
if (toolArgs["project_number"] === void 0) {
|
|
3100
|
+
const repoStr = typeof toolArgs["repo"] === "string" ? toolArgs["repo"] : typeof toolArgs["project"] === "string" ? toolArgs["project"] : void 0;
|
|
3101
|
+
if (repoStr !== void 0 && repoStr !== "") toolArgs["project_number"] = repoStr;
|
|
3102
|
+
}
|
|
3103
|
+
if (typeof toolArgs["project_number"] === "string") {
|
|
3104
|
+
const strVal = toolArgs["project_number"];
|
|
3105
|
+
const parsed = Number(strVal);
|
|
3106
|
+
if (!Number.isNaN(parsed)) {
|
|
3107
|
+
toolArgs["project_number"] = parsed;
|
|
3108
|
+
} else if (options.projectRegistry !== void 0) {
|
|
3109
|
+
let entry = options.projectRegistry[strVal];
|
|
3110
|
+
if (entry === void 0 && strVal.includes("/")) {
|
|
3111
|
+
const repoName = strVal.split("/").pop();
|
|
3112
|
+
if (repoName !== void 0 && repoName !== "") entry = options.projectRegistry[repoName];
|
|
3113
|
+
}
|
|
3114
|
+
if (entry?.project_number !== void 0) toolArgs["project_number"] = entry.project_number;
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
const currentName = reqParams.name;
|
|
3118
|
+
if (currentName !== void 0 && currentName !== "") {
|
|
3119
|
+
if (ALIASED_EXECUTE_CODE_NAMES.has(currentName)) {
|
|
3120
|
+
reqParams.name = "mj_execute_code";
|
|
3121
|
+
} else if (currentName === "create_entry_minimal") {
|
|
3122
|
+
reqParams.name = "create_entry";
|
|
3123
|
+
if (toolArgs["entry_type"] === void 0) toolArgs["entry_type"] = "personal_reflection";
|
|
3124
|
+
} else if (ALIASED_LIST_PROJECTS_NAMES.has(currentName)) {
|
|
3125
|
+
reqParams.name = "list_projects";
|
|
3126
|
+
} else if (ALIASED_GET_PROJECT_NAMES.has(currentName)) {
|
|
3127
|
+
reqParams.name = "get_project";
|
|
3128
|
+
} else if (ALIASED_GREP_SEARCH_NAMES.has(currentName)) {
|
|
3129
|
+
reqParams.name = "grep_search";
|
|
3130
|
+
} else if (ALIASED_VIEW_FILE_NAMES.has(currentName)) {
|
|
3131
|
+
reqParams.name = "view_file";
|
|
3132
|
+
} else if (ALIASED_LIST_DIR_NAMES.has(currentName)) {
|
|
3133
|
+
reqParams.name = "list_dir";
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
function attachCallToolInterceptor(requestHandlers, context, options, prompts, allTools, allToolNames, customToolHandlerConfig) {
|
|
3138
|
+
const originalHandler = requestHandlers?.get("tools/call");
|
|
3139
|
+
if (originalHandler === void 0 || requestHandlers === void 0) return;
|
|
3140
|
+
requestHandlers.set("tools/call", async (request2, extra) => {
|
|
3141
|
+
try {
|
|
3142
|
+
const req = request2;
|
|
3143
|
+
const healingEnabled = options.agentHealing !== false && customToolHandlerConfig.agentHealing !== false;
|
|
3144
|
+
if (req.params?.arguments !== void 0 && healingEnabled) {
|
|
3145
|
+
normalizeAndAliasToolCall(req.params, options);
|
|
3146
|
+
const toolArgs = req.params.arguments;
|
|
3147
|
+
if (req.params.name !== void 0 && req.params.name !== "") {
|
|
3148
|
+
const intercept = applyArgInterceptions(req.params.name, [toolArgs]);
|
|
3149
|
+
if ("error" in intercept) {
|
|
3150
|
+
const errorResult = intercept.error;
|
|
3151
|
+
logAgentIssue({
|
|
3152
|
+
source: "MCP",
|
|
3153
|
+
action: req.params.name,
|
|
3154
|
+
input: toolArgs,
|
|
3155
|
+
error: errorResult["error"] ?? "Validation Error"
|
|
3156
|
+
});
|
|
3157
|
+
return formatTokenEstimatedError(errorResult, false);
|
|
3158
|
+
}
|
|
3159
|
+
const normalizedArgs = intercept.args?.[0];
|
|
3160
|
+
if (normalizedArgs !== null && normalizedArgs !== void 0 && typeof normalizedArgs === "object" && !Array.isArray(normalizedArgs)) {
|
|
3161
|
+
req.params.arguments = normalizedArgs;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
if (req.params?.name !== void 0 && req.params.name !== "" && !allToolNames.has(req.params.name)) {
|
|
3166
|
+
const requestedTool = req.params.name;
|
|
3167
|
+
const toolArgs = req.params.arguments ?? {};
|
|
3168
|
+
const normalized = requestedTool.replace(/^mj_/, "").replace(/_/g, "-");
|
|
3169
|
+
const matchingPrompt = prompts.find(
|
|
3170
|
+
(p) => p.name === normalized || p.name === requestedTool || p.name === requestedTool.replace(/^mj_/, "")
|
|
3171
|
+
);
|
|
3172
|
+
if (healingEnabled) {
|
|
3173
|
+
const fallbackResponse = await tryAutonomousUnknownToolFallback(
|
|
3174
|
+
requestedTool,
|
|
3175
|
+
toolArgs,
|
|
3176
|
+
matchingPrompt,
|
|
3177
|
+
context,
|
|
3178
|
+
allTools,
|
|
3179
|
+
allToolNames,
|
|
3180
|
+
customToolHandlerConfig
|
|
3181
|
+
);
|
|
3182
|
+
if (fallbackResponse !== void 0) return fallbackResponse;
|
|
3183
|
+
}
|
|
3184
|
+
let suggestion = `Tool '${requestedTool}' does not exist. Use tools/list to see available tools.`;
|
|
3185
|
+
const isFilteredTool = ALL_KNOWN_GROUP_TOOLS.has(requestedTool);
|
|
3186
|
+
if (isFilteredTool) {
|
|
3187
|
+
suggestion = `'${requestedTool}' is a valid tool but it is not currently exposed because of your active --tool-filter or codemode restrictions. If you are in Code Mode, invoke it via 'mj_execute_code' (e.g. 'await mj.core.${requestedTool}(...)').`;
|
|
3188
|
+
} else if (matchingPrompt !== void 0) {
|
|
3189
|
+
suggestion = `'${requestedTool}' is an MCP Prompt, not an MCP Tool. Please use the 'get_prompt' tool (or your native MCP Prompts integration) to evaluate it, then use 'create_entry' to save the result.`;
|
|
3190
|
+
} else if (requestedTool.startsWith("mj_")) {
|
|
3191
|
+
suggestion = `'${requestedTool}' is not a valid root tool. If you are trying to use Code Mode, you must invoke the 'mj_execute_code' tool and write javascript (e.g. 'await mj.core.searchEntries(...)').`;
|
|
3192
|
+
}
|
|
3193
|
+
const errorResult = {
|
|
3194
|
+
success: false,
|
|
3195
|
+
error: `MCP error -32602: Tool ${requestedTool} not found`,
|
|
3196
|
+
code: "TOOL_NOT_FOUND",
|
|
3197
|
+
category: "hallucination",
|
|
3198
|
+
suggestion,
|
|
3199
|
+
recoverable: false
|
|
3200
|
+
};
|
|
3201
|
+
if (healingEnabled) {
|
|
3202
|
+
logAgentIssue({
|
|
3203
|
+
source: "MCP",
|
|
3204
|
+
action: requestedTool,
|
|
3205
|
+
input: toolArgs,
|
|
3206
|
+
error: errorResult.error
|
|
3207
|
+
});
|
|
3208
|
+
}
|
|
3209
|
+
return formatTokenEstimatedError(errorResult, true);
|
|
3210
|
+
}
|
|
3211
|
+
const result = await originalHandler(request2, extra);
|
|
3212
|
+
if (result !== null && result !== void 0 && typeof result === "object" && "isError" in result && result.isError === true) {
|
|
3213
|
+
const resObj = result;
|
|
3214
|
+
if (Array.isArray(resObj.content) && resObj.content.length > 0) {
|
|
3215
|
+
const text = resObj.content[0]?.text;
|
|
3216
|
+
if (typeof text === "string" && text.includes("MCP error -32602")) {
|
|
3217
|
+
const errorMessage = parseZodErrorsFromMessage(
|
|
3218
|
+
text,
|
|
3219
|
+
"MCP error -32602: Input validation error: "
|
|
3220
|
+
);
|
|
3221
|
+
const errorResult = {
|
|
3222
|
+
success: false,
|
|
3223
|
+
error: errorMessage,
|
|
3224
|
+
code: "VALIDATION_ERROR",
|
|
3225
|
+
category: "validation",
|
|
3226
|
+
suggestion: "Check input parameters against the tool schema",
|
|
3227
|
+
recoverable: false
|
|
3228
|
+
};
|
|
3229
|
+
logAgentIssue({
|
|
3230
|
+
source: "MCP",
|
|
3231
|
+
action: req.params?.name ?? "unknown",
|
|
3232
|
+
input: req.params?.arguments ?? {},
|
|
3233
|
+
error: errorMessage
|
|
3234
|
+
});
|
|
3235
|
+
return formatTokenEstimatedError(errorResult, false);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
return result;
|
|
3240
|
+
} catch (error) {
|
|
3241
|
+
const err = error;
|
|
3242
|
+
if (err.code === -32602) {
|
|
3243
|
+
let errorMessage = err.message ?? "Validation Error";
|
|
3244
|
+
if (typeof errorMessage === "string" && errorMessage.includes("Invalid arguments for tool")) {
|
|
3245
|
+
errorMessage = parseZodErrorsFromMessage(errorMessage);
|
|
3246
|
+
}
|
|
3247
|
+
const errorResult = {
|
|
3248
|
+
success: false,
|
|
3249
|
+
error: errorMessage,
|
|
3250
|
+
code: "VALIDATION_ERROR",
|
|
3251
|
+
category: "validation",
|
|
3252
|
+
suggestion: "Check input parameters against the tool schema",
|
|
3253
|
+
recoverable: false
|
|
3254
|
+
};
|
|
3255
|
+
const fallbackReq = request2;
|
|
3256
|
+
logAgentIssue({
|
|
3257
|
+
source: "MCP",
|
|
3258
|
+
action: fallbackReq.params?.name ?? "unknown",
|
|
3259
|
+
input: fallbackReq.params?.arguments ?? {},
|
|
3260
|
+
error: errorMessage
|
|
3261
|
+
});
|
|
3262
|
+
return formatTokenEstimatedError(errorResult, true);
|
|
3263
|
+
}
|
|
3264
|
+
throw error;
|
|
3265
|
+
}
|
|
3266
|
+
});
|
|
3267
|
+
}
|
|
3268
|
+
|
|
3269
|
+
// src/server/mcp-server/tool-registration/register-tools.ts
|
|
3270
|
+
var DEFAULT_MAX_TOOL_INPUT_ELEMENTS = 25e3;
|
|
3271
|
+
function resolveEffectiveMaxToolInputElements(configured) {
|
|
3272
|
+
if (configured === void 0) return DEFAULT_MAX_TOOL_INPUT_ELEMENTS;
|
|
3273
|
+
return configured === 0 || configured === Infinity ? Infinity : configured;
|
|
3274
|
+
}
|
|
3275
|
+
var MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
3276
|
+
"create_entry",
|
|
3277
|
+
"update_entry",
|
|
3278
|
+
"delete_entry",
|
|
3279
|
+
"restore_entry",
|
|
3280
|
+
"batch_create_entries",
|
|
3281
|
+
"batch_update_entries",
|
|
3282
|
+
"batch_delete_entries",
|
|
3283
|
+
"team_add_member",
|
|
3284
|
+
"team_update_member_role",
|
|
3285
|
+
"team_remove_member"
|
|
3286
|
+
]);
|
|
3287
|
+
var toolRegistrationOptionsCache = /* @__PURE__ */ new WeakMap();
|
|
3288
|
+
function buildToolRegistrationOptions(tool) {
|
|
3289
|
+
const cached = toolRegistrationOptionsCache.get(tool);
|
|
3290
|
+
if (cached !== void 0) return cached;
|
|
3291
|
+
const toolOptions = { description: tool.description };
|
|
3292
|
+
if (tool.title !== void 0 && tool.title !== "") toolOptions.title = tool.title;
|
|
3293
|
+
if (tool.inputSchema !== void 0) {
|
|
3294
|
+
const schema = tool.inputSchema;
|
|
3295
|
+
const fallbackInputSchema = schema;
|
|
3296
|
+
if (typeof schema === "object" && schema !== null && "partial" in schema && typeof schema.partial === "function") {
|
|
3297
|
+
try {
|
|
3298
|
+
const relaxed = schema.partial();
|
|
3299
|
+
toolOptions.inputSchema = typeof relaxed.passthrough === "function" ? relaxed.passthrough() : fallbackInputSchema;
|
|
3300
|
+
} catch {
|
|
3301
|
+
toolOptions.inputSchema = fallbackInputSchema;
|
|
3302
|
+
}
|
|
3303
|
+
} else {
|
|
3304
|
+
toolOptions.inputSchema = fallbackInputSchema;
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
if (tool.outputSchema !== void 0) {
|
|
3308
|
+
const outSchema = tool.outputSchema;
|
|
3309
|
+
const fallbackOutputSchema = outSchema;
|
|
3310
|
+
if (typeof outSchema === "object" && outSchema !== null && "passthrough" in outSchema && typeof outSchema.passthrough === "function") {
|
|
3311
|
+
try {
|
|
3312
|
+
toolOptions.outputSchema = outSchema.passthrough();
|
|
3313
|
+
} catch {
|
|
3314
|
+
toolOptions.outputSchema = fallbackOutputSchema;
|
|
3315
|
+
}
|
|
3316
|
+
} else {
|
|
3317
|
+
toolOptions.outputSchema = fallbackOutputSchema;
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
if (tool.annotations !== void 0) toolOptions.annotations = tool.annotations;
|
|
3321
|
+
if (tool.icons !== void 0) toolOptions.icons = [{ src: tool.icons.iconUrl }];
|
|
3322
|
+
toolRegistrationOptionsCache.set(tool, toolOptions);
|
|
3323
|
+
return toolOptions;
|
|
3324
|
+
}
|
|
3325
|
+
function createServerInstance(context, options, prompts, resources, allTools, allToolNames, customToolHandlerConfig) {
|
|
3326
|
+
const {
|
|
3327
|
+
configManager,
|
|
3328
|
+
db,
|
|
3329
|
+
teamDb,
|
|
3330
|
+
vectorManager,
|
|
3331
|
+
teamVectorManager,
|
|
3332
|
+
github,
|
|
3333
|
+
scheduler,
|
|
3334
|
+
allowedIoRoots,
|
|
3335
|
+
runtime
|
|
3336
|
+
} = context;
|
|
3337
|
+
const { defaultProjectNumber } = options;
|
|
3338
|
+
const getInstructions = () => {
|
|
3339
|
+
const currentConfig = configManager.getConfig();
|
|
3340
|
+
const enabledSet = currentConfig.toolFilterConfig?.enabledTools ?? allToolNames;
|
|
3341
|
+
const groups = currentConfig.toolFilterConfig ? getEnabledGroups(currentConfig.toolFilterConfig.enabledTools) : void 0;
|
|
3342
|
+
const isCodeModeOnly = enabledSet.size === 1 && enabledSet.has("mj_execute_code");
|
|
3343
|
+
const mappedPrompts = prompts.map((p) => {
|
|
3344
|
+
const prompt = p;
|
|
3345
|
+
return {
|
|
3346
|
+
name: prompt.name,
|
|
3347
|
+
...prompt.description !== void 0 ? { description: prompt.description } : {}
|
|
3348
|
+
};
|
|
3349
|
+
});
|
|
3350
|
+
if (isCodeModeOnly || currentConfig.toolFilterConfig?.raw === "codemode") {
|
|
3351
|
+
const finalGroups = currentConfig.codemodeInternalFullAccess === true ? new Set(Object.keys(TOOL_GROUPS)) : groups;
|
|
3352
|
+
const finalEnabledTools = currentConfig.codemodeInternalFullAccess === true ? allToolNames : enabledSet;
|
|
3353
|
+
return generateCodeModeInstructions(
|
|
3354
|
+
finalEnabledTools,
|
|
3355
|
+
mappedPrompts,
|
|
3356
|
+
void 0,
|
|
3357
|
+
finalGroups,
|
|
3358
|
+
currentConfig.briefingConfig
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
return generateStandardInstructions(
|
|
3362
|
+
enabledSet,
|
|
3363
|
+
mappedPrompts,
|
|
3364
|
+
void 0,
|
|
3365
|
+
groups,
|
|
3366
|
+
currentConfig.briefingConfig
|
|
3367
|
+
);
|
|
3368
|
+
};
|
|
3369
|
+
const server = new McpServer(
|
|
3370
|
+
{ name: "memory-journal-mcp", version: VERSION },
|
|
3371
|
+
{
|
|
3372
|
+
capabilities: {
|
|
3373
|
+
logging: {},
|
|
3374
|
+
prompts: { listChanged: true },
|
|
3375
|
+
tools: { listChanged: true },
|
|
3376
|
+
resources: { subscribe: true, listChanged: true },
|
|
3377
|
+
experimental: { progress: {} }
|
|
3378
|
+
},
|
|
3379
|
+
instructions: getInstructions(),
|
|
3380
|
+
maxToolInputElements: resolveEffectiveMaxToolInputElements(options.maxToolInputElements)
|
|
3381
|
+
}
|
|
3382
|
+
);
|
|
3383
|
+
if (context.skillCatalog !== void 0 && typeof server.isConnected === "function") {
|
|
3384
|
+
context.skillCatalog.attach(server);
|
|
3385
|
+
}
|
|
3386
|
+
for (const tool of allTools) {
|
|
3387
|
+
const toolOptions = buildToolRegistrationOptions(tool);
|
|
3388
|
+
const hasOutputSchema = Boolean(tool.outputSchema);
|
|
3389
|
+
server.registerTool(
|
|
3390
|
+
tool.name,
|
|
3391
|
+
toolOptions,
|
|
3392
|
+
async (args, extra) => {
|
|
3393
|
+
try {
|
|
3394
|
+
const extraMeta = extra;
|
|
3395
|
+
const progressToken = extraMeta?.mcpReq?._meta?.progressToken;
|
|
3396
|
+
const progressContext = progressToken !== void 0 ? { server: server.server, progressToken } : void 0;
|
|
3397
|
+
const currentConfig = configManager.getConfig();
|
|
3398
|
+
customToolHandlerConfig.filterConfig = currentConfig.toolFilterConfig;
|
|
3399
|
+
customToolHandlerConfig.briefingConfig = currentConfig.briefingConfig;
|
|
3400
|
+
const toolArgs = typeof args === "object" && args !== null ? args : {};
|
|
3401
|
+
const result = await callTool(
|
|
3402
|
+
tool.name,
|
|
3403
|
+
toolArgs,
|
|
3404
|
+
db,
|
|
3405
|
+
vectorManager,
|
|
3406
|
+
github,
|
|
3407
|
+
customToolHandlerConfig,
|
|
3408
|
+
progressContext,
|
|
3409
|
+
teamDb ?? void 0,
|
|
3410
|
+
teamVectorManager ?? void 0
|
|
3411
|
+
);
|
|
3412
|
+
const isSuccess = typeof result === "object" && result !== null && result["success"] === true;
|
|
3413
|
+
if (isSuccess) {
|
|
3414
|
+
const isMutation = MUTATING_TOOLS.has(tool.name) || tool.name.startsWith("team_") && tool.annotations.readOnlyHint !== true;
|
|
3415
|
+
if (isMutation) {
|
|
3416
|
+
void globalSubscriptionManager.notifyResourceUpdated("memory://briefing");
|
|
3417
|
+
void globalSubscriptionManager.notifyResourceUpdated("memory://recent");
|
|
3418
|
+
void globalSubscriptionManager.notifyResourceUpdated(
|
|
3419
|
+
"memory://statistics"
|
|
3420
|
+
);
|
|
3421
|
+
if (tool.name.startsWith("team_")) {
|
|
3422
|
+
void globalSubscriptionManager.notifyResourceUpdated(
|
|
3423
|
+
"memory://team/recent"
|
|
3424
|
+
);
|
|
3425
|
+
void globalSubscriptionManager.notifyResourceUpdated(
|
|
3426
|
+
"memory://team/statistics"
|
|
3427
|
+
);
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
const textContent = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
3432
|
+
if (hasOutputSchema) {
|
|
3433
|
+
return {
|
|
3434
|
+
content: [{ type: "text", text: textContent }],
|
|
3435
|
+
structuredContent: result
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
return { content: [{ type: "text", text: textContent }] };
|
|
3439
|
+
} catch (error) {
|
|
3440
|
+
let errorResult;
|
|
3441
|
+
if (error instanceof Error && "toResponse" in error && typeof error.toResponse === "function") {
|
|
3442
|
+
errorResult = error.toResponse();
|
|
3443
|
+
} else {
|
|
3444
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3445
|
+
errorResult = {
|
|
3446
|
+
success: false,
|
|
3447
|
+
error: errorMessage,
|
|
3448
|
+
code: "INTERNAL_ERROR",
|
|
3449
|
+
category: "internal",
|
|
3450
|
+
recoverable: false
|
|
3451
|
+
};
|
|
3452
|
+
}
|
|
3453
|
+
logAgentIssue({
|
|
3454
|
+
source: "MCP",
|
|
3455
|
+
action: tool.name,
|
|
3456
|
+
input: args,
|
|
3457
|
+
error: errorResult["error"] ?? "Unknown error"
|
|
3458
|
+
});
|
|
3459
|
+
return {
|
|
3460
|
+
content: [
|
|
3461
|
+
{
|
|
3462
|
+
type: "text",
|
|
3463
|
+
text: JSON.stringify(errorResult, null, 2)
|
|
3464
|
+
}
|
|
3465
|
+
],
|
|
3466
|
+
...hasOutputSchema ? { structuredContent: errorResult } : {},
|
|
3467
|
+
isError: true
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
);
|
|
3472
|
+
}
|
|
3473
|
+
const handleResourceRead = async (uri, mimeType) => {
|
|
3474
|
+
const currentConfig = configManager.getConfig();
|
|
3475
|
+
const resolvedDefaultProj = currentConfig.briefingConfig.defaultProjectNumber ?? defaultProjectNumber;
|
|
3476
|
+
const activeBriefingConfig = {
|
|
3477
|
+
...currentConfig.briefingConfig,
|
|
3478
|
+
...resolvedDefaultProj !== void 0 ? { defaultProjectNumber: resolvedDefaultProj } : {},
|
|
3479
|
+
...options.projectRegistry !== void 0 ? { projectRegistry: options.projectRegistry } : {},
|
|
3480
|
+
allowedIoRoots
|
|
3481
|
+
};
|
|
3482
|
+
try {
|
|
3483
|
+
const result = await readResource(
|
|
3484
|
+
uri.href,
|
|
3485
|
+
db,
|
|
3486
|
+
vectorManager,
|
|
3487
|
+
currentConfig.toolFilterConfig,
|
|
3488
|
+
github,
|
|
3489
|
+
scheduler,
|
|
3490
|
+
teamDb ?? void 0,
|
|
3491
|
+
activeBriefingConfig,
|
|
3492
|
+
runtime
|
|
3493
|
+
);
|
|
3494
|
+
runtime.metrics.recordResourceRead(uri.href, false);
|
|
3495
|
+
const dataStr = typeof result.data === "string" ? result.data : JSON.stringify(result.data, null, 2);
|
|
3496
|
+
return {
|
|
3497
|
+
contents: [
|
|
3498
|
+
{
|
|
3499
|
+
uri: uri.href,
|
|
3500
|
+
mimeType,
|
|
3501
|
+
text: dataStr,
|
|
3502
|
+
...result.annotations !== void 0 ? { annotations: result.annotations } : {}
|
|
3503
|
+
}
|
|
3504
|
+
]
|
|
3505
|
+
};
|
|
3506
|
+
} catch (error) {
|
|
3507
|
+
runtime.metrics.recordResourceRead(uri.href, true);
|
|
3508
|
+
throw error;
|
|
3509
|
+
}
|
|
3510
|
+
};
|
|
3511
|
+
registerResources(server, resources, handleResourceRead, runtime);
|
|
3512
|
+
server.server.setRequestHandler("resources/subscribe", (request2, extra) => {
|
|
3513
|
+
const sessionId = extra?.sessionId;
|
|
3514
|
+
const transportSessionId = sessionId !== void 0 && sessionId !== "" ? sessionId : "stdio";
|
|
3515
|
+
validateResourceSubscription(request2.params.uri, runtime);
|
|
3516
|
+
globalSubscriptionManager.registerServer(transportSessionId, server);
|
|
3517
|
+
globalSubscriptionManager.subscribe(request2.params.uri, transportSessionId);
|
|
3518
|
+
return {};
|
|
3519
|
+
});
|
|
3520
|
+
server.server.setRequestHandler("resources/unsubscribe", (request2, extra) => {
|
|
3521
|
+
const sessionId = extra?.sessionId;
|
|
3522
|
+
const transportSessionId = sessionId !== void 0 && sessionId !== "" ? sessionId : "stdio";
|
|
3523
|
+
globalSubscriptionManager.unsubscribe(request2.params.uri, transportSessionId);
|
|
3524
|
+
return {};
|
|
3525
|
+
});
|
|
3526
|
+
const briefingConfig = configManager.getConfig().briefingConfig;
|
|
3527
|
+
registerPrompts(
|
|
3528
|
+
server,
|
|
3529
|
+
prompts,
|
|
3530
|
+
db,
|
|
3531
|
+
teamDb ?? void 0,
|
|
3532
|
+
runtime,
|
|
3533
|
+
context.github,
|
|
3534
|
+
briefingConfig
|
|
3535
|
+
);
|
|
3536
|
+
const serverObj = server.server;
|
|
3537
|
+
const requestHandlers = serverObj._requestHandlers;
|
|
3538
|
+
attachListToolsInterceptor(requestHandlers, configManager, allToolNames);
|
|
3539
|
+
attachCallToolInterceptor(
|
|
3540
|
+
requestHandlers,
|
|
3541
|
+
context,
|
|
3542
|
+
options,
|
|
3543
|
+
prompts,
|
|
3544
|
+
allTools,
|
|
3545
|
+
allToolNames,
|
|
3546
|
+
customToolHandlerConfig
|
|
3547
|
+
);
|
|
3548
|
+
return server;
|
|
3549
|
+
}
|
|
3550
|
+
function startMetricsServer(runtime, metricsPort) {
|
|
3551
|
+
const portStr = process.env["MJ_METRICS_PORT"];
|
|
3552
|
+
const port = metricsPort ?? (portStr !== void 0 && portStr !== "" ? parseInt(portStr, 10) : 9465);
|
|
3553
|
+
const server = http.createServer((req, res) => {
|
|
3554
|
+
if (req.url === "/metrics" && req.method === "GET") {
|
|
3555
|
+
try {
|
|
3556
|
+
const metrics = formatPrometheusMetrics(runtime.metrics);
|
|
3557
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
3558
|
+
res.end(metrics);
|
|
3559
|
+
} catch (error) {
|
|
3560
|
+
logger.error("Failed to generate metrics", { error: error instanceof Error ? error.message : String(error) });
|
|
3561
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
3562
|
+
res.end("Internal Server Error");
|
|
3563
|
+
}
|
|
3564
|
+
} else if (req.url === "/health" && req.method === "GET") {
|
|
3565
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
3566
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
3567
|
+
} else {
|
|
3568
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
3569
|
+
res.end("Not Found");
|
|
3570
|
+
}
|
|
3571
|
+
});
|
|
3572
|
+
server.on("error", (error) => {
|
|
3573
|
+
const err = error;
|
|
3574
|
+
if (typeof err === "object" && err !== null && err.code === "EADDRINUSE") {
|
|
3575
|
+
logger.warning(`Metrics server port ${port} is already in use; standalone metrics server disabled for this instance`, { module: "MetricsServer" });
|
|
3576
|
+
} else {
|
|
3577
|
+
logger.error("Metrics server error", { error: error instanceof Error ? error.message : String(error), module: "MetricsServer" });
|
|
3578
|
+
}
|
|
3579
|
+
});
|
|
3580
|
+
const rawHost = process.env["MJ_METRICS_HOST"]?.trim();
|
|
3581
|
+
const host = rawHost !== void 0 && rawHost !== "" ? rawHost : "127.0.0.1";
|
|
3582
|
+
server.listen(port, host, () => {
|
|
3583
|
+
logger.info(`Standalone metrics server listening on ${host}:${port}`, { module: "MetricsServer" });
|
|
3584
|
+
});
|
|
3585
|
+
return () => {
|
|
3586
|
+
return new Promise((resolve, reject) => {
|
|
3587
|
+
server.close((err) => {
|
|
3588
|
+
if (err) {
|
|
3589
|
+
logger.error("Failed to close metrics server", { error: err.message, module: "MetricsServer" });
|
|
3590
|
+
reject(err);
|
|
3591
|
+
} else {
|
|
3592
|
+
logger.info("Metrics server closed", { module: "MetricsServer" });
|
|
3593
|
+
resolve();
|
|
3594
|
+
}
|
|
3595
|
+
});
|
|
3596
|
+
});
|
|
3597
|
+
};
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3600
|
+
// src/server/mcp-server/core.ts
|
|
3601
|
+
async function createServer2(options) {
|
|
3602
|
+
const context = await initializeDependencies(options);
|
|
3603
|
+
const { db, testDb, teamDb, testTeamDb, runtime, vectorManager, teamVectorManager, github, configManager, scheduler, allowedIoRoots, activeMetricsPath } = context;
|
|
3604
|
+
const { transport, defaultProjectNumber } = options;
|
|
3605
|
+
const filterConfig = configManager.getConfig().toolFilterConfig;
|
|
3606
|
+
const baseConfig = {
|
|
3607
|
+
defaultProjectNumber,
|
|
3608
|
+
defaultWorkspaceId: options.defaultWorkspaceId,
|
|
3609
|
+
projectRegistry: options.projectRegistry,
|
|
3610
|
+
additionalTeamDbs: options.additionalTeamDbs,
|
|
3611
|
+
allowedIoRoots,
|
|
3612
|
+
filterConfig,
|
|
3613
|
+
authEnabled: Boolean(options.authToken ?? process.env["MCP_AUTH_TOKEN"]),
|
|
3614
|
+
oauthEnabled: options.oauthEnabled,
|
|
3615
|
+
codemodeEnabled: true,
|
|
3616
|
+
codemodeInternalFullAccess: options.codemodeInternalFullAccess,
|
|
3617
|
+
agentHealing: options.agentHealing,
|
|
3618
|
+
teamDefaultRole: options.teamDefaultRole,
|
|
3619
|
+
teamAdmin: options.teamAdmin,
|
|
3620
|
+
runtime,
|
|
3621
|
+
subscriptionManager: globalSubscriptionManager,
|
|
3622
|
+
archiveOlderThanDays: options.archiveOlderThanDays,
|
|
3623
|
+
pruneOlderThanDays: options.pruneOlderThanDays,
|
|
3624
|
+
hardDeleteOlderThanDays: options.hardDeleteOlderThanDays,
|
|
3625
|
+
pruneImportanceThreshold: options.pruneImportanceThreshold
|
|
3626
|
+
};
|
|
3627
|
+
const dispatch = (name, args) => callTool(
|
|
3628
|
+
name,
|
|
3629
|
+
args,
|
|
3630
|
+
db,
|
|
3631
|
+
vectorManager,
|
|
3632
|
+
github,
|
|
3633
|
+
baseConfig,
|
|
3634
|
+
void 0,
|
|
3635
|
+
teamDb ?? void 0,
|
|
3636
|
+
teamVectorManager ?? void 0
|
|
3637
|
+
);
|
|
3638
|
+
const customToolHandlerConfig = { ...baseConfig, dispatch };
|
|
3639
|
+
const allTools = getTools(
|
|
3640
|
+
db,
|
|
3641
|
+
filterConfig,
|
|
3642
|
+
vectorManager,
|
|
3643
|
+
github,
|
|
3644
|
+
customToolHandlerConfig,
|
|
3645
|
+
teamDb ?? void 0,
|
|
3646
|
+
teamVectorManager ?? void 0
|
|
3647
|
+
);
|
|
3648
|
+
const allToolNames = new Set(allTools.map((t) => t.name));
|
|
3649
|
+
for (const toolName of allToolNames) {
|
|
3650
|
+
getRequiredScope(toolName);
|
|
3651
|
+
}
|
|
3652
|
+
const resources = getResources();
|
|
3653
|
+
const prompts = getPrompts();
|
|
3654
|
+
configManager.on("changed", (newConfig) => {
|
|
3655
|
+
baseConfig.filterConfig = newConfig.toolFilterConfig;
|
|
3656
|
+
baseConfig.briefingConfig = newConfig.briefingConfig;
|
|
3657
|
+
customToolHandlerConfig.filterConfig = newConfig.toolFilterConfig;
|
|
3658
|
+
customToolHandlerConfig.briefingConfig = newConfig.briefingConfig;
|
|
3659
|
+
void globalSubscriptionManager.notifyResourceUpdated("memory://briefing");
|
|
3660
|
+
try {
|
|
3661
|
+
void globalSubscriptionManager.broadcastNotification("notifications/tools/list_changed");
|
|
3662
|
+
void globalSubscriptionManager.broadcastNotification("notifications/resources/list_changed");
|
|
3663
|
+
} catch (error) {
|
|
3664
|
+
logger.debug("Failed to send list_changed notifications to MCP client", {
|
|
3665
|
+
module: "McpServer",
|
|
3666
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3669
|
+
});
|
|
3670
|
+
const getServerInstance = () => createServerInstance(
|
|
3671
|
+
context,
|
|
3672
|
+
options,
|
|
3673
|
+
prompts,
|
|
3674
|
+
resources,
|
|
3675
|
+
allTools,
|
|
3676
|
+
allToolNames,
|
|
3677
|
+
customToolHandlerConfig
|
|
3678
|
+
);
|
|
3679
|
+
let shutdownMetrics;
|
|
3680
|
+
if (options.metricsExport === "prometheus") {
|
|
3681
|
+
shutdownMetrics = startMetricsServer(runtime, options.metricsPort);
|
|
3682
|
+
}
|
|
3683
|
+
if (transport === "stdio") {
|
|
3684
|
+
const stdioTransport = new StdioServerTransport();
|
|
3685
|
+
const server = getServerInstance();
|
|
3686
|
+
await server.connect(stdioTransport);
|
|
3687
|
+
logger.info("MCP server started on stdio", { module: "McpServer" });
|
|
3688
|
+
const handleStdioShutdown = () => {
|
|
3689
|
+
logger.info("Shutting down...", { module: "McpServer" });
|
|
3690
|
+
if (runtime.auditLogger) {
|
|
3691
|
+
void runtime.auditLogger.close();
|
|
3692
|
+
}
|
|
3693
|
+
if (shutdownMetrics) {
|
|
3694
|
+
void shutdownMetrics().catch((err) => {
|
|
3695
|
+
logger.debug("Error shutting down metrics server", { module: "McpServer", error: String(err) });
|
|
3696
|
+
});
|
|
3697
|
+
}
|
|
3698
|
+
if (activeMetricsPath) {
|
|
3699
|
+
void runtime.metrics.saveToFile(activeMetricsPath).then(() => {
|
|
3700
|
+
db.close();
|
|
3701
|
+
testDb?.close();
|
|
3702
|
+
teamDb?.close();
|
|
3703
|
+
testTeamDb?.close();
|
|
3704
|
+
process.exit(0);
|
|
3705
|
+
});
|
|
3706
|
+
} else {
|
|
3707
|
+
db.close();
|
|
3708
|
+
testDb?.close();
|
|
3709
|
+
teamDb?.close();
|
|
3710
|
+
testTeamDb?.close();
|
|
3711
|
+
process.exit(0);
|
|
3712
|
+
}
|
|
3713
|
+
};
|
|
3714
|
+
process.on("SIGINT", handleStdioShutdown);
|
|
3715
|
+
process.on("SIGTERM", handleStdioShutdown);
|
|
3716
|
+
} else {
|
|
3717
|
+
const port = options.port ?? 3e3;
|
|
3718
|
+
const host = options.host ?? "localhost";
|
|
3719
|
+
const corsRaw = process.env["MCP_CORS_ORIGIN"];
|
|
3720
|
+
const corsOrigins = options.corsOrigins ?? (corsRaw ? corsRaw.split(",").map((s) => s.trim()) : []);
|
|
3721
|
+
const authToken = options.authToken ?? process.env["MCP_AUTH_TOKEN"] ?? void 0;
|
|
3722
|
+
const httpTransport = new HttpTransport({
|
|
3723
|
+
port,
|
|
3724
|
+
host,
|
|
3725
|
+
corsOrigins,
|
|
3726
|
+
stateless: options.statelessHttp === true,
|
|
3727
|
+
authToken,
|
|
3728
|
+
enableHSTS: options.enableHSTS,
|
|
3729
|
+
oauthEnabled: options.oauthEnabled,
|
|
3730
|
+
oauthIssuer: options.oauthIssuer,
|
|
3731
|
+
oauthAudience: options.oauthAudience,
|
|
3732
|
+
oauthJwksUri: options.oauthJwksUri,
|
|
3733
|
+
oauthClockTolerance: options.oauthClockTolerance,
|
|
3734
|
+
allowPlaintextLoopbackOAuth: options.allowPlaintextLoopbackOAuth,
|
|
3735
|
+
trustProxy: options.trustProxy,
|
|
3736
|
+
publicOrigin: options.publicOrigin,
|
|
3737
|
+
metricsExport: options.metricsExport
|
|
3738
|
+
});
|
|
3739
|
+
await httpTransport.start(getServerInstance, scheduler, runtime);
|
|
3740
|
+
const handleHttpShutdown = () => {
|
|
3741
|
+
void (async () => {
|
|
3742
|
+
if (shutdownMetrics) {
|
|
3743
|
+
await shutdownMetrics().catch((err) => {
|
|
3744
|
+
logger.debug("Error shutting down metrics server", { module: "McpServer", error: String(err) });
|
|
3745
|
+
});
|
|
3746
|
+
}
|
|
3747
|
+
await httpTransport.stop(scheduler);
|
|
3748
|
+
if (runtime.auditLogger) {
|
|
3749
|
+
await runtime.auditLogger.close();
|
|
3750
|
+
}
|
|
3751
|
+
if (activeMetricsPath) {
|
|
3752
|
+
await runtime.metrics.saveToFile(activeMetricsPath);
|
|
3753
|
+
}
|
|
3754
|
+
db.close();
|
|
3755
|
+
testDb?.close();
|
|
3756
|
+
teamDb?.close();
|
|
3757
|
+
testTeamDb?.close();
|
|
3758
|
+
process.exit(0);
|
|
3759
|
+
})();
|
|
3760
|
+
};
|
|
3761
|
+
process.on("SIGINT", handleHttpShutdown);
|
|
3762
|
+
process.on("SIGTERM", handleHttpShutdown);
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
|
|
3766
|
+
export { VectorSearchManager, createServer2 as createServer, initializeDependencies };
|