memory-journal-mcp 7.7.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -56
- package/dist/chunk-6OHRCNYW.js +3231 -0
- package/dist/chunk-JFMITANR.js +5168 -0
- package/dist/{chunk-QCQPAF4I.js → chunk-MWNLAEHR.js} +301 -4321
- package/dist/{chunk-ARLYSFSI.js → chunk-UHSO65A4.js} +4242 -6092
- package/dist/cli.js +21 -3
- package/dist/index.d.ts +16 -13
- package/dist/index.js +4 -2
- package/dist/resources-IJVKDFGS.js +2 -0
- package/dist/tools-44DGXE3V.js +2 -0
- package/dist/worker-script.js +201 -20
- package/package.json +7 -4
- package/skills/README.md +62 -25
- package/skills/adversarial-performance/SKILL.md +139 -0
- package/skills/adversarial-performance/references/audit-categories.md +462 -0
- package/skills/adversarial-performance/references/copilot-performance-prompts.md +44 -0
- package/skills/adversarial-performance/references/copilot-usage.md +16 -0
- package/skills/adversarial-performance/references/feedback-loop.md +177 -0
- package/skills/adversarial-performance/references/multi-pass-performance-protocol.md +398 -0
- package/skills/adversarial-planner/SKILL.md +23 -54
- package/skills/adversarial-planner/references/copilot-integration.md +25 -40
- package/skills/adversarial-planner/references/copilot-usage.md +16 -0
- package/skills/adversarial-planner/references/multi-pass-protocol.md +4 -0
- package/skills/adversarial-security/SKILL.md +149 -0
- package/skills/adversarial-security/references/adversarial-base-protocol.md +44 -0
- package/skills/adversarial-security/references/audit-categories.md +723 -0
- package/skills/adversarial-security/references/copilot-security-prompts.md +142 -0
- package/skills/adversarial-security/references/copilot-usage.md +16 -0
- package/skills/adversarial-security/references/feedback-loop.md +206 -0
- package/skills/adversarial-security/references/journal-opt-out.md +7 -0
- package/skills/adversarial-security/references/multi-pass-security-protocol.md +403 -0
- package/skills/adversarial-skill-audit/SKILL.md +118 -0
- package/skills/adversarial-skill-audit/references/audit-categories.md +308 -0
- package/skills/adversarial-skill-audit/references/copilot-skill-prompts.md +68 -0
- package/skills/adversarial-skill-audit/references/copilot-usage.md +16 -0
- package/skills/adversarial-skill-audit/references/feedback-loop.md +155 -0
- package/skills/adversarial-skill-audit/references/multi-pass-skill-protocol.md +367 -0
- package/skills/adversarial-skill-audit/scripts/check-skills.ps1 +48 -0
- package/skills/adversarial-skill-audit/scripts/run-copilot.ps1 +52 -0
- package/skills/adversarial-workflow-audit/SKILL.md +82 -0
- package/skills/adversarial-workflow-audit/references/audit-categories.md +28 -0
- package/skills/adversarial-workflow-audit/references/copilot-usage.md +16 -0
- package/skills/adversarial-workflow-audit/scripts/check-workflows.ps1 +24 -0
- package/skills/agents-sdk/SKILL.md +220 -0
- package/skills/agents-sdk/references/callable.md +92 -0
- package/skills/agents-sdk/references/codemode.md +209 -0
- package/skills/agents-sdk/references/email.md +144 -0
- package/skills/agents-sdk/references/mcp/SKILL.md +65 -0
- package/skills/agents-sdk/references/mcp/code-mode-reference.md +245 -0
- package/skills/agents-sdk/references/mcp/oauth-reference.md +359 -0
- package/skills/agents-sdk/references/mcp/references/architecture-reference.md +208 -0
- package/skills/agents-sdk/references/mcp/references/cloudflare-quickstart.md +156 -0
- package/skills/agents-sdk/references/mcp/references/error-handling.md +343 -0
- package/skills/agents-sdk/references/mcp/references/http-security.md +164 -0
- package/skills/agents-sdk/references/mcp/references/implementation-guide.md +507 -0
- package/skills/agents-sdk/references/mcp/references/testing-reference.md +171 -0
- package/skills/agents-sdk/references/mcp.md +157 -0
- package/skills/agents-sdk/references/state-scheduling.md +164 -0
- package/skills/agents-sdk/references/streaming-chat.md +168 -0
- package/skills/agents-sdk/references/workflows.md +136 -0
- package/skills/auth-identity/SKILL.md +48 -0
- package/skills/autonomous-dev/SKILL.md +46 -23
- package/skills/autonomous-dev/references/workflow_orchestration.md +22 -0
- package/skills/aws/SKILL.md +39 -0
- package/skills/azure/SKILL.md +38 -0
- package/skills/bin/sync.js +7 -1
- package/skills/biome/SKILL.md +59 -0
- package/skills/bun/SKILL.md +8 -2
- package/skills/cloudflare/SKILL.md +37 -0
- package/skills/cloudflare/references/agents-sdk/README.md +95 -0
- package/skills/cloudflare/references/agents-sdk/api.md +195 -0
- package/skills/cloudflare/references/agents-sdk/configuration.md +178 -0
- package/skills/cloudflare/references/agents-sdk/gotchas.md +173 -0
- package/skills/cloudflare/references/agents-sdk/patterns.md +215 -0
- package/skills/cloudflare/references/ai-gateway/README.md +176 -0
- package/skills/cloudflare/references/ai-gateway/configuration.md +117 -0
- package/skills/cloudflare/references/ai-gateway/dynamic-routing.md +88 -0
- package/skills/cloudflare/references/ai-gateway/features.md +96 -0
- package/skills/cloudflare/references/ai-gateway/sdk-integration.md +110 -0
- package/skills/cloudflare/references/ai-gateway/troubleshooting.md +90 -0
- package/skills/cloudflare/references/ai-search/README.md +145 -0
- package/skills/cloudflare/references/ai-search/api.md +87 -0
- package/skills/cloudflare/references/ai-search/configuration.md +91 -0
- package/skills/cloudflare/references/ai-search/gotchas.md +92 -0
- package/skills/cloudflare/references/ai-search/patterns.md +87 -0
- package/skills/cloudflare/references/analytics-engine/README.md +96 -0
- package/skills/cloudflare/references/analytics-engine/api.md +112 -0
- package/skills/cloudflare/references/analytics-engine/configuration.md +107 -0
- package/skills/cloudflare/references/analytics-engine/gotchas.md +87 -0
- package/skills/cloudflare/references/analytics-engine/patterns.md +83 -0
- package/skills/cloudflare/references/api/README.md +66 -0
- package/skills/cloudflare/references/api/api.md +205 -0
- package/skills/cloudflare/references/api/configuration.md +158 -0
- package/skills/cloudflare/references/api/gotchas.md +231 -0
- package/skills/cloudflare/references/api/patterns.md +208 -0
- package/skills/cloudflare/references/api-shield/README.md +44 -0
- package/skills/cloudflare/references/api-shield/api.md +153 -0
- package/skills/cloudflare/references/api-shield/configuration.md +210 -0
- package/skills/cloudflare/references/api-shield/gotchas.md +132 -0
- package/skills/cloudflare/references/api-shield/patterns.md +185 -0
- package/skills/cloudflare/references/argo-smart-routing/README.md +96 -0
- package/skills/cloudflare/references/argo-smart-routing/api.md +253 -0
- package/skills/cloudflare/references/argo-smart-routing/configuration.md +205 -0
- package/skills/cloudflare/references/argo-smart-routing/gotchas.md +115 -0
- package/skills/cloudflare/references/argo-smart-routing/patterns.md +107 -0
- package/skills/cloudflare/references/bindings/README.md +127 -0
- package/skills/cloudflare/references/bindings/api.md +214 -0
- package/skills/cloudflare/references/bindings/configuration.md +200 -0
- package/skills/cloudflare/references/bindings/gotchas.md +210 -0
- package/skills/cloudflare/references/bindings/patterns.md +205 -0
- package/skills/cloudflare/references/bot-management/README.md +95 -0
- package/skills/cloudflare/references/bot-management/api.md +175 -0
- package/skills/cloudflare/references/bot-management/configuration.md +175 -0
- package/skills/cloudflare/references/bot-management/gotchas.md +116 -0
- package/skills/cloudflare/references/bot-management/patterns.md +181 -0
- package/skills/cloudflare/references/browser-rendering/README.md +84 -0
- package/skills/cloudflare/references/browser-rendering/api.md +108 -0
- package/skills/cloudflare/references/browser-rendering/configuration.md +78 -0
- package/skills/cloudflare/references/browser-rendering/gotchas.md +91 -0
- package/skills/cloudflare/references/browser-rendering/patterns.md +93 -0
- package/skills/cloudflare/references/c3/README.md +111 -0
- package/skills/cloudflare/references/c3/api.md +71 -0
- package/skills/cloudflare/references/c3/configuration.md +85 -0
- package/skills/cloudflare/references/c3/gotchas.md +97 -0
- package/skills/cloudflare/references/c3/patterns.md +84 -0
- package/skills/cloudflare/references/cache-reserve/README.md +150 -0
- package/skills/cloudflare/references/cache-reserve/api.md +184 -0
- package/skills/cloudflare/references/cache-reserve/configuration.md +170 -0
- package/skills/cloudflare/references/cache-reserve/gotchas.md +136 -0
- package/skills/cloudflare/references/cache-reserve/patterns.md +197 -0
- package/skills/cloudflare/references/containers/README.md +87 -0
- package/skills/cloudflare/references/containers/api.md +197 -0
- package/skills/cloudflare/references/containers/configuration.md +191 -0
- package/skills/cloudflare/references/containers/gotchas.md +182 -0
- package/skills/cloudflare/references/containers/patterns.md +204 -0
- package/skills/cloudflare/references/cron-triggers/README.md +101 -0
- package/skills/cloudflare/references/cron-triggers/api.md +224 -0
- package/skills/cloudflare/references/cron-triggers/configuration.md +190 -0
- package/skills/cloudflare/references/cron-triggers/gotchas.md +207 -0
- package/skills/cloudflare/references/cron-triggers/patterns.md +274 -0
- package/skills/cloudflare/references/d1/README.md +137 -0
- package/skills/cloudflare/references/d1/api.md +213 -0
- package/skills/cloudflare/references/d1/configuration.md +198 -0
- package/skills/cloudflare/references/d1/gotchas.md +98 -0
- package/skills/cloudflare/references/d1/patterns.md +240 -0
- package/skills/cloudflare/references/ddos/README.md +42 -0
- package/skills/cloudflare/references/ddos/api.md +158 -0
- package/skills/cloudflare/references/ddos/configuration.md +94 -0
- package/skills/cloudflare/references/ddos/gotchas.md +114 -0
- package/skills/cloudflare/references/ddos/patterns.md +220 -0
- package/skills/cloudflare/references/decision-trees.md +95 -0
- package/skills/cloudflare/references/do-storage/README.md +79 -0
- package/skills/cloudflare/references/do-storage/api.md +107 -0
- package/skills/cloudflare/references/do-storage/configuration.md +114 -0
- package/skills/cloudflare/references/do-storage/gotchas.md +153 -0
- package/skills/cloudflare/references/do-storage/patterns.md +210 -0
- package/skills/cloudflare/references/do-storage/testing.md +186 -0
- package/skills/cloudflare/references/durable-objects/README.md +194 -0
- package/skills/cloudflare/references/durable-objects/api.md +205 -0
- package/skills/cloudflare/references/durable-objects/configuration.md +160 -0
- package/skills/cloudflare/references/durable-objects/gotchas.md +200 -0
- package/skills/cloudflare/references/durable-objects/patterns.md +205 -0
- package/skills/cloudflare/references/email-routing/README.md +89 -0
- package/skills/cloudflare/references/email-routing/api.md +192 -0
- package/skills/cloudflare/references/email-routing/configuration.md +187 -0
- package/skills/cloudflare/references/email-routing/gotchas.md +203 -0
- package/skills/cloudflare/references/email-routing/patterns.md +241 -0
- package/skills/cloudflare/references/email-workers/README.md +153 -0
- package/skills/cloudflare/references/email-workers/api.md +227 -0
- package/skills/cloudflare/references/email-workers/configuration.md +115 -0
- package/skills/cloudflare/references/email-workers/gotchas.md +133 -0
- package/skills/cloudflare/references/email-workers/patterns.md +108 -0
- package/skills/cloudflare/references/graphql-api/README.md +147 -0
- package/skills/cloudflare/references/graphql-api/api.md +175 -0
- package/skills/cloudflare/references/graphql-api/configuration.md +151 -0
- package/skills/cloudflare/references/graphql-api/gotchas.md +111 -0
- package/skills/cloudflare/references/graphql-api/patterns.md +276 -0
- package/skills/cloudflare/references/hyperdrive/README.md +84 -0
- package/skills/cloudflare/references/hyperdrive/api.md +149 -0
- package/skills/cloudflare/references/hyperdrive/configuration.md +166 -0
- package/skills/cloudflare/references/hyperdrive/gotchas.md +77 -0
- package/skills/cloudflare/references/hyperdrive/patterns.md +203 -0
- package/skills/cloudflare/references/images/README.md +65 -0
- package/skills/cloudflare/references/images/api.md +101 -0
- package/skills/cloudflare/references/images/configuration.md +206 -0
- package/skills/cloudflare/references/images/gotchas.md +106 -0
- package/skills/cloudflare/references/images/patterns.md +126 -0
- package/skills/cloudflare/references/kv/README.md +90 -0
- package/skills/cloudflare/references/kv/api.md +163 -0
- package/skills/cloudflare/references/kv/configuration.md +148 -0
- package/skills/cloudflare/references/kv/gotchas.md +133 -0
- package/skills/cloudflare/references/kv/patterns.md +195 -0
- package/skills/cloudflare/references/miniflare/README.md +113 -0
- package/skills/cloudflare/references/miniflare/api.md +204 -0
- package/skills/cloudflare/references/miniflare/configuration.md +174 -0
- package/skills/cloudflare/references/miniflare/gotchas.md +179 -0
- package/skills/cloudflare/references/miniflare/patterns.md +187 -0
- package/skills/cloudflare/references/network-interconnect/README.md +104 -0
- package/skills/cloudflare/references/network-interconnect/api.md +220 -0
- package/skills/cloudflare/references/network-interconnect/configuration.md +123 -0
- package/skills/cloudflare/references/network-interconnect/gotchas.md +175 -0
- package/skills/cloudflare/references/network-interconnect/patterns.md +174 -0
- package/skills/cloudflare/references/observability/README.md +93 -0
- package/skills/cloudflare/references/observability/api.md +168 -0
- package/skills/cloudflare/references/observability/configuration.md +178 -0
- package/skills/cloudflare/references/observability/gotchas.md +125 -0
- package/skills/cloudflare/references/observability/patterns.md +105 -0
- package/skills/cloudflare/references/pages/README.md +92 -0
- package/skills/cloudflare/references/pages/api.md +205 -0
- package/skills/cloudflare/references/pages/configuration.md +216 -0
- package/skills/cloudflare/references/pages/gotchas.md +218 -0
- package/skills/cloudflare/references/pages/patterns.md +215 -0
- package/skills/cloudflare/references/pages-functions/README.md +104 -0
- package/skills/cloudflare/references/pages-functions/api.md +159 -0
- package/skills/cloudflare/references/pages-functions/configuration.md +130 -0
- package/skills/cloudflare/references/pages-functions/gotchas.md +102 -0
- package/skills/cloudflare/references/pages-functions/patterns.md +148 -0
- package/skills/cloudflare/references/pipelines/README.md +109 -0
- package/skills/cloudflare/references/pipelines/api.md +214 -0
- package/skills/cloudflare/references/pipelines/configuration.md +98 -0
- package/skills/cloudflare/references/pipelines/gotchas.md +84 -0
- package/skills/cloudflare/references/pipelines/patterns.md +87 -0
- package/skills/cloudflare/references/product-index.md +112 -0
- package/skills/cloudflare/references/pulumi/README.md +113 -0
- package/skills/cloudflare/references/pulumi/api.md +230 -0
- package/skills/cloudflare/references/pulumi/configuration.md +213 -0
- package/skills/cloudflare/references/pulumi/gotchas.md +205 -0
- package/skills/cloudflare/references/pulumi/patterns.md +260 -0
- package/skills/cloudflare/references/queues/README.md +99 -0
- package/skills/cloudflare/references/queues/api.md +211 -0
- package/skills/cloudflare/references/queues/configuration.md +151 -0
- package/skills/cloudflare/references/queues/gotchas.md +210 -0
- package/skills/cloudflare/references/queues/patterns.md +220 -0
- package/skills/cloudflare/references/r2/README.md +97 -0
- package/skills/cloudflare/references/r2/api.md +235 -0
- package/skills/cloudflare/references/r2/configuration.md +176 -0
- package/skills/cloudflare/references/r2/gotchas.md +190 -0
- package/skills/cloudflare/references/r2/patterns.md +203 -0
- package/skills/cloudflare/references/r2-data-catalog/README.md +157 -0
- package/skills/cloudflare/references/r2-data-catalog/api.md +199 -0
- package/skills/cloudflare/references/r2-data-catalog/configuration.md +205 -0
- package/skills/cloudflare/references/r2-data-catalog/gotchas.md +170 -0
- package/skills/cloudflare/references/r2-data-catalog/patterns.md +191 -0
- package/skills/cloudflare/references/r2-sql/README.md +138 -0
- package/skills/cloudflare/references/r2-sql/SKILL.md.backup +512 -0
- package/skills/cloudflare/references/r2-sql/api.md +159 -0
- package/skills/cloudflare/references/r2-sql/configuration.md +152 -0
- package/skills/cloudflare/references/r2-sql/gotchas.md +228 -0
- package/skills/cloudflare/references/r2-sql/patterns.md +230 -0
- package/skills/cloudflare/references/realtime-sfu/README.md +66 -0
- package/skills/cloudflare/references/realtime-sfu/api.md +164 -0
- package/skills/cloudflare/references/realtime-sfu/configuration.md +141 -0
- package/skills/cloudflare/references/realtime-sfu/gotchas.md +138 -0
- package/skills/cloudflare/references/realtime-sfu/patterns.md +187 -0
- package/skills/cloudflare/references/realtimekit/README.md +118 -0
- package/skills/cloudflare/references/realtimekit/api.md +234 -0
- package/skills/cloudflare/references/realtimekit/configuration.md +226 -0
- package/skills/cloudflare/references/realtimekit/gotchas.md +206 -0
- package/skills/cloudflare/references/realtimekit/patterns.md +240 -0
- package/skills/cloudflare/references/sandbox/README.md +104 -0
- package/skills/cloudflare/references/sandbox/api.md +200 -0
- package/skills/cloudflare/references/sandbox/configuration.md +154 -0
- package/skills/cloudflare/references/sandbox/gotchas.md +201 -0
- package/skills/cloudflare/references/sandbox/patterns.md +195 -0
- package/skills/cloudflare/references/secrets-store/README.md +77 -0
- package/skills/cloudflare/references/secrets-store/api.md +199 -0
- package/skills/cloudflare/references/secrets-store/configuration.md +187 -0
- package/skills/cloudflare/references/secrets-store/gotchas.md +97 -0
- package/skills/cloudflare/references/secrets-store/patterns.md +218 -0
- package/skills/cloudflare/references/smart-placement/README.md +143 -0
- package/skills/cloudflare/references/smart-placement/api.md +192 -0
- package/skills/cloudflare/references/smart-placement/configuration.md +202 -0
- package/skills/cloudflare/references/smart-placement/gotchas.md +180 -0
- package/skills/cloudflare/references/smart-placement/patterns.md +190 -0
- package/skills/cloudflare/references/snippets/README.md +74 -0
- package/skills/cloudflare/references/snippets/api.md +214 -0
- package/skills/cloudflare/references/snippets/configuration.md +239 -0
- package/skills/cloudflare/references/snippets/gotchas.md +104 -0
- package/skills/cloudflare/references/snippets/patterns.md +135 -0
- package/skills/cloudflare/references/spectrum/README.md +52 -0
- package/skills/cloudflare/references/spectrum/api.md +184 -0
- package/skills/cloudflare/references/spectrum/configuration.md +203 -0
- package/skills/cloudflare/references/spectrum/gotchas.md +155 -0
- package/skills/cloudflare/references/spectrum/patterns.md +206 -0
- package/skills/cloudflare/references/static-assets/README.md +65 -0
- package/skills/cloudflare/references/static-assets/api.md +201 -0
- package/skills/cloudflare/references/static-assets/configuration.md +186 -0
- package/skills/cloudflare/references/static-assets/gotchas.md +164 -0
- package/skills/cloudflare/references/static-assets/patterns.md +189 -0
- package/skills/cloudflare/references/stream/README.md +123 -0
- package/skills/cloudflare/references/stream/api-live.md +202 -0
- package/skills/cloudflare/references/stream/api.md +206 -0
- package/skills/cloudflare/references/stream/configuration.md +151 -0
- package/skills/cloudflare/references/stream/gotchas.md +139 -0
- package/skills/cloudflare/references/stream/patterns.md +217 -0
- package/skills/cloudflare/references/tail-workers/README.md +92 -0
- package/skills/cloudflare/references/tail-workers/api.md +203 -0
- package/skills/cloudflare/references/tail-workers/configuration.md +178 -0
- package/skills/cloudflare/references/tail-workers/gotchas.md +206 -0
- package/skills/cloudflare/references/tail-workers/patterns.md +190 -0
- package/skills/cloudflare/references/terraform/README.md +100 -0
- package/skills/cloudflare/references/terraform/api.md +178 -0
- package/skills/cloudflare/references/terraform/configuration.md +197 -0
- package/skills/cloudflare/references/terraform/gotchas.md +150 -0
- package/skills/cloudflare/references/terraform/patterns.md +174 -0
- package/skills/cloudflare/references/tunnel/README.md +137 -0
- package/skills/cloudflare/references/tunnel/api.md +205 -0
- package/skills/cloudflare/references/tunnel/configuration.md +163 -0
- package/skills/cloudflare/references/tunnel/gotchas.md +159 -0
- package/skills/cloudflare/references/tunnel/networking.md +174 -0
- package/skills/cloudflare/references/tunnel/patterns.md +199 -0
- package/skills/cloudflare/references/turn/README.md +86 -0
- package/skills/cloudflare/references/turn/api.md +236 -0
- package/skills/cloudflare/references/turn/configuration.md +181 -0
- package/skills/cloudflare/references/turn/gotchas.md +236 -0
- package/skills/cloudflare/references/turn/patterns.md +228 -0
- package/skills/cloudflare/references/turnstile/README.md +102 -0
- package/skills/cloudflare/references/turnstile/api.md +253 -0
- package/skills/cloudflare/references/turnstile/configuration.md +242 -0
- package/skills/cloudflare/references/turnstile/gotchas.md +253 -0
- package/skills/cloudflare/references/turnstile/patterns.md +195 -0
- package/skills/cloudflare/references/vectorize/README.md +133 -0
- package/skills/cloudflare/references/vectorize/api.md +89 -0
- package/skills/cloudflare/references/vectorize/configuration.md +91 -0
- package/skills/cloudflare/references/vectorize/gotchas.md +83 -0
- package/skills/cloudflare/references/vectorize/patterns.md +92 -0
- package/skills/cloudflare/references/waf/README.md +125 -0
- package/skills/cloudflare/references/waf/api.md +203 -0
- package/skills/cloudflare/references/waf/configuration.md +215 -0
- package/skills/cloudflare/references/waf/gotchas.md +208 -0
- package/skills/cloudflare/references/waf/patterns.md +236 -0
- package/skills/cloudflare/references/web-analytics/README.md +149 -0
- package/skills/cloudflare/references/web-analytics/configuration.md +81 -0
- package/skills/cloudflare/references/web-analytics/gotchas.md +86 -0
- package/skills/cloudflare/references/web-analytics/integration.md +63 -0
- package/skills/cloudflare/references/web-analytics/patterns.md +98 -0
- package/skills/cloudflare/references/workerd/README.md +85 -0
- package/skills/cloudflare/references/workerd/api.md +219 -0
- package/skills/cloudflare/references/workerd/configuration.md +200 -0
- package/skills/cloudflare/references/workerd/gotchas.md +151 -0
- package/skills/cloudflare/references/workerd/patterns.md +205 -0
- package/skills/cloudflare/references/workers/README.md +110 -0
- package/skills/cloudflare/references/workers/api.md +197 -0
- package/skills/cloudflare/references/workers/configuration.md +184 -0
- package/skills/cloudflare/references/workers/frameworks.md +200 -0
- package/skills/cloudflare/references/workers/gotchas.md +145 -0
- package/skills/cloudflare/references/workers/patterns.md +220 -0
- package/skills/cloudflare/references/workers-ai/README.md +206 -0
- package/skills/cloudflare/references/workers-ai/api.md +115 -0
- package/skills/cloudflare/references/workers-ai/configuration.md +98 -0
- package/skills/cloudflare/references/workers-ai/gotchas.md +130 -0
- package/skills/cloudflare/references/workers-ai/patterns.md +122 -0
- package/skills/cloudflare/references/workers-for-platforms/README.md +95 -0
- package/skills/cloudflare/references/workers-for-platforms/api.md +212 -0
- package/skills/cloudflare/references/workers-for-platforms/configuration.md +178 -0
- package/skills/cloudflare/references/workers-for-platforms/gotchas.md +134 -0
- package/skills/cloudflare/references/workers-for-platforms/patterns.md +210 -0
- package/skills/cloudflare/references/workers-playground/README.md +131 -0
- package/skills/cloudflare/references/workers-playground/api.md +101 -0
- package/skills/cloudflare/references/workers-playground/configuration.md +169 -0
- package/skills/cloudflare/references/workers-playground/gotchas.md +88 -0
- package/skills/cloudflare/references/workers-playground/patterns.md +134 -0
- package/skills/cloudflare/references/workers-vpc/README.md +130 -0
- package/skills/cloudflare/references/workers-vpc/api.md +196 -0
- package/skills/cloudflare/references/workers-vpc/configuration.md +151 -0
- package/skills/cloudflare/references/workers-vpc/gotchas.md +171 -0
- package/skills/cloudflare/references/workers-vpc/patterns.md +235 -0
- package/skills/cloudflare/references/workflows/README.md +72 -0
- package/skills/cloudflare/references/workflows/api.md +237 -0
- package/skills/cloudflare/references/workflows/configuration.md +158 -0
- package/skills/cloudflare/references/workflows/gotchas.md +97 -0
- package/skills/cloudflare/references/workflows/patterns.md +245 -0
- package/skills/cloudflare/references/wrangler/README.md +143 -0
- package/skills/cloudflare/references/wrangler/api.md +188 -0
- package/skills/cloudflare/references/wrangler/configuration.md +198 -0
- package/skills/cloudflare/references/wrangler/gotchas.md +212 -0
- package/skills/cloudflare/references/wrangler/patterns.md +211 -0
- package/skills/cloudflare/references/zaraz/IMPLEMENTATION_SUMMARY.md +131 -0
- package/skills/cloudflare/references/zaraz/README.md +114 -0
- package/skills/cloudflare/references/zaraz/api.md +118 -0
- package/skills/cloudflare/references/zaraz/configuration.md +94 -0
- package/skills/cloudflare/references/zaraz/gotchas.md +88 -0
- package/skills/cloudflare/references/zaraz/patterns.md +77 -0
- package/skills/docker/SKILL.md +7 -101
- package/skills/docker/references/advanced-examples.md +71 -0
- package/skills/docker/references/templates.md +34 -0
- package/skills/docs-marketer/SKILL.md +178 -0
- package/skills/docs-marketer/references/audit-categories.md +328 -0
- package/skills/docs-marketer/references/copilot-docs-prompts.md +88 -0
- package/skills/docs-marketer/references/copilot-usage.md +16 -0
- package/skills/docs-marketer/references/feedback-loop.md +155 -0
- package/skills/docs-marketer/references/multi-pass-docs-protocol.md +410 -0
- package/skills/drizzle-orm/SKILL.md +82 -0
- package/skills/durable-objects/SKILL.md +167 -0
- package/skills/durable-objects/references/advanced_features.md +29 -0
- package/skills/durable-objects/references/rules.md +300 -0
- package/skills/durable-objects/references/testing.md +261 -0
- package/skills/durable-objects/references/workers.md +336 -0
- package/skills/gcp/SKILL.md +37 -0
- package/skills/github-actions/SKILL.md +5 -58
- package/skills/github-actions/references/templates.md +65 -0
- package/skills/github-commander/SKILL.md +13 -21
- package/skills/github-commander/workflows/copilot-audit.md +12 -12
- package/skills/github-copilot-cli/SKILL.md +21 -26
- package/skills/github-repo-setup/SKILL.md +136 -0
- package/skills/github-repo-setup/references/community-standards.md +136 -0
- package/skills/github-repo-setup/references/github-automation.md +490 -0
- package/skills/github-repo-setup/references/inline-templates.md +205 -0
- package/skills/github-repo-setup/references/project-config.md +320 -0
- package/skills/gitlab/SKILL.md +7 -2
- package/skills/gitlab/package-lock.json +389 -389
- package/skills/golang/SKILL.md +8 -1
- package/skills/graphql/SKILL.md +30 -0
- package/skills/hono/SKILL.md +82 -0
- package/skills/journal-optimizer/SKILL.md +206 -0
- package/skills/journal-optimizer/references/optimizer-scripts.md +169 -0
- package/skills/llm-app-engineering/SKILL.md +18 -0
- package/skills/monorepo/SKILL.md +56 -0
- package/skills/multi-agent-orchestration/SKILL.md +14 -0
- package/skills/mysql/SKILL.md +6 -2
- package/skills/next-best-practices/SKILL.md +86 -0
- package/skills/next-best-practices/references/cache-components-examples.md +234 -0
- package/skills/next-best-practices/references/cache-components.md +210 -0
- package/skills/next-best-practices/references/upgrade-decision-tree.md +33 -0
- package/skills/next-best-practices/references/upgrade.md +43 -0
- package/skills/next-cache-components/SKILL.md +441 -0
- package/skills/next-upgrade/SKILL.md +43 -0
- package/skills/next-upgrade/references/decision-tree.md +33 -0
- package/skills/nodejs/SKILL.md +46 -0
- package/skills/opentelemetry/SKILL.md +62 -0
- package/skills/package.json +39 -4
- package/skills/playwright-standard/SKILL.md +6 -11
- package/skills/playwright-standard/references/locators.md +7 -0
- package/skills/postgres/SKILL.md +6 -1
- package/skills/python/SKILL.md +8 -70
- package/skills/python/references/advanced-patterns.md +37 -0
- package/skills/python/references/config-templates.md +48 -0
- package/skills/rag-pipelines/SKILL.md +14 -0
- package/skills/redis/SKILL.md +31 -0
- package/skills/render/SKILL.md +35 -0
- package/skills/rust/SKILL.md +15 -25
- package/skills/rust/references/borrow-checker.md +13 -0
- package/skills/rust/references/ecosystem.md +11 -0
- package/skills/sandbox-sdk/SKILL.md +186 -0
- package/skills/sandbox-sdk/references/api-quick-ref.md +113 -0
- package/skills/sandbox-sdk/references/examples.md +52 -0
- package/skills/shadcn-ui/SKILL.md +22 -57
- package/skills/skill-builder/SKILL.md +23 -424
- package/skills/skill-builder/references/tutorial.md +457 -0
- package/skills/sqlite/SKILL.md +16 -5
- package/skills/table.md +59 -0
- package/skills/tailwind-css/SKILL.md +11 -60
- package/skills/tailwind-css/references/component-patterns.md +52 -0
- package/skills/trpc/SKILL.md +56 -0
- package/skills/typescript/SKILL.md +30 -433
- package/skills/typescript/references/tutorial.md +453 -0
- package/skills/vercel-ai-sdk/SKILL.md +48 -0
- package/skills/vitest-standard/SKILL.md +5 -11
- package/skills/vitest-standard/references/assertions.md +11 -0
- package/skills/web-perf/SKILL.md +207 -0
- package/skills/workers-best-practices/SKILL.md +120 -0
- package/skills/workers-best-practices/references/anti-patterns.md +18 -0
- package/skills/workers-best-practices/references/review.md +174 -0
- package/skills/workers-best-practices/references/rules.md +485 -0
- package/skills/wrangler/SKILL.md +43 -0
- package/skills/wrangler/references/cli-commands.md +861 -0
- package/skills/zod/SKILL.md +48 -0
- package/dist/tools-P4VGG4FH.js +0 -1
- package/skills/react-best-practices/AGENTS.md +0 -2883
- package/skills/react-best-practices/SKILL.md +0 -138
- /package/skills/{react-best-practices → next-best-practices}/README.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/metadata.json +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/_sections.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/_template.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-event-handler-refs.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-init-once.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-use-latest.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-api-routes.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-defer-await.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-dependencies.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-parallel.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-suspense-boundaries.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-barrel-imports.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-conditional.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-defer-third-party.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-dynamic-imports.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-preload.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-event-listeners.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-localstorage-schema.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-passive-event-listeners.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-swr-dedup.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-batch-dom-css.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-function-results.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-property-access.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-storage.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-combine-iterations.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-early-exit.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-hoist-regexp.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-index-maps.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-length-check-first.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-min-max-loop.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-set-map-lookups.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-tosorted-immutable.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-activity.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-conditional-render.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-content-visibility.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hoist-jsx.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hydration-suppress-warning.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-svg-precision.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-usetransition-loading.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-defer-reads.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-dependencies.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-derived-state-no-effect.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-derived-state.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-functional-setstate.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-lazy-state-init.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-memo-with-default-value.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-memo.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-move-effect-to-event.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-simple-expression-in-memo.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-transitions.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-use-ref-transient-values.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-after-nonblocking.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-auth-actions.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-cache-lru.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-cache-react.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-dedup-props.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-parallel-fetching.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-serialization.md +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Building MCP Servers on Cloudflare
|
|
2
|
+
|
|
3
|
+
Creates production-ready Model Context Protocol servers on Cloudflare Workers with tools, authentication, and deployment.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Cloudflare account with Workers enabled
|
|
8
|
+
- Node.js 18+ and npm/pnpm/yarn
|
|
9
|
+
- Wrangler CLI (`npm install -g wrangler`)
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Option 1: Public Server (No Auth)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm create cloudflare@latest -- my-mcp-server \
|
|
17
|
+
--template=cloudflare/ai/demos/remote-mcp-authless
|
|
18
|
+
cd my-mcp-server
|
|
19
|
+
npm start
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Server runs at `http://localhost:8788/mcp`
|
|
23
|
+
|
|
24
|
+
### Option 2: Authenticated Server (OAuth)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm create cloudflare@latest -- my-mcp-server \
|
|
28
|
+
--template=cloudflare/ai/demos/remote-mcp-github-oauth
|
|
29
|
+
cd my-mcp-server
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Requires OAuth app setup.
|
|
33
|
+
|
|
34
|
+
## Core Workflow
|
|
35
|
+
|
|
36
|
+
### Step 1: Define Tools
|
|
37
|
+
|
|
38
|
+
Tools are functions MCP clients can call. Define them using `server.tool()`:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { McpAgent } from 'agents/mcp'
|
|
42
|
+
import { z } from 'zod'
|
|
43
|
+
|
|
44
|
+
export class MyMCP extends McpAgent {
|
|
45
|
+
server = new Server({ name: 'my-mcp', version: '1.0.0' })
|
|
46
|
+
|
|
47
|
+
async init() {
|
|
48
|
+
// Simple tool with parameters
|
|
49
|
+
this.server.tool('add', { a: z.number(), b: z.number() }, async ({ a, b }) => ({
|
|
50
|
+
content: [{ type: 'text', text: String(a + b) }],
|
|
51
|
+
}))
|
|
52
|
+
|
|
53
|
+
// Tool that calls external API
|
|
54
|
+
this.server.tool('get_weather', { city: z.string() }, async ({ city }) => {
|
|
55
|
+
// Prevent SSRF: Always construct URLs safely, never interpolate raw strings into the base URL path
|
|
56
|
+
const url = new URL('https://api.weather.com/v1/current')
|
|
57
|
+
url.searchParams.set('city', city)
|
|
58
|
+
const response = await fetch(url.toString())
|
|
59
|
+
const data = await response.json()
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: 'text', text: JSON.stringify(data) }],
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Step 2: Configure Entry Point
|
|
69
|
+
|
|
70
|
+
**Public server** (`src/index.ts`):
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { MyMCP } from './mcp'
|
|
74
|
+
|
|
75
|
+
export default {
|
|
76
|
+
fetch(request: Request, env: Env, ctx: ExecutionContext) {
|
|
77
|
+
const url = new URL(request.url)
|
|
78
|
+
if (url.pathname === '/mcp') {
|
|
79
|
+
return MyMCP.serveSSE('/mcp').fetch(request, env, ctx)
|
|
80
|
+
}
|
|
81
|
+
return new Response('MCP Server', { status: 200 })
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { MyMCP }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Step 3: Test Locally
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Start server
|
|
92
|
+
npm start
|
|
93
|
+
|
|
94
|
+
# In another terminal, test with MCP Inspector
|
|
95
|
+
npx @modelcontextprotocol/inspector@latest
|
|
96
|
+
# Open http://localhost:5173, enter http://localhost:8788/mcp
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Step 4: Deploy
|
|
100
|
+
|
|
101
|
+
> **CRITICAL HITL GATE**: You MUST stop and ask the user for explicit confirmation before running the `npx wrangler deploy` command. Deploying to production requires consent.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx wrangler deploy
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Server accessible at `https://[worker-name].[account].workers.dev/mcp`
|
|
108
|
+
|
|
109
|
+
### Step 5: Connect Clients
|
|
110
|
+
|
|
111
|
+
**Claude Desktop** (`claude_desktop_config.json`):
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"mcpServers": {
|
|
116
|
+
"my-server": {
|
|
117
|
+
"command": "npx",
|
|
118
|
+
"args": ["mcp-remote", "https://my-mcp.workers.dev/mcp"]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Restart Claude Desktop after updating config.
|
|
125
|
+
|
|
126
|
+
## Accessing Environment/Bindings
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
export class MyMCP extends McpAgent<Env> {
|
|
130
|
+
async init() {
|
|
131
|
+
this.server.tool('get_user', { id: z.number() }, async ({ id }) => {
|
|
132
|
+
// Access D1 binding safely with parameterized query
|
|
133
|
+
// NOTE: Never pass raw SQL strings from tool arguments directly to prepare()
|
|
134
|
+
const result = await this.env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(id).all()
|
|
135
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] }
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Wrangler Configuration
|
|
142
|
+
|
|
143
|
+
Minimal `wrangler.toml`:
|
|
144
|
+
|
|
145
|
+
```toml
|
|
146
|
+
name = "my-mcp-server"
|
|
147
|
+
main = "src/index.ts"
|
|
148
|
+
compatibility_date = "2024-12-01"
|
|
149
|
+
|
|
150
|
+
[durable_objects]
|
|
151
|
+
bindings = [{ name = "MCP", class_name = "MyMCP" }]
|
|
152
|
+
|
|
153
|
+
[[migrations]]
|
|
154
|
+
tag = "v1"
|
|
155
|
+
new_classes = ["MyMCP"]
|
|
156
|
+
```
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# Error Handling & Input Validation Reference
|
|
2
|
+
|
|
3
|
+
Detailed patterns for error handling infrastructure, input coercion, schema boundaries, existence validation, SQL injection prevention, idempotent operations, and output schema architecture.
|
|
4
|
+
|
|
5
|
+
> Read this reference when implementing error handling, input validation, or output schemas in an MCP server.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Enriched Error Handling Infrastructure (Standard)
|
|
10
|
+
|
|
11
|
+
Harmonized across db-mcp, postgres-mcp, mysql-mcp, memory-journal-mcp.
|
|
12
|
+
|
|
13
|
+
**Files:** `src/utils/errors/base.ts` (abstract base), `src/utils/errors/classes.ts` (subclasses), `src/utils/errors/categories.ts` (enum + interfaces), `src/utils/errors/format.ts` (formatter), `src/utils/errors/error-response-fields.ts` (ErrorFieldsMixin SSoT), `src/utils/errors/suggestions.ts` (fuzzy typo hints).
|
|
14
|
+
|
|
15
|
+
**Base Class:** `{Server}McpError extends Error` with `category`, `code`, `suggestion`, `details`, `recoverable`, `cause`, and `toResponse(): ErrorResponse`. Replace `{Server}` with prefix: `DbMcpError`, `PostgresMcpError`, etc.
|
|
16
|
+
|
|
17
|
+
**Error Code Auto-Refinement:** The base class constructor auto-refines generic codes to specific ones. When a `QueryError` (code: `DB_QUERY_FAILED`) has an error message matching a known pattern (like "no such table"), the constructor auto-refines the code to `TABLE_NOT_FOUND`. This ensures consistent, machine-readable codes across all tools without manual mapping in each handler.
|
|
18
|
+
|
|
19
|
+
The auto-refinement mechanism:
|
|
20
|
+
|
|
21
|
+
- `ERROR_SUGGESTIONS` entries include an optional `code` field
|
|
22
|
+
- Constructor checks if the current code is generic (from a whitelist: `DB_QUERY_FAILED`, `DB_WRITE_FAILED`, `QUERY_ERROR`, `RESOURCE_ERROR`, `UNKNOWN_ERROR`)
|
|
23
|
+
- If generic AND a matched suggestion has a specific `code`, the specific code replaces the generic one
|
|
24
|
+
- Supported refinements: `TABLE_NOT_FOUND`, `COLUMN_NOT_FOUND`, `VIEW_NOT_FOUND`, `FILE_NOT_FOUND`, `MALFORMED_JSON`, `TRANSACTION_CONFLICT`, `DIMENSION_MISMATCH`, `VECTOR_NOT_FOUND`, `DUPLICATE_MIGRATION`, `DUPLICATE_VERSION`, `ALREADY_ROLLED_BACK`, etc.
|
|
25
|
+
|
|
26
|
+
**Standard Subclasses:**
|
|
27
|
+
|
|
28
|
+
| Subclass | Code | Category | Recoverable |
|
|
29
|
+
| ---------------------------- | --------------------- | -------------- | ----------- |
|
|
30
|
+
| `ConnectionError` | `CONNECTION_FAILED` | connection | false |
|
|
31
|
+
| `QueryError` | `QUERY_FAILED` | query | true |
|
|
32
|
+
| `ValidationError` | `VALIDATION_FAILED` | validation | true |
|
|
33
|
+
| `ResourceNotFoundError` | `RESOURCE_NOT_FOUND` | resource | true |
|
|
34
|
+
| `ConfigurationError` | `CONFIGURATION_ERROR` | configuration | false |
|
|
35
|
+
| `PermissionError` | `PERMISSION_DENIED` | permission | true |
|
|
36
|
+
| `TransactionError` | `TRANSACTION_FAILED` | query | true |
|
|
37
|
+
| `InternalError` | `INTERNAL_ERROR` | internal | false |
|
|
38
|
+
| `AuthenticationError` | `AUTH_FAILED` | authentication | false |
|
|
39
|
+
| `AuthorizationError` | `AUTH_SCOPE_DENIED` | authorization | true |
|
|
40
|
+
| `ExtensionNotAvailableError` | `EXTENSION_MISSING` | configuration | false |
|
|
41
|
+
|
|
42
|
+
`TransactionError` accepts optional `ErrorContext` (`tool`, `table`, `sql`) for diagnostic context. `ExtensionNotAvailableError` auto-generates a `suggestion` field containing the extension name (e.g., `"Install the SpatiaLite extension: --spatialite"`).
|
|
43
|
+
|
|
44
|
+
DB servers also add `PoolError` (code: `POOL_ERROR`, category: connection, recoverable: false).
|
|
45
|
+
|
|
46
|
+
**Single Formatter:** `formatHandlerError(err, context?)` — handles `{Server}McpError` (`.toResponse()`), `ZodError` (extracts field paths, e.g., `table: Required`), and raw `Error` (matches `ERROR_SUGGESTIONS`). Use in every handler's `catch` block.
|
|
47
|
+
|
|
48
|
+
**Context-Aware Variant (DB Servers):** For database-backed servers, pass an `ErrorContext` parameter (`{tool, sql?, table?, schema?, target?, objectType?}`) to enable engine-specific error code mapping. The context flows into the engine's error parser for actionable diagnostics.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Context-aware formatter:
|
|
52
|
+
return formatHandlerError(error, { tool: 'pg_create_index', table: 'users' })
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Engine-Specific Error Parsers:** For DB servers, implement a dedicated `error-parser.ts` in the engine's `tools/core/` directory. This parser maps database-native error codes (e.g., PostgreSQL `42P01` → `TABLE_NOT_FOUND`, MySQL `1146` → `TABLE_NOT_FOUND`) to structured error subclasses. Complementary to `ERROR_SUGGESTIONS` auto-refinement — the parser handles raw database exceptions, while auto-refinement handles error message pattern matching in the base class constructor.
|
|
56
|
+
|
|
57
|
+
> [!IMPORTANT]
|
|
58
|
+
> **Use ONE formatter, not two.** All handler catch blocks must use `return formatHandlerError(error)` or `return formatHandlerError(error, context)` — never re-wrap the result.
|
|
59
|
+
|
|
60
|
+
**`structuredContent` on Error Responses:** When a tool has an `outputSchema`, the `registerTool()` wrapper must include `structuredContent` on error responses so clients receive machine-readable error payloads:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// In registerTool() catch block:
|
|
64
|
+
if (toolDef.outputSchema) {
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: 'text', text: JSON.stringify(errorResult) }],
|
|
67
|
+
structuredContent: errorResult,
|
|
68
|
+
isError: true,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**ErrorFieldsMixin** — merge into every `outputSchema`:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
export const ErrorFieldsMixin = z.object({
|
|
77
|
+
error: z.string().optional(),
|
|
78
|
+
code: z.string().optional(),
|
|
79
|
+
category: z.string().optional(),
|
|
80
|
+
suggestion: z.string().optional(),
|
|
81
|
+
recoverable: z.boolean().optional(),
|
|
82
|
+
details: z.unknown().optional(),
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// Usage: z.object({ success: z.boolean(), result: z.string().optional() }).extend(ErrorFieldsMixin.shape);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> [!CAUTION]
|
|
89
|
+
> **`outputSchema` + `structuredContent` pitfall:** If `formatHandlerError()` returns error fields but the schema has required success-path fields (e.g., `result: z.string()`), Zod validation fails. **All success-path fields must be `.optional()`.**
|
|
90
|
+
|
|
91
|
+
**Integration:** `OAuthError` and `SecurityError` (with `InvalidDateFormatError`, `PathTraversalError`) both extend the server's base class, inheriting `toResponse()` and structured error semantics.
|
|
92
|
+
|
|
93
|
+
> [!IMPORTANT]
|
|
94
|
+
> **Error classification:** Input validation errors → Tool Execution Errors (`isError: true`), not Protocol Errors. Tool errors enable model self-correction; protocol errors don't.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Input Coercion & Refinement Leak Prevention
|
|
99
|
+
|
|
100
|
+
The MCP SDK wraps `inputSchema` with `.partial()` before validation. This means Zod refinements (`.min()`, `.max()`, `.regex()`, `z.enum()`) can leak raw `-32602` protocol errors before handler code can intercept them. This is the #1 source of "conversation-killer" errors in agent orchestration.
|
|
101
|
+
|
|
102
|
+
**Required patterns:**
|
|
103
|
+
|
|
104
|
+
| Input Type | Registration Schema | Handler Validation |
|
|
105
|
+
| ------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
106
|
+
| Required enum | `z.string().describe("One of: a, b, c")` | Validate against exported `const VALID_VALUES = ['a', 'b', 'c'] as const` in handler |
|
|
107
|
+
| Optional enum | `z.preprocess(coerceEnumValues(VALID_VALUES, 'default'), z.enum(VALID_VALUES))` | Or use `z.string().optional()` + handler validation |
|
|
108
|
+
| Numeric param | `z.preprocess(coerceNumber, z.number().optional())` **or** `z.coerce.number().optional()` + NaN guard | See tradeoffs below |
|
|
109
|
+
| Boolean param | `z.preprocess(coerceBoolean, z.boolean().optional())` | Handle `"true"`, `"false"` string inputs |
|
|
110
|
+
| Array param | `z.preprocess(v => Array.isArray(v) ? v : [], z.array(...))` | Coerce non-arrays to empty arrays for `.partial()` compatibility |
|
|
111
|
+
| Refinements | Move `.min()`, `.max()`, `.regex()` to handler-level validation | Never put these on the registration schema |
|
|
112
|
+
|
|
113
|
+
**Numeric coercion — two acceptable approaches:**
|
|
114
|
+
|
|
115
|
+
| Approach | Pros | Cons | Used By |
|
|
116
|
+
| --------------------------------- | ----------------------------------------------- | ----------------------------------------------------- | ------------------------------------------- |
|
|
117
|
+
| `z.preprocess(coerceNumber, ...)` | Returns `undefined` on bad input (safe default) | More verbose, requires custom helper | db-mcp, mysql-mcp, postgres-mcp (migrating) |
|
|
118
|
+
| `z.coerce.number().optional()` | Idiomatic Zod, less boilerplate | Produces `NaN` on `"abc"` — **must guard in handler** | postgres-mcp (legacy, being replaced) |
|
|
119
|
+
|
|
120
|
+
When using `z.coerce.number()`, always guard against NaN in the handler — ideally via `coerceLimit()` (see below) or an explicit `isNaN()` check before using the value.
|
|
121
|
+
|
|
122
|
+
**Coercion factories (for `z.preprocess` approach):**
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
export function coerceNumber(val: unknown): unknown {
|
|
126
|
+
if (typeof val === 'number') return val
|
|
127
|
+
if (typeof val === 'string') {
|
|
128
|
+
const n = Number(val)
|
|
129
|
+
return Number.isNaN(n) ? undefined : n
|
|
130
|
+
}
|
|
131
|
+
return undefined
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function coerceBoolean(val: unknown): unknown {
|
|
135
|
+
if (typeof val === 'boolean') return val
|
|
136
|
+
if (val === 'true') return true
|
|
137
|
+
if (val === 'false') return false
|
|
138
|
+
return undefined
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Limit Coercion (Standard):** For `limit` parameters (ubiquitous across DB tools), use shared helpers in `utils/query-helpers.ts`:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
export const DEFAULT_QUERY_LIMIT = 100
|
|
146
|
+
|
|
147
|
+
/** Coerce raw limit → usable value. 0 = unlimited (null), NaN/undefined → default. */
|
|
148
|
+
export function coerceLimit(raw: unknown, defaultLimit = DEFAULT_QUERY_LIMIT): number | null {
|
|
149
|
+
if (raw === undefined) return defaultLimit
|
|
150
|
+
const num = Number(raw)
|
|
151
|
+
if (isNaN(num)) return defaultLimit
|
|
152
|
+
if (num === 0) return null
|
|
153
|
+
return num > 0 ? num : defaultLimit
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Build SQL LIMIT clause from coerced value. null = no limit. */
|
|
157
|
+
export function buildLimitClause(limitVal: number | null): string {
|
|
158
|
+
return limitVal !== null ? ` LIMIT ${String(limitVal)}` : ''
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
> [!TIP]
|
|
163
|
+
> `coerceLimit()` safely handles both `z.preprocess` and `z.coerce.number()` outputs — it guards NaN, undefined, and zero semantics in one place.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Input Schema Boundary Handling
|
|
168
|
+
|
|
169
|
+
The SDK wraps `inputSchema` with `.partial()` before validation. Two approaches exist for handling this safely:
|
|
170
|
+
|
|
171
|
+
**Approach A — Dual-Schema Pattern (Preferred):** Define two schemas per tool — a strict `XxxSchema` for handler-level validation and a relaxed `XxxSchemaMcp` for SDK registration. The `SchemaMcp` variants use coercion factories (e.g., `relaxedNumber()`, `relaxedArray()`) to handle type mismatches from agent inputs.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// Strict schema (handler-level validation):
|
|
175
|
+
const SearchEntriesSchema = z.object({
|
|
176
|
+
query: z.string().min(1),
|
|
177
|
+
limit: z.number().optional(),
|
|
178
|
+
tags: z.array(z.string()).optional(),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Relaxed schema (SDK registration — coercion, no refinements):
|
|
182
|
+
const SearchEntriesSchemaMcp = z.object({
|
|
183
|
+
query: z.string().describe('Search query'),
|
|
184
|
+
limit: relaxedNumber().describe('Max results'),
|
|
185
|
+
tags: relaxedArray(z.string()).describe('Filter by tags'),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Registration uses relaxed schema:
|
|
189
|
+
{ name: 'search_entries', inputSchema: SearchEntriesSchemaMcp, ... }
|
|
190
|
+
|
|
191
|
+
// Handler uses strict schema:
|
|
192
|
+
try {
|
|
193
|
+
const parsed = SearchEntriesSchema.parse(params);
|
|
194
|
+
// ... business logic
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return formatHandlerError(error);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Why this is preferred:** Explicit schema separation prevents `.partial()` from masking required field validation. Coercion is handled at the schema level rather than requiring post-parse handling. The SDK's internal wrapping behavior has changed between versions, making explicit schema separation more robust.
|
|
201
|
+
|
|
202
|
+
**Coercion factories** (used in `SchemaMcp` variants):
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
/** Relaxed number that accepts string/number/undefined without crashing SDK */
|
|
206
|
+
export function relaxedNumber() {
|
|
207
|
+
return z.preprocess(coerceNumber, z.number().optional())
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Relaxed array that accepts non-arrays gracefully */
|
|
211
|
+
export function relaxedArray<T extends z.ZodTypeAny>(item: T) {
|
|
212
|
+
return z.preprocess((v) => (Array.isArray(v) ? v : []), z.array(item).optional())
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Approach B — `.partial().passthrough()` Wrapping:** For adapter-based servers (db-mcp, postgres-mcp) where schemas are generated or engine-specific, wrap `inputSchema` directly.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
// In registerTool():
|
|
220
|
+
const sdkSchema = toolDef.inputSchema.partial().passthrough()
|
|
221
|
+
|
|
222
|
+
// In handler:
|
|
223
|
+
try {
|
|
224
|
+
const resolved = resolveAliases(params) // tableName → table, sql → query
|
|
225
|
+
const parsed = StrictSchema.parse(resolved)
|
|
226
|
+
// ... business logic
|
|
227
|
+
} catch (error) {
|
|
228
|
+
return formatHandlerError(error)
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Two boundaries (both approaches):**
|
|
233
|
+
|
|
234
|
+
- **SDK boundary:** relaxed schema or `.partial().passthrough()` — accepts any parameter subset
|
|
235
|
+
- **Handler boundary:** strict `Schema.parse(params)` inside try/catch → `formatHandlerError()`
|
|
236
|
+
|
|
237
|
+
**Backward-compatible aliases:** Use `resolveAliases()` preprocess before Zod parsing. Canonical names take precedence when both alias and canonical are supplied.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Proactive Existence Validation
|
|
242
|
+
|
|
243
|
+
All database tools must validate object existence before executing DML. This prevents raw SQL errors from leaking to the client and ensures consistent, machine-readable error codes across the fleet.
|
|
244
|
+
|
|
245
|
+
**Validation hierarchy:** TABLE_NOT_FOUND → COLUMN_NOT_FOUND → domain-specific validation.
|
|
246
|
+
|
|
247
|
+
**Standard validators** (in shared `tools/column-validation.ts`):
|
|
248
|
+
|
|
249
|
+
- `validateTableExists(adapter, table)` — checks system catalog before proceeding
|
|
250
|
+
- `validateColumnExists(adapter, table, column)` — checks table existence _first_, then column via metadata query
|
|
251
|
+
- `validateColumnsExist(adapter, table, columns)` — batch version, single metadata query + in-memory membership check (N+1 elimination)
|
|
252
|
+
- All return structured `{success: false, code: "TABLE_NOT_FOUND" | "COLUMN_NOT_FOUND"}` errors
|
|
253
|
+
|
|
254
|
+
**Usage:** Imported by geo, stats, text, FTS, vector, window tool groups.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## WHERE Clause Validation (SQL Injection Prevention)
|
|
259
|
+
|
|
260
|
+
Every tool that interpolates a user-provided `whereClause` into SQL must call `validateWhereClause()` before SQL construction. This is non-negotiable for multi-agent orchestration where WHERE clauses may originate from untrusted agent chains.
|
|
261
|
+
|
|
262
|
+
**Blocked patterns:**
|
|
263
|
+
|
|
264
|
+
- Semicolon-chained keywords: `; SELECT`, `; DROP`, `; INSERT`, `; UPDATE`, `; DELETE`, `; ALTER`, `; CREATE`
|
|
265
|
+
- Comment injection: `--`, `/* */`
|
|
266
|
+
- String-literal stripping: test blocked patterns against SQL with string literals removed (prevents false positives on quoted values)
|
|
267
|
+
- Semicolon-chained blocking requires the semicolon prefix (allows legitimate `IN (SELECT ...)`)
|
|
268
|
+
|
|
269
|
+
**Implementation:** `src/utils/where-clause.ts` — shared utility imported by all tools with `whereClause` parameters.
|
|
270
|
+
|
|
271
|
+
**FTS Configuration Validation (DB Servers):** For servers with full-text search, validate FTS configuration names (e.g., `'english'`, `'my_custom_config'`) against database identifier rules via `validateFtsConfig()` in `utils/fts-config.ts`. This prevents SQL injection through the FTS config parameter — a vector that `validateWhereClause()` doesn't cover since config names are interpolated outside WHERE clauses.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Idempotent Operation Reporting
|
|
276
|
+
|
|
277
|
+
Tools that create or drop objects must distinguish between "action taken" and "no-op" responses. This is critical for idempotent workflow design in agent orchestration.
|
|
278
|
+
|
|
279
|
+
**Pattern:**
|
|
280
|
+
|
|
281
|
+
- Pre-check existence before `CREATE ... IF NOT EXISTS` or `DROP ... IF EXISTS`
|
|
282
|
+
- Return `alreadyExists: true` or `alreadyDropped: true` flag in response
|
|
283
|
+
- Return descriptive message: `"Index 'idx_name' already exists (no changes made)"`
|
|
284
|
+
- Prevents misleading success messages that don't reflect actual state changes
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Before CREATE INDEX IF NOT EXISTS:
|
|
288
|
+
const exists = await checkIndexExists(adapter, indexName)
|
|
289
|
+
if (exists) {
|
|
290
|
+
return {
|
|
291
|
+
success: true,
|
|
292
|
+
alreadyExists: true,
|
|
293
|
+
message: `Index '${indexName}' already exists (no changes made)`,
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
await adapter.execute(`CREATE INDEX ${indexName} ...`)
|
|
297
|
+
return { success: true, alreadyExists: false, message: `Index '${indexName}' created` }
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Output Schema Architecture
|
|
303
|
+
|
|
304
|
+
Output schemas must **never be inline** in handler files. Two organizational patterns exist depending on server type:
|
|
305
|
+
|
|
306
|
+
**Pattern A — Co-located `schemas.ts` (Non-adapter servers):** Output schemas live in `schemas.ts` files alongside their handler groups. Input schemas may be co-located in handler files when using the dual-schema pattern.
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
handlers/tools/
|
|
310
|
+
schemas.ts — Shared output schemas (core, search, admin, etc.)
|
|
311
|
+
error-fields-mixin.ts — Re-export stub → utils/errors/error-response-fields.ts
|
|
312
|
+
github/
|
|
313
|
+
schemas.ts — GitHub-specific output schemas (16 tools)
|
|
314
|
+
team/
|
|
315
|
+
schemas.ts — Team-specific output schemas (20 tools)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
This pattern works well when schemas are tightly coupled to their handler groups and the server uses the dual-schema input pattern. Output schemas are centralized per group; input schemas stay with handlers for locality.
|
|
319
|
+
|
|
320
|
+
**Pattern B — Top-level `schemas/` directory (Adapter-based servers):** For servers with engine-specific schemas (db-mcp, postgres-mcp, mysql-mcp), output schemas live in a centralized directory.
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
schemas/ # (or output-schemas/)
|
|
324
|
+
error-response-fields.ts — ErrorFieldsMixin (6 optional error fields, SSoT)
|
|
325
|
+
core-exports.ts — Core schema barrel exports
|
|
326
|
+
extension-exports.ts — Extension schema barrel exports
|
|
327
|
+
core/ — Core group schemas (input + output per file)
|
|
328
|
+
jsonb/ — JSONB group schemas
|
|
329
|
+
stats/ — Stats group schemas (base, input, output, preprocessing)
|
|
330
|
+
vector/ — Vector group schemas (input, output)
|
|
331
|
+
postgis/ — PostGIS group schemas
|
|
332
|
+
extensions/ — Extension schemas (citext, ltree, pgcrypto, kcache, shared)
|
|
333
|
+
{group}/ — One subdirectory per additional tool group
|
|
334
|
+
index.ts — Barrel re-export
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Rules (both patterns):**
|
|
338
|
+
|
|
339
|
+
- Zero inline output schema `z.object()` definitions in handler files — import from dedicated `schemas.ts` or `schemas/` directory
|
|
340
|
+
- All output schemas extend `ErrorFieldsMixin.shape` — domain fields are `.optional()` so error responses pass validation
|
|
341
|
+
- Every group gets its own file (no stuffing unrelated schemas into `common.ts`)
|
|
342
|
+
- Bespoke schemas over generic: `ListViewsOutputSchema` not reusing `ListTablesOutputSchema` ("Shared Template Fatigue" prevention)
|
|
343
|
+
- Orphan schema detection: no schemas should exist without corresponding tools
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# HTTP Transport & Security Reference
|
|
2
|
+
|
|
3
|
+
Detailed patterns for OAuth 2.1 authentication, HTTP transport hardening, security headers, rate limiting, CORS, and dual-protocol support.
|
|
4
|
+
|
|
5
|
+
> Read this reference when implementing HTTP/SSE transport or OAuth authentication for an MCP server.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## OAuth 2.1 Authentication (Required for production HTTP servers)
|
|
10
|
+
|
|
11
|
+
All production HTTP servers must implement OAuth 2.1 as opt-in. Fallback chain: OAuth → simple token (`MCP_AUTH_TOKEN`) → no auth. `jose` is a transitive dependency of `@modelcontextprotocol/sdk`.
|
|
12
|
+
|
|
13
|
+
**Module:** `src/auth/` — 11 files. `OAuthError` extends server's base error class with `httpStatus` + `wwwAuthenticate`. Category auto-inferred (401 → AUTHENTICATION, 403 → AUTHORIZATION). 5 CLI flags with env var fallbacks. `/.well-known/oauth-protected-resource` always registered.
|
|
14
|
+
|
|
15
|
+
> [!TIP]
|
|
16
|
+
> The `src/auth/` module is copy-pasteable between servers. Only `scopes.ts`, `scope-map.ts`, and the `extends` declaration need customization.
|
|
17
|
+
|
|
18
|
+
> See [`oauth-reference.md`](../oauth-reference.md) for module structure, RFC compliance, scope model, error hierarchy, token validation, middleware patterns, CLI flags, testing (8 test files), and integration checklist.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## HTTP Transport Hardening (Required for HTTP/SSE servers)
|
|
23
|
+
|
|
24
|
+
**Modular Architecture:**
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
src/transports/http/
|
|
28
|
+
server.ts — HTTP/SSE transport orchestrator (route registration, server lifecycle)
|
|
29
|
+
streamable.ts — Streamable HTTP transport handler (POST/GET/DELETE /mcp)
|
|
30
|
+
stateless.ts — Stateless HTTP transport handler (serverless mode)
|
|
31
|
+
legacy-sse.ts — Legacy SSE transport handler (GET /sse, POST /messages)
|
|
32
|
+
handlers.ts — Route handlers (health, 404, shared utilities)
|
|
33
|
+
security.ts — Security headers, rate limiting, CORS, DNS rebinding, body parsing
|
|
34
|
+
types.ts — Config interfaces, constants, JSON-RPC codes, timeout constants
|
|
35
|
+
index.ts — Barrel re-export
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**7 Security Headers** (every response):
|
|
39
|
+
|
|
40
|
+
| Header | Value | Purpose |
|
|
41
|
+
| --------------------------- | -------------------------------------------- | ---------------------------- |
|
|
42
|
+
| `X-Content-Type-Options` | `nosniff` | Prevent MIME sniffing |
|
|
43
|
+
| `X-Frame-Options` | `DENY` | Prevent clickjacking |
|
|
44
|
+
| `Content-Security-Policy` | `default-src 'none'; frame-ancestors 'none'` | Strict CSP |
|
|
45
|
+
| `Cache-Control` | `no-store, no-cache, must-revalidate` | Prevent data caching |
|
|
46
|
+
| `Referrer-Policy` | `no-referrer` | Prevent referrer leakage |
|
|
47
|
+
| `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` | Restrict browser APIs |
|
|
48
|
+
| `Strict-Transport-Security` | `max-age=31536000; includeSubDomains` | HSTS (**opt-in** via config) |
|
|
49
|
+
|
|
50
|
+
> [!IMPORTANT]
|
|
51
|
+
> HSTS must be **opt-in** (e.g., `--enable-hsts`), not auto-detected from `X-Forwarded-Proto`.
|
|
52
|
+
|
|
53
|
+
**Built-in Rate Limiting** (zero dependencies): Sliding window `Map<string, {count, resetTime}>`, 100 req/min per IP (configurable). `429` + `Retry-After`. Health endpoint exempt. `setInterval().unref()` cleanup.
|
|
54
|
+
|
|
55
|
+
**Server Timeouts:** Request 120s, keep-alive 65s, headers 66s.
|
|
56
|
+
|
|
57
|
+
**CORS:** Default `[]` (deny-all), multi-origin via `--cors-origin`, wildcard subdomain support, `Access-Control-Max-Age: 86400`, `Vary: Origin`. Startup warning on wildcard `*`. Explicit configuration required for cross-origin access.
|
|
58
|
+
|
|
59
|
+
**Additional Hardening:**
|
|
60
|
+
|
|
61
|
+
- **Body size limit:** 1 MB default, `413` on excess
|
|
62
|
+
- **Trust proxy:** Opt-in for `X-Forwarded-For` extraction
|
|
63
|
+
- **Cross-protocol guard:** SSE IDs rejected on `/mcp` and vice versa
|
|
64
|
+
- **404 handler:** `{ error: "Not found" }` — never expose stack traces
|
|
65
|
+
- **Health endpoint:** `GET /health` always responds regardless of auth/rate limit
|
|
66
|
+
- **DNS rebinding:** SDK ≥1.24.0 provides `localhostHostValidation()` middleware. Implementations may use the SDK utility directly or a custom `validateHostHeader()` function in `security.ts` — both are valid. Apply to all custom Express configs
|
|
67
|
+
- **Constant-time token comparison:** Use `crypto.timingSafeEqual` for simple bearer token validation — never raw `===`. Both values must be `Buffer.from()`-wrapped with length pre-check (short-circuit on different lengths is acceptable since length is not the secret)
|
|
68
|
+
- **JWT claims sanitization:** Filter prototype-polluting keys (`__proto__`, `constructor`, `prototype`) from JWT payload before spreading into `TokenClaims`. Prevents prototype pollution via crafted tokens
|
|
69
|
+
- **Bearer auth scope limitation:** Simple bearer auth (`--auth-token`) authenticates but does NOT enforce per-tool scopes. Emit a startup warning when bearer auth is configured: `"Simple token auth does not enforce per-tool scopes. Use OAuth 2.1 for granular access control."`
|
|
70
|
+
- **Fail-closed scope default:** `getRequiredScope()` returns `'admin'` for unmapped tools (`toolScopeMap.get(toolName) ?? 'admin'`), not `'read'`. Unknown tools require maximum privilege
|
|
71
|
+
- **Path traversal validation:** `validateSameDirPath()` or `assertNoPathTraversal()` in `utils/validate-path.ts` for tools that write files (backup, dump, restore, attach). Resolves canonical path and rejects `..` traversal
|
|
72
|
+
|
|
73
|
+
> [!CAUTION]
|
|
74
|
+
> **CVE-2026-25536 — Cross-client data leakage (SDK 1.10.0–1.25.3):** Reusing a single `McpServer` instance across multiple transports can route responses to wrong clients. **Fix:** upgrade to SDK ≥1.26.0, or create separate instances per connection.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Tool Poisoning Defense (MCP-Specific)
|
|
79
|
+
|
|
80
|
+
Tool poisoning is a form of indirect prompt injection where malicious instructions are hidden in tool descriptions, annotations, or schema metadata. These instructions are invisible to human users but interpreted by AI models. OWASP Top 10 for LLM Applications 2025 ranks Prompt Injection #1 and Supply Chain #3 — tool description injection is the MCP-specific variant of both threats combined.
|
|
81
|
+
|
|
82
|
+
### Attack Vectors
|
|
83
|
+
|
|
84
|
+
| Vector | Description |
|
|
85
|
+
| ----------------------------- | -------------------------------------------------------------------------------------------- |
|
|
86
|
+
| **Description injection** | Malicious prompts embedded in tool `description` fields — agent follows them as instructions |
|
|
87
|
+
| **Schema metadata injection** | Hidden instructions in parameter `description` fields within `inputSchema` or `outputSchema` |
|
|
88
|
+
| **Rug pull** | Tool definitions are legitimate initially, then silently modified after installation |
|
|
89
|
+
| **Cross-tool poisoning** | One poisoned tool's output influences how the agent uses other tools |
|
|
90
|
+
|
|
91
|
+
### Mitigation
|
|
92
|
+
|
|
93
|
+
- **Tool pinning:** Pin MCP server versions (npm lockfile, Docker image digest). Never float on `latest` in production
|
|
94
|
+
- **Schema integrity:** Consider digitally signing tool schemas. Verify signatures before accepting tool definitions from third-party servers
|
|
95
|
+
- **Description review:** Treat tool descriptions as code — review changes in PRs. Automated scanners can flag linguistic patterns common in prompt injection
|
|
96
|
+
- **Minimal privilege:** Each tool must have accurate `annotations`. Don't mark tools as `readOnlyHint: true` when they perform writes
|
|
97
|
+
- **HITL for sensitive ops:** Tools that access secrets, modify auth, or perform destructive operations should prompt for user confirmation
|
|
98
|
+
- **Audit logging:** Log all tool invocations with parameters for forensic analysis
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Code Mode Security Hardening
|
|
103
|
+
|
|
104
|
+
Additional security requirements for servers implementing Code Mode (`{prefix}_execute_code`):
|
|
105
|
+
|
|
106
|
+
**Frozen Built-In Prototypes:** Inside the `vm` context, freeze all built-in prototypes to prevent constructor chain escapes (e.g., `'con'+'structor'` string concatenation bypasses static blocked pattern scanning):
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// In sandbox.ts / worker-script.ts — before executing user code:
|
|
110
|
+
const FROZEN_BUILTINS = [
|
|
111
|
+
Object,
|
|
112
|
+
Function,
|
|
113
|
+
Error,
|
|
114
|
+
Array,
|
|
115
|
+
Promise,
|
|
116
|
+
String,
|
|
117
|
+
Number,
|
|
118
|
+
Boolean,
|
|
119
|
+
RegExp,
|
|
120
|
+
Map,
|
|
121
|
+
Set,
|
|
122
|
+
WeakMap,
|
|
123
|
+
WeakSet,
|
|
124
|
+
ArrayBuffer,
|
|
125
|
+
SharedArrayBuffer,
|
|
126
|
+
DataView,
|
|
127
|
+
Int8Array,
|
|
128
|
+
Uint8Array,
|
|
129
|
+
Float64Array /* ... all typed arrays */,
|
|
130
|
+
]
|
|
131
|
+
for (const builtin of FROZEN_BUILTINS) {
|
|
132
|
+
Object.freeze(builtin.prototype)
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Additional Blocked Patterns** (in `security.ts`):
|
|
137
|
+
|
|
138
|
+
| Pattern | Why Blocked |
|
|
139
|
+
| ----------- | -------------------------------------------------------------------------------------------------------- |
|
|
140
|
+
| `Reflect.` | Reflection API enables prototype traversal |
|
|
141
|
+
| `Symbol.` | Symbol access can bypass property enumeration guards |
|
|
142
|
+
| `new Proxy` | Proxy traps can intercept and redirect any operation |
|
|
143
|
+
| `(SELECT` | WHERE clause subquery injection (blind data exfiltration via `CASE WHEN (SELECT ...) THEN ... ELSE ...`) |
|
|
144
|
+
|
|
145
|
+
**Filesystem Boundary Enforcement:** For servers with file I/O tools (backup, restore, import, export), implement `ALLOWED_IO_ROOTS` — a fail-closed allowlist of directories. Validate every file path argument against these roots before execution:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const ALLOWED_IO_ROOTS = [config.dataDir, config.backupDir].filter(Boolean)
|
|
149
|
+
|
|
150
|
+
function assertWithinBoundary(filePath: string): void {
|
|
151
|
+
const resolved = path.resolve(filePath)
|
|
152
|
+
if (!ALLOWED_IO_ROOTS.some((root) => resolved.startsWith(root))) {
|
|
153
|
+
throw new SecurityError(`Path '${filePath}' is outside allowed directories`)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Key Security Resources
|
|
161
|
+
|
|
162
|
+
- **OWASP Top 10 for LLM Applications 2025:** https://owasp.org/www-project-top-10-for-large-language-model-applications/
|
|
163
|
+
- **MCP Security Best Practices:** https://modelcontextprotocol.io/specification/draft/best-practices.md
|
|
164
|
+
- **RFC 9700 — OAuth 2.0 Security BCP (Jan 2025):** https://datatracker.ietf.org/doc/rfc9700/
|