@cyanheads/mcp-ts-core 0.13.9 → 0.13.11

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.
Files changed (192) hide show
  1. package/AGENTS.md +41 -15
  2. package/CLAUDE.md +41 -15
  3. package/README.md +37 -11
  4. package/biome.json +1 -1
  5. package/changelog/0.13.x/0.13.10.md +118 -0
  6. package/changelog/0.13.x/0.13.11.md +113 -0
  7. package/dist/cli/app-render.d.ts +11 -0
  8. package/dist/cli/app-render.d.ts.map +1 -0
  9. package/dist/cli/app-render.js +150 -0
  10. package/dist/cli/app-render.js.map +1 -0
  11. package/dist/cli/init.d.ts +2 -1
  12. package/dist/cli/init.d.ts.map +1 -1
  13. package/dist/cli/init.js +10 -2
  14. package/dist/cli/init.js.map +1 -1
  15. package/dist/config/index.d.ts +3 -0
  16. package/dist/config/index.d.ts.map +1 -1
  17. package/dist/config/index.js +11 -0
  18. package/dist/config/index.js.map +1 -1
  19. package/dist/core/app.d.ts.map +1 -1
  20. package/dist/core/app.js +15 -1
  21. package/dist/core/app.js.map +1 -1
  22. package/dist/core/context.d.ts +92 -22
  23. package/dist/core/context.d.ts.map +1 -1
  24. package/dist/core/context.js +65 -16
  25. package/dist/core/context.js.map +1 -1
  26. package/dist/core/index.d.ts +1 -1
  27. package/dist/core/index.d.ts.map +1 -1
  28. package/dist/core/index.js.map +1 -1
  29. package/dist/core/worker.d.ts +6 -0
  30. package/dist/core/worker.d.ts.map +1 -1
  31. package/dist/core/worker.js +1 -0
  32. package/dist/core/worker.js.map +1 -1
  33. package/dist/linter/rules/error-contract-rules.d.ts +3 -44
  34. package/dist/linter/rules/error-contract-rules.d.ts.map +1 -1
  35. package/dist/linter/rules/error-contract-rules.js +8 -144
  36. package/dist/linter/rules/error-contract-rules.js.map +1 -1
  37. package/dist/linter/rules/index.d.ts +1 -1
  38. package/dist/linter/rules/index.d.ts.map +1 -1
  39. package/dist/linter/rules/index.js +1 -1
  40. package/dist/linter/rules/index.js.map +1 -1
  41. package/dist/linter/rules/resource-rules.d.ts.map +1 -1
  42. package/dist/linter/rules/resource-rules.js +1 -2
  43. package/dist/linter/rules/resource-rules.js.map +1 -1
  44. package/dist/linter/rules/tool-rules.d.ts.map +1 -1
  45. package/dist/linter/rules/tool-rules.js +1 -2
  46. package/dist/linter/rules/tool-rules.js.map +1 -1
  47. package/dist/mcp-server/handlerContext.d.ts +26 -13
  48. package/dist/mcp-server/handlerContext.d.ts.map +1 -1
  49. package/dist/mcp-server/handlerContext.js +32 -17
  50. package/dist/mcp-server/handlerContext.js.map +1 -1
  51. package/dist/mcp-server/inputRequired.d.ts +120 -8
  52. package/dist/mcp-server/inputRequired.d.ts.map +1 -1
  53. package/dist/mcp-server/inputRequired.js +177 -12
  54. package/dist/mcp-server/inputRequired.js.map +1 -1
  55. package/dist/mcp-server/prompts/prompt-registration.d.ts +10 -2
  56. package/dist/mcp-server/prompts/prompt-registration.d.ts.map +1 -1
  57. package/dist/mcp-server/prompts/prompt-registration.js +49 -11
  58. package/dist/mcp-server/prompts/prompt-registration.js.map +1 -1
  59. package/dist/mcp-server/resources/resource-registration.d.ts +4 -2
  60. package/dist/mcp-server/resources/resource-registration.d.ts.map +1 -1
  61. package/dist/mcp-server/resources/resource-registration.js +6 -4
  62. package/dist/mcp-server/resources/resource-registration.js.map +1 -1
  63. package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts +4 -3
  64. package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
  65. package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +60 -21
  66. package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
  67. package/dist/mcp-server/server.d.ts +9 -0
  68. package/dist/mcp-server/server.d.ts.map +1 -1
  69. package/dist/mcp-server/server.js +14 -13
  70. package/dist/mcp-server/server.js.map +1 -1
  71. package/dist/mcp-server/tools/tool-registration.d.ts +7 -3
  72. package/dist/mcp-server/tools/tool-registration.d.ts.map +1 -1
  73. package/dist/mcp-server/tools/tool-registration.js +9 -5
  74. package/dist/mcp-server/tools/tool-registration.js.map +1 -1
  75. package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts +17 -9
  76. package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts.map +1 -1
  77. package/dist/mcp-server/tools/utils/toolHandlerFactory.js +91 -50
  78. package/dist/mcp-server/tools/utils/toolHandlerFactory.js.map +1 -1
  79. package/dist/mcp-server/transports/http/httpErrorHandler.d.ts.map +1 -1
  80. package/dist/mcp-server/transports/http/httpErrorHandler.js +7 -1
  81. package/dist/mcp-server/transports/http/httpErrorHandler.js.map +1 -1
  82. package/dist/services/mirror/sqlite/handle.d.ts +11 -5
  83. package/dist/services/mirror/sqlite/handle.d.ts.map +1 -1
  84. package/dist/services/mirror/sqlite/handle.js +46 -8
  85. package/dist/services/mirror/sqlite/handle.js.map +1 -1
  86. package/dist/services/mirror/sqlite/sqliteMirrorStore.d.ts +6 -1
  87. package/dist/services/mirror/sqlite/sqliteMirrorStore.d.ts.map +1 -1
  88. package/dist/services/mirror/sqlite/sqliteMirrorStore.js.map +1 -1
  89. package/dist/testing/apps/browser.d.ts +27 -0
  90. package/dist/testing/apps/browser.d.ts.map +1 -0
  91. package/dist/testing/apps/browser.js +162 -0
  92. package/dist/testing/apps/browser.js.map +1 -0
  93. package/dist/testing/apps/cdp-pipe.d.ts +79 -0
  94. package/dist/testing/apps/cdp-pipe.d.ts.map +1 -0
  95. package/dist/testing/apps/cdp-pipe.js +200 -0
  96. package/dist/testing/apps/cdp-pipe.js.map +1 -0
  97. package/dist/testing/apps/csp.d.ts +17 -0
  98. package/dist/testing/apps/csp.d.ts.map +1 -0
  99. package/dist/testing/apps/csp.js +50 -0
  100. package/dist/testing/apps/csp.js.map +1 -0
  101. package/dist/testing/apps/host-pages.d.ts +47 -0
  102. package/dist/testing/apps/host-pages.d.ts.map +1 -0
  103. package/dist/testing/apps/host-pages.js +138 -0
  104. package/dist/testing/apps/host-pages.js.map +1 -0
  105. package/dist/testing/apps/index.d.ts +167 -0
  106. package/dist/testing/apps/index.d.ts.map +1 -0
  107. package/dist/testing/apps/index.js +36 -0
  108. package/dist/testing/apps/index.js.map +1 -0
  109. package/dist/testing/apps/partial-json.d.ts +14 -0
  110. package/dist/testing/apps/partial-json.d.ts.map +1 -0
  111. package/dist/testing/apps/partial-json.js +71 -0
  112. package/dist/testing/apps/partial-json.js.map +1 -0
  113. package/dist/testing/apps/run.d.ts +13 -0
  114. package/dist/testing/apps/run.d.ts.map +1 -0
  115. package/dist/testing/apps/run.js +659 -0
  116. package/dist/testing/apps/run.js.map +1 -0
  117. package/dist/testing/index.d.ts +17 -2
  118. package/dist/testing/index.d.ts.map +1 -1
  119. package/dist/testing/index.js +21 -7
  120. package/dist/testing/index.js.map +1 -1
  121. package/dist/types-global/errors.d.ts +18 -15
  122. package/dist/types-global/errors.d.ts.map +1 -1
  123. package/dist/utils/index.d.ts +1 -1
  124. package/dist/utils/index.d.ts.map +1 -1
  125. package/dist/utils/index.js +1 -1
  126. package/dist/utils/index.js.map +1 -1
  127. package/dist/utils/internal/error-handler/errorHandler.d.ts +5 -4
  128. package/dist/utils/internal/error-handler/errorHandler.d.ts.map +1 -1
  129. package/dist/utils/internal/error-handler/errorHandler.js +9 -7
  130. package/dist/utils/internal/error-handler/errorHandler.js.map +1 -1
  131. package/dist/utils/internal/error-handler/types.d.ts +3 -1
  132. package/dist/utils/internal/error-handler/types.d.ts.map +1 -1
  133. package/dist/utils/internal/logger.d.ts +21 -1
  134. package/dist/utils/internal/logger.d.ts.map +1 -1
  135. package/dist/utils/internal/logger.js +31 -14
  136. package/dist/utils/internal/logger.js.map +1 -1
  137. package/dist/utils/internal/performance.d.ts +7 -3
  138. package/dist/utils/internal/performance.d.ts.map +1 -1
  139. package/dist/utils/internal/performance.js +16 -9
  140. package/dist/utils/internal/performance.js.map +1 -1
  141. package/dist/utils/internal/telemetryMessages.d.ts +0 -1
  142. package/dist/utils/internal/telemetryMessages.d.ts.map +1 -1
  143. package/dist/utils/internal/telemetryMessages.js +0 -1
  144. package/dist/utils/internal/telemetryMessages.js.map +1 -1
  145. package/dist/utils/security/sanitization.d.ts +16 -13
  146. package/dist/utils/security/sanitization.d.ts.map +1 -1
  147. package/dist/utils/security/sanitization.js +74 -33
  148. package/dist/utils/security/sanitization.js.map +1 -1
  149. package/dist/utils/telemetry/attributes.d.ts +12 -5
  150. package/dist/utils/telemetry/attributes.d.ts.map +1 -1
  151. package/dist/utils/telemetry/attributes.js +12 -5
  152. package/dist/utils/telemetry/attributes.js.map +1 -1
  153. package/framework-skills/add-app-tool/SKILL.md +2 -1
  154. package/framework-skills/add-service/SKILL.md +3 -12
  155. package/framework-skills/add-test/SKILL.md +20 -17
  156. package/framework-skills/add-tool/SKILL.md +30 -34
  157. package/framework-skills/api-config/SKILL.md +12 -2
  158. package/framework-skills/api-context/SKILL.md +156 -41
  159. package/framework-skills/api-errors/SKILL.md +43 -47
  160. package/framework-skills/api-linter/SKILL.md +5 -29
  161. package/framework-skills/api-mirror/SKILL.md +4 -3
  162. package/framework-skills/api-telemetry/SKILL.md +16 -10
  163. package/framework-skills/api-testing/SKILL.md +47 -11
  164. package/framework-skills/api-utils/SKILL.md +3 -3
  165. package/framework-skills/api-workers/SKILL.md +3 -1
  166. package/framework-skills/code-simplifier/SKILL.md +2 -2
  167. package/framework-skills/design-mcp-server/SKILL.md +5 -5
  168. package/framework-skills/field-test/SKILL.md +53 -8
  169. package/framework-skills/git-wrapup/SKILL.md +2 -2
  170. package/framework-skills/orchestrations/SKILL.md +1 -1
  171. package/framework-skills/orchestrations/workflows/greenfield-build.md +2 -2
  172. package/framework-skills/polish-docs-meta/SKILL.md +4 -3
  173. package/framework-skills/polish-docs-meta/references/server-json.md +24 -26
  174. package/framework-skills/release-and-publish/SKILL.md +3 -3
  175. package/framework-skills/release-pr-review/SKILL.md +6 -6
  176. package/framework-skills/security-pass/SKILL.md +8 -7
  177. package/framework-skills/setup/SKILL.md +2 -2
  178. package/package.json +38 -22
  179. package/scripts/devcheck.ts +43 -21
  180. package/scripts/install-otel.ts +84 -0
  181. package/scripts/lint-packaging.ts +279 -28
  182. package/scripts/prune-musl-packages.ts +146 -0
  183. package/templates/.env.example +2 -0
  184. package/templates/.github/workflows/codeql.yml +10 -1
  185. package/templates/AGENTS.md +5 -4
  186. package/templates/CLAUDE.md +5 -4
  187. package/templates/Dockerfile +76 -50
  188. package/templates/_.dockerignore +3 -5
  189. package/templates/_.gitignore +4 -4
  190. package/templates/package.json +4 -4
  191. package/templates/server.json +7 -21
  192. package/templates/src/mcp-server/tools/definitions/echo.tool.ts +3 -8
