@cyanheads/mcp-ts-core 0.11.4 → 0.12.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/AGENTS.md +28 -24
- package/CLAUDE.md +28 -24
- package/README.md +10 -10
- package/biome.json +1 -1
- package/changelog/0.11.x/0.11.5.md +28 -0
- package/changelog/0.12.x/0.12.0.md +96 -0
- package/changelog/template.md +55 -16
- package/dist/cli/init.js +1 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/config/index.d.ts +0 -18
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +0 -25
- package/dist/config/index.js.map +1 -1
- package/dist/core/app.d.ts +5 -7
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +18 -27
- package/dist/core/app.js.map +1 -1
- package/dist/core/context.d.ts +90 -57
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +32 -33
- package/dist/core/context.js.map +1 -1
- package/dist/core/gcPressure.d.ts.map +1 -1
- package/dist/core/gcPressure.js +3 -4
- package/dist/core/gcPressure.js.map +1 -1
- package/dist/core/index.d.ts +6 -7
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +10 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/serverManifest.d.ts +1 -3
- package/dist/core/serverManifest.d.ts.map +1 -1
- package/dist/core/serverManifest.js +9 -4
- package/dist/core/serverManifest.js.map +1 -1
- package/dist/core/worker.d.ts.map +1 -1
- package/dist/core/worker.js +32 -35
- package/dist/core/worker.js.map +1 -1
- package/dist/logs/combined.log +10 -0
- package/dist/logs/error.log +6 -0
- package/dist/logs/interactions.log +0 -0
- package/dist/mcp-server/inputRequired.d.ts +52 -0
- package/dist/mcp-server/inputRequired.d.ts.map +1 -0
- package/dist/mcp-server/inputRequired.js +76 -0
- package/dist/mcp-server/inputRequired.js.map +1 -0
- package/dist/mcp-server/notifications.d.ts +33 -31
- package/dist/mcp-server/notifications.d.ts.map +1 -1
- package/dist/mcp-server/notifications.js +34 -26
- package/dist/mcp-server/notifications.js.map +1 -1
- package/dist/mcp-server/prompts/prompt-registration.d.ts +2 -2
- package/dist/mcp-server/prompts/prompt-registration.d.ts.map +1 -1
- package/dist/mcp-server/prompts/prompt-registration.js +15 -5
- package/dist/mcp-server/prompts/prompt-registration.js.map +1 -1
- package/dist/mcp-server/prompts/utils/promptDefinition.d.ts +1 -1
- package/dist/mcp-server/prompts/utils/promptDefinition.d.ts.map +1 -1
- package/dist/mcp-server/resources/resource-registration.d.ts +3 -3
- package/dist/mcp-server/resources/resource-registration.d.ts.map +1 -1
- package/dist/mcp-server/resources/resource-registration.js +8 -15
- package/dist/mcp-server/resources/resource-registration.js.map +1 -1
- package/dist/mcp-server/resources/resourceSubscriptions.d.ts +45 -0
- package/dist/mcp-server/resources/resourceSubscriptions.d.ts.map +1 -0
- package/dist/mcp-server/resources/resourceSubscriptions.js +51 -0
- package/dist/mcp-server/resources/resourceSubscriptions.js.map +1 -0
- package/dist/mcp-server/resources/utils/resourceDefinition.d.ts +3 -5
- package/dist/mcp-server/resources/utils/resourceDefinition.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceDefinition.js +1 -1
- package/dist/mcp-server/resources/utils/resourceDefinition.js.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts +8 -15
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +21 -22
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
- package/dist/mcp-server/server.d.ts +12 -21
- package/dist/mcp-server/server.d.ts.map +1 -1
- package/dist/mcp-server/server.js +38 -28
- package/dist/mcp-server/server.js.map +1 -1
- package/dist/mcp-server/tools/tool-registration.d.ts +11 -33
- package/dist/mcp-server/tools/tool-registration.d.ts.map +1 -1
- package/dist/mcp-server/tools/tool-registration.js +17 -243
- package/dist/mcp-server/tools/tool-registration.js.map +1 -1
- package/dist/mcp-server/tools/utils/toolDefinition.d.ts +1 -3
- package/dist/mcp-server/tools/utils/toolDefinition.d.ts.map +1 -1
- package/dist/mcp-server/tools/utils/toolDefinition.js +48 -1
- package/dist/mcp-server/tools/utils/toolDefinition.js.map +1 -1
- package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts +46 -20
- package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/tools/utils/toolHandlerFactory.js +131 -25
- package/dist/mcp-server/tools/utils/toolHandlerFactory.js.map +1 -1
- package/dist/mcp-server/transports/ITransport.d.ts +2 -2
- package/dist/mcp-server/transports/ITransport.d.ts.map +1 -1
- package/dist/mcp-server/transports/auth/authFactory.js +1 -1
- package/dist/mcp-server/transports/auth/authFactory.js.map +1 -1
- package/dist/mcp-server/transports/auth/lib/authTypes.d.ts +1 -1
- package/dist/mcp-server/transports/auth/lib/authTypes.d.ts.map +1 -1
- package/dist/mcp-server/transports/auth/lib/authUtils.d.ts.map +1 -1
- package/dist/mcp-server/transports/auth/lib/authUtils.js +5 -13
- package/dist/mcp-server/transports/auth/lib/authUtils.js.map +1 -1
- package/dist/mcp-server/transports/auth/strategies/jwtStrategy.js +5 -11
- package/dist/mcp-server/transports/auth/strategies/jwtStrategy.js.map +1 -1
- package/dist/mcp-server/transports/auth/strategies/oauthStrategy.d.ts.map +1 -1
- package/dist/mcp-server/transports/auth/strategies/oauthStrategy.js +9 -22
- package/dist/mcp-server/transports/auth/strategies/oauthStrategy.js.map +1 -1
- package/dist/mcp-server/transports/heartbeat.d.ts.map +1 -1
- package/dist/mcp-server/transports/heartbeat.js +4 -8
- package/dist/mcp-server/transports/heartbeat.js.map +1 -1
- package/dist/mcp-server/transports/http/httpErrorHandler.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/httpErrorHandler.js +6 -24
- package/dist/mcp-server/transports/http/httpErrorHandler.js.map +1 -1
- package/dist/mcp-server/transports/http/httpServer.d.ts +3 -3
- package/dist/mcp-server/transports/http/httpServer.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/httpServer.js +15 -32
- package/dist/mcp-server/transports/http/httpServer.js.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.d.ts +25 -8
- package/dist/mcp-server/transports/http/httpTransport.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.js +156 -310
- package/dist/mcp-server/transports/http/httpTransport.js.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/assets/styles.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/assets/styles.js +0 -1
- package/dist/mcp-server/transports/http/landing-page/assets/styles.js.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/handler.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/handler.js +4 -8
- package/dist/mcp-server/transports/http/landing-page/handler.js.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/sections/tools.js +0 -2
- package/dist/mcp-server/transports/http/landing-page/sections/tools.js.map +1 -1
- package/dist/mcp-server/transports/http/protectedResourceMetadata.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/protectedResourceMetadata.js +2 -6
- package/dist/mcp-server/transports/http/protectedResourceMetadata.js.map +1 -1
- package/dist/mcp-server/transports/http/robotsTxt.js +2 -2
- package/dist/mcp-server/transports/http/robotsTxt.js.map +1 -1
- package/dist/mcp-server/transports/http/serverCard.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/serverCard.js +2 -6
- package/dist/mcp-server/transports/http/serverCard.js.map +1 -1
- package/dist/mcp-server/transports/http/sessionStore.d.ts +48 -45
- package/dist/mcp-server/transports/http/sessionStore.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/sessionStore.js +141 -185
- package/dist/mcp-server/transports/http/sessionStore.js.map +1 -1
- package/dist/mcp-server/transports/manager.d.ts +12 -4
- package/dist/mcp-server/transports/manager.d.ts.map +1 -1
- package/dist/mcp-server/transports/manager.js +35 -33
- package/dist/mcp-server/transports/manager.js.map +1 -1
- package/dist/mcp-server/transports/stdio/stdioTransport.d.ts +24 -31
- package/dist/mcp-server/transports/stdio/stdioTransport.d.ts.map +1 -1
- package/dist/mcp-server/transports/stdio/stdioTransport.js +23 -38
- package/dist/mcp-server/transports/stdio/stdioTransport.js.map +1 -1
- package/dist/mcp-server/types.d.ts +25 -0
- package/dist/mcp-server/types.d.ts.map +1 -0
- package/dist/mcp-server/types.js +10 -0
- package/dist/mcp-server/types.js.map +1 -0
- package/dist/services/canvas/core/CanvasInstance.d.ts +2 -2
- package/dist/services/canvas/core/CanvasInstance.d.ts.map +1 -1
- package/dist/services/canvas/core/CanvasInstance.js.map +1 -1
- package/dist/services/canvas/core/CanvasRegistry.d.ts +4 -4
- package/dist/services/canvas/core/CanvasRegistry.d.ts.map +1 -1
- package/dist/services/canvas/core/CanvasRegistry.js +8 -18
- package/dist/services/canvas/core/CanvasRegistry.js.map +1 -1
- package/dist/services/canvas/core/DataCanvas.d.ts +5 -5
- package/dist/services/canvas/core/DataCanvas.d.ts.map +1 -1
- package/dist/services/canvas/core/DataCanvas.js +2 -3
- package/dist/services/canvas/core/DataCanvas.js.map +1 -1
- package/dist/services/canvas/core/IDataCanvasProvider.d.ts +11 -11
- package/dist/services/canvas/core/IDataCanvasProvider.d.ts.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts +11 -11
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +4 -10
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
- package/dist/services/llm/providers/openrouter.provider.d.ts.map +1 -1
- package/dist/services/llm/providers/openrouter.provider.js +2 -5
- package/dist/services/llm/providers/openrouter.provider.js.map +1 -1
- package/dist/services/mirror/core/defineMirror.js +1 -1
- package/dist/services/mirror/core/defineMirror.js.map +1 -1
- package/dist/services/mirror/types.d.ts +5 -5
- package/dist/services/mirror/types.d.ts.map +1 -1
- package/dist/services/speech/providers/elevenlabs.provider.js +1 -1
- package/dist/services/speech/providers/elevenlabs.provider.js.map +1 -1
- package/dist/services/speech/providers/whisper.provider.js +1 -1
- package/dist/services/speech/providers/whisper.provider.js.map +1 -1
- package/dist/storage/core/StorageService.d.ts +1 -1
- package/dist/storage/core/StorageService.d.ts.map +1 -1
- package/dist/storage/core/StorageService.js +12 -20
- package/dist/storage/core/StorageService.js.map +1 -1
- package/dist/storage/core/storageFactory.d.ts.map +1 -1
- package/dist/storage/core/storageFactory.js.map +1 -1
- package/dist/storage/core/storageValidation.d.ts +1 -1
- package/dist/storage/core/storageValidation.d.ts.map +1 -1
- package/dist/storage/core/storageValidation.js +2 -2
- package/dist/storage/core/storageValidation.js.map +1 -1
- package/dist/storage/providers/cloudflare/d1Provider.d.ts +1 -1
- package/dist/storage/providers/cloudflare/d1Provider.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/d1Provider.js +4 -12
- package/dist/storage/providers/cloudflare/d1Provider.js.map +1 -1
- package/dist/storage/providers/cloudflare/kvProvider.d.ts +1 -1
- package/dist/storage/providers/cloudflare/kvProvider.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/kvProvider.js +3 -8
- package/dist/storage/providers/cloudflare/kvProvider.js.map +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.d.ts +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.js +3 -8
- package/dist/storage/providers/cloudflare/r2Provider.js.map +1 -1
- package/dist/storage/providers/inMemory/inMemoryProvider.d.ts +1 -1
- package/dist/storage/providers/inMemory/inMemoryProvider.d.ts.map +1 -1
- package/dist/storage/providers/inMemory/inMemoryProvider.js +2 -4
- package/dist/storage/providers/inMemory/inMemoryProvider.js.map +1 -1
- package/dist/testing/index.d.ts +35 -12
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +53 -38
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/vitest.d.ts +1 -1
- package/dist/testing/vitest.d.ts.map +1 -1
- package/dist/types-global/errors.d.ts +28 -15
- package/dist/types-global/errors.d.ts.map +1 -1
- package/dist/types-global/errors.js +8 -1
- package/dist/types-global/errors.js.map +1 -1
- package/dist/utils/formatting/diffFormatter.d.ts +5 -5
- package/dist/utils/formatting/diffFormatter.d.ts.map +1 -1
- package/dist/utils/formatting/diffFormatter.js +7 -20
- package/dist/utils/formatting/diffFormatter.js.map +1 -1
- package/dist/utils/formatting/tableFormatter.d.ts +3 -3
- package/dist/utils/formatting/tableFormatter.d.ts.map +1 -1
- package/dist/utils/formatting/tableFormatter.js +6 -17
- package/dist/utils/formatting/tableFormatter.js.map +1 -1
- package/dist/utils/formatting/treeFormatter.d.ts +3 -3
- package/dist/utils/formatting/treeFormatter.d.ts.map +1 -1
- package/dist/utils/formatting/treeFormatter.js +5 -18
- package/dist/utils/formatting/treeFormatter.js.map +1 -1
- package/dist/utils/index.d.ts +4 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/internal/error-handler/errorHandler.d.ts +1 -1
- package/dist/utils/internal/error-handler/errorHandler.d.ts.map +1 -1
- package/dist/utils/internal/error-handler/errorHandler.js +23 -11
- package/dist/utils/internal/error-handler/errorHandler.js.map +1 -1
- package/dist/utils/internal/error-handler/types.d.ts +10 -13
- package/dist/utils/internal/error-handler/types.d.ts.map +1 -1
- package/dist/utils/internal/logger.d.ts +3 -3
- package/dist/utils/internal/logger.d.ts.map +1 -1
- package/dist/utils/internal/logger.js +11 -5
- package/dist/utils/internal/logger.js.map +1 -1
- package/dist/utils/internal/performance.d.ts +1 -1
- package/dist/utils/internal/performance.d.ts.map +1 -1
- package/dist/utils/internal/performance.js +57 -13
- package/dist/utils/internal/performance.js.map +1 -1
- package/dist/utils/internal/requestContext.d.ts +79 -55
- package/dist/utils/internal/requestContext.d.ts.map +1 -1
- package/dist/utils/internal/requestContext.js +77 -32
- package/dist/utils/internal/requestContext.js.map +1 -1
- package/dist/utils/metrics/tokenCounter.d.ts +3 -3
- package/dist/utils/metrics/tokenCounter.d.ts.map +1 -1
- package/dist/utils/metrics/tokenCounter.js.map +1 -1
- package/dist/utils/network/fetchWithTimeout.d.ts +2 -2
- package/dist/utils/network/fetchWithTimeout.d.ts.map +1 -1
- package/dist/utils/network/fetchWithTimeout.js +8 -24
- package/dist/utils/network/fetchWithTimeout.js.map +1 -1
- package/dist/utils/network/retry.d.ts +2 -2
- package/dist/utils/network/retry.d.ts.map +1 -1
- package/dist/utils/overflow/outlineOnOverflow.d.ts +1 -1
- package/dist/utils/overflow/outlineOnOverflow.d.ts.map +1 -1
- package/dist/utils/pagination/pagination.d.ts +3 -3
- package/dist/utils/pagination/pagination.d.ts.map +1 -1
- package/dist/utils/pagination/pagination.js +3 -3
- package/dist/utils/pagination/pagination.js.map +1 -1
- package/dist/utils/parsing/csvParser.d.ts +2 -2
- package/dist/utils/parsing/csvParser.d.ts.map +1 -1
- package/dist/utils/parsing/csvParser.js +4 -8
- package/dist/utils/parsing/csvParser.js.map +1 -1
- package/dist/utils/parsing/dateParser.d.ts +3 -3
- package/dist/utils/parsing/dateParser.d.ts.map +1 -1
- package/dist/utils/parsing/dateParser.js +3 -2
- package/dist/utils/parsing/dateParser.js.map +1 -1
- package/dist/utils/parsing/frontmatterParser.d.ts +2 -2
- package/dist/utils/parsing/frontmatterParser.d.ts.map +1 -1
- package/dist/utils/parsing/frontmatterParser.js +7 -10
- package/dist/utils/parsing/frontmatterParser.js.map +1 -1
- package/dist/utils/parsing/htmlExtractor.d.ts +2 -2
- package/dist/utils/parsing/htmlExtractor.d.ts.map +1 -1
- package/dist/utils/parsing/htmlExtractor.js +6 -11
- package/dist/utils/parsing/htmlExtractor.js.map +1 -1
- package/dist/utils/parsing/jsonParser.d.ts +2 -2
- package/dist/utils/parsing/jsonParser.d.ts.map +1 -1
- package/dist/utils/parsing/jsonParser.js +4 -8
- package/dist/utils/parsing/jsonParser.js.map +1 -1
- package/dist/utils/parsing/pdfParser.d.ts +10 -10
- package/dist/utils/parsing/pdfParser.d.ts.map +1 -1
- package/dist/utils/parsing/pdfParser.js +26 -89
- package/dist/utils/parsing/pdfParser.js.map +1 -1
- package/dist/utils/parsing/xmlParser.d.ts +2 -2
- package/dist/utils/parsing/xmlParser.d.ts.map +1 -1
- package/dist/utils/parsing/xmlParser.js +4 -8
- package/dist/utils/parsing/xmlParser.js.map +1 -1
- package/dist/utils/parsing/yamlParser.d.ts +2 -2
- package/dist/utils/parsing/yamlParser.d.ts.map +1 -1
- package/dist/utils/parsing/yamlParser.js +4 -8
- package/dist/utils/parsing/yamlParser.js.map +1 -1
- package/dist/utils/scheduling/scheduler.d.ts.map +1 -1
- package/dist/utils/scheduling/scheduler.js +5 -6
- package/dist/utils/scheduling/scheduler.js.map +1 -1
- package/dist/utils/security/rateLimiter.d.ts +2 -2
- package/dist/utils/security/rateLimiter.d.ts.map +1 -1
- package/dist/utils/security/rateLimiter.js +1 -1
- package/dist/utils/security/rateLimiter.js.map +1 -1
- package/dist/utils/telemetry/attributes.d.ts +23 -7
- package/dist/utils/telemetry/attributes.d.ts.map +1 -1
- package/dist/utils/telemetry/attributes.js +23 -10
- package/dist/utils/telemetry/attributes.js.map +1 -1
- package/dist/utils/telemetry/trace.d.ts +3 -3
- package/dist/utils/telemetry/trace.d.ts.map +1 -1
- package/dist/utils/telemetry/trace.js +4 -2
- package/dist/utils/telemetry/trace.js.map +1 -1
- package/package.json +22 -26
- package/scripts/lint-mcp.ts +1 -3
- package/scripts/lint-packaging.ts +1 -1
- package/skills/add-service/SKILL.md +2 -2
- package/skills/add-test/SKILL.md +42 -20
- package/skills/add-tool/SKILL.md +68 -19
- package/skills/api-canvas/SKILL.md +2 -2
- package/skills/api-config/SKILL.md +1 -11
- package/skills/api-context/SKILL.md +175 -111
- package/skills/api-linter/SKILL.md +2 -2
- package/skills/api-telemetry/SKILL.md +8 -12
- package/skills/api-testing/SKILL.md +53 -52
- package/skills/code-simplifier/SKILL.md +2 -2
- package/skills/design-mcp-server/SKILL.md +34 -18
- package/skills/field-test/SKILL.md +4 -2
- package/skills/git-wrapup/SKILL.md +3 -3
- package/skills/polish-docs-meta/SKILL.md +1 -1
- package/skills/polish-docs-meta/references/agent-protocol.md +2 -2
- package/skills/polish-docs-meta/references/readme.md +1 -1
- package/skills/release-and-publish/SKILL.md +3 -1
- package/skills/report-issue-framework/SKILL.md +2 -2
- package/skills/report-issue-local/SKILL.md +2 -2
- package/skills/security-pass/SKILL.md +16 -14
- package/templates/.github/CODE_OF_CONDUCT.md +28 -0
- package/templates/.github/CONTRIBUTING.md +50 -0
- package/templates/.github/SECURITY.md +24 -0
- package/templates/AGENTS.md +6 -6
- package/templates/CLAUDE.md +6 -6
- package/templates/changelog/template.md +55 -16
- package/templates/tests/resources/echo.resource.test.ts +16 -9
- package/dist/mcp-server/elicitation.d.ts +0 -64
- package/dist/mcp-server/elicitation.d.ts.map +0 -1
- package/dist/mcp-server/elicitation.js +0 -81
- package/dist/mcp-server/elicitation.js.map +0 -1
- package/dist/mcp-server/protocolSession.d.ts +0 -34
- package/dist/mcp-server/protocolSession.d.ts.map +0 -1
- package/dist/mcp-server/protocolSession.js +0 -13
- package/dist/mcp-server/protocolSession.js.map +0 -1
- package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.d.ts +0 -53
- package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.d.ts.map +0 -1
- package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.js +0 -65
- package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.js.map +0 -1
- package/dist/mcp-server/tasks/core/sessionAwareTaskStore.d.ts +0 -70
- package/dist/mcp-server/tasks/core/sessionAwareTaskStore.d.ts.map +0 -1
- package/dist/mcp-server/tasks/core/sessionAwareTaskStore.js +0 -130
- package/dist/mcp-server/tasks/core/sessionAwareTaskStore.js.map +0 -1
- package/dist/mcp-server/tasks/core/storageBackedTaskStore.d.ts +0 -109
- package/dist/mcp-server/tasks/core/storageBackedTaskStore.d.ts.map +0 -1
- package/dist/mcp-server/tasks/core/storageBackedTaskStore.js +0 -209
- package/dist/mcp-server/tasks/core/storageBackedTaskStore.js.map +0 -1
- package/dist/mcp-server/tasks/core/taskManager.d.ts +0 -91
- package/dist/mcp-server/tasks/core/taskManager.d.ts.map +0 -1
- package/dist/mcp-server/tasks/core/taskManager.js +0 -210
- package/dist/mcp-server/tasks/core/taskManager.js.map +0 -1
- package/dist/mcp-server/tasks/core/taskTypes.d.ts +0 -18
- package/dist/mcp-server/tasks/core/taskTypes.d.ts.map +0 -1
- package/dist/mcp-server/tasks/core/taskTypes.js +0 -20
- package/dist/mcp-server/tasks/core/taskTypes.js.map +0 -1
- package/dist/mcp-server/tasks/utils/taskToolDefinition.d.ts +0 -101
- package/dist/mcp-server/tasks/utils/taskToolDefinition.d.ts.map +0 -1
- package/dist/mcp-server/tasks/utils/taskToolDefinition.js +0 -14
- package/dist/mcp-server/tasks/utils/taskToolDefinition.js.map +0 -1
package/skills/add-tool/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Scaffold a new MCP tool definition. Use when the user asks to add a tool, create a new tool, or implement a new capability for the server.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.18"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -16,8 +16,7 @@ Tools use the `tool()` builder from `@cyanheads/mcp-ts-core`. Each tool lives in
|
|
|
16
16
|
## Steps
|
|
17
17
|
|
|
18
18
|
1. **Gather** the tool's name, purpose, and input/output shape from the user's request — ask only if genuinely absent
|
|
19
|
-
2. **Determine if
|
|
20
|
-
multi-step async work, it should use `task: true`
|
|
19
|
+
2. **Determine if it needs input the caller may not supply** — a confirmation, a choice, the client's roots — which makes it a multi-round-trip handler (`ctx.requestInput` / `ctx.inputs`, see `api-context`)
|
|
21
20
|
3. **Create the file** at `src/mcp-server/tools/definitions/{{tool-name}}.tool.ts`
|
|
22
21
|
4. **Register** the tool in the project's existing `createApp()` tool list (directly in `src/index.ts` for fresh scaffolds, or via a barrel if the repo already has one)
|
|
23
22
|
5. **Run `bun run devcheck`** to verify — if Biome reports formatting issues, run `bun run format` to auto-fix, then re-run devcheck
|
|
@@ -130,31 +129,48 @@ export const {{TOOL_EXPORT}} = tool('{{tool_name}}', {
|
|
|
130
129
|
});
|
|
131
130
|
```
|
|
132
131
|
|
|
133
|
-
###
|
|
132
|
+
### Multi-round-trip variant
|
|
134
133
|
|
|
135
|
-
|
|
134
|
+
A handler that needs something the caller didn't supply returns `ctx.requestInput(...)` and is re-entered with the answers on `ctx.inputs`. There is no mid-handler `await` for user input, and no capability check — the surface is always present, on every transport and both protocol eras.
|
|
136
135
|
|
|
137
136
|
```typescript
|
|
137
|
+
import { inputRequired, tool, z } from '@cyanheads/mcp-ts-core';
|
|
138
|
+
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
139
|
+
|
|
140
|
+
const Confirm = z.object({ confirm: z.boolean().describe('Whether to proceed.') });
|
|
141
|
+
|
|
138
142
|
export const {{TOOL_EXPORT}} = tool('{{tool_name}}', {
|
|
139
143
|
description: '{{TOOL_DESCRIPTION}}',
|
|
140
|
-
task: true,
|
|
141
144
|
input: z.object({ /* ... */ }),
|
|
142
145
|
output: z.object({ /* ... */ }),
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
annotations: { destructiveHint: true },
|
|
147
|
+
|
|
148
|
+
handler(input, ctx) {
|
|
149
|
+
// Read what a prior round collected before asking for anything.
|
|
150
|
+
const answer = ctx.inputs.accepted('confirm', Confirm);
|
|
151
|
+
if (!answer) {
|
|
152
|
+
// A declined or cancelled prompt is a dead end — don't re-ask it.
|
|
153
|
+
const view = ctx.inputs.view('confirm');
|
|
154
|
+
if (view.kind === 'elicit' && view.action !== 'accept') {
|
|
155
|
+
throw validationError(`User ${view.action} the confirmation.`);
|
|
156
|
+
}
|
|
157
|
+
return ctx.requestInput({
|
|
158
|
+
inputRequests: {
|
|
159
|
+
confirm: inputRequired.elicit({
|
|
160
|
+
message: `Proceed with ${input.target}?`,
|
|
161
|
+
requestedSchema: Confirm,
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
});
|
|
152
165
|
}
|
|
166
|
+
// `answer` is narrowed here.
|
|
153
167
|
return { /* output */ };
|
|
154
168
|
},
|
|
155
169
|
});
|
|
156
170
|
```
|
|
157
171
|
|
|
172
|
+
Write it as `return ctx.requestInput(...)` — the `never` return type makes it valid in return position for any output, and it is what lets TypeScript narrow the line below. Full reference (`inputRequired.elicitUrl` / `.createMessage` / `.listRoots`, `requestState`, decline handling): `skills/api-context`.
|
|
173
|
+
|
|
158
174
|
### Registration
|
|
159
175
|
|
|
160
176
|
```typescript
|
|
@@ -208,7 +224,40 @@ export const submitObservations = getServerConfig().enableWrites
|
|
|
208
224
|
| `/.well-known/mcp.json` `definitions.tools` (Server Card) | **Yes**, with `disabled` field — discovery agents see them as present-but-uncallable |
|
|
209
225
|
| `/` (HTML landing page) | **Yes**, in a 4th muted bucket after `read \| write \| destructive` |
|
|
210
226
|
|
|
211
|
-
The wrapper
|
|
227
|
+
The wrapper preserves all original definition fields (handler, schemas, auth scopes, error contracts) — when re-enabled, the tool already conforms to every lint rule.
|
|
228
|
+
|
|
229
|
+
## Schemas: what the framework stores vs. what clients see
|
|
230
|
+
|
|
231
|
+
`tool()` and the handler factory do not hand your Zod schemas to the SDK verbatim. Two deliberate transforms sit in between.
|
|
232
|
+
|
|
233
|
+
### Input is strict
|
|
234
|
+
|
|
235
|
+
`tool()` stores `input` with `.strict()` applied, and the advertised `inputSchema` carries `additionalProperties: false` to match. An unrecognized argument key is **rejected by name** before the handler runs:
|
|
236
|
+
|
|
237
|
+
```text
|
|
238
|
+
Input validation error: Invalid arguments for tool <name>: Unrecognized key: "querry"
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
That arrives as an `isError: true` result, not a JSON-RPC error, and produces no framework span or log. The alternative — silently stripping the key — turns a caller's typo into a wrong answer they cannot detect: the value vanishes before the handler runs and the call fails downstream pointing at the wrong problem.
|
|
242
|
+
|
|
243
|
+
Two limits worth knowing when you write a schema:
|
|
244
|
+
|
|
245
|
+
- **Root level only**, matching `.strict()` itself. A nested `z.object()` inside the input still strips unknown keys unless it is strict in its own right — mark the nested option objects you want guarded.
|
|
246
|
+
- **An explicit opening wins.** A definition that declared `.passthrough()` or `.catchall(...)` asked for an open object, and `tool()` leaves it alone. Use that (deliberately) for tools that proxy arbitrary upstream query parameters.
|
|
247
|
+
|
|
248
|
+
### The advertised `outputSchema` is widened
|
|
249
|
+
|
|
250
|
+
The framework parses a successful result against the strict effective schema — `output`, extended with the `enrichment` block when one is declared — so a required field the handler never populated still fails loudly. What it *advertises* in `tools/list` is a widened projection of that schema: every success field optional, plus a declared `error` property describing the failure envelope.
|
|
251
|
+
|
|
252
|
+
The reason is client-side validation. A failing tool returns `structuredContent: { error: … }`, which can never satisfy a success-only schema; clients whose SDK validates `structuredContent` without first checking `isError` reject that envelope with `-32602` before the error ever reaches the agent. Widening the advertised schema is the only fix a server can ship, because the validator runs in the caller.
|
|
253
|
+
|
|
254
|
+
The root stays `type: 'object'` (a discriminated union would emit `anyOf` with no `type`, which the 2025-era legacy projection rewrites — breaking the success path to fix the error path). The `required` list that the object form drops is recovered by an `anyOf` refinement in schema metadata: a result must satisfy either the success branch (success fields present, no `error`) or the failure branch (`error` present).
|
|
255
|
+
|
|
256
|
+
Practical consequence: **do not read the advertised schema as the contract your handler must satisfy.** `output` is still the contract. The widened form is emission only.
|
|
257
|
+
|
|
258
|
+
`data.reason` inside that envelope stays an unconstrained string. An `errors[]` contract covers what the *handler* throws, but a service it calls can raise its own reason (the SQL gate's `denied_function`, a parser's `yaml_parse_failed`), and that reaches the wire verbatim — an enum of the declared reasons would reject precisely those envelopes, recreating the `-32602` the widening exists to prevent. The declared reasons are emitted as `examples` and spelled out in the description instead.
|
|
259
|
+
|
|
260
|
+
**`error` is a reserved output field name.** `tool()` throws if `output` or `enrichment` declares one: on the wire a failure *is* `structuredContent.error`, so a success payload using the same key cannot be told apart from a failure. Rename it (`errorText`, `failureDetail`).
|
|
212
261
|
|
|
213
262
|
## Tool Response Design
|
|
214
263
|
|
|
@@ -218,7 +267,7 @@ Tool responses are the LLM's only window into what happened. Every response shou
|
|
|
218
267
|
|
|
219
268
|
Empty-result notices, the query/filter as the server parsed it, pagination totals — the context an agent *reasons with*, as opposed to the domain payload itself — must reach **both** client surfaces: `structuredContent` (from `output`) and `content[]` (from `format()`). Hand-authored into `format()` text alone, this context reaches `content[]` but is invisible to `structuredContent`-only clients (Claude Code, MCP-SDK API callers).
|
|
220
269
|
|
|
221
|
-
Declare it as an `enrichment` block — the success-path counterpart to `errors[]` — and populate it via `ctx.enrich(...)` (or the kind-tagged helpers `ctx.enrich.notice()` / `.total()` / `.echo()`). The framework merges enrichment into `structuredContent`,
|
|
270
|
+
Declare it as an `enrichment` block — the success-path counterpart to `errors[]` — and populate it via `ctx.enrich(...)` (or the kind-tagged helpers `ctx.enrich.notice()` / `.total()` / `.echo()`). The framework merges enrichment into `structuredContent`, folds the block into the tool's advertised `outputSchema` (see [Schemas](#schemas-what-the-framework-stores-vs-what-clients-see)), and mirrors it into a `content[]` trailer — both surfaces, no `format()` entry, never touched by `format-parity`. `ctx.enrich` lives on the base `Context` (like `ctx.log`), so the service layer can populate it too.
|
|
222
271
|
|
|
223
272
|
```typescript
|
|
224
273
|
enrichment: {
|
|
@@ -673,8 +722,8 @@ return { items: hits };
|
|
|
673
722
|
- [ ] `auth` scopes declared if the tool needs authorization
|
|
674
723
|
- [ ] `errors: [...]` contract declared for the tool's domain-specific failure modes — or block deleted if no domain failures apply (baseline codes bubble freely)
|
|
675
724
|
- [ ] Error contract declared inline on this tool — not imported from a shared module, even when other tools have near-identical entries
|
|
676
|
-
- [ ]
|
|
677
|
-
- [ ] If
|
|
725
|
+
- [ ] Long loops check `ctx.signal.aborted` so a cancelled request (or a closed transport) stops the work
|
|
726
|
+
- [ ] If the tool needs caller input it may not have been given: reads `ctx.inputs` first, requests only what is missing via `return ctx.requestInput(...)`, and treats a declined/cancelled response as terminal rather than re-asking
|
|
678
727
|
- [ ] If tool returns unbounded arrays: pagination with total count, or `spillover()` / DataCanvas for *analytical* working sets (an agent would SQL them — not a discovery/search surface). If any tool emits a `canvas_id`, a `dataframe_query` tool is registered in the same server — a token with no query tool is dead output
|
|
679
728
|
- [ ] If tool returns one large *document* (not a row set) that can overflow context: `outlineOnOverflow()` returns a `full | outline` union so the agent re-calls with `sections: [...]` — not one-sided truncation
|
|
680
729
|
- [ ] If tool is feature-gated: evaluated whether `disabledTool()` wrapper is appropriate (present in manifest but uncallable)
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
DataCanvas primitive reference — a Tier 3 SQL/analytical workspace for tabular MCP servers, backed by DuckDB. Use when registering tables from upstream APIs, running ad-hoc SQL across them, and exporting results. Covers the acquire → register → query → export flow, per-table TTL, the token-sharing pattern for multi-agent collaboration, env config, and Cloudflare Workers fail-closed behavior.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.1"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -296,7 +296,7 @@ Most canvas use cases are public-data analytics: fetch from an upstream API, sta
|
|
|
296
296
|
| Table naming | `spillover()` auto-names the table `spilled_<id>`; pass `tableName` for a stable handle. A dataframe-query surface commonly adds its own `df_<id>` convention. |
|
|
297
297
|
| Access control | Possession of the `canvas_id` is access — unguessable in practice (see [token-sharing model](#the-token-sharing-model)). TTL + the framework rate limiter backstop brute force. |
|
|
298
298
|
| Enable flag | None of your own — canvas presence is the gate (`CANVAS_PROVIDER_TYPE=duckdb`; `getCanvas()` returns `undefined` otherwise). |
|
|
299
|
-
| Tools | A fetcher that spills **plus
|
|
299
|
+
| Tools | A fetcher that spills **plus the dataframe trio — all three ship whenever canvas is integrated**. `dataframe_query` is mandatory once anything emits a `canvas_id`: a token with no query tool in the same server is dead output (the agent can't reach the staged data). `dataframe_describe` is required alongside it — the agent discovers staged table and column names before writing SQL. `dataframe_drop` is implemented but **opt-in via a server env var**: when the flag is off, register it with `disabledTool()` (see `add-tool`) so it stays visible in the manifest with the enable hint while uncallable. None are framework-provided; you register them. |
|
|
300
300
|
| Fetcher output | Two things in one response: the inline preview (answer to the immediate question) and the table handle (escape hatch for follow-up SQL via `dataframe_query`). Neither replaces the other. |
|
|
301
301
|
|
|
302
302
|
> The `MCP_HTTP_MAX_BODY_BYTES` request-body cap is **inbound-only** — it bounds the JSON-RPC request, not the upstream data a handler stages into the canvas or the rows it returns. Canvas servers send small requests (queries, SQL, canvas IDs) regardless of dataset size, so the cap never constrains canvas ingestion.
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Reference for core and server configuration in `@cyanheads/mcp-ts-core`. Covers env var tables with defaults, priority order, server-specific Zod schema pattern, and Workers lazy-parsing requirement.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.10"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -177,16 +177,6 @@ Activated when both `SUPABASE_URL` and `SUPABASE_ANON_KEY` are set.
|
|
|
177
177
|
|
|
178
178
|
---
|
|
179
179
|
|
|
180
|
-
### Tasks
|
|
181
|
-
|
|
182
|
-
| Env Var | `AppConfig` field | Default | Notes |
|
|
183
|
-
|:--------|:-----------------|:--------|:------|
|
|
184
|
-
| `TASK_STORE_TYPE` | `tasks.storeType` | `in-memory` | `in-memory` \| `storage`; aliases: `mem`/`memory`→`in-memory`, `persistent`→`storage` |
|
|
185
|
-
| `TASK_STORE_TENANT_ID` | `tasks.tenantId` | `system-tasks` | Tenant ID for task state storage |
|
|
186
|
-
| `TASK_STORE_DEFAULT_TTL_MS` | `tasks.defaultTtlMs` | — | TTL for completed tasks (ms); null = no expiry |
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
180
|
### Speech (optional sub-object)
|
|
191
181
|
|
|
192
182
|
Activated when `SPEECH_TTS_ENABLED` or `SPEECH_STT_ENABLED` is set.
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-context
|
|
3
3
|
description: >
|
|
4
|
-
Canonical reference for the unified `Context` object passed to every tool and resource handler in `@cyanheads/mcp-ts-core`. Covers the full interface, all sub-APIs (`ctx.log`, `ctx.state`, `ctx.
|
|
4
|
+
Canonical reference for the unified `Context` object passed to every tool and resource handler in `@cyanheads/mcp-ts-core`. Covers the full interface, its `RequestContext` base, all sub-APIs (`ctx.log`, `ctx.state`, `ctx.requestInput`, `ctx.inputs`, `ctx.enrich`, `ctx.content`), and when to use each.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "
|
|
7
|
+
version: "2.0"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Overview
|
|
13
13
|
|
|
14
|
-
Every tool and resource handler receives a single `Context` (`ctx`) argument. It provides request identity, structured logging, tenant-scoped storage,
|
|
14
|
+
Every tool and resource handler receives a single `Context` (`ctx`) argument. It provides request identity, structured logging, tenant-scoped storage, multi-round-trip input collection, and cancellation — all auto-correlated to the current request.
|
|
15
15
|
|
|
16
16
|
The framework auto-instruments every handler call (OTel span, duration, payload metrics). Use `ctx.log` for domain-specific logging and `ctx.state` for storage inside handlers. Use the global `logger` and `StorageService` directly only in lifecycle/background code (`setup()`, services).
|
|
17
17
|
|
|
@@ -22,8 +22,8 @@ The framework auto-instruments every handler call (OTel span, duration, payload
|
|
|
22
22
|
```ts
|
|
23
23
|
import type { Context } from '@cyanheads/mcp-ts-core';
|
|
24
24
|
|
|
25
|
-
interface Context {
|
|
26
|
-
// Identity & tracing
|
|
25
|
+
interface Context extends RequestContext {
|
|
26
|
+
// Identity & tracing (inherited from RequestContext — see § RequestContext)
|
|
27
27
|
readonly requestId: string; // Unique per request, auto-generated
|
|
28
28
|
readonly timestamp: string; // ISO 8601 request start time
|
|
29
29
|
readonly tenantId?: string; // JWT 'tid' claim; 'default' for stdio and HTTP+MCP_AUTH_MODE=none
|
|
@@ -31,15 +31,19 @@ interface Context {
|
|
|
31
31
|
readonly traceId?: string; // OTEL trace ID (present when OTEL enabled)
|
|
32
32
|
readonly spanId?: string; // OTEL span ID (present when OTEL enabled)
|
|
33
33
|
readonly auth?: AuthContext; // Parsed auth claims (clientId, scopes, sub)
|
|
34
|
+
readonly operation?: string; // Label for the operation this context belongs to
|
|
35
|
+
readonly extra?: Readonly<Record<string, unknown>>; // Correlation bag — the one open field
|
|
34
36
|
|
|
35
|
-
// Structured logging — auto-includes requestId, traceId, tenantId
|
|
37
|
+
// Structured logging — auto-includes requestId, traceId, tenantId.
|
|
38
|
+
// Dual-sink: Pino on the server, plus notifications/message to the client.
|
|
36
39
|
readonly log: ContextLogger;
|
|
37
40
|
|
|
38
41
|
// Tenant-scoped key-value storage
|
|
39
42
|
readonly state: ContextState;
|
|
40
43
|
|
|
41
|
-
//
|
|
42
|
-
readonly
|
|
44
|
+
// Multi-round-trip input — always present, both eras (see § ctx.requestInput)
|
|
45
|
+
readonly requestInput: RequestInputFn; // (spec) => never — suspends and asks the caller
|
|
46
|
+
readonly inputs: ContextInputs; // reader over a retried request's responses
|
|
43
47
|
|
|
44
48
|
// List-changed / resource-updated notifications — wired in every handler ctx;
|
|
45
49
|
// delivery is request-scoped (see § list-changed notifications)
|
|
@@ -51,9 +55,6 @@ interface Context {
|
|
|
51
55
|
// Cancellation
|
|
52
56
|
readonly signal: AbortSignal;
|
|
53
57
|
|
|
54
|
-
// Task progress — present only when tool is defined with task: true
|
|
55
|
-
readonly progress?: ContextProgress;
|
|
56
|
-
|
|
57
58
|
// Raw URI — present only for resource handlers
|
|
58
59
|
readonly uri?: URL;
|
|
59
60
|
|
|
@@ -91,10 +92,65 @@ interface Context {
|
|
|
91
92
|
|
|
92
93
|
---
|
|
93
94
|
|
|
95
|
+
## `RequestContext` — the one canonical request shape
|
|
96
|
+
|
|
97
|
+
`Context extends RequestContext`. There is a single request-shape type; the handler-facing `Context` adds handler-only surfaces (`log`, `state`, `signal`, `requestInput`, `inputs`, `enrich`, `content`, `uri`) on top of it and redeclares none of the identity fields. A handler's `ctx` is therefore assignable anywhere a `RequestContext` is — services, storage, the framework logger — with no slice helper and no cast.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { requestContextService, withExtra } from '@cyanheads/mcp-ts-core/utils';
|
|
101
|
+
import type { RequestContext } from '@cyanheads/mcp-ts-core/utils';
|
|
102
|
+
|
|
103
|
+
// A service typed against RequestContext accepts a handler ctx directly.
|
|
104
|
+
async function fetchUser(id: string, ctx: RequestContext) { /* … */ }
|
|
105
|
+
await fetchUser('123', ctx); // ctx is a Context — no conversion
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Closed by design
|
|
109
|
+
|
|
110
|
+
`RequestContext` has **no index signature**. Its fields are exactly: `auth`, `extra`, `operation`, `requestId`, `sessionId`, `spanId`, `tenantId`, `timestamp`, `traceId`. A misspelled canonical field (`tenatId`) is a compile error instead of a silently-ignored key.
|
|
111
|
+
|
|
112
|
+
Operation-specific correlation data goes in **`extra`** — the one deliberate open bag (`Readonly<Record<string, unknown>>`). The logger flattens `extra` into the emitted line, so log output looks the same as a top-level spread.
|
|
113
|
+
|
|
114
|
+
### Adding correlation data
|
|
115
|
+
|
|
116
|
+
Three supported ways, most common first:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
// 1. Per-log-call metadata — the common case. Nothing lands on the context.
|
|
120
|
+
ctx.log.info('Retrying upstream call', { attempt, url });
|
|
121
|
+
|
|
122
|
+
// 2. A copy of this context carrying extra fields. `withExtra` MERGES into any
|
|
123
|
+
// bag the parent already had; a hand-written `{ ...ctx, extra: {…} }` replaces it.
|
|
124
|
+
logger.warning('Retrying upstream call', withExtra(ctx, { attempt, url }));
|
|
125
|
+
|
|
126
|
+
// 3. A derived context for a sub-operation. `additionalContext` lands on `extra`,
|
|
127
|
+
// merged over whatever the parent already carried.
|
|
128
|
+
const childCtx = requestContextService.createRequestContext({
|
|
129
|
+
parentContext: ctx,
|
|
130
|
+
operation: 'processItem',
|
|
131
|
+
additionalContext: { itemId: item.id }, // → childCtx.extra.itemId
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Reading an ad-hoc key back off a context:
|
|
135
|
+
const itemId = childCtx.extra?.itemId;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`createRequestContext(params)` takes a closed parameter object — `additionalContext`, `operation`, `parentContext`, `tenantId` — and nothing else; a key it doesn't declare is a compile error rather than an arbitrary passthrough.
|
|
139
|
+
|
|
140
|
+
Never re-open the shape to get past a type error: no index signature, no widening a parameter back to `Record<string, unknown>`, no `as` cast. A `{ ...ctx, someKey }` object literal that fails to compile is the signal to move `someKey` into `extra`, not to loosen the type.
|
|
141
|
+
|
|
142
|
+
`ErrorContext` (the `ErrorHandler` call's `context`) is `Partial<RequestContext>` and is closed the same way — put ad-hoc keys under `extra` via `withExtra`, or pass them in the `ErrorHandler` call's own `context` field.
|
|
143
|
+
|
|
144
|
+
`RequestContextLike` is a deprecated alias for `RequestContext`, kept for one minor. Replace every use with `RequestContext`, and collapse any `RequestContextLike | RequestContext` parameter union to plain `RequestContext`.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
94
148
|
## `ctx.log`
|
|
95
149
|
|
|
96
150
|
Request-scoped structured logger. Every log line is automatically annotated with `requestId`, `traceId`, and `tenantId` — no manual spreading needed.
|
|
97
151
|
|
|
152
|
+
**Dual-sink.** Each call writes to Pino *and* mirrors onto the MCP wire as a `notifications/message` (the framework advertises the `logging` capability, and the SDK filters by the level the client set via `logging/setLevel`). The wire payload is `{ message, ...data }`; `ctx.log.error` adds `error: <message>`. Delivery is fire-and-forget — a client that never upgraded to SSE, set a higher level, or already disconnected drops the notification, and a failed send never fails the handler. Treat `ctx.log` as client-visible: it is no longer a server-only sink, so don't log anything there you wouldn't put in a tool result.
|
|
153
|
+
|
|
98
154
|
### Methods
|
|
99
155
|
|
|
100
156
|
| Method | Level |
|
|
@@ -255,71 +311,120 @@ await ctx.state.set(sessionKey, value);
|
|
|
255
311
|
### Behavior notes
|
|
256
312
|
|
|
257
313
|
- **Not a tenant boundary.** `ctx.state` is still tenant-scoped. Building session-scoped state is the consumer's responsibility — prefix with `session/${ctx.sessionId}/` as shown above.
|
|
258
|
-
- **
|
|
314
|
+
- **Protocol revision.** Sessions belong to the 2025-era arm, which negotiates its revision through `initialize` and carries `Mcp-Session-Id`. The [2026-07-28 revision](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports) has no session at all — it is per-request, selected by the request's own `_meta` envelope — so `ctx.sessionId` is `undefined` for every request served on that leg.
|
|
259
315
|
- **Worker bundle.** Workers use the same HTTP transport plumbing; session behavior matches Node HTTP.
|
|
260
316
|
|
|
261
317
|
---
|
|
262
318
|
|
|
263
|
-
## `ctx.
|
|
319
|
+
## `ctx.requestInput` / `ctx.inputs`
|
|
320
|
+
|
|
321
|
+
Always present, on every transport and both protocol eras. A handler that needs something the caller didn't supply **returns** `ctx.requestInput(...)` and is re-entered with the answers on `ctx.inputs` — there is no mid-handler `await` for user input.
|
|
264
322
|
|
|
265
|
-
|
|
323
|
+
`ctx.requestInput(spec)` never returns: it throws an `InputRequiredSignal` that the tool, resource, and prompt handler factories catch and convert into the protocol's [`input_required`](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr) result. It bypasses the error classifier entirely — no span, no log, no `isError`.
|
|
266
324
|
|
|
267
|
-
|
|
325
|
+
One code path serves both eras. A 2026-07-28 client fulfils the embedded requests and retries the call; for a 2025-era session the SDK's legacy shim fulfils the same returns by issuing real `elicitation/create` / `sampling/createMessage` / `roots/list` round trips and re-entering the handler itself.
|
|
268
326
|
|
|
269
|
-
###
|
|
327
|
+
### The shape of a multi-round-trip handler
|
|
270
328
|
|
|
271
|
-
|
|
329
|
+
Read `ctx.inputs` first, request only what is still missing, and write the call in return position so TypeScript narrows the line below it.
|
|
272
330
|
|
|
273
331
|
```ts
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
332
|
+
import { inputRequired, tool, z } from '@cyanheads/mcp-ts-core';
|
|
333
|
+
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
334
|
+
|
|
335
|
+
const Confirm = z.object({
|
|
336
|
+
confirm: z.boolean().describe('Whether to proceed with the deletion.'),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
export const deletePath = tool('delete_path', {
|
|
340
|
+
description: 'Delete a path after confirming with the user.',
|
|
341
|
+
input: z.object({ path: z.string().describe('Path to delete') }),
|
|
342
|
+
output: z.object({ deleted: z.string().describe('The path that was deleted') }),
|
|
343
|
+
annotations: { destructiveHint: true },
|
|
344
|
+
|
|
345
|
+
handler(input, ctx) {
|
|
346
|
+
// A declined or cancelled prompt is a dead end, not a round to retry —
|
|
347
|
+
// re-asking loops until the round budget runs out.
|
|
348
|
+
const view = ctx.inputs.view('confirm');
|
|
349
|
+
if (view.kind === 'elicit' && view.action !== 'accept') {
|
|
350
|
+
throw validationError(`User ${view.action} the confirmation.`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const answer = ctx.inputs.accepted('confirm', Confirm);
|
|
354
|
+
if (!answer) {
|
|
355
|
+
return ctx.requestInput({
|
|
356
|
+
inputRequests: {
|
|
357
|
+
confirm: inputRequired.elicit({
|
|
358
|
+
message: `Delete ${input.path}?`,
|
|
359
|
+
requestedSchema: Confirm,
|
|
360
|
+
}),
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
// `answer` is narrowed here.
|
|
365
|
+
if (!answer.confirm) throw validationError('Deletion not confirmed.');
|
|
366
|
+
|
|
367
|
+
return { deleted: remove(input.path) };
|
|
368
|
+
},
|
|
369
|
+
});
|
|
291
370
|
```
|
|
292
371
|
|
|
293
|
-
`
|
|
372
|
+
`ctx.requestInput` returns `never`, so `return ctx.requestInput(...)` type-checks against any output type. Calling it as a bare statement works at runtime — and is the only option from a service-layer helper — but TypeScript will not narrow across it.
|
|
373
|
+
|
|
374
|
+
### Building the embedded requests
|
|
375
|
+
|
|
376
|
+
`inputRequired` is re-exported from the main entry. Its per-kind constructors build the entries of `inputRequests`:
|
|
377
|
+
|
|
378
|
+
| Constructor | Wire request | Notes |
|
|
379
|
+
|:---|:---|:---|
|
|
380
|
+
| `inputRequired.elicit({ message, requestedSchema })` | `elicitation/create` (form) | `requestedSchema` accepts a Zod schema; shapes the restricted elicitation JSON Schema can't express throw a `TypeError` before anything is sent |
|
|
381
|
+
| `inputRequired.elicitUrl({ message, url })` | `elicitation/create` (URL) | Authorization flows, hosted forms. On 2026-07-28 URL mode rides the same multi-round-trip flow; the 2025-era `elicitationId` is not part of that shape — correlate with your own identifier inside `requestState` |
|
|
382
|
+
| `inputRequired.createMessage(params)` | `sampling/createMessage` | Ask the client's model |
|
|
383
|
+
| `inputRequired.listRoots()` | `roots/list` | Ask for the client's filesystem roots |
|
|
384
|
+
|
|
385
|
+
At least one of `inputRequests` or `requestState` must be supplied — the builder throws a `TypeError` otherwise.
|
|
386
|
+
|
|
387
|
+
### `requestState` — carrying server state across rounds
|
|
294
388
|
|
|
295
389
|
```ts
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
390
|
+
return ctx.requestInput({
|
|
391
|
+
inputRequests: { confirm: inputRequired.elicit({ message, requestedSchema: Confirm }) },
|
|
392
|
+
requestState: JSON.stringify({ jobId }),
|
|
393
|
+
});
|
|
394
|
+
// Next round:
|
|
395
|
+
const state = ctx.inputs.state<string>();
|
|
302
396
|
```
|
|
303
397
|
|
|
304
|
-
|
|
398
|
+
`requestState` round-trips **through the client** and comes back as attacker-controlled input. Integrity-protect (HMAC/AEAD) anything that influences authorization, resource access, or business logic, and reject state that fails verification — the SDK does not do this for you.
|
|
399
|
+
|
|
400
|
+
### `ctx.inputs` — reading a retried request's responses
|
|
401
|
+
|
|
402
|
+
Empty on the first round; populated on re-entry.
|
|
403
|
+
|
|
404
|
+
| Member | Returns |
|
|
405
|
+
|:---|:---|
|
|
406
|
+
| `accepted(key, schema?)` | The accepted form-mode content for `key`, or `undefined` when the key is missing, the user declined or cancelled, the response was another kind, or (with a schema) validation failed |
|
|
407
|
+
| `view(key)` | Discriminated view of one entry: `{ kind: 'missing' }` \| `{ kind: 'elicit', action, content? }` \| `{ kind: 'sampling', result }` \| `{ kind: 'roots', roots }` |
|
|
408
|
+
| `state<T>()` | This round's `requestState` — verified value, raw wire string when no verifier is configured, or `undefined` on the first round |
|
|
409
|
+
| `dropped` | Keys the SDK dropped because the client sent a wrapped rather than a bare response object. Re-issue those requests instead of hard-failing |
|
|
410
|
+
| `responses` | The raw response map, for kinds the helpers don't cover |
|
|
411
|
+
|
|
412
|
+
Two rules follow from what the SDK does *not* do:
|
|
413
|
+
|
|
414
|
+
- **Responses are never re-validated against the schema the request advertised.** Pass the schema to `accepted(key, schema)` wherever the content matters, and treat every value as untrusted client input.
|
|
415
|
+
- **`undefined` from `accepted()` collapses five different outcomes into one.** Missing, declined, cancelled, wrong response kind, and schema-invalid are indistinguishable through it. Branch on `view(key)` when decline/cancel needs different handling from "not asked yet" — as above, re-issuing a request the user already declined just burns rounds.
|
|
305
416
|
|
|
306
|
-
###
|
|
417
|
+
### Testing
|
|
307
418
|
|
|
308
|
-
|
|
419
|
+
`createMockContext({ inputResponses, requestState })` seeds `ctx.inputs`, so a handler can be driven straight into its second round:
|
|
309
420
|
|
|
310
421
|
```ts
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
'https://example.com/oauth/authorize?state=...',
|
|
315
|
-
);
|
|
316
|
-
if (result.action !== 'accept') throw forbidden('Authorization declined');
|
|
317
|
-
}
|
|
422
|
+
const ctx = createMockContext({
|
|
423
|
+
inputResponses: { confirm: { action: 'accept', content: { confirm: true } } },
|
|
424
|
+
});
|
|
318
425
|
```
|
|
319
426
|
|
|
320
|
-
`
|
|
321
|
-
|
|
322
|
-
**Convention:** Only call `ctx.elicit` from tool handlers, not from services.
|
|
427
|
+
**Convention:** only call `ctx.requestInput` from tool, resource, and prompt handlers — not from services.
|
|
323
428
|
|
|
324
429
|
---
|
|
325
430
|
|
|
@@ -342,15 +447,21 @@ A notification fired **from inside a handler** routes through that request's own
|
|
|
342
447
|
| Fired from | stdio | HTTP / Workers |
|
|
343
448
|
|:-----------|:------|:---------------|
|
|
344
449
|
| A tool / resource handler | ✅ delivered | ✅ delivered (on the request's SSE response stream) |
|
|
345
|
-
| A `
|
|
450
|
+
| A `setup()` hook, cron job, or any non-request scope | ✅ delivered | ⚠️ dropped — no request scope to route through |
|
|
451
|
+
|
|
452
|
+
The background-under-HTTP gap is a known limitation; a session-scoped notification bus would close it.
|
|
453
|
+
|
|
454
|
+
### `notifyResourceUpdated` is subscription-scoped
|
|
346
455
|
|
|
347
|
-
The
|
|
456
|
+
The framework advertises `resources: { subscribe: true }` and backs it with real `resources/subscribe` / `resources/unsubscribe` handlers, so `notifyResourceUpdated(uri)` emits only for URIs the connected client actually subscribed to; an unsubscribed URI logs at debug and sends nothing. Both handlers are idempotent — re-subscribing is a no-op, and unsubscribing from a URI that was never subscribed succeeds.
|
|
457
|
+
|
|
458
|
+
The registry's scope is the `McpServer` instance, which is also the connection: one persistent instance per session on the 2025-era sessionful arm, one per request under per-request serving. On the per-request leg a subscription cannot outlive the request that created it, so a handler-time `ctx.notifyResourceUpdated(uri)` delivers only when that same exchange subscribed first.
|
|
348
459
|
|
|
349
460
|
---
|
|
350
461
|
|
|
351
462
|
## `ctx.signal`
|
|
352
463
|
|
|
353
|
-
Standard `AbortSignal`. Present on every context.
|
|
464
|
+
Standard `AbortSignal`. Present on every context. Fires when the client cancels the request — and when the transport closes, which aborts every in-flight handler.
|
|
354
465
|
|
|
355
466
|
```ts
|
|
356
467
|
// Check before expensive operations
|
|
@@ -366,55 +477,6 @@ for (const item of items) {
|
|
|
366
477
|
}
|
|
367
478
|
```
|
|
368
479
|
|
|
369
|
-
In task tools (`task: true`), the framework signals `ctx.signal` when the client sends a cancellation request.
|
|
370
|
-
|
|
371
|
-
---
|
|
372
|
-
|
|
373
|
-
## `ctx.progress`
|
|
374
|
-
|
|
375
|
-
Present only when the tool definition includes `task: true`. Undefined for standard (non-task) tools and all resource handlers.
|
|
376
|
-
|
|
377
|
-
### Methods
|
|
378
|
-
|
|
379
|
-
| Method | Purpose |
|
|
380
|
-
|:-------|:--------|
|
|
381
|
-
| `ctx.progress.setTotal(n)` | Set the total number of steps (enables percentage calculation on client) |
|
|
382
|
-
| `ctx.progress.increment(amount?)` | Advance progress by `amount` (default: 1) |
|
|
383
|
-
| `ctx.progress.update(message)` | Send a descriptive status message without advancing the counter |
|
|
384
|
-
|
|
385
|
-
### Usage
|
|
386
|
-
|
|
387
|
-
```ts
|
|
388
|
-
const asyncCountdown = tool('async_countdown', {
|
|
389
|
-
description: 'Count down from a number with progress updates.',
|
|
390
|
-
task: true,
|
|
391
|
-
input: z.object({
|
|
392
|
-
count: z.number().int().positive().describe('Number to count down from'),
|
|
393
|
-
delayMs: z.number().default(1000).describe('Delay between counts in ms'),
|
|
394
|
-
}),
|
|
395
|
-
output: z.object({
|
|
396
|
-
finalCount: z.number().describe('Final count value'),
|
|
397
|
-
message: z.string().describe('Completion message'),
|
|
398
|
-
}),
|
|
399
|
-
|
|
400
|
-
async handler(input, ctx) {
|
|
401
|
-
await ctx.progress!.setTotal(input.count);
|
|
402
|
-
|
|
403
|
-
for (let i = input.count; i > 0; i--) {
|
|
404
|
-
if (ctx.signal.aborted) break;
|
|
405
|
-
|
|
406
|
-
await ctx.progress!.update(`Counting: ${i}`);
|
|
407
|
-
await new Promise(resolve => setTimeout(resolve, input.delayMs));
|
|
408
|
-
await ctx.progress!.increment();
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
return { finalCount: 0, message: 'Countdown complete' };
|
|
412
|
-
},
|
|
413
|
-
});
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
**Note:** Use the non-null assertion (`ctx.progress!`) when accessing inside a `task: true` handler — the type is `ContextProgress | undefined` even though it's guaranteed present at runtime. TypeScript cannot narrow based on the `task` flag.
|
|
417
|
-
|
|
418
480
|
---
|
|
419
481
|
|
|
420
482
|
## `ctx.uri`
|
|
@@ -548,7 +610,7 @@ The `≥5 words` lint rule on contract `recovery` (validated at lint time) makes
|
|
|
548
610
|
|
|
549
611
|
## `ctx.enrich`
|
|
550
612
|
|
|
551
|
-
Always present on `Context`. Accumulates agent-facing **success-path** context — empty-result notices, the query/filter as the server parsed it, pagination totals — onto the request. The framework merges it into `structuredContent`,
|
|
613
|
+
Always present on `Context`. Accumulates agent-facing **success-path** context — empty-result notices, the query/filter as the server parsed it, pagination totals — onto the request. The framework merges it into `structuredContent`, folds the `enrichment` block into the tool's advertised `outputSchema`, and mirrors it into a `content[]` trailer. The success-path counterpart to `ctx.fail` / `ctx.recoveryFor`.
|
|
552
614
|
|
|
553
615
|
```ts
|
|
554
616
|
export const search = tool('search', {
|
|
@@ -698,21 +760,23 @@ Test content blocks with `getContentBlocks(ctx)` from `@cyanheads/mcp-ts-core/te
|
|
|
698
760
|
| `ctx.requestId` | `string` | Always |
|
|
699
761
|
| `ctx.timestamp` | `string` | Always |
|
|
700
762
|
| `ctx.tenantId` | `string \| undefined` | Stdio (`'default'`); HTTP+`MCP_AUTH_MODE=none` (`'default'`); HTTP+`jwt`/`oauth` (JWT `tid` claim — undefined if absent) |
|
|
701
|
-
| `ctx.sessionId` | `string \| undefined` | HTTP `stateful` / `auto` mode; stateless HTTP only when `createApp({ context: { exposeStatelessSessionId: true } })`; never in stdio or
|
|
763
|
+
| `ctx.sessionId` | `string \| undefined` | HTTP `stateful` / `auto` mode; stateless HTTP only when `createApp({ context: { exposeStatelessSessionId: true } })`; never in stdio or on the session-less 2026-07-28 leg |
|
|
702
764
|
| `ctx.traceId` | `string \| undefined` | OTEL enabled |
|
|
703
765
|
| `ctx.spanId` | `string \| undefined` | OTEL enabled |
|
|
704
766
|
| `ctx.auth` | `AuthContext \| undefined` | Auth enabled |
|
|
767
|
+
| `ctx.operation` | `string \| undefined` | Set by the context that created it (`'HandleToolRequest'` for tool calls) |
|
|
768
|
+
| `ctx.extra` | `Readonly<Record<string, unknown>> \| undefined` | When correlation data was attached — the one open bag on the closed shape |
|
|
705
769
|
| `ctx.log` | `ContextLogger` | Always |
|
|
706
770
|
| `ctx.state` | `ContextState` | Always (throws if `tenantId` missing) |
|
|
707
771
|
| `ctx.signal` | `AbortSignal` | Always |
|
|
708
772
|
| `ctx.enrich` | `Enrich` | Always; typed on `HandlerContext<R, E>` when an `enrichment` block is declared |
|
|
709
773
|
| `ctx.content` | `ContentCollect` | Always — prepends image/audio blocks to `content[]`, never `structuredContent` |
|
|
710
|
-
| `ctx.
|
|
774
|
+
| `ctx.requestInput` | `(spec) => never` | Always — suspends the handler and asks the caller for more input |
|
|
775
|
+
| `ctx.inputs` | `ContextInputs` | Always; empty until the request is retried with responses |
|
|
711
776
|
| `ctx.notifyResourceListChanged` | `function \| undefined` | Always in handler ctx; delivery request-scoped (see [§ list-changed notifications](#list-changed-notifications-ctxnotify)) |
|
|
712
|
-
| `ctx.notifyResourceUpdated` | `function \| undefined` | Always in handler ctx; delivery request-scoped |
|
|
777
|
+
| `ctx.notifyResourceUpdated` | `function \| undefined` | Always in handler ctx; delivery request-scoped **and** limited to URIs the client subscribed to |
|
|
713
778
|
| `ctx.notifyPromptListChanged` | `function \| undefined` | Always in handler ctx; delivery request-scoped |
|
|
714
779
|
| `ctx.notifyToolListChanged` | `function \| undefined` | Always in handler ctx; delivery request-scoped |
|
|
715
|
-
| `ctx.progress` | `ContextProgress \| undefined` | Tool defined with `task: true` |
|
|
716
780
|
| `ctx.uri` | `URL \| undefined` | Resource handlers only |
|
|
717
781
|
| `ctx.fail` | `(reason, msg?, data?, opts?) => McpError` | Definition declares `errors[]` contract |
|
|
718
782
|
| `ctx.recoveryFor` | `(reason) => { recovery: { hint } } \| {}` | Always (no-op when no contract); strictly typed on `HandlerContext<R>` |
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
MCP definition linter rules reference. Use when `bun run lint:mcp` or `bun run devcheck` reports a lint error or warning (`format-parity`, `schema-is-object`, `name-format`, `server-json-*`, etc.) and you need to understand the rule, its severity, and how to fix it. Every rule ID the linter emits has an entry in this doc.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.10"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -789,7 +789,7 @@ The diagnostic message includes the declared reason(s) for the code so you can c
|
|
|
789
789
|
|
|
790
790
|
## Enrichment rules
|
|
791
791
|
|
|
792
|
-
Validate the `enrichment` block — the success-path counterpart to `errors[]`. Enrichment fields are merged into `structuredContent` and advertised
|
|
792
|
+
Validate the `enrichment` block — the success-path counterpart to `errors[]`. Enrichment fields are merged into `structuredContent` and folded into the advertised `outputSchema`, so the linter guards the block's shape and its disjointness from `output`. See `api-context`'s `ctx.enrich` and `add-tool`'s **Tool Response Design**.
|
|
793
793
|
|
|
794
794
|
### enrichment-type
|
|
795
795
|
|