memory-journal-mcp 6.1.2 → 6.2.1
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 +44 -28
- package/dist/{chunk-X4SWFATC.js → chunk-BI4ZNSKA.js} +38 -24
- package/dist/{chunk-HCEWINSB.js → chunk-N6EBIDN7.js} +99 -102
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/tools-WPRY5MJ6.js +2 -0
- package/package.json +10 -1
- package/skills/github-commander/SKILL.md +151 -0
- package/skills/github-commander/config/project-config.example.md +125 -0
- package/skills/github-commander/workflows/code-quality-audit.md +80 -0
- package/skills/github-commander/workflows/full-audit.md +134 -0
- package/skills/github-commander/workflows/issue-triage.md +239 -0
- package/skills/github-commander/workflows/milestone-sprint.md +81 -0
- package/skills/github-commander/workflows/perf-audit.md +142 -0
- package/skills/github-commander/workflows/pr-review.md +123 -0
- package/skills/github-commander/workflows/security-audit.md +170 -0
- package/skills/github-commander/workflows/update-deps.md +109 -0
- package/.dockerignore +0 -139
- package/.gitattributes +0 -20
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -95
- package/.github/ISSUE_TEMPLATE/config.yml +0 -11
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -110
- package/.github/ISSUE_TEMPLATE/question.md +0 -78
- package/.github/aw/actions-lock.json +0 -14
- package/.github/copilot-instructions.md +0 -122
- package/.github/dependabot.yml +0 -93
- package/.github/pull_request_template.md +0 -135
- package/.github/workflows/README.md +0 -133
- package/.github/workflows/agentics-maintenance.yml +0 -141
- package/.github/workflows/auto-release.yml +0 -68
- package/.github/workflows/ci-health-monitor.lock.yml +0 -1121
- package/.github/workflows/ci-health-monitor.md +0 -87
- package/.github/workflows/codeql.yml +0 -41
- package/.github/workflows/dependabot-auto-merge.yml +0 -42
- package/.github/workflows/dependency-maintenance.lock.yml +0 -1182
- package/.github/workflows/dependency-maintenance.md +0 -147
- package/.github/workflows/docker-publish.yml +0 -254
- package/.github/workflows/docs-drift-detector.lock.yml +0 -1142
- package/.github/workflows/docs-drift-detector.md +0 -115
- package/.github/workflows/lint-and-test.yml +0 -60
- package/.github/workflows/publish-npm.yml +0 -85
- package/.github/workflows/secrets-scanning.yml +0 -32
- package/.github/workflows/security-update.yml +0 -127
- package/.gitleaks.toml +0 -9
- package/.prettierignore +0 -21
- package/.prettierrc +0 -33
- package/.scout-ignore +0 -12
- package/.trivyignore +0 -21
- package/CHANGELOG.md +0 -1814
- package/CODE_OF_CONDUCT.md +0 -133
- package/CONTRIBUTING.md +0 -263
- package/DOCKER_README.md +0 -331
- package/Dockerfile +0 -128
- package/SECURITY.md +0 -227
- package/UNRELEASED.md +0 -1
- package/dist/tools-T4U5A3X4.js +0 -2
- package/docker-compose.yml +0 -71
- package/docs/README.md +0 -18
- package/docs/agentic-journal-synergy.md +0 -175
- package/docs/copilot-setup.md +0 -72
- package/eslint.config.js +0 -110
- package/mcp-config-example.json +0 -21
- package/playwright.config.ts +0 -35
- package/releases/v2.1.0.md +0 -220
- package/releases/v2.2.0.md +0 -168
- package/releases/v3.0.0.md +0 -237
- package/releases/v3.1.0.md +0 -104
- package/releases/v3.1.1.md +0 -42
- package/releases/v3.1.2.md +0 -40
- package/releases/v3.1.3.md +0 -64
- package/releases/v3.1.4.md +0 -32
- package/releases/v3.1.5.md +0 -44
- package/releases/v4.0.0.md +0 -71
- package/releases/v4.1.0.md +0 -88
- package/releases/v4.2.0.md +0 -90
- package/releases/v4.3.0.md +0 -92
- package/releases/v4.3.1.md +0 -69
- package/releases/v4.4.0.md +0 -120
- package/releases/v4.4.1.md +0 -33
- package/releases/v4.4.2.md +0 -31
- package/releases/v4.5.0.md +0 -116
- package/releases/v5.0.0.md +0 -105
- package/releases/v5.0.1.md +0 -25
- package/releases/v5.1.0.md +0 -83
- package/releases/v5.1.1.md +0 -10
- package/releases/v6.0.0.md +0 -48
- package/releases/v6.0.1.md +0 -36
- package/releases/v6.1.0.md +0 -68
- package/releases/v6.1.1.md +0 -30
- package/releases/v6.1.2.md +0 -23
- package/scripts/generate-server-instructions.ts +0 -306
- package/scripts/server-instructions-function-body.ts +0 -107
- package/scripts/server-instructions-gotchas.ts +0 -45
- package/server.json +0 -42
- package/social-preview.png +0 -0
- package/src/auth/auth-context.ts +0 -78
- package/src/auth/authorization-server-discovery.ts +0 -263
- package/src/auth/errors.ts +0 -215
- package/src/auth/index.ts +0 -58
- package/src/auth/middleware.ts +0 -392
- package/src/auth/oauth-resource-server.ts +0 -170
- package/src/auth/scope-map.ts +0 -46
- package/src/auth/scopes.ts +0 -256
- package/src/auth/token-validator.ts +0 -293
- package/src/auth/transport-agnostic.ts +0 -164
- package/src/auth/types.ts +0 -372
- package/src/cli.ts +0 -279
- package/src/codemode/api-constants.ts +0 -263
- package/src/codemode/api.ts +0 -302
- package/src/codemode/auto-return.ts +0 -65
- package/src/codemode/index.ts +0 -47
- package/src/codemode/sandbox-factory.ts +0 -144
- package/src/codemode/sandbox.ts +0 -220
- package/src/codemode/security.ts +0 -155
- package/src/codemode/types.ts +0 -228
- package/src/codemode/worker-sandbox.ts +0 -277
- package/src/codemode/worker-script.ts +0 -239
- package/src/constants/icons.ts +0 -183
- package/src/constants/server-instructions.md +0 -166
- package/src/constants/server-instructions.ts +0 -514
- package/src/database/adapter-factory.ts +0 -16
- package/src/database/core/entry-columns.ts +0 -10
- package/src/database/core/interfaces.ts +0 -188
- package/src/database/core/schema.ts +0 -152
- package/src/database/sqlite-adapter/backup.ts +0 -167
- package/src/database/sqlite-adapter/entries/crud.ts +0 -233
- package/src/database/sqlite-adapter/entries/importance.ts +0 -76
- package/src/database/sqlite-adapter/entries/index.ts +0 -142
- package/src/database/sqlite-adapter/entries/search.ts +0 -294
- package/src/database/sqlite-adapter/entries/shared.ts +0 -102
- package/src/database/sqlite-adapter/entries/statistics.ts +0 -162
- package/src/database/sqlite-adapter/index.ts +0 -265
- package/src/database/sqlite-adapter/native-connection.ts +0 -301
- package/src/database/sqlite-adapter/relationships.ts +0 -70
- package/src/database/sqlite-adapter/tags.ts +0 -182
- package/src/filtering/tool-filter.ts +0 -312
- package/src/github/github-integration/client.ts +0 -114
- package/src/github/github-integration/index.ts +0 -297
- package/src/github/github-integration/insights.ts +0 -155
- package/src/github/github-integration/issues.ts +0 -213
- package/src/github/github-integration/milestones.ts +0 -262
- package/src/github/github-integration/projects.ts +0 -414
- package/src/github/github-integration/pull-requests.ts +0 -235
- package/src/github/github-integration/repository.ts +0 -110
- package/src/github/github-integration/types.ts +0 -43
- package/src/handlers/prompts/github.ts +0 -210
- package/src/handlers/prompts/index.ts +0 -97
- package/src/handlers/prompts/workflow.ts +0 -361
- package/src/handlers/resources/core/briefing/context-section.ts +0 -182
- package/src/handlers/resources/core/briefing/github-section.ts +0 -354
- package/src/handlers/resources/core/briefing/index.ts +0 -106
- package/src/handlers/resources/core/briefing/user-message.ts +0 -114
- package/src/handlers/resources/core/health.ts +0 -75
- package/src/handlers/resources/core/index.ts +0 -31
- package/src/handlers/resources/core/instructions.ts +0 -45
- package/src/handlers/resources/core/utilities.ts +0 -310
- package/src/handlers/resources/github.ts +0 -340
- package/src/handlers/resources/graph.ts +0 -218
- package/src/handlers/resources/help.ts +0 -410
- package/src/handlers/resources/index.ts +0 -143
- package/src/handlers/resources/shared.ts +0 -219
- package/src/handlers/resources/team.ts +0 -134
- package/src/handlers/resources/templates.ts +0 -334
- package/src/handlers/tools/admin.ts +0 -351
- package/src/handlers/tools/analytics.ts +0 -346
- package/src/handlers/tools/backup.ts +0 -272
- package/src/handlers/tools/codemode.ts +0 -188
- package/src/handlers/tools/core.ts +0 -359
- package/src/handlers/tools/error-fields-mixin.ts +0 -10
- package/src/handlers/tools/export.ts +0 -150
- package/src/handlers/tools/github/copilot-tools.ts +0 -72
- package/src/handlers/tools/github/helpers.ts +0 -125
- package/src/handlers/tools/github/insights-tools.ts +0 -112
- package/src/handlers/tools/github/issue-tools.ts +0 -442
- package/src/handlers/tools/github/kanban-tools.ts +0 -153
- package/src/handlers/tools/github/milestone-tools.ts +0 -371
- package/src/handlers/tools/github/mutation-tools.ts +0 -17
- package/src/handlers/tools/github/read-tools.ts +0 -302
- package/src/handlers/tools/github/schemas.ts +0 -435
- package/src/handlers/tools/github.ts +0 -39
- package/src/handlers/tools/index.ts +0 -255
- package/src/handlers/tools/relationships.ts +0 -390
- package/src/handlers/tools/schemas.ts +0 -165
- package/src/handlers/tools/search.ts +0 -448
- package/src/handlers/tools/team/admin-tools.ts +0 -164
- package/src/handlers/tools/team/analytics-tools.ts +0 -233
- package/src/handlers/tools/team/backup-tools.ts +0 -83
- package/src/handlers/tools/team/core-tools.ts +0 -197
- package/src/handlers/tools/team/export-tools.ts +0 -130
- package/src/handlers/tools/team/helpers.ts +0 -66
- package/src/handlers/tools/team/index.ts +0 -45
- package/src/handlers/tools/team/relationship-tools.ts +0 -219
- package/src/handlers/tools/team/schemas.ts +0 -558
- package/src/handlers/tools/team/search-tools.ts +0 -145
- package/src/handlers/tools/team/vector-tools.ts +0 -261
- package/src/index.ts +0 -57
- package/src/server/mcp-server.ts +0 -446
- package/src/server/registration.ts +0 -141
- package/src/server/scheduler.ts +0 -283
- package/src/transports/http/handlers.ts +0 -78
- package/src/transports/http/index.ts +0 -8
- package/src/transports/http/security.ts +0 -147
- package/src/transports/http/server/index.ts +0 -397
- package/src/transports/http/server/legacy-sse.ts +0 -87
- package/src/transports/http/server/stateful.ts +0 -222
- package/src/transports/http/server/stateless.ts +0 -42
- package/src/transports/http/types.ts +0 -132
- package/src/types/entities.ts +0 -145
- package/src/types/error-types.ts +0 -92
- package/src/types/errors.ts +0 -200
- package/src/types/filtering.ts +0 -55
- package/src/types/github.ts +0 -216
- package/src/types/index.ts +0 -348
- package/src/utils/error-helpers.ts +0 -78
- package/src/utils/errors/error-response-fields.ts +0 -29
- package/src/utils/errors/suggestions.ts +0 -94
- package/src/utils/github-helpers.ts +0 -33
- package/src/utils/logger.ts +0 -107
- package/src/utils/mcp-logger.ts +0 -155
- package/src/utils/progress-utils.ts +0 -100
- package/src/utils/query-helpers.ts +0 -78
- package/src/utils/resource-annotations.ts +0 -75
- package/src/utils/security-utils.ts +0 -198
- package/src/utils/vector-index-helpers.ts +0 -24
- package/src/vector/vector-search-manager.ts +0 -409
- package/src/version.ts +0 -15
- package/test-server/README.md +0 -193
- package/test-server/code-map.md +0 -399
- package/test-server/test-agent-experience.md +0 -213
- package/test-server/test-filter-instructions.mjs +0 -295
- package/test-server/test-instruction-levels.mjs +0 -102
- package/test-server/test-preflight.md +0 -55
- package/test-server/test-prompts.mjs +0 -185
- package/test-server/test-scheduler.mjs +0 -174
- package/test-server/test-tool-annotations.mjs +0 -115
- package/test-server/test-tools-codemode.md +0 -632
- package/test-server/test-tools-codemode2.md +0 -1218
- package/test-server/test-tools-team.md +0 -215
- package/test-server/test-tools.md +0 -429
- package/test-server/test-tools2.md +0 -361
- package/test-server/test-tools3.md +0 -396
- package/test-server/tool-reference.md +0 -231
- package/tests/README.md +0 -54
- package/tests/auth/auth-context.test.ts +0 -162
- package/tests/auth/authorization-server-discovery.test.ts +0 -265
- package/tests/auth/errors.test.ts +0 -170
- package/tests/auth/middleware.test.ts +0 -585
- package/tests/auth/oauth-resource-server.test.ts +0 -173
- package/tests/auth/scope-map.test.ts +0 -66
- package/tests/auth/scopes.test.ts +0 -347
- package/tests/auth/token-validator.test.ts +0 -271
- package/tests/codemode/api.test.ts +0 -396
- package/tests/codemode/auto-return.test.ts +0 -167
- package/tests/codemode/codemode-tool-handlers.test.ts +0 -197
- package/tests/codemode/sandbox-factory.test.ts +0 -152
- package/tests/codemode/sandbox.test.ts +0 -190
- package/tests/codemode/security.test.ts +0 -242
- package/tests/codemode/worker-sandbox.test.ts +0 -106
- package/tests/constants/icons.test.ts +0 -101
- package/tests/constants/server-instructions.test.ts +0 -514
- package/tests/database/crud-workflow-branches.test.ts +0 -418
- package/tests/database/database-branches.test.ts +0 -132
- package/tests/database/entries-auth-branches.test.ts +0 -390
- package/tests/database/native-connection.test.ts +0 -249
- package/tests/database/shared-helpers.test.ts +0 -103
- package/tests/database/sqlite-adapter.bench.ts +0 -63
- package/tests/database/sqlite-adapter.test.ts +0 -690
- package/tests/database/tags.test.ts +0 -134
- package/tests/e2e/README.md +0 -39
- package/tests/e2e/auth.spec.ts +0 -106
- package/tests/e2e/codemode-abuse.spec.ts +0 -75
- package/tests/e2e/health.spec.ts +0 -63
- package/tests/e2e/helpers.ts +0 -139
- package/tests/e2e/oauth-discovery.spec.ts +0 -102
- package/tests/e2e/oauth-scopes.spec.ts +0 -222
- package/tests/e2e/payloads-admin.spec.ts +0 -76
- package/tests/e2e/payloads-analytics.spec.ts +0 -37
- package/tests/e2e/payloads-backup-restore.spec.ts +0 -102
- package/tests/e2e/payloads-backup.spec.ts +0 -44
- package/tests/e2e/payloads-codemode-api.spec.ts +0 -131
- package/tests/e2e/payloads-codemode-readonly.spec.ts +0 -116
- package/tests/e2e/payloads-codemode.spec.ts +0 -116
- package/tests/e2e/payloads-core.spec.ts +0 -82
- package/tests/e2e/payloads-error-contracts.spec.ts +0 -159
- package/tests/e2e/payloads-export.spec.ts +0 -46
- package/tests/e2e/payloads-github-degradation.spec.ts +0 -73
- package/tests/e2e/payloads-github.spec.ts +0 -176
- package/tests/e2e/payloads-relationships.spec.ts +0 -56
- package/tests/e2e/payloads-search.spec.ts +0 -64
- package/tests/e2e/payloads-team-happy.spec.ts +0 -231
- package/tests/e2e/payloads-team.spec.ts +0 -174
- package/tests/e2e/prompts-expanded.spec.ts +0 -137
- package/tests/e2e/prompts.spec.ts +0 -62
- package/tests/e2e/protocols.spec.ts +0 -134
- package/tests/e2e/rate-limiting.spec.ts +0 -291
- package/tests/e2e/resources-briefing-env.spec.ts +0 -106
- package/tests/e2e/resources-complete.spec.ts +0 -180
- package/tests/e2e/resources-expanded.spec.ts +0 -83
- package/tests/e2e/resources-instructions-levels.spec.ts +0 -145
- package/tests/e2e/resources-templates.spec.ts +0 -123
- package/tests/e2e/resources.spec.ts +0 -103
- package/tests/e2e/scheduler.spec.ts +0 -79
- package/tests/e2e/security.spec.ts +0 -112
- package/tests/e2e/session-advanced.spec.ts +0 -152
- package/tests/e2e/sessions.spec.ts +0 -95
- package/tests/e2e/stateless.spec.ts +0 -79
- package/tests/e2e/streaming.spec.ts +0 -176
- package/tests/e2e/tool-filtering-presets.spec.ts +0 -192
- package/tests/e2e/tool-filtering.spec.ts +0 -77
- package/tests/e2e/tools.spec.ts +0 -111
- package/tests/filtering/tool-filter.test.ts +0 -314
- package/tests/github/client-issues-errors.test.ts +0 -433
- package/tests/github/github-integration-branches.test.ts +0 -490
- package/tests/github/github-integration.test.ts +0 -1015
- package/tests/github/github-managers-branches.test.ts +0 -907
- package/tests/github/pull-requests.test.ts +0 -334
- package/tests/handlers/analytics-branches.test.ts +0 -222
- package/tests/handlers/backup-branches.test.ts +0 -270
- package/tests/handlers/briefing-context-section.test.ts +0 -388
- package/tests/handlers/briefing-github-section.test.ts +0 -392
- package/tests/handlers/briefing-user-message.test.ts +0 -405
- package/tests/handlers/codemode-tools.test.ts +0 -85
- package/tests/handlers/copilot-tools.test.ts +0 -126
- package/tests/handlers/error-path-coverage.test.ts +0 -324
- package/tests/handlers/export-tools.test.ts +0 -203
- package/tests/handlers/github-resource-handlers.test.ts +0 -929
- package/tests/handlers/github-tool-handlers.test.ts +0 -1452
- package/tests/handlers/handler-error-branches.test.ts +0 -346
- package/tests/handlers/help-resource.test.ts +0 -92
- package/tests/handlers/prompt-handler-coverage.test.ts +0 -108
- package/tests/handlers/prompt-handlers.test.ts +0 -131
- package/tests/handlers/resource-handler-coverage.test.ts +0 -281
- package/tests/handlers/resource-handlers.test.ts +0 -357
- package/tests/handlers/resource-prompt-branches.test.ts +0 -495
- package/tests/handlers/search-tool-handlers.test.ts +0 -379
- package/tests/handlers/targeted-gap-closure.test.ts +0 -387
- package/tests/handlers/team-admin.test.ts +0 -291
- package/tests/handlers/team-analytics.test.ts +0 -220
- package/tests/handlers/team-core.test.ts +0 -148
- package/tests/handlers/team-data.test.ts +0 -198
- package/tests/handlers/team-relationships.test.ts +0 -271
- package/tests/handlers/team-resource-handlers.test.ts +0 -161
- package/tests/handlers/team-search.test.ts +0 -134
- package/tests/handlers/team-tool-handlers.test.ts +0 -301
- package/tests/handlers/team-vector.test.ts +0 -213
- package/tests/handlers/template-github-branches.test.ts +0 -676
- package/tests/handlers/tool-annotations.test.ts +0 -90
- package/tests/handlers/tool-handler-coverage.test.ts +0 -514
- package/tests/handlers/tool-handlers.test.ts +0 -510
- package/tests/handlers/tool-output-schemas.test.ts +0 -116
- package/tests/handlers/vector-tool-handlers.test.ts +0 -238
- package/tests/security/sql-injection.test.ts +0 -284
- package/tests/server/mcp-server.bench.ts +0 -55
- package/tests/server/mcp-server.test.ts +0 -1326
- package/tests/server/scheduler.test.ts +0 -400
- package/tests/transports/http-legacy-sse.test.ts +0 -275
- package/tests/transports/http-security.test.ts +0 -322
- package/tests/transports/http-stateful.test.ts +0 -487
- package/tests/transports/http-transport-server.test.ts +0 -301
- package/tests/transports/http-transport.test.ts +0 -771
- package/tests/utils/github-helpers.test.ts +0 -58
- package/tests/utils/logger.test.ts +0 -180
- package/tests/utils/mcp-logger.test.ts +0 -211
- package/tests/utils/progress-utils.test.ts +0 -156
- package/tests/utils/query-helpers.test.ts +0 -80
- package/tests/utils/security-utils.test.ts +0 -82
- package/tests/vector/vector-search-branches.test.ts +0 -111
- package/tests/vector/vector-search-manager.test.ts +0 -375
- package/tests/vector/vector-search.bench.ts +0 -48
- package/tsconfig.json +0 -42
- package/tsup.config.ts +0 -19
- package/vitest.config.ts +0 -25
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E2E Tests: OAuth 2.1 Scope Enforcement
|
|
3
|
-
*
|
|
4
|
-
* Verifies that the HTTP middleware enforces RFC 8414/9728 scope logic
|
|
5
|
-
* per tool group before requests reach the MCP handler.
|
|
6
|
-
*
|
|
7
|
-
* read: get_recent_entries (core group)
|
|
8
|
-
* write: get_github_issues (github group)
|
|
9
|
-
* admin: rebuild_vector_index (admin group)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { test, expect } from '@playwright/test'
|
|
13
|
-
import { spawn, type ChildProcess } from 'node:child_process'
|
|
14
|
-
import { setTimeout as delay } from 'node:timers/promises'
|
|
15
|
-
import * as jose from 'jose'
|
|
16
|
-
import express from 'express'
|
|
17
|
-
import type { Server } from 'node:http'
|
|
18
|
-
|
|
19
|
-
const OAUTH_SCOPES_PORT = 3113
|
|
20
|
-
const JWKS_PORT = 3114
|
|
21
|
-
|
|
22
|
-
test.describe.configure({ mode: 'serial' })
|
|
23
|
-
|
|
24
|
-
test.describe('OAuth 2.1 Scope Enforcement E2E', () => {
|
|
25
|
-
let serverProcess: ChildProcess
|
|
26
|
-
let jwksServer: Server
|
|
27
|
-
let privateKey: jose.KeyLike
|
|
28
|
-
let publicKey: jose.KeyLike
|
|
29
|
-
|
|
30
|
-
// JWTs
|
|
31
|
-
let readToken: string
|
|
32
|
-
let writeToken: string
|
|
33
|
-
let adminToken: string
|
|
34
|
-
|
|
35
|
-
// To gracefully exit HTTP servers
|
|
36
|
-
const closeServer = (server: Server) =>
|
|
37
|
-
new Promise<void>((resolve) => server.close(() => resolve()))
|
|
38
|
-
|
|
39
|
-
test.beforeAll(async () => {
|
|
40
|
-
// 1. Generate local keypair
|
|
41
|
-
const keypair = await jose.generateKeyPair('RS256')
|
|
42
|
-
privateKey = keypair.privateKey
|
|
43
|
-
publicKey = keypair.publicKey
|
|
44
|
-
|
|
45
|
-
const jwk = await jose.exportJWK(publicKey)
|
|
46
|
-
jwk.kid = 'test-kid-1'
|
|
47
|
-
jwk.use = 'sig'
|
|
48
|
-
jwk.alg = 'RS256'
|
|
49
|
-
|
|
50
|
-
// 2. Start mock JWKS HTTP server
|
|
51
|
-
const app = express()
|
|
52
|
-
app.get('/jwks', (req, res) => {
|
|
53
|
-
res.json({ keys: [jwk] })
|
|
54
|
-
})
|
|
55
|
-
await new Promise<void>((resolve) => {
|
|
56
|
-
jwksServer = app.listen(JWKS_PORT, () => resolve())
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
// 3. Generate tokens
|
|
60
|
-
const issuer = 'https://auth.example.com/mock'
|
|
61
|
-
const audience = 'memory-journal-mcp'
|
|
62
|
-
|
|
63
|
-
const makeToken = async (scope: string) => {
|
|
64
|
-
return await new jose.SignJWT({ scope })
|
|
65
|
-
.setProtectedHeader({ alg: 'RS256', kid: 'test-kid-1' })
|
|
66
|
-
.setIssuedAt()
|
|
67
|
-
.setIssuer(issuer)
|
|
68
|
-
.setAudience(audience)
|
|
69
|
-
.setExpirationTime('1h')
|
|
70
|
-
.sign(privateKey)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
readToken = await makeToken('read')
|
|
74
|
-
writeToken = await makeToken('read write') // Usually inclusive
|
|
75
|
-
adminToken = await makeToken('admin read write') // Admin includes all
|
|
76
|
-
|
|
77
|
-
// 4. Start MCP Server with OAuth enabled
|
|
78
|
-
serverProcess = spawn(
|
|
79
|
-
'node',
|
|
80
|
-
[
|
|
81
|
-
'dist/cli.js',
|
|
82
|
-
'--transport',
|
|
83
|
-
'http',
|
|
84
|
-
'--port',
|
|
85
|
-
String(OAUTH_SCOPES_PORT),
|
|
86
|
-
'--db',
|
|
87
|
-
'./.test-output/e2e/test-oauth-scopes.db',
|
|
88
|
-
'--oauth-enabled',
|
|
89
|
-
'--oauth-issuer',
|
|
90
|
-
issuer,
|
|
91
|
-
'--oauth-audience',
|
|
92
|
-
audience,
|
|
93
|
-
'--oauth-jwks-uri',
|
|
94
|
-
`http://localhost:${JWKS_PORT}/jwks`,
|
|
95
|
-
],
|
|
96
|
-
{
|
|
97
|
-
cwd: process.cwd(),
|
|
98
|
-
stdio: 'pipe',
|
|
99
|
-
env: { ...process.env, MCP_RATE_LIMIT_MAX: '10000' },
|
|
100
|
-
}
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
for (let i = 0; i < 30; i++) {
|
|
104
|
-
try {
|
|
105
|
-
const res = await fetch(`http://localhost:${OAUTH_SCOPES_PORT}/health`)
|
|
106
|
-
if (res.ok) break
|
|
107
|
-
} catch {}
|
|
108
|
-
await delay(500)
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
test.afterAll(async () => {
|
|
113
|
-
if (serverProcess) {
|
|
114
|
-
serverProcess.kill('SIGTERM')
|
|
115
|
-
}
|
|
116
|
-
if (jwksServer) {
|
|
117
|
-
await closeServer(jwksServer)
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Execute a tool call directly against the MCP endpoint.
|
|
123
|
-
*
|
|
124
|
-
* For scope-denied cases (expectSuccess=false): a bare tools/call POST with no
|
|
125
|
-
* session hits the scope middleware BEFORE session validation → 403.
|
|
126
|
-
*
|
|
127
|
-
* For scope-allowed cases (expectSuccess=true): performs a full session handshake
|
|
128
|
-
* (initialize → mcp-session-id → tools/call) so the MCP handler receives a
|
|
129
|
-
* valid request and returns 200.
|
|
130
|
-
*/
|
|
131
|
-
async function executeToolDirectly(
|
|
132
|
-
token: string,
|
|
133
|
-
tool: string,
|
|
134
|
-
args: Record<string, unknown>,
|
|
135
|
-
expectSuccess: boolean
|
|
136
|
-
) {
|
|
137
|
-
const base = `http://localhost:${OAUTH_SCOPES_PORT}/mcp`
|
|
138
|
-
const headers = {
|
|
139
|
-
'Content-Type': 'application/json',
|
|
140
|
-
Accept: 'application/json, text/event-stream',
|
|
141
|
-
Authorization: `Bearer ${token}`,
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!expectSuccess) {
|
|
145
|
-
// Scope middleware fires before session check → expect 403 immediately
|
|
146
|
-
const res = await fetch(base, {
|
|
147
|
-
method: 'POST',
|
|
148
|
-
headers,
|
|
149
|
-
body: JSON.stringify({
|
|
150
|
-
jsonrpc: '2.0',
|
|
151
|
-
id: Math.floor(Math.random() * 10000),
|
|
152
|
-
method: 'tools/call',
|
|
153
|
-
params: { name: tool, arguments: args },
|
|
154
|
-
}),
|
|
155
|
-
})
|
|
156
|
-
expect(res.status).toBe(403)
|
|
157
|
-
const body = (await res.json()) as Record<string, unknown>
|
|
158
|
-
expect(body.error).toBe('insufficient_scope')
|
|
159
|
-
return
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Success path: need a valid session (stateful server)
|
|
163
|
-
const initRes = await fetch(base, {
|
|
164
|
-
method: 'POST',
|
|
165
|
-
headers,
|
|
166
|
-
body: JSON.stringify({
|
|
167
|
-
jsonrpc: '2.0',
|
|
168
|
-
id: 1,
|
|
169
|
-
method: 'initialize',
|
|
170
|
-
params: {
|
|
171
|
-
protocolVersion: '2025-03-26',
|
|
172
|
-
capabilities: {},
|
|
173
|
-
clientInfo: { name: 'test-client', version: '1.0' },
|
|
174
|
-
},
|
|
175
|
-
}),
|
|
176
|
-
})
|
|
177
|
-
expect(initRes.status).toBe(200)
|
|
178
|
-
const sessionId = initRes.headers.get('mcp-session-id')
|
|
179
|
-
expect(sessionId).toBeTruthy()
|
|
180
|
-
|
|
181
|
-
// Notify server that client is initialized
|
|
182
|
-
await fetch(base, {
|
|
183
|
-
method: 'POST',
|
|
184
|
-
headers: { ...headers, 'mcp-session-id': sessionId! },
|
|
185
|
-
body: JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' }),
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
// Now call the tool on the established session
|
|
189
|
-
const res = await fetch(base, {
|
|
190
|
-
method: 'POST',
|
|
191
|
-
headers: { ...headers, 'mcp-session-id': sessionId! },
|
|
192
|
-
body: JSON.stringify({
|
|
193
|
-
jsonrpc: '2.0',
|
|
194
|
-
id: 2,
|
|
195
|
-
method: 'tools/call',
|
|
196
|
-
params: { name: tool, arguments: args },
|
|
197
|
-
}),
|
|
198
|
-
})
|
|
199
|
-
expect(res.status).toBe(200)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
test('read token can read core tools, but gets 403 on write-scoped tools', async () => {
|
|
203
|
-
// Read-scoped core tool — allowed (core group requires read)
|
|
204
|
-
await executeToolDirectly(readToken, 'get_recent_entries', { limit: 1 }, true)
|
|
205
|
-
|
|
206
|
-
// Write-scoped tool — blocked (github group requires write)
|
|
207
|
-
await executeToolDirectly(readToken, 'get_github_issues', {}, false)
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
test('write token can call write-scoped tools, but gets 403 on admin tools', async () => {
|
|
211
|
-
// Write-scoped tool allowed (github group requires write, write token has write scope)
|
|
212
|
-
await executeToolDirectly(writeToken, 'get_github_issues', {}, true)
|
|
213
|
-
|
|
214
|
-
// Admin tools blocked (admin group requires admin, write token has only read+write)
|
|
215
|
-
await executeToolDirectly(writeToken, 'rebuild_vector_index', {}, false)
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
test('admin token can call admin-scoped tools', async () => {
|
|
219
|
-
// Admin access granted (admin scope satisfies admin group requirement)
|
|
220
|
-
await executeToolDirectly(adminToken, 'rebuild_vector_index', {}, true)
|
|
221
|
-
})
|
|
222
|
-
})
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Admin
|
|
3
|
-
*
|
|
4
|
-
* Validates response shapes for 5 admin tools:
|
|
5
|
-
* update_entry, delete_entry, merge_tags, rebuild_vector_index, add_to_vector_index.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { test, expect } from '@playwright/test'
|
|
9
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
10
|
-
import { createClient, callToolAndParse, expectSuccess } from './helpers.js'
|
|
11
|
-
|
|
12
|
-
test.describe.configure({ mode: 'serial' })
|
|
13
|
-
|
|
14
|
-
test.describe('Payload Contracts: Admin', () => {
|
|
15
|
-
let client: Client
|
|
16
|
-
let entryId: number
|
|
17
|
-
|
|
18
|
-
test.beforeAll(async () => {
|
|
19
|
-
client = await createClient()
|
|
20
|
-
// Create an entry for admin operations
|
|
21
|
-
const e = await callToolAndParse(client, 'create_entry', {
|
|
22
|
-
content: 'Admin test entry',
|
|
23
|
-
entry_type: 'test_entry',
|
|
24
|
-
tags: ['admin-test', 'merge-source'],
|
|
25
|
-
})
|
|
26
|
-
entryId = (e.entry as Record<string, unknown>).id as number
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test.afterAll(async () => {
|
|
30
|
-
await client.close()
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('update_entry returns { success, entry }', async () => {
|
|
34
|
-
const payload = await callToolAndParse(client, 'update_entry', {
|
|
35
|
-
entry_id: entryId,
|
|
36
|
-
content: 'Updated admin test entry',
|
|
37
|
-
})
|
|
38
|
-
expectSuccess(payload)
|
|
39
|
-
expect(payload.success).toBe(true)
|
|
40
|
-
expect(payload.entry).toBeDefined()
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('add_to_vector_index returns { success, entryId }', async () => {
|
|
44
|
-
const payload = await callToolAndParse(client, 'add_to_vector_index', {
|
|
45
|
-
entry_id: entryId,
|
|
46
|
-
})
|
|
47
|
-
// Vector search may not be available in test environments
|
|
48
|
-
expect(typeof payload.success).toBe('boolean')
|
|
49
|
-
expect(payload.entryId).toBe(entryId)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('merge_tags returns merge result', async () => {
|
|
53
|
-
const payload = await callToolAndParse(client, 'merge_tags', {
|
|
54
|
-
source_tag: 'merge-source',
|
|
55
|
-
target_tag: 'admin-test',
|
|
56
|
-
})
|
|
57
|
-
expectSuccess(payload)
|
|
58
|
-
expect(typeof payload).toBe('object')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
test('rebuild_vector_index returns { success, entriesIndexed }', async () => {
|
|
62
|
-
const payload = await callToolAndParse(client, 'rebuild_vector_index', {})
|
|
63
|
-
// Embedding model may not be available in test environments
|
|
64
|
-
expect(typeof payload.success).toBe('boolean')
|
|
65
|
-
expect(typeof payload.entriesIndexed).toBe('number')
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('delete_entry returns { success, entryId }', async () => {
|
|
69
|
-
const payload = await callToolAndParse(client, 'delete_entry', {
|
|
70
|
-
entry_id: entryId,
|
|
71
|
-
})
|
|
72
|
-
expectSuccess(payload)
|
|
73
|
-
expect(payload.success).toBeDefined()
|
|
74
|
-
expect(payload.entryId).toBe(entryId)
|
|
75
|
-
})
|
|
76
|
-
})
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Analytics
|
|
3
|
-
*
|
|
4
|
-
* Validates response shapes for 2 analytics tools:
|
|
5
|
-
* get_statistics, get_cross_project_insights.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { test, expect } from '@playwright/test'
|
|
9
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
10
|
-
import { createClient, callToolAndParse, expectSuccess } from './helpers.js'
|
|
11
|
-
|
|
12
|
-
test.describe.configure({ mode: 'serial' })
|
|
13
|
-
|
|
14
|
-
test.describe('Payload Contracts: Analytics', () => {
|
|
15
|
-
let client: Client
|
|
16
|
-
|
|
17
|
-
test.beforeAll(async () => {
|
|
18
|
-
client = await createClient()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test.afterAll(async () => {
|
|
22
|
-
await client.close()
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
test('get_statistics returns stats object', async () => {
|
|
26
|
-
const payload = await callToolAndParse(client, 'get_statistics', {})
|
|
27
|
-
expectSuccess(payload)
|
|
28
|
-
expect(typeof payload.groupBy).toBe('string')
|
|
29
|
-
expect(typeof payload).toBe('object')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('get_cross_project_insights returns insights', async () => {
|
|
33
|
-
const payload = await callToolAndParse(client, 'get_cross_project_insights', {})
|
|
34
|
-
expectSuccess(payload)
|
|
35
|
-
expect(typeof payload).toBe('object')
|
|
36
|
-
})
|
|
37
|
-
})
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Backup Restore
|
|
3
|
-
*
|
|
4
|
-
* Tests the restore_backup workflow that was missing from
|
|
5
|
-
* payloads-backup.spec.ts: confirm=false rejection, nonexistent
|
|
6
|
-
* backup error, and full backup→restore cycle.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { test, expect } from '@playwright/test'
|
|
10
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
11
|
-
import { createClient, callToolAndParse, expectSuccess } from './helpers.js'
|
|
12
|
-
|
|
13
|
-
test.describe.configure({ mode: 'serial' })
|
|
14
|
-
|
|
15
|
-
test.describe('Payload Contracts: Backup Restore', () => {
|
|
16
|
-
let client: Client
|
|
17
|
-
|
|
18
|
-
test.beforeAll(async () => {
|
|
19
|
-
client = await createClient()
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test.afterAll(async () => {
|
|
23
|
-
await client.close()
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('restore_backup(confirm: false) returns structured validation error', async () => {
|
|
27
|
-
// When confirm is false, the handler returns a structured error response.
|
|
28
|
-
// The MCP SDK marks tool responses containing { success: false } as isError when
|
|
29
|
-
// the outputSchema is validated — use raw callTool here instead of callToolAndParse.
|
|
30
|
-
const response = await client.callTool({
|
|
31
|
-
name: 'restore_backup',
|
|
32
|
-
arguments: {
|
|
33
|
-
filename: 'nonexistent.db',
|
|
34
|
-
confirm: false,
|
|
35
|
-
},
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
// isError may be true because the SDK detected a structured error response
|
|
39
|
-
// The key assertion is that the content is a well-formed error, not an exception
|
|
40
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
41
|
-
const content = response.content as Array<{ type: string; text?: string }>
|
|
42
|
-
expect(content.length).toBeGreaterThan(0)
|
|
43
|
-
expect(content[0]!.type).toBe('text')
|
|
44
|
-
|
|
45
|
-
const payload = JSON.parse(content[0]!.text!) as Record<string, unknown>
|
|
46
|
-
expect(payload.success).toBe(false)
|
|
47
|
-
expect(typeof payload.error).toBe('string')
|
|
48
|
-
expect((payload.error as string).toLowerCase()).toContain('confirm')
|
|
49
|
-
expect(payload.code).toBe('VALIDATION_ERROR')
|
|
50
|
-
expect(payload.category).toBe('validation')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('restore_backup with nonexistent file returns structured error', async () => {
|
|
54
|
-
const response = await client.callTool({
|
|
55
|
-
name: 'restore_backup',
|
|
56
|
-
arguments: {
|
|
57
|
-
filename: 'nonexistent-backup-file-that-does-not-exist.db',
|
|
58
|
-
confirm: true,
|
|
59
|
-
},
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
63
|
-
const payload = JSON.parse(
|
|
64
|
-
(response.content as Array<{ type: string; text: string }>)[0]!.text
|
|
65
|
-
) as Record<string, unknown>
|
|
66
|
-
expect(payload.success).toBe(false)
|
|
67
|
-
expect(typeof payload.error).toBe('string')
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
test('full backup → restore cycle succeeds', async () => {
|
|
71
|
-
// Step 1: Create an entry so the DB is non-empty
|
|
72
|
-
const entry = await callToolAndParse(client, 'create_entry', {
|
|
73
|
-
content: 'Backup restore cycle test entry',
|
|
74
|
-
entry_type: 'test_entry',
|
|
75
|
-
tags: ['backup-restore-test'],
|
|
76
|
-
})
|
|
77
|
-
expectSuccess(entry)
|
|
78
|
-
|
|
79
|
-
// Step 2: Create a backup
|
|
80
|
-
const backup = await callToolAndParse(client, 'backup_journal', {})
|
|
81
|
-
expectSuccess(backup)
|
|
82
|
-
expect(backup.success).toBe(true)
|
|
83
|
-
expect(typeof backup.filename).toBe('string')
|
|
84
|
-
|
|
85
|
-
const backupFilename = backup.filename as string
|
|
86
|
-
|
|
87
|
-
// Step 3: Restore from the backup (use filename directly from backup result)
|
|
88
|
-
const restore = await client.callTool({
|
|
89
|
-
name: 'restore_backup',
|
|
90
|
-
arguments: {
|
|
91
|
-
filename: backupFilename,
|
|
92
|
-
confirm: true,
|
|
93
|
-
},
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
expect(Array.isArray(restore.content)).toBe(true)
|
|
97
|
-
const restorePayload = JSON.parse(
|
|
98
|
-
(restore.content as Array<{ type: string; text: string }>)[0]!.text
|
|
99
|
-
) as Record<string, unknown>
|
|
100
|
-
expect(restorePayload.success).toBe(true)
|
|
101
|
-
})
|
|
102
|
-
})
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Backup
|
|
3
|
-
*
|
|
4
|
-
* Validates response shapes for 4 backup tools:
|
|
5
|
-
* backup_journal, list_backups, cleanup_backups, restore_backup.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { test, expect } from '@playwright/test'
|
|
9
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
10
|
-
import { createClient, callToolAndParse, expectSuccess } from './helpers.js'
|
|
11
|
-
|
|
12
|
-
test.describe.configure({ mode: 'serial' })
|
|
13
|
-
|
|
14
|
-
test.describe('Payload Contracts: Backup', () => {
|
|
15
|
-
let client: Client
|
|
16
|
-
|
|
17
|
-
test.beforeAll(async () => {
|
|
18
|
-
client = await createClient()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test.afterAll(async () => {
|
|
22
|
-
await client.close()
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
test('backup_journal returns { success }', async () => {
|
|
26
|
-
const payload = await callToolAndParse(client, 'backup_journal', {})
|
|
27
|
-
expectSuccess(payload)
|
|
28
|
-
expect(payload.success).toBe(true)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
test('list_backups returns backup list', async () => {
|
|
32
|
-
const payload = await callToolAndParse(client, 'list_backups', {})
|
|
33
|
-
expectSuccess(payload)
|
|
34
|
-
expect(typeof payload).toBe('object')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('cleanup_backups returns cleanup result', async () => {
|
|
38
|
-
const payload = await callToolAndParse(client, 'cleanup_backups', {
|
|
39
|
-
keep_count: 5,
|
|
40
|
-
})
|
|
41
|
-
expectSuccess(payload)
|
|
42
|
-
expect(typeof payload).toBe('object')
|
|
43
|
-
})
|
|
44
|
-
})
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Code Mode API Bridge Depth
|
|
3
|
-
*
|
|
4
|
-
* Exercises the mj.* API bridge beyond basic execution:
|
|
5
|
-
* - mj.search.searchEntries() returns { entries, count }
|
|
6
|
-
* - mj.analytics.getStatistics() returns stats object
|
|
7
|
-
* - Multi-step: createEntry + searchEntries with data dependency
|
|
8
|
-
* - mj.help() returns API group listing with expected group names
|
|
9
|
-
* - mj.help() lists all expected top-level namespaces
|
|
10
|
-
*
|
|
11
|
-
* Note: Code Mode wraps execution results as { success, result, metrics }.
|
|
12
|
-
* The user's return value is in payload.result; we stringify payload to check
|
|
13
|
-
* presence of expected fields across both paths.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { test, expect } from '@playwright/test'
|
|
17
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
18
|
-
import { createClient, callToolAndParse } from './helpers.js'
|
|
19
|
-
|
|
20
|
-
test.describe.configure({ mode: 'serial' })
|
|
21
|
-
|
|
22
|
-
test.describe('Payload Contracts: Code Mode API Bridge Depth', () => {
|
|
23
|
-
let client: Client
|
|
24
|
-
|
|
25
|
-
test.beforeAll(async () => {
|
|
26
|
-
client = await createClient()
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test.afterAll(async () => {
|
|
30
|
-
await client.close()
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('mj.search.searchEntries() returns { entries, count }', async () => {
|
|
34
|
-
const payload = await callToolAndParse(client, 'mj_execute_code', {
|
|
35
|
-
code: `
|
|
36
|
-
const result = await mj.search.searchEntries({ query: 'test' });
|
|
37
|
-
return result;
|
|
38
|
-
`,
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
expect(typeof payload).toBe('object')
|
|
42
|
-
// Code Mode result is in payload.result; but we stringify for robustness
|
|
43
|
-
const flat = JSON.stringify(payload)
|
|
44
|
-
// Should contain entries array field
|
|
45
|
-
expect(flat).toMatch(/"entries"/)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test('mj.analytics.getStatistics() returns stats object with expected fields', async () => {
|
|
49
|
-
const payload = await callToolAndParse(client, 'mj_execute_code', {
|
|
50
|
-
code: `
|
|
51
|
-
const result = await mj.analytics.getStatistics({});
|
|
52
|
-
return result;
|
|
53
|
-
`,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
expect(typeof payload).toBe('object')
|
|
57
|
-
// Should not be a hard failure
|
|
58
|
-
expect(JSON.stringify(payload)).not.toContain('"success":false')
|
|
59
|
-
// Stats response should have groupBy or totalEntries
|
|
60
|
-
const flat = JSON.stringify(payload)
|
|
61
|
-
expect(flat).toMatch(/groupBy|totalEntries/)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test('multi-step: createEntry then searchEntries finds created content', async () => {
|
|
65
|
-
const uniqueTag = `codemode-api-e2e-${Date.now()}`
|
|
66
|
-
|
|
67
|
-
const payload = await callToolAndParse(client, 'mj_execute_code', {
|
|
68
|
-
code: `
|
|
69
|
-
// Step 1: create entry with a unique tag
|
|
70
|
-
const created = await mj.core.createEntry({
|
|
71
|
-
content: 'Code mode API bridge depth test',
|
|
72
|
-
entry_type: 'test_entry',
|
|
73
|
-
tags: ['${uniqueTag}'],
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Step 2: search using the tag
|
|
77
|
-
const results = await mj.search.searchEntries({ query: '${uniqueTag}' });
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
createdId: created.entry?.id,
|
|
81
|
-
foundCount: results.count,
|
|
82
|
-
createSuccess: created.success,
|
|
83
|
-
};
|
|
84
|
-
`,
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
expect(typeof payload).toBe('object')
|
|
88
|
-
// Overall execution must succeed
|
|
89
|
-
const flat = JSON.stringify(payload)
|
|
90
|
-
expect(flat).not.toContain('"success":false')
|
|
91
|
-
// The entry was created (result.createdId should be a number)
|
|
92
|
-
const result = payload.result as Record<string, unknown> | undefined
|
|
93
|
-
if (result) {
|
|
94
|
-
expect(typeof result.createdId).toBe('number')
|
|
95
|
-
// Both API calls returned well-formed results (count is a number)
|
|
96
|
-
expect(typeof result.foundCount).toBe('number')
|
|
97
|
-
}
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
test('mj.help() returns API group listing', async () => {
|
|
101
|
-
const payload = await callToolAndParse(client, 'mj_execute_code', {
|
|
102
|
-
code: `
|
|
103
|
-
const help = await mj.help();
|
|
104
|
-
return { help, type: typeof help };
|
|
105
|
-
`,
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
expect(typeof payload).toBe('object')
|
|
109
|
-
// Either the call succeeded with a result, or we at least got a non-null response
|
|
110
|
-
const flat = JSON.stringify(payload)
|
|
111
|
-
// help() should produce something non-empty
|
|
112
|
-
expect(flat.length).toBeGreaterThan(10)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
test('mj.help() output mentions expected API groups', async () => {
|
|
116
|
-
const payload = await callToolAndParse(client, 'mj_execute_code', {
|
|
117
|
-
code: `
|
|
118
|
-
const help = await mj.help();
|
|
119
|
-
const helpText = JSON.stringify(help);
|
|
120
|
-
return { helpText };
|
|
121
|
-
`,
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
expect(typeof payload).toBe('object')
|
|
125
|
-
// Full serialized payload should mention core and search group names
|
|
126
|
-
const flat = JSON.stringify(payload)
|
|
127
|
-
expect(flat).toMatch(/core/i)
|
|
128
|
-
expect(flat).toMatch(/search/i)
|
|
129
|
-
expect(flat).toMatch(/analytics/i)
|
|
130
|
-
})
|
|
131
|
-
})
|