@@ -4,7 +4,7 @@ description: >
4
4
  Post-init orientation for an MCP server built on @cyanheads/mcp-ts-core. Use after running `@cyanheads/mcp-ts-core init` to understand the project structure, conventions, and skill sync model. Also use when onboarding to an existing project for the first time.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.11"
7
+ version: "1.12"
8
8
  audience: external
9
9
  type: workflow
10
10
  ---
@@ -40,7 +40,7 @@ Dockerfile # Starter multi-stage image
40
40
  .vscode/ # Recommended extensions + editor settings
41
41
  server.json # MCP Registry publishing metadata
42
42
  changelog/template.md # Format reference for per-version changelog files
43
- scripts/ # build, clean, devcheck, lint-mcp, list-skills, build-changelog, tree, check-docs-sync
43
+ scripts/ # Framework scripts (build, devcheck and its checks, lint-mcp, lint-packaging, Docker install-otel and prune-musl-packages, release-github, …), re-synced by `maintenance`
44
44
  framework-skills/ # External skills copied from the package (source of truth)
45
45
  src/
46
46
  index.ts # createApp() entry point
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/mcp-ts-core",
3
- "version": "0.13.9",
3
+ "version": "0.13.11",
4
4
  "mcpName": "io.github.cyanheads/mcp-ts-core",
