@ttctl/mcp 0.0.0 → 0.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +72 -9
  2. package/dist/auth.d.ts +40 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +69 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/data-handling.d.ts +91 -0
  7. package/dist/data-handling.d.ts.map +1 -0
  8. package/dist/data-handling.js +129 -0
  9. package/dist/data-handling.js.map +1 -0
  10. package/dist/diagnostic.d.ts +262 -0
  11. package/dist/diagnostic.d.ts.map +1 -0
  12. package/dist/diagnostic.js +362 -0
  13. package/dist/diagnostic.js.map +1 -0
  14. package/dist/errors.d.ts +54 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +48 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/index.d.ts +8 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +7 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/kill-switch-hook.d.ts +67 -0
  23. package/dist/kill-switch-hook.d.ts.map +1 -0
  24. package/dist/kill-switch-hook.js +61 -0
  25. package/dist/kill-switch-hook.js.map +1 -0
  26. package/dist/server.d.ts +100 -0
  27. package/dist/server.d.ts.map +1 -0
  28. package/dist/server.js +157 -0
  29. package/dist/server.js.map +1 -0
  30. package/dist/tools/_shared.d.ts +227 -0
  31. package/dist/tools/_shared.d.ts.map +1 -0
  32. package/dist/tools/_shared.js +238 -0
  33. package/dist/tools/_shared.js.map +1 -0
  34. package/dist/tools/applications.d.ts +27 -0
  35. package/dist/tools/applications.d.ts.map +1 -0
  36. package/dist/tools/applications.js +192 -0
  37. package/dist/tools/applications.js.map +1 -0
  38. package/dist/tools/availability.d.ts +33 -0
  39. package/dist/tools/availability.d.ts.map +1 -0
  40. package/dist/tools/availability.js +272 -0
  41. package/dist/tools/availability.js.map +1 -0
  42. package/dist/tools/contracts.d.ts +29 -0
  43. package/dist/tools/contracts.d.ts.map +1 -0
  44. package/dist/tools/contracts.js +157 -0
  45. package/dist/tools/contracts.js.map +1 -0
  46. package/dist/tools/engagements.d.ts +36 -0
  47. package/dist/tools/engagements.d.ts.map +1 -0
  48. package/dist/tools/engagements.js +408 -0
  49. package/dist/tools/engagements.js.map +1 -0
  50. package/dist/tools/file-upload.d.ts +133 -0
  51. package/dist/tools/file-upload.d.ts.map +1 -0
  52. package/dist/tools/file-upload.js +247 -0
  53. package/dist/tools/file-upload.js.map +1 -0
  54. package/dist/tools/index.d.ts +28 -0
  55. package/dist/tools/index.d.ts.map +1 -0
  56. package/dist/tools/index.js +131 -0
  57. package/dist/tools/index.js.map +1 -0
  58. package/dist/tools/jobs.d.ts +37 -0
  59. package/dist/tools/jobs.d.ts.map +1 -0
  60. package/dist/tools/jobs.js +505 -0
  61. package/dist/tools/jobs.js.map +1 -0
  62. package/dist/tools/output-schemas.d.ts +115 -0
  63. package/dist/tools/output-schemas.d.ts.map +1 -0
  64. package/dist/tools/output-schemas.js +130 -0
  65. package/dist/tools/output-schemas.js.map +1 -0
  66. package/dist/tools/payments.d.ts +36 -0
  67. package/dist/tools/payments.d.ts.map +1 -0
  68. package/dist/tools/payments.js +373 -0
  69. package/dist/tools/payments.js.map +1 -0
  70. package/dist/tools/profile/certifications.d.ts +18 -0
  71. package/dist/tools/profile/certifications.d.ts.map +1 -0
  72. package/dist/tools/profile/certifications.js +193 -0
  73. package/dist/tools/profile/certifications.js.map +1 -0
  74. package/dist/tools/profile/education.d.ts +23 -0
  75. package/dist/tools/profile/education.d.ts.map +1 -0
  76. package/dist/tools/profile/education.js +196 -0
  77. package/dist/tools/profile/education.js.map +1 -0
  78. package/dist/tools/profile/employment.d.ts +23 -0
  79. package/dist/tools/profile/employment.d.ts.map +1 -0
  80. package/dist/tools/profile/employment.js +228 -0
  81. package/dist/tools/profile/employment.js.map +1 -0
  82. package/dist/tools/profile/industries.d.ts +22 -0
  83. package/dist/tools/profile/industries.d.ts.map +1 -0
  84. package/dist/tools/profile/industries.js +168 -0
  85. package/dist/tools/profile/industries.js.map +1 -0
  86. package/dist/tools/profile/portfolio.d.ts +22 -0
  87. package/dist/tools/profile/portfolio.d.ts.map +1 -0
  88. package/dist/tools/profile/portfolio.js +341 -0
  89. package/dist/tools/profile/portfolio.js.map +1 -0
  90. package/dist/tools/profile/resume.d.ts +16 -0
  91. package/dist/tools/profile/resume.d.ts.map +1 -0
  92. package/dist/tools/profile/resume.js +107 -0
  93. package/dist/tools/profile/resume.js.map +1 -0
  94. package/dist/tools/profile/shared.d.ts +85 -0
  95. package/dist/tools/profile/shared.d.ts.map +1 -0
  96. package/dist/tools/profile/shared.js +128 -0
  97. package/dist/tools/profile/shared.js.map +1 -0
  98. package/dist/tools/profile/visas.d.ts +15 -0
  99. package/dist/tools/profile/visas.d.ts.map +1 -0
  100. package/dist/tools/profile/visas.js +170 -0
  101. package/dist/tools/profile/visas.js.map +1 -0
  102. package/dist/tools/profile_basic_photo_show.d.ts +14 -0
  103. package/dist/tools/profile_basic_photo_show.d.ts.map +1 -0
  104. package/dist/tools/profile_basic_photo_show.js +59 -0
  105. package/dist/tools/profile_basic_photo_show.js.map +1 -0
  106. package/dist/tools/profile_basic_photo_upload.d.ts +24 -0
  107. package/dist/tools/profile_basic_photo_upload.d.ts.map +1 -0
  108. package/dist/tools/profile_basic_photo_upload.js +90 -0
  109. package/dist/tools/profile_basic_photo_upload.js.map +1 -0
  110. package/dist/tools/profile_basic_show.d.ts +19 -0
  111. package/dist/tools/profile_basic_show.d.ts.map +1 -0
  112. package/dist/tools/profile_basic_show.js +64 -0
  113. package/dist/tools/profile_basic_show.js.map +1 -0
  114. package/dist/tools/profile_basic_update.d.ts +37 -0
  115. package/dist/tools/profile_basic_update.d.ts.map +1 -0
  116. package/dist/tools/profile_basic_update.js +97 -0
  117. package/dist/tools/profile_basic_update.js.map +1 -0
  118. package/dist/tools/profile_external_advanced_wizard_show.d.ts +14 -0
  119. package/dist/tools/profile_external_advanced_wizard_show.d.ts.map +1 -0
  120. package/dist/tools/profile_external_advanced_wizard_show.js +56 -0
  121. package/dist/tools/profile_external_advanced_wizard_show.js.map +1 -0
  122. package/dist/tools/profile_external_custom_requirements_set.d.ts +13 -0
  123. package/dist/tools/profile_external_custom_requirements_set.d.ts.map +1 -0
  124. package/dist/tools/profile_external_custom_requirements_set.js +75 -0
  125. package/dist/tools/profile_external_custom_requirements_set.js.map +1 -0
  126. package/dist/tools/profile_external_custom_requirements_show.d.ts +14 -0
  127. package/dist/tools/profile_external_custom_requirements_show.d.ts.map +1 -0
  128. package/dist/tools/profile_external_custom_requirements_show.js +56 -0
  129. package/dist/tools/profile_external_custom_requirements_show.js.map +1 -0
  130. package/dist/tools/profile_external_readiness.d.ts +12 -0
  131. package/dist/tools/profile_external_readiness.d.ts.map +1 -0
  132. package/dist/tools/profile_external_readiness.js +54 -0
  133. package/dist/tools/profile_external_readiness.js.map +1 -0
  134. package/dist/tools/profile_external_recommendations.d.ts +15 -0
  135. package/dist/tools/profile_external_recommendations.d.ts.map +1 -0
  136. package/dist/tools/profile_external_recommendations.js +57 -0
  137. package/dist/tools/profile_external_recommendations.js.map +1 -0
  138. package/dist/tools/profile_external_update.d.ts +14 -0
  139. package/dist/tools/profile_external_update.d.ts.map +1 -0
  140. package/dist/tools/profile_external_update.js +79 -0
  141. package/dist/tools/profile_external_update.js.map +1 -0
  142. package/dist/tools/profile_reviews_approve_item.d.ts +17 -0
  143. package/dist/tools/profile_reviews_approve_item.d.ts.map +1 -0
  144. package/dist/tools/profile_reviews_approve_item.js +77 -0
  145. package/dist/tools/profile_reviews_approve_item.js.map +1 -0
  146. package/dist/tools/profile_reviews_approve_section.d.ts +15 -0
  147. package/dist/tools/profile_reviews_approve_section.d.ts.map +1 -0
  148. package/dist/tools/profile_reviews_approve_section.js +70 -0
  149. package/dist/tools/profile_reviews_approve_section.js.map +1 -0
  150. package/dist/tools/profile_reviews_list.d.ts +16 -0
  151. package/dist/tools/profile_reviews_list.d.ts.map +1 -0
  152. package/dist/tools/profile_reviews_list.js +58 -0
  153. package/dist/tools/profile_reviews_list.js.map +1 -0
  154. package/dist/tools/profile_reviews_submit_for_review.d.ts +14 -0
  155. package/dist/tools/profile_reviews_submit_for_review.d.ts.map +1 -0
  156. package/dist/tools/profile_reviews_submit_for_review.js +56 -0
  157. package/dist/tools/profile_reviews_submit_for_review.js.map +1 -0
  158. package/dist/tools/profile_skills_add.d.ts +4 -0
  159. package/dist/tools/profile_skills_add.d.ts.map +1 -0
  160. package/dist/tools/profile_skills_add.js +52 -0
  161. package/dist/tools/profile_skills_add.js.map +1 -0
  162. package/dist/tools/profile_skills_autocomplete.d.ts +4 -0
  163. package/dist/tools/profile_skills_autocomplete.d.ts.map +1 -0
  164. package/dist/tools/profile_skills_autocomplete.js +78 -0
  165. package/dist/tools/profile_skills_autocomplete.js.map +1 -0
  166. package/dist/tools/profile_skills_list.d.ts +16 -0
  167. package/dist/tools/profile_skills_list.d.ts.map +1 -0
  168. package/dist/tools/profile_skills_list.js +65 -0
  169. package/dist/tools/profile_skills_list.js.map +1 -0
  170. package/dist/tools/profile_skills_readiness.d.ts +4 -0
  171. package/dist/tools/profile_skills_readiness.d.ts.map +1 -0
  172. package/dist/tools/profile_skills_readiness.js +53 -0
  173. package/dist/tools/profile_skills_readiness.js.map +1 -0
  174. package/dist/tools/profile_skills_remove.d.ts +4 -0
  175. package/dist/tools/profile_skills_remove.d.ts.map +1 -0
  176. package/dist/tools/profile_skills_remove.js +53 -0
  177. package/dist/tools/profile_skills_remove.js.map +1 -0
  178. package/dist/tools/profile_skills_show.d.ts +4 -0
  179. package/dist/tools/profile_skills_show.d.ts.map +1 -0
  180. package/dist/tools/profile_skills_show.js +51 -0
  181. package/dist/tools/profile_skills_show.js.map +1 -0
  182. package/dist/tools/profile_skills_update.d.ts +11 -0
  183. package/dist/tools/profile_skills_update.d.ts.map +1 -0
  184. package/dist/tools/profile_skills_update.js +97 -0
  185. package/dist/tools/profile_skills_update.js.map +1 -0
  186. package/dist/tools/timesheet.d.ts +29 -0
  187. package/dist/tools/timesheet.d.ts.map +1 -0
  188. package/dist/tools/timesheet.js +257 -0
  189. package/dist/tools/timesheet.js.map +1 -0
  190. package/package.json +33 -13
  191. package/index.js +0 -7