5
5
  "description": "Agent-native TypeScript framework for MCP servers. Includes runtime infrastructure and agent skills for building, testing, and shipping servers.",
6
6
  "files": [
@@ -16,9 +16,11 @@
16
16
  "scripts/clean-mcpb.ts",
17
17
  "scripts/clean.ts",
18
18
  "scripts/devcheck.ts",
19
+ "scripts/install-otel.ts",
19
20
  "scripts/lint-mcp.ts",
20
21
  "scripts/lint-packaging.ts",
21
22
  "scripts/list-skills.ts",
23
+ "scripts/prune-musl-packages.ts",
22
24
  "scripts/release-github.ts",
23
25
  "scripts/tree.ts",
24
26
  "framework-skills/",
@@ -113,6 +115,11 @@
113
115
  "import": "./dist/testing/index.js",
114
116
  "default": "./dist/testing/index.js"
115
117
  },
118
+ "./testing/apps": {
119
+ "types": "./dist/testing/apps/index.d.ts",
120
+ "import": "./dist/testing/apps/index.js",
121
+ "default": "./dist/testing/apps/index.js"
122
+ },
116
123
  "./testing/fuzz": {
117
124
  "types": "./dist/testing/fuzz.d.ts",
118
125
  "import": "./dist/testing/fuzz.js",
@@ -196,12 +203,13 @@
196
203
  "publish-mcp": "mcp-publisher login github -token \"$(security find-generic-password -a \"$USER\" -s mcp-publisher-github-pat -w)\" && mcp-publisher publish"
197
204
  },
198
205
  "devDependencies": {
199
- "@biomejs/biome": "2.5.14",
206
+ "@biomejs/biome": "2.5.15",
200
207
  "@cloudflare/vitest-pool-workers": "^0.22.0",
201
- "@cloudflare/workers-types": "5.20260922.1",
202
- "@duckdb/node-api": "^1.5.5-r.5",
203
- "@hono/otel": "^1.1.2",
204
- "@modelcontextprotocol/client": "^2.1.0",
208
+ "@cloudflare/workers-types": "5.20260930.2",
209
+ "@duckdb/node-api": "^1.5.6-r.1",
210
+ "@hono/otel": "^1.2.0",
211
+ "@modelcontextprotocol/client": "^2.2.0",
212
+ "@modelcontextprotocol/ext-apps": "^2.0.3",
205
213
  "@opentelemetry/api-logs": "^0.222.0",
206
214
  "@opentelemetry/exporter-logs-otlp-http": "^0.222.0",
207
215
  "@opentelemetry/exporter-metrics-otlp-http": "^0.222.0",
@@ -215,11 +223,11 @@
215
223
  "@opentelemetry/sdk-trace-node": "^2.11.0",
216
224
  "@opentelemetry/semantic-conventions": "^1.43.0",
217
225
  "@socketsecurity/bun-security-scanner": "^1.1.3",
218
- "@supabase/supabase-js": "^2.117.1",
226
+ "@supabase/supabase-js": "^2.117.2",
219
227
  "@types/bun": "^1.4.2",
220
- "@types/node": "26.6.2",
228
+ "@types/node": "26.6.3",
221
229
  "@types/papaparse": "^5.5.2",
222
- "@types/sanitize-html": "^2.16.1",
230
+ "@types/sanitize-html": "^2.16.2",
223
231
  "@vitest/coverage-istanbul": "4.1.11",
224
232
  "@vitest/ui": "4.1.11",
225
233
  "better-sqlite3": "^13.0.3",
@@ -230,24 +238,24 @@
230
238
  "diff": "^9.0.0",
231
239
  "execa": "^10.0.1",
232
240
  "fast-check": "^4.10.2",
233
- "fast-xml-parser": "^5.11.1",
234
- "ignore": "^7.0.10",
241
+ "fast-xml-parser": "^5.11.2",
242
+ "ignore": "^7.0.11",
235
243
  "js-yaml": "^5.4.2",
236
244
  "linkedom": "^0.18.13",
237
245
  "node-cron": "^4.6.0",
238
- "openai": "^7.23.0",
246
+ "openai": "^7.25.0",
239
247
  "papaparse": "^5.7.0",
240
248
  "partial-json": "^0.1.7",
241
249
  "pdf-lib": "^1.17.1",
242
250
  "pino-pretty": "^13.1.3",
243
251
  "repomix": "^1.18.1",
244
- "sanitize-html": "^2.17.7",
245
- "tsc-alias": "^1.9.5",
252
+ "sanitize-html": "^2.18.0",
253
+ "tsc-alias": "^1.9.7",
246
254
  "typedoc": "^0.28.20",
247
255
  "typescript": "^7.0.2",
248
256
  "typescript-v6": "npm:typescript@^6.0.3",
249
257
  "unpdf": "^1.8.1",
250
- "vite": "8.3.0",
258
+ "vite": "8.3.1",
251
259
  "vitest": "^4.1.11"
252
260
  },