@@ -0,0 +1,54 @@
1
+ import { TtctlError } from "@ttctl/core";
2
+ /**
3
+ * MCP tool-error response shape. Mirrors the Model Context Protocol's
4
+ * `CallToolResult` for error cases (`isError: true` + `content: [TextContent]`).
5
+ *
6
+ * Defined locally rather than re-exporting from `@modelcontextprotocol/sdk`
7
+ * to keep the typing focused on what TTCtl emits — the upstream SDK type is
8
+ * a wide union covering all content types we don't return. This shape is
9
+ * the SUBSET we promise.
10
+ *
11
+ * The `[key: string]: unknown` index signature keeps the type structurally
12
+ * compatible with the SDK's `CallToolResult` (whose own type carries the
13
+ * same signature for forward-compatibility with new optional fields).
14
+ * Without it, returning this shape from a `registerTool` callback fails
15
+ * strict type-checking even though the runtime values are identical.
16
+ */
17
+ export interface ToolErrorResponse {
18
+ [key: string]: unknown;
19
+ isError: true;
20
+ content: [{
21
+ type: "text";
22
+ text: string;
23
+ }];
24
+ }
25
+ /**
26
+ * Render a `TtctlError` as an MCP tool-error response (issue #77 § MCP
27
+ * error presentation).
28
+ *
29
+ * The text payload follows the same Error/Recovery/Code blocks the CLI
30
+ * surface emits, with the `code` echoed as a structured tag MCP-aware LLM
31
+ * clients can detect programmatically without parsing prose. Multi-line
32
+ * content stays in `text` since MCP's `TextContent` is a free-form string.
33
+ */
34
+ export declare function ttctlErrorToToolResponse(err: TtctlError): ToolErrorResponse;
35
+ /**
36
+ * Convenience guard for tool implementations: if `err` is a `TtctlError`,
37
+ * return the structured tool response; otherwise fall through (return
38
+ * `null`) so the caller can apply its own non-typed-error handling.
39
+ *
40
+ * Tool implementations consume this as:
41
+ *
42
+ * ```ts
43
+ * try {
44
+ * const value = await someService(...);
45
+ * return successResponse(value);
46
+ * } catch (err) {
47
+ * const typed = ttctlErrorToToolResponseOrNull(err);
48
+ * if (typed !== null) return typed;
49
+ * throw err; // or generic-error response
50
+ * }
51
+ * ```
52
+ */
53
+ export declare function ttctlErrorToToolResponseOrNull(err: unknown): ToolErrorResponse | null;
54
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,iBAAiB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,UAAU,GAAG,iBAAiB,CAU3E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,GAAG,IAAI,CAKrF"}
package/dist/errors.js ADDED
@@ -0,0 +1,48 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { TtctlError } from "@ttctl/core";
4
+ /**
5
+ * Render a `TtctlError` as an MCP tool-error response (issue #77 § MCP
6
+ * error presentation).
7
+ *
8
+ * The text payload follows the same Error/Recovery/Code blocks the CLI
9
+ * surface emits, with the `code` echoed as a structured tag MCP-aware LLM
10
+ * clients can detect programmatically without parsing prose. Multi-line
11
+ * content stays in `text` since MCP's `TextContent` is a free-form string.
12
+ */
13
+ export function ttctlErrorToToolResponse(err) {
14
+ return {
15
+ isError: true,
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: [`Error: ${err.message}`, "", `Recovery: ${err.recovery}`, "", `(Code: ${err.code})`].join("\n"),
20
+ },
21
+ ],
22
+ };
23
+ }
24
+ /**
25
+ * Convenience guard for tool implementations: if `err` is a `TtctlError`,
26
+ * return the structured tool response; otherwise fall through (return
27
+ * `null`) so the caller can apply its own non-typed-error handling.
28
+ *
29
+ * Tool implementations consume this as:
30
+ *
31
+ * ```ts
32
+ * try {
33
+ * const value = await someService(...);
34
+ * return successResponse(value);
35
+ * } catch (err) {
36
+ * const typed = ttctlErrorToToolResponseOrNull(err);
37
+ * if (typed !== null) return typed;
38
+ * throw err; // or generic-error response
39
+ * }
40
+ * ```
41
+ */
42
+ export function ttctlErrorToToolResponseOrNull(err) {
43
+ if (err instanceof TtctlError) {
44
+ return ttctlErrorToToolResponse(err);
45
+ }
46
+ return null;
47
+ }
48
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAuBzC;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAe;IACtD,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,aAAa,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;aACvG;SACF;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,8BAA8B,CAAC,GAAY;IACzD,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;QAC9B,OAAO,wBAAwB,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { buildServer, runMcpStdio } from "./server.js";
2
+ export type { BuildServerOptions } from "./server.js";
3
+ export { DATA_HANDLING_FOOTER, HIGH_RISK_TOOLS, THIRDPARTY_FREETEXT_FOOTER, composeDescription, } from "./data-handling.js";
4
+ export { ttctlErrorToToolResponse, ttctlErrorToToolResponseOrNull } from "./errors.js";
5
+ export type { ToolErrorResponse } from "./errors.js";
6
+ export { emitMcpAuthResolve, emitMcpDebug, extractTransportStatus, extractTransportSurface, getMcpDiagnosticLogger, isTransportError, redactToolArgs, resetMcpDiagnosticLogger, setMcpDiagnosticLogger, wrapToolHandler, } from "./diagnostic.js";
7
+ export type { McpAuthResolveRecord, McpDebugRecord, McpDiagnosticLogger, McpToolInvokeEndRecord, McpToolInvokeStartRecord, McpToolInvokeStatus, McpTransportErrorRecord, } from "./diagnostic.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AACvF,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EACd,wBAAwB,EACxB,sBAAsB,EACtB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ export { buildServer, runMcpStdio } from "./server.js";
4
+ export { DATA_HANDLING_FOOTER, HIGH_RISK_TOOLS, THIRDPARTY_FREETEXT_FOOTER, composeDescription, } from "./data-handling.js";
5
+ export { ttctlErrorToToolResponse, ttctlErrorToToolResponseOrNull } from "./errors.js";
6
+ export { emitMcpAuthResolve, emitMcpDebug, extractTransportStatus, extractTransportSurface, getMcpDiagnosticLogger, isTransportError, redactToolArgs, resetMcpDiagnosticLogger, setMcpDiagnosticLogger, wrapToolHandler, } from "./diagnostic.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAGvF,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EACd,wBAAwB,EACxB,sBAAsB,EACtB,eAAe,GAChB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * MCP-side wire-up for the remote version-killed manifest (#312).
3
+ *
4
+ * Invoked from `buildServer` at construction time (AC 4). Two
5
+ * differences from the CLI hook:
6
+ *
7
+ * 1. **Fire-and-forget**: the server constructor must stay sync
8
+ * (the MCP SDK's `McpServer` doesn't support an async build path,
9
+ * and a long blocking startup would interrupt the JSON-RPC
10
+ * handshake with the client). The check runs as a detached
11
+ * Promise; the warning lands on stderr whenever the fetch
12
+ * resolves.
13
+ * 2. **Always warn, never refuse**: refusing a long-lived MCP
14
+ * server has no usable semantics — mid-flight tool calls would
15
+ * be interrupted, the Claude Desktop / Cursor session would
16
+ * receive a partial response, and the operator may not see the
17
+ * stderr trail. The runbook documents this asymmetry.
18
+ *
19
+ * Also schedules a recurring refetch every ~24h per the issue's
20
+ * frequency spec, with `.unref()` so the timer never holds the
21
+ * process alive — natural Node exit semantics remain intact.
22
+ *
23
+ * **Fail-silent contract**: every error path is swallowed. Even an
24
+ * unexpected throw inside the fire-and-forget Promise is caught (via
25
+ * the `.catch()` on the returned Promise) so no `unhandledRejection`
26
+ * fires.
27
+ */
28
+ export interface McpKillSwitchHookOptions {
29
+ /** Override stderr writer. Default: `process.stderr.write`. */
30
+ writeStderr?: (chunk: string) => void;
31
+ /** Override the running version (default: read from this package's package.json). */
32
+ version?: string;
33
+ /** Override the manifest URL. */
34
+ url?: string;
35
+ /** Override the per-fetch timeout (ms). */
36
+ timeoutMs?: number;
37
+ /** Override the refetch interval (ms). Default: ~24h. */
38
+ refetchIntervalMs?: number;
39
+ /** Injected fetch. Tests pass a mock. */
40
+ fetchFn?: typeof globalThis.fetch;
41
+ /**
42
+ * Override `setInterval`. Tests inject a controllable timer to verify
43
+ * the refetch loop without waiting 24h. The returned handle must
44
+ * carry an `unref` method (Node's `Timeout`). When omitted, the real
45
+ * `setInterval` is used.
46
+ */
47
+ setIntervalFn?: typeof globalThis.setInterval;
48
+ }
49
+ /** Returned handle for callers that want to cancel the refetch loop. */
50
+ export interface McpKillSwitchHandle {
51
+ /** Stop the refetch timer. After this, no further checks fire. */
52
+ stop: () => void;
53
+ /**
54
+ * The Promise from the initial at-startup check. Exposed for tests
55
+ * that need to await the first-fetch completion. Production callers
56
+ * do NOT await this — buildServer is sync.
57
+ */
58
+ initialCheck: Promise<void>;
59
+ }
60
+ /**
61
+ * Schedule the startup + recurring kill-switch checks for the MCP
62
+ * server. Returns a handle the caller can use to stop the refetch
63
+ * timer (mostly useful for tests; production callers ignore it — the
64
+ * `.unref()` timer dies naturally on process exit).
65
+ */
66
+ export declare function scheduleMcpKillSwitch(opts?: McpKillSwitchHookOptions): McpKillSwitchHandle;
67
+ //# sourceMappingURL=kill-switch-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kill-switch-hook.d.ts","sourceRoot":"","sources":["../src/kill-switch-hook.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,WAAW,wBAAwB;IACvC,+DAA+D;IAC/D,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAClC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,UAAU,CAAC,WAAW,CAAC;CAC/C;AAED,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAmCD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,wBAA6B,GAAG,mBAAmB,CAwB9F"}
@@ -0,0 +1,61 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { checkKillSwitch, formatKillSwitchMessage, KILL_SWITCH_DEFAULT_REFETCH_INTERVAL_MS, KILL_SWITCH_DEFAULT_TIMEOUT_MS, readPackageVersion, } from "@ttctl/core";
4
+ async function runOnce(opts, version) {
5
+ try {
6
+ const result = await checkKillSwitch({
7
+ version,
8
+ ...(opts.url !== undefined ? { url: opts.url } : {}),
9
+ timeoutMs: opts.timeoutMs ?? KILL_SWITCH_DEFAULT_TIMEOUT_MS,
10
+ ...(opts.fetchFn !== undefined ? { fetchFn: opts.fetchFn } : {}),
11
+ });
12
+ if (result.status !== "match")
13
+ return;
14
+ const writeStderr = opts.writeStderr ??
15
+ ((chunk) => {
16
+ process.stderr.write(chunk);
17
+ });
18
+ writeStderr(formatKillSwitchMessage({
19
+ toolName: "ttctl mcp",
20
+ version,
21
+ entry: result.entry,
22
+ }));
23
+ // Per docstring: MCP always warns even when entry.action === "refuse".
24
+ // No process.exit, no server-side enforcement of refuse.
25
+ }
26
+ catch {
27
+ // Outer envelope: even if checkKillSwitch were to throw (it shouldn't —
28
+ // it returns a discriminated result for every failure path), swallow
29
+ // here so the fire-and-forget Promise never surfaces as an
30
+ // unhandledRejection.
31
+ }
32
+ }
33
+ /**
34
+ * Schedule the startup + recurring kill-switch checks for the MCP
35
+ * server. Returns a handle the caller can use to stop the refetch
36
+ * timer (mostly useful for tests; production callers ignore it — the
37
+ * `.unref()` timer dies naturally on process exit).
38
+ */
39
+ export function scheduleMcpKillSwitch(opts = {}) {
40
+ const version = opts.version ?? readPackageVersion(import.meta.url);
41
+ const refetchIntervalMs = opts.refetchIntervalMs ?? KILL_SWITCH_DEFAULT_REFETCH_INTERVAL_MS;
42
+ const setIntervalImpl = opts.setIntervalFn ?? globalThis.setInterval;
43
+ const initialCheck = runOnce(opts, version);
44
+ const timer = setIntervalImpl(() => {
45
+ void runOnce(opts, version);
46
+ }, refetchIntervalMs);
47
+ // Don't hold the process alive solely for this timer — natural Node
48
+ // exit semantics (e.g., stdin EOF terminating the MCP transport)
49
+ // must still terminate the daemon. The injected setIntervalFn type
50
+ // is `typeof globalThis.setInterval` which returns NodeJS.Timeout —
51
+ // .unref() is always present on the contract; tests supply a stub
52
+ // that includes the method.
53
+ timer.unref();
54
+ return {
55
+ stop: () => {
56
+ clearInterval(timer);
57
+ },
58
+ initialCheck,
59
+ };
60
+ }
61
+ //# sourceMappingURL=kill-switch-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kill-switch-hook.js","sourceRoot":"","sources":["../src/kill-switch-hook.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,uCAAuC,EACvC,8BAA8B,EAC9B,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAgErB,KAAK,UAAU,OAAO,CAAC,IAA8B,EAAE,OAAe;IACpE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;YACnC,OAAO;YACP,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,8BAA8B;YAC3D,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;YAAE,OAAO;QAEtC,MAAM,WAAW,GACf,IAAI,CAAC,WAAW;YAChB,CAAC,CAAC,KAAa,EAAQ,EAAE;gBACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;QACL,WAAW,CACT,uBAAuB,CAAC;YACtB,QAAQ,EAAE,WAAW;YACrB,OAAO;YACP,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CACH,CAAC;QACF,uEAAuE;QACvE,yDAAyD;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,qEAAqE;QACrE,2DAA2D;QAC3D,sBAAsB;IACxB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAiC,EAAE;IACvE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpE,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,uCAAuC,CAAC;IAC5F,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,IAAI,UAAU,CAAC,WAAW,CAAC;IAErE,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE5C,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,EAAE;QACjC,KAAK,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9B,CAAC,EAAE,iBAAiB,CAAC,CAAC;IACtB,oEAAoE;IACpE,iEAAiE;IACjE,mEAAmE;IACnE,oEAAoE;IACpE,kEAAkE;IAClE,4BAA4B;IAC5B,KAAK,CAAC,KAAK,EAAE,CAAC;IAEd,OAAO;QACL,IAAI,EAAE,GAAS,EAAE;YACf,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type McpDiagnosticLogger } from "./diagnostic.js";
3
+ import { type McpKillSwitchHookOptions } from "./kill-switch-hook.js";
4
+ /**
5
+ * Options accepted by `buildServer` and `runMcpStdio`.
6
+ *
7
+ * - `configPath` — explicit config-file path captured by the CLI's
8
+ * `--config <path>` flag (or any future SSE/HTTP transport entry).
9
+ * When undefined, `resolveConfig` falls through to the
10
+ * `TTCTL_CONFIG_FILE` env var, then to `~/.ttctl.yaml` (the canonical
11
+ * 3-step chain documented in CLAUDE.md § Config File Resolution).
12
+ * - `logger` — optional MCP diagnostic logger override (issue #224).
13
+ * When supplied to `runMcpStdio`, the logger is installed BEFORE
14
+ * `buildServer` runs, so every tool-registration instrumentation +
15
+ * every per-call emission routes through the injected logger.
16
+ * Production callers omit this field; tests inject a capturing
17
+ * logger to assert emission shape without manipulating
18
+ * `process.env`. When `runMcpStdio` is called with no `logger`, the
19
+ * module-default env-gated stderr emitter (`TTCTL_DEBUG_MCP=1`) is
20
+ * used. `buildServer` itself does NOT install the logger — it
21
+ * only consumes the currently-installed one when wrapping tool
22
+ * handlers — so callers that bypass `runMcpStdio` (e.g. tests
23
+ * building a server directly) must call
24
+ * `setMcpDiagnosticLogger` themselves if they want custom emission.
25
+ */
26
+ export interface BuildServerOptions {
27
+ configPath?: string;
28
+ logger?: McpDiagnosticLogger;
29
+ /**
30
+ * Remote version-killed manifest check (#312, AC 4). When omitted,
31
+ * `buildServer` fires the default at-startup check and schedules a
32
+ * recurring ~24h refetch. Production callers omit this; tests inject
33
+ * a mocked `fetchFn` + `setIntervalFn` + `writeStderr` to assert
34
+ * the wiring without hitting the network or polluting stderr.
35
+ *
36
+ * Set to `null` to opt out entirely (used by some test setups where
37
+ * the kill-switch is exercised separately or is irrelevant to the
38
+ * scenario under test).
39
+ */
40
+ killSwitch?: McpKillSwitchHookOptions | null;
41
+ }
42
+ /**
43
+ * Build the TTCtl MCP server. Tools are wired in via `registerAllTools` —
44
+ * a single registration site that pulls in every per-tool module so each
45
+ * tool file stays focused on its own input shape.
46
+ *
47
+ * Trust model: process-level — any process that can spawn `ttctl mcp` gets
48
+ * full access to the user's Toptal Talent session. See SECURITY.md.
49
+ *
50
+ * Tools are registered in `tools/index.ts`. Today's surface: 4
51
+ * `profile.basic` + 7 `profile.skills` (#73) + 5 `profile.industries` +
52
+ * 5 `profile.education` + 5 `profile.certifications` +
53
+ * 6 `profile.employment` (#74) = 32 tools. MCP tool names use ONLY the
54
+ * canonical sub-domain names per project policy (#72) — CLI aliases like
55
+ * `certs` and `experience` are CLI-only and never appear in the MCP catalog.
56
+ *
57
+ * Path capture (#113): `resolveConfig` is invoked ONCE here at server-
58
+ * construction time. The resolved absolute path is captured into closures
59
+ * for each per-tool auth resolver (`resolveToolAuth`, `loadTokenForTool`,
60
+ * `resolveTokenForTool`) so subsequent tool invocations read AND write
61
+ * the path that was canonical at startup. Mid-session env-var shifts
62
+ * (e.g., parent shell re-exporting `TTCTL_CONFIG_FILE`) are intentionally
63
+ * ignored — long-running MCP sessions need read/write symmetry.
64
+ *
65
+ * Diagnostic instrumentation (#224): every tool registered through this
66
+ * server has its callback wrapped with `wrapToolHandler` so the active
67
+ * MCP diagnostic logger sees `mcp_tool_invoke_start` BEFORE the callback
68
+ * runs, `mcp_tool_invoke_end` AFTER it resolves (or throws), and
69
+ * `mcp_transport_error` when the throw is a transport-class error
70
+ * (`Cf403Error`, `Cf403PersistentError`, `SchedulerBearerExpired`). The
71
+ * wrap is applied transparently by monkey-patching `server.registerTool`
72
+ * BEFORE `registerAllTools` runs, so per-tool files (~30+ registrars)
73
+ * are not aware of the instrumentation — the wiring lives in this one
74
+ * place.
75
+ *
76
+ * Fail-fast: any `ConfigError` thrown by the startup-time `resolveConfig`
77
+ * (e.g., `NO_CREDS` when no candidate file exists) propagates verbatim —
78
+ * the server does NOT start in a half-initialized state.
79
+ */
80
+ export declare function buildServer(opts?: BuildServerOptions): McpServer;
81
+ /**
82
+ * Run the MCP server over stdio (the canonical transport for Claude Desktop /
83
+ * Claude Code / Cursor / Windsurf).
84
+ *
85
+ * Accepts the same `configPath` knob as `buildServer`. Threading the path
86
+ * through here keeps the umbrella `ttctl mcp [--config <path>]` entry
87
+ * surface as the single point of CLI-flag parsing, with no per-tool
88
+ * config knowledge needed inside the server module.
89
+ *
90
+ * Diagnostic logger wiring (issue #224): when `opts.logger` is supplied,
91
+ * `setMcpDiagnosticLogger(opts.logger)` is called BEFORE `buildServer`
92
+ * so the tool-registration wrapping in `buildServer` already routes
93
+ * through the injected logger. When omitted, the module-scoped default
94
+ * (env-gated stderr emitter for `TTCTL_DEBUG_MCP=1`) remains active.
95
+ * Tests calling `runMcpStdio` with a fake logger thus get full
96
+ * tool-start / tool-end / transport-error visibility without needing
97
+ * to manipulate `process.env`.
98
+ */
99
+ export declare function runMcpStdio(opts?: BuildServerOptions): Promise<void>;
100
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,OAAO,EAAE,KAAK,mBAAmB,EAA2C,MAAM,iBAAiB,CAAC;AACpG,OAAO,EAAyB,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAK7F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,SAAS,CAsFpE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9E"}
package/dist/server.js ADDED
@@ -0,0 +1,157 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { resolveConfig } from "@ttctl/core";
6
+ import { createToolAuthResolver } from "./auth.js";
7
+ import { composeDescription } from "./data-handling.js";
8
+ import { setMcpDiagnosticLogger, wrapToolHandler } from "./diagnostic.js";
9
+ import { scheduleMcpKillSwitch } from "./kill-switch-hook.js";
10
+ import { createTokenLoader } from "./tools/_shared.js";
11
+ import { createTokenResolver } from "./tools/profile/shared.js";
12
+ import { registerAllTools } from "./tools/index.js";
13
+ /**
14
+ * Build the TTCtl MCP server. Tools are wired in via `registerAllTools` —
15
+ * a single registration site that pulls in every per-tool module so each
16
+ * tool file stays focused on its own input shape.
17
+ *
18
+ * Trust model: process-level — any process that can spawn `ttctl mcp` gets
19
+ * full access to the user's Toptal Talent session. See SECURITY.md.
20
+ *
21
+ * Tools are registered in `tools/index.ts`. Today's surface: 4
22
+ * `profile.basic` + 7 `profile.skills` (#73) + 5 `profile.industries` +
23
+ * 5 `profile.education` + 5 `profile.certifications` +
24
+ * 6 `profile.employment` (#74) = 32 tools. MCP tool names use ONLY the
25
+ * canonical sub-domain names per project policy (#72) — CLI aliases like
26
+ * `certs` and `experience` are CLI-only and never appear in the MCP catalog.
27
+ *
28
+ * Path capture (#113): `resolveConfig` is invoked ONCE here at server-
29
+ * construction time. The resolved absolute path is captured into closures
30
+ * for each per-tool auth resolver (`resolveToolAuth`, `loadTokenForTool`,
31
+ * `resolveTokenForTool`) so subsequent tool invocations read AND write
32
+ * the path that was canonical at startup. Mid-session env-var shifts
33
+ * (e.g., parent shell re-exporting `TTCTL_CONFIG_FILE`) are intentionally
34
+ * ignored — long-running MCP sessions need read/write symmetry.
35
+ *
36
+ * Diagnostic instrumentation (#224): every tool registered through this
37
+ * server has its callback wrapped with `wrapToolHandler` so the active
38
+ * MCP diagnostic logger sees `mcp_tool_invoke_start` BEFORE the callback
39
+ * runs, `mcp_tool_invoke_end` AFTER it resolves (or throws), and
40
+ * `mcp_transport_error` when the throw is a transport-class error
41
+ * (`Cf403Error`, `Cf403PersistentError`, `SchedulerBearerExpired`). The
42
+ * wrap is applied transparently by monkey-patching `server.registerTool`
43
+ * BEFORE `registerAllTools` runs, so per-tool files (~30+ registrars)
44
+ * are not aware of the instrumentation — the wiring lives in this one
45
+ * place.
46
+ *
47
+ * Fail-fast: any `ConfigError` thrown by the startup-time `resolveConfig`
48
+ * (e.g., `NO_CREDS` when no candidate file exists) propagates verbatim —
49
+ * the server does NOT start in a half-initialized state.
50
+ */
51
+ export function buildServer(opts = {}) {
52
+ // resolveConfig honors `path` when provided, else falls through to the
53
+ // env→home chain. We always read the canonical absolute path off the
54
+ // returned `path` field; that's what the resolvers close over.
55
+ const resolved = opts.configPath !== undefined ? resolveConfig({ path: opts.configPath }) : resolveConfig();
56
+ const capturedPath = resolved.path;
57
+ const server = new McpServer({
58
+ name: "ttctl",
59
+ version: "0.0.0",
60
+ });
61
+ // Monkey-patch `server.registerTool` BEFORE `registerAllTools` runs so
62
+ // every per-tool registrar's callback is transparently wrapped with the
63
+ // diagnostic-instrumentation contract (#224) AND every per-tool
64
+ // description is augmented with response-side data-handling guidance
65
+ // (#265). The patch:
66
+ // 1. Captures `originalRegisterTool` bound to the McpServer instance
67
+ // so the SDK's internal `_registeredTools` bookkeeping fires normally.
68
+ // 2. Replaces `server.registerTool` with a wrapper that (a) augments
69
+ // the config's `description` field via `composeDescription` (#265),
70
+ // and (b) wraps the callback with `wrapToolHandler(name, cb)` (#224).
71
+ // The wrapper's return is the same `RegisteredTool` handle as the
72
+ // original — `.enable()` / `.disable()` / `.update()` work unchanged
73
+ // on the registered tool.
74
+ // 3. Uses an `unknown` cast on the patch because `registerTool`'s
75
+ // generic signature (with `ZodRawShapeCompat | AnySchema` + the
76
+ // output schema variant) is hostile to a single typed override.
77
+ // The wrapper preserves runtime behavior; type safety at the
78
+ // callsites (each registrar) is unaffected.
79
+ // The signature of McpServer.registerTool is an overload set that
80
+ // resolves to `never` under `Parameters<...>`, so we type the patch
81
+ // as a permissive `(...args: unknown[]) => unknown` and lean on the
82
+ // outer cast to restore the McpServer's view. Runtime semantics are
83
+ // unchanged — name is always args[0]: string, config args[1]: object,
84
+ // cb args[2]: function — and the original registerTool reapplies the
85
+ // overload-correct type check on its side.
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ const originalRegisterTool = server.registerTool.bind(server);
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ const patchedRegisterTool = (...args) => {
90
+ const name = args[0];
91
+ const config = args[1];
92
+ const cb = args[2];
93
+ // Augment the tool's description with response-side data-handling
94
+ // guidance (#265). The augmentation is at registration time so every
95
+ // tool — current and future — inherits the footer without per-tool
96
+ // boilerplate. High-risk tools (per the threat-model § 5 audit, set
97
+ // membership lives in `data-handling.ts`) additionally get a
98
+ // third-party-content notice.
99
+ let patchedConfig = config;
100
+ if (typeof config === "object" && config !== null) {
101
+ const cfg = config;
102
+ patchedConfig = {
103
+ ...cfg,
104
+ description: composeDescription(name, cfg.description),
105
+ };
106
+ }
107
+ const wrappedCb = wrapToolHandler(name, cb);
108
+ return originalRegisterTool(name, patchedConfig, wrappedCb);
109
+ };
110
+ server.registerTool = patchedRegisterTool;
111
+ registerAllTools(server, {
112
+ resolveToolAuth: createToolAuthResolver(capturedPath),
113
+ loadTokenForTool: createTokenLoader(capturedPath),
114
+ resolveTokenForTool: createTokenResolver(capturedPath),
115
+ });
116
+ // Fire-and-forget kill-switch check (#312, AC 4). Detached on
117
+ // purpose — buildServer is sync (the MCP SDK has no async-build
118
+ // path), and a synchronous block here would delay the JSON-RPC
119
+ // handshake. The check writes to stderr when the running version
120
+ // matches an entry; never throws (fail-silent contract); never
121
+ // refuses (refusing a long-lived MCP server has no usable
122
+ // semantics — see kill-switch-hook.ts docstring).
123
+ //
124
+ // Schedules a ~24h refetch with `.unref()` so the timer doesn't
125
+ // keep the process alive solely for the recurring fetch.
126
+ if (opts.killSwitch !== null) {
127
+ scheduleMcpKillSwitch(opts.killSwitch ?? {});
128
+ }
129
+ return server;
130
+ }
131
+ /**
132
+ * Run the MCP server over stdio (the canonical transport for Claude Desktop /
133
+ * Claude Code / Cursor / Windsurf).
134
+ *
135
+ * Accepts the same `configPath` knob as `buildServer`. Threading the path
136
+ * through here keeps the umbrella `ttctl mcp [--config <path>]` entry
137
+ * surface as the single point of CLI-flag parsing, with no per-tool
138
+ * config knowledge needed inside the server module.
139
+ *
140
+ * Diagnostic logger wiring (issue #224): when `opts.logger` is supplied,
141
+ * `setMcpDiagnosticLogger(opts.logger)` is called BEFORE `buildServer`
142
+ * so the tool-registration wrapping in `buildServer` already routes
143
+ * through the injected logger. When omitted, the module-scoped default
144
+ * (env-gated stderr emitter for `TTCTL_DEBUG_MCP=1`) remains active.
145
+ * Tests calling `runMcpStdio` with a fake logger thus get full
146
+ * tool-start / tool-end / transport-error visibility without needing
147
+ * to manipulate `process.env`.
148
+ */
149
+ export async function runMcpStdio(opts = {}) {
150
+ if (opts.logger !== undefined) {
151
+ setMcpDiagnosticLogger(opts.logger);
152
+ }
153
+ const server = buildServer(opts);
154
+ const transport = new StdioServerTransport();
155
+ await server.connect(transport);
156
+ }
157
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}