253
261
  "keywords": [
@@ -289,17 +297,19 @@
289
297
  "access": "public"
290
298
  },
291
299
  "dependencies": {
292
- "@hono/node-server": "^2.1.1",
293
- "@modelcontextprotocol/server": "^2.1.0",
300
+ "@hono/node-server": "^2.1.3",
301
+ "@modelcontextprotocol/server": "^2.2.0",
294
302
  "@opentelemetry/api": "^1.9.1",
295
- "hono": "^4.13.8",
303
+ "hono": "^4.13.12",
296
304
  "jose": "^6.2.12",
297
305
  "pino": "^10.3.1",
298
306
  "zod": "^4.6.5"
299
307
  },
300
308
  "peerDependencies": {
301
- "@duckdb/node-api": "^1.5.5-r.1",
309
+ "@duckdb/node-api": "^1.5.5-r.1 || ^1.5.6-r.1",
302
310
  "@hono/otel": "^1.1.2",
311
+ "@modelcontextprotocol/client": "^2.1.0",
312
+ "@modelcontextprotocol/ext-apps": "^2.0.0",
303
313
  "@opentelemetry/api-logs": "^0.222.0",
304
314
  "@opentelemetry/exporter-logs-otlp-http": "^0.222.0",
305
315
  "@opentelemetry/exporter-metrics-otlp-http": "^0.222.0",
@@ -338,6 +348,12 @@
338
348
  "@hono/otel": {
339
349
  "optional": true
340
350
  },
351
+ "@modelcontextprotocol/client": {
352
+ "optional": true
353
+ },
354
+ "@modelcontextprotocol/ext-apps": {
355
+ "optional": true
356
+ },
341
357
  "@opentelemetry/api-logs": {
342
358
  "optional": true
343
359
  },
@@ -427,12 +443,12 @@
427
443
  }
428
444
  },
429
445
  "overrides": {
430
- "brace-expansion": "^2.1.3",
446
+ "brace-expansion": "^2.1.7",
431
447
  "postcss": "^8.5.23",
432
448
  "protobufjs": "^7.6.5",
433
449
  "sharp": "^0.35.3",
434
- "fast-uri": "^3.1.6",
435
- "ip-address": "^10.3.1",
450
+ "fast-uri": "^3.1.8",
451
+ "ip-address": "^10.7.1",
436
452
  "nanoid": "^3.3.18"
437
453
  }
438
454
  }
@@ -639,15 +639,25 @@ const ALL_CHECKS: Check[] = [
639
639
  canFix: false,
640
640
  getCommand: (ctx) => {
641
641
  if (!isGitRepo()) return null; // no repo to grep — fresh scaffold before `git init`
642
- // git grep -n (line number) -E (extended regex) -i (case-insensitive)
643
- const baseCmd = ['git', 'grep', '-nEi', '\\b(TODO|FIXME)\\b'];
644
- // Exclude files where TODO/FIXME appears as prose or intentional stubs
642
+ // -w is git's own whole-word test: macOS's regex library reads `\b` in an
643
+ // extended regex as a literal `b`. Case-sensitive, so a lowercase `todo`
644
+ // variable or stop word is not a marker.
645
+ const baseCmd = ['git', 'grep', '-nwE', '(TODO|FIXME)'];
646
+ // Exclude files where TODO/FIXME appears as prose or intentional stubs:
647
+ // changelogs, tests, this script, and the framework's skill prose wherever
648
+ // the maintenance sync copies it.
645
649
  const excludes = [
646
650
  ':!CHANGELOG.md',
647
651
  ':!changelog/',
648
652
  ':!*.lock',
649
653
  ':!scripts/devcheck.ts',
650
654
  ':!tests/',
655
+ ':!framework-skills/',
656
+ ':!.claude/skills/',
657
+ ':!.agents/skills/',
658
+ ':!.codex/skills/',
659
+ ':!.cursor/skills/',
660
+ ':!.windsurf/skills/',
651
661
  ];
652
662
  if (ctx.isHuskyHook && ctx.stagedFiles.length > 0) {
653
663
  // Check only staged files in the working tree
@@ -670,28 +680,38 @@ const ALL_CHECKS: Check[] = [
670
680
  name: 'Tracked Secrets',
671
681
  flag: '--no-secrets',
672
682
  canFix: false,
673
- // Check if common sensitive files are tracked by git.
683
+ // Check if common sensitive files are tracked by git. `:(glob)` makes `**/`
684
+ // match zero or more directories, so each shape is caught at the repository
685
+ // root too; under it `*` stops at `/`, so the two name-prefix shapes carry a
686
+ // `/**` twin for the files inside a directory of that name (`secrets/`,
687
+ // `.env.d/`).
674
688
  getCommand: () => {
675
689
  if (!isGitRepo()) return null; // no repo — `git ls-files` would exit 128, not a finding
676
690
  return [
677
691
  'git',
678
692
  'ls-files',
679
- '*.env*',
680
- '**/.npmrc',
681
- '**/.netrc',
682
- '**/credentials.json',
683
- '**/*.pem',
684
- '**/*.key',
685
- '**/secret*',
686
- '**/.htpasswd',
693
+ ':(glob)**/*.env*',
694
+ ':(glob)**/*.env*/**',
695
+ ':(glob)**/.npmrc',
696
+ ':(glob)**/.netrc',
697
+ ':(glob)**/credentials.json',
698
+ ':(glob)**/*.pem',
699
+ ':(glob)**/*.key',
700
+ ':(glob)**/secret*',
701
+ ':(glob)**/secret*/**',
702
+ ':(glob)**/.htpasswd',
687
703
  ];
688
704
  },
689
- // Success if output is empty OR only contains safe patterns.
705
+ // Success if output is empty OR only contains safe files: `.env` templates
706
+ // anywhere, and GitHub's secret scanning config at the one path it reads.
690
707
  isSuccess: (result, _mode) => {
691
708
  if (result.exitCode !== 0) return false;
692
- const SAFE_PATTERNS = ['.env.example', '.env.template', '.env.sample'];
709
+ const SAFE_SUFFIXES = ['.env.example', '.env.template', '.env.sample'];
710
+ const SAFE_PATHS = ['.github/secret_scanning.yml'];
693
711
  const files = result.stdout.trim().split('\n').filter(Boolean);
694
- const dangerous = files.filter((f) => !SAFE_PATTERNS.some((safe) => f.endsWith(safe)));
712
+ const dangerous = files.filter(
713
+ (f) => !SAFE_PATHS.includes(f) && !SAFE_SUFFIXES.some((safe) => f.endsWith(safe)),
714
+ );
695
715
  return dangerous.length === 0;
696
716
  },
697
717
  tip: (c) =>
@@ -712,11 +732,12 @@ const ALL_CHECKS: Check[] = [
712
732
  // Validates env var alignment between manifest.json (MCPB bundle) and
713
733
  // server.json (MCP Registry), plus plugin marketplace manifests (#240), the
714
734
  // bundle-content guards on .mcpbignore (#343), the README version badge
715
- // (#418), and the Dockerfile build platform. Runs when any of those inputs
716
- // is present; skipped cleanly when none exist — consumers on an HTTP-only
717
- // deploy are unaffected. README.md and Dockerfile are triggers in their own
718
- // right: each check must gate a project that carries no bundle or plugin
719
- // metadata at all, which the other inputs only covered incidentally.
735
+ // (#418), the Dockerfile build platform, and the launch shape of server.json
736
+ // npm entries (#622). Runs when any of those inputs is present; skipped
737
+ // cleanly when none exist — consumers on an HTTP-only deploy are unaffected.
738
+ // README.md, Dockerfile, and server.json are triggers in their own right:
739
+ // each check must gate a project that carries no bundle or plugin metadata
740
+ // at all, which the other inputs only covered incidentally.
720
741
  getCommand: () => {
721
742
  const inputs = [
722
743
  'manifest.json',
@@ -726,12 +747,13 @@ const ALL_CHECKS: Check[] = [
726
747
  '.mcpbignore',
727
748
  'README.md',
728
749
  'Dockerfile',
750
+ 'server.json',
729
751
  ];
730
752
  if (!inputs.some((input) => existsSync(path.join(ROOT_DIR, input)))) return null;
731
753
  return ['bun', 'run', 'scripts/lint-packaging.ts'];
732
754
  },
733
755
  tip: (c) =>
734
- `Align env var names between ${c.bold('manifest.json')} ${c.bold('mcp_config.env')} and ${c.bold('server.json')} stdio package ${c.bold('environmentVariables[]')}.`,
756
+ `Each ${c.bold('✗')} line above names the file and the change that fixes it; ${c.bold('scripts/lint-packaging.ts')} documents every check.`,
735
757
  },
736
758
  {
737
759
  name: 'Framework Antipatterns',
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * @fileoverview Installs the OpenTelemetry packages the framework loads at
4
+ * runtime into a production dependency tree — the Dockerfile's OTel step.
5
+ *
6
+ * The list is every `peerDependencies` entry named `@opentelemetry/*`, plus
7
+ * `@hono/otel`, in `@cyanheads/mcp-ts-core/package.json` resolved from the
8
+ * project root: the installed framework in a server, the package itself (by
9
+ * self-reference) in the framework. Each package moves into the project's
10
+ * `dependencies` at its declared peer range, out of `peerDependencies`,
11
+ * `peerDependenciesMeta`, and `devDependencies`, so `--omit=peer` keeps it
12
+ * while every other optional peer stays out. Then `bun install --omit=dev
13
+ * --omit=peer --ignore-scripts` runs with every argument given to this script
14
+ * appended, under the project's `bunfig.toml`, and its exit code is this
15
+ * script's. Not `--production`: it implies `--frozen-lockfile`, which fails
16
+ * once the manifest gains packages the lockfile lacks.
17
+ *
18
+ * @example
19
+ * // In a Dockerfile stage on $BUILDPLATFORM, cross-installing for the target:
20
+ * // bun scripts/install-otel.ts --os=linux --cpu=x64
21
+ * @module scripts/install-otel
22
+ */
23
+ import { spawnSync } from 'node:child_process';
24
+ import { readFileSync, writeFileSync } from 'node:fs';
25
+ import { createRequire } from 'node:module';
26
+ import { join, resolve } from 'node:path';
27
+ import { fileURLToPath } from 'node:url';
28
+
29
+ interface Manifest {
30
+ dependencies?: Record<string, string>;
31
+ devDependencies?: Record<string, string>;
32
+ peerDependencies?: Record<string, string>;
33
+ peerDependenciesMeta?: Record<string, unknown>;
34
+ }
35
+
36
+ /** The OTel optional peers a framework manifest declares, keyed by name, at their declared ranges. */
37
+ export function otelPeers(framework: Manifest): Record<string, string> {
38
+ return Object.fromEntries(
39
+ Object.entries(framework.peerDependencies ?? {}).filter(
40
+ ([name]) => name.startsWith('@opentelemetry/') || name === '@hono/otel',
41
+ ),
42
+ );
43
+ }
44
+
45
+ function main(args: string[]): number {
46
+ const manifestPath = join(process.cwd(), 'package.json');
47
+ const frameworkPath = createRequire(manifestPath).resolve('@cyanheads/mcp-ts-core/package.json');
48
+ const peers = otelPeers(JSON.parse(readFileSync(frameworkPath, 'utf8')) as Manifest);
49
+ const names = Object.keys(peers);
50
+ if (names.length === 0) {
51
+ console.error(
52
+ `install-otel: ${frameworkPath} declares no @opentelemetry/* or @hono/otel peerDependencies — nothing to install.`,
53
+ );
54
+ return 1;
55
+ }
56
+
57
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as Manifest;
58
+ manifest.dependencies = { ...manifest.dependencies, ...peers };
59
+ for (const name of names) {
60
+ delete manifest.peerDependencies?.[name];
61
+ delete manifest.peerDependenciesMeta?.[name];
62
+ delete manifest.devDependencies?.[name];
63
+ }
64
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
65
+ console.log(
66
+ `install-otel: ${names.length} OpenTelemetry packages from ${frameworkPath}: ` +
67
+ names.map((name) => `${name}@${peers[name]}`).join(' '),
68
+ );
69
+
70
+ const install = spawnSync(
71
+ 'bun',
72
+ ['install', '--omit=dev', '--omit=peer', '--ignore-scripts', ...args],
73
+ { stdio: 'inherit' },
74
+ );
75
+ if (install.error) {
76
+ console.error(`install-otel: could not run bun install: ${install.error.message}`);
77
+ return 1;
78
+ }
79
+ return install.status ?? 1;
80
+ }
81
+
82
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
83
+ process.exit(main(process.argv.slice(2)));
84
+ }