@ttctl/mcp 0.0.0 → 0.1.0-rc.2

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 (195) 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 +133 -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 +129 -0
  63. package/dist/tools/output-schemas.d.ts.map +1 -0
  64. package/dist/tools/output-schemas.js +138 -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 +219 -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 +222 -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 +254 -0
  81. package/dist/tools/profile/employment.js.map +1 -0
  82. package/dist/tools/profile/industries.d.ts +30 -0
  83. package/dist/tools/profile/industries.d.ts.map +1 -0
  84. package/dist/tools/profile/industries.js +196 -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 +64 -0
  111. package/dist/tools/profile_basic_show.d.ts.map +1 -0
  112. package/dist/tools/profile_basic_show.js +108 -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_show.d.ts +15 -0
  139. package/dist/tools/profile_external_show.d.ts.map +1 -0
  140. package/dist/tools/profile_external_show.js +59 -0
  141. package/dist/tools/profile_external_show.js.map +1 -0
  142. package/dist/tools/profile_external_update.d.ts +14 -0
  143. package/dist/tools/profile_external_update.d.ts.map +1 -0
  144. package/dist/tools/profile_external_update.js +79 -0
  145. package/dist/tools/profile_external_update.js.map +1 -0
  146. package/dist/tools/profile_reviews_approve_item.d.ts +17 -0
  147. package/dist/tools/profile_reviews_approve_item.d.ts.map +1 -0
  148. package/dist/tools/profile_reviews_approve_item.js +77 -0
  149. package/dist/tools/profile_reviews_approve_item.js.map +1 -0
  150. package/dist/tools/profile_reviews_approve_section.d.ts +15 -0
  151. package/dist/tools/profile_reviews_approve_section.d.ts.map +1 -0
  152. package/dist/tools/profile_reviews_approve_section.js +70 -0
  153. package/dist/tools/profile_reviews_approve_section.js.map +1 -0
  154. package/dist/tools/profile_reviews_list.d.ts +16 -0
  155. package/dist/tools/profile_reviews_list.d.ts.map +1 -0
  156. package/dist/tools/profile_reviews_list.js +58 -0
  157. package/dist/tools/profile_reviews_list.js.map +1 -0
  158. package/dist/tools/profile_reviews_submit_for_review.d.ts +14 -0
  159. package/dist/tools/profile_reviews_submit_for_review.d.ts.map +1 -0
  160. package/dist/tools/profile_reviews_submit_for_review.js +56 -0
  161. package/dist/tools/profile_reviews_submit_for_review.js.map +1 -0
  162. package/dist/tools/profile_skills_add.d.ts +4 -0
  163. package/dist/tools/profile_skills_add.d.ts.map +1 -0
  164. package/dist/tools/profile_skills_add.js +52 -0
  165. package/dist/tools/profile_skills_add.js.map +1 -0
  166. package/dist/tools/profile_skills_autocomplete.d.ts +4 -0
  167. package/dist/tools/profile_skills_autocomplete.d.ts.map +1 -0
  168. package/dist/tools/profile_skills_autocomplete.js +78 -0
  169. package/dist/tools/profile_skills_autocomplete.js.map +1 -0
  170. package/dist/tools/profile_skills_list.d.ts +16 -0
  171. package/dist/tools/profile_skills_list.d.ts.map +1 -0
  172. package/dist/tools/profile_skills_list.js +65 -0
  173. package/dist/tools/profile_skills_list.js.map +1 -0
  174. package/dist/tools/profile_skills_readiness.d.ts +4 -0
  175. package/dist/tools/profile_skills_readiness.d.ts.map +1 -0
  176. package/dist/tools/profile_skills_readiness.js +53 -0
  177. package/dist/tools/profile_skills_readiness.js.map +1 -0
  178. package/dist/tools/profile_skills_remove.d.ts +4 -0
  179. package/dist/tools/profile_skills_remove.d.ts.map +1 -0
  180. package/dist/tools/profile_skills_remove.js +53 -0
  181. package/dist/tools/profile_skills_remove.js.map +1 -0
  182. package/dist/tools/profile_skills_show.d.ts +4 -0
  183. package/dist/tools/profile_skills_show.d.ts.map +1 -0
  184. package/dist/tools/profile_skills_show.js +51 -0
  185. package/dist/tools/profile_skills_show.js.map +1 -0
  186. package/dist/tools/profile_skills_update.d.ts +11 -0
  187. package/dist/tools/profile_skills_update.d.ts.map +1 -0
  188. package/dist/tools/profile_skills_update.js +97 -0
  189. package/dist/tools/profile_skills_update.js.map +1 -0
  190. package/dist/tools/timesheet.d.ts +29 -0
  191. package/dist/tools/timesheet.d.ts.map +1 -0
  192. package/dist/tools/timesheet.js +257 -0
  193. package/dist/tools/timesheet.js.map +1 -0
  194. package/package.json +33 -13
  195. package/index.js +0 -7
@@ -0,0 +1,108 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { profile } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { buildMcpDryRunPreview, domainErrorResponse, dryRunResponse, genericErrorResponse, isToolErrorResponse, jsonResponse, } from "./_shared.js";
7
+ const TOOL_NAME = "ttctl_profile_basic_show";
8
+ /**
9
+ * Register the `ttctl_profile_basic_show` MCP tool. Mirrors the
10
+ * `ttctl profile basic show` CLI leaf — fetches the signed-in user's
11
+ * profile from both the mobile-gateway and the talent-profile surfaces
12
+ * and returns the merged payload.
13
+ *
14
+ * Two-call read surface (parity with CLI's post-#129 path, closed in
15
+ * this PR for MCP per #340):
16
+ *
17
+ * 1. `profile.basic.show()` → `mobile-gateway` for identity, role,
18
+ * vertical, skills, hours, rate.
19
+ * 2. `profile.basic.getBasicInfo()` → `talent_profile/graphql` for
20
+ * `bio` (`Profile.about`), `headline` (`Profile.quote`), and
21
+ * `languages`.
22
+ *
23
+ * Errors from the secondary `getBasicInfo()` call are non-fatal: the
24
+ * tool swallows non-session failures and renders `basicInfo: null`, so a
25
+ * glitch on the secondary surface doesn't blank the whole show. Session-
26
+ * level errors (`AuthRevokedError`, `Cf403Error`) still propagate — they
27
+ * indicate the bearer is no longer valid; the primary `show()` would
28
+ * have hit them too.
29
+ *
30
+ * Auth token identifies the user. MCP is the LLM-facing surface, so the
31
+ * description includes example user-intent phrases the model can match
32
+ * against, and reflects the bio/headline/languages coverage added in
33
+ * this PR.
34
+ *
35
+ * Dry-run path (issue #165): when `dryRun: true`, the tool returns a
36
+ * structured preview of the primary `ProfileShow` query — no transport
37
+ * call. The preview shows only the mobile-gateway operation; the
38
+ * secondary `GET_BASIC_INFO` call on the talent-profile surface is also
39
+ * dispatched on the apply path but is not part of the preview envelope
40
+ * (single-op envelope is the cross-cutting dry-run contract; the
41
+ * secondary read is an implementation detail of the merged response).
42
+ */
43
+ export function registerProfileBasicShowTool(server, ctx) {
44
+ server.registerTool(TOOL_NAME, {
45
+ title: "Show profile basic info",
46
+ description: [
47
+ "Fetch the signed-in user's Toptal Talent profile (identity, role, vertical, skills, hours, rate, bio, headline, languages).",
48
+ "",
49
+ "Returns the merged read payload from both the mobile-gateway (`profile`) and the talent-profile (`basicInfo`) surfaces. `basicInfo.bio` mirrors `Profile.about`; `basicInfo.headline` mirrors `Profile.quote`. `basicInfo` is `null` when the secondary read call fails non-fatally.",
50
+ "",
51
+ "Pass `dryRun: true` to preview the primary request without firing the query.",
52
+ "",
53
+ "Example user prompts that should map to this tool:",
54
+ ' - "What\'s on my Toptal profile?"',
55
+ ' - "Show me my Toptal Talent details."',
56
+ ' - "What\'s my hourly rate and vertical?"',
57
+ ' - "Show my bio and headline."',
58
+ ' - "What languages do I have set?"',
59
+ ].join("\n"),
60
+ inputSchema: {
61
+ dryRun: z
62
+ .boolean()
63
+ .optional()
64
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview: DryRunPreview }` with operationName + variables + redacted bearer header for the primary ProfileShow query. Default: false."),
65
+ },
66
+ }, async (input) => {
67
+ const auth = await ctx.loadTokenForTool(TOOL_NAME);
68
+ if (isToolErrorResponse(auth))
69
+ return auth;
70
+ if (input.dryRun === true) {
71
+ return dryRunResponse(buildMcpDryRunPreview("ProfileShow", "mobile-gateway", {}, auth.token));
72
+ }
73
+ let profilePayload;
74
+ try {
75
+ profilePayload = await profile.basic.show(auth.token);
76
+ }
77
+ catch (err) {
78
+ const typed = ttctlErrorToToolResponseOrNull(err);
79
+ if (typed !== null)
80
+ return typed;
81
+ if (err instanceof profile.basic.ProfileError) {
82
+ return domainErrorResponse(TOOL_NAME, err);
83
+ }
84
+ return genericErrorResponse(TOOL_NAME, err);
85
+ }
86
+ let basicInfo;
87
+ try {
88
+ basicInfo = await profile.basic.getBasicInfo(auth.token);
89
+ }
90
+ catch (err) {
91
+ // Session-level errors (AuthRevokedError, Cf403Error) propagate —
92
+ // the user's bearer is no longer valid and they need to act on it.
93
+ // The primary `show()` call would have hit the same issue, so the
94
+ // user must be told. Anything else (NETWORK_ERROR, GRAPHQL_ERROR
95
+ // on the talent-profile surface) is non-fatal: the primary payload
96
+ // landed, so the tool returns the partial result with
97
+ // `basicInfo: null`. Mirrors the CLI's post-#129 read-handler
98
+ // policy in `packages/cli/src/commands/profile/basic/show.ts`.
99
+ const typed = ttctlErrorToToolResponseOrNull(err);
100
+ if (typed !== null)
101
+ return typed;
102
+ basicInfo = null;
103
+ }
104
+ const payload = { profile: profilePayload, basicInfo };
105
+ return jsonResponse(payload);
106
+ });
107
+ }
108
+ //# sourceMappingURL=profile_basic_show.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_basic_show.js","sourceRoot":"","sources":["../../src/tools/profile_basic_show.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,GAEb,MAAM,cAAc,CAAC;AAEtB,MAAM,SAAS,GAAG,0BAA0B,CAAC;AA0B7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,4BAA4B,CAAC,MAAiB,EAAE,GAA4B;IAC1F,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE;YACX,6HAA6H;YAC7H,EAAE;YACF,sRAAsR;YACtR,EAAE;YACF,8EAA8E;YAC9E,EAAE;YACF,oDAAoD;YACpD,qCAAqC;YACrC,yCAAyC;YACzC,4CAA4C;YAC5C,iCAAiC;YACjC,qCAAqC;SACtC,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE;YACX,MAAM,EAAE,CAAC;iBACN,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CACP,gNAAgN,CACjN;SACJ;KACF,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAE3C,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,cAAc,CAAC,qBAAqB,CAAC,aAAa,EAAE,gBAAgB,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAChG,CAAC;QAED,IAAI,cAAgC,CAAC;QACrC,IAAI,CAAC;YACH,cAAc,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,GAAG,YAAY,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;gBAC9C,OAAO,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,oBAAoB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,SAAyC,CAAC;QAC9C,IAAI,CAAC;YACH,SAAS,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,kEAAkE;YAClE,mEAAmE;YACnE,kEAAkE;YAClE,iEAAiE;YACjE,mEAAmE;YACnE,sDAAsD;YACtD,8DAA8D;YAC9D,+DAA+D;YAC/D,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACjC,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;QAED,MAAM,OAAO,GAAqB,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC;QACzE,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_profile_basic_update` MCP tool. Mirrors the
5
+ * `ttctl profile basic update --bio --headline` CLI leaf — updates the
6
+ * signed-in user's bio and/or headline via the talent-profile surface.
7
+ *
8
+ * Free-text input modes (stdin / `@file` / `--edit`) are CLI-specific
9
+ * affordances and DO NOT apply here: MCP callers pass the resolved
10
+ * string verbatim. The `bio` and `headline` parameters are both
11
+ * optional; at least one must be supplied (the core layer validates
12
+ * this and raises a `VALIDATION_ERROR` if both are omitted).
13
+ *
14
+ * Dry-run path (issue #10, harmonised under #165): when `dryRun: true`
15
+ * is supplied, the tool routes through
16
+ * `profile.basic.set(token, changes, { dryRun: true })` which returns a
17
+ * `SetOutcomePreview`. The MCP layer projects that to the uniform
18
+ * `{ ok: true, dryRun: true, preview }` envelope shared by every #165
19
+ * dry-run path. The apply path returns the `UpdateProfileResult`
20
+ * payload directly (the prior `{ kind: "applied", result }` wrapper is
21
+ * dropped — see "Breaking change" note below).
22
+ *
23
+ * **Breaking change vs #10's original wire format (pre-1.0, acceptable):**
24
+ *
25
+ * - Old apply: `{ kind: "applied", result: { profile, notice } }`
26
+ * - New apply: `{ profile, notice }`
27
+ * - Old dry-run: `{ kind: "preview", preview: { ... } }`
28
+ * - New dry-run: `{ ok: true, dryRun: true, preview: { ... } }`
29
+ *
30
+ * The new envelopes match the rest of the MCP surface — every tool's
31
+ * dry-run path emits `{ ok: true, dryRun: true, preview }` uniformly
32
+ * (issue #165), and apply paths emit the domain payload directly.
33
+ * Bearer token redaction in `headers.authorization` is honored by
34
+ * `buildDryRunPreview` in core; the MCP tool is a thin pass-through.
35
+ */
36
+ export declare function registerProfileBasicUpdateTool(server: McpServer, ctx: ToolRegistrationContext): void;
37
+ //# sourceMappingURL=profile_basic_update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_basic_update.d.ts","sourceRoot":"","sources":["../../src/tools/profile_basic_update.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAML,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAKtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CA6DpG"}
@@ -0,0 +1,97 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { profile } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { domainErrorResponse, dryRunResponse, genericErrorResponse, isToolErrorResponse, jsonResponse, } from "./_shared.js";
7
+ import { profileBasicUpdateOutputSchema } from "./output-schemas.js";
8
+ const TOOL_NAME = "ttctl_profile_basic_update";
9
+ /**
10
+ * Register the `ttctl_profile_basic_update` MCP tool. Mirrors the
11
+ * `ttctl profile basic update --bio --headline` CLI leaf — updates the
12
+ * signed-in user's bio and/or headline via the talent-profile surface.
13
+ *
14
+ * Free-text input modes (stdin / `@file` / `--edit`) are CLI-specific
15
+ * affordances and DO NOT apply here: MCP callers pass the resolved
16
+ * string verbatim. The `bio` and `headline` parameters are both
17
+ * optional; at least one must be supplied (the core layer validates
18
+ * this and raises a `VALIDATION_ERROR` if both are omitted).
19
+ *
20
+ * Dry-run path (issue #10, harmonised under #165): when `dryRun: true`
21
+ * is supplied, the tool routes through
22
+ * `profile.basic.set(token, changes, { dryRun: true })` which returns a
23
+ * `SetOutcomePreview`. The MCP layer projects that to the uniform
24
+ * `{ ok: true, dryRun: true, preview }` envelope shared by every #165
25
+ * dry-run path. The apply path returns the `UpdateProfileResult`
26
+ * payload directly (the prior `{ kind: "applied", result }` wrapper is
27
+ * dropped — see "Breaking change" note below).
28
+ *
29
+ * **Breaking change vs #10's original wire format (pre-1.0, acceptable):**
30
+ *
31
+ * - Old apply: `{ kind: "applied", result: { profile, notice } }`
32
+ * - New apply: `{ profile, notice }`
33
+ * - Old dry-run: `{ kind: "preview", preview: { ... } }`
34
+ * - New dry-run: `{ ok: true, dryRun: true, preview: { ... } }`
35
+ *
36
+ * The new envelopes match the rest of the MCP surface — every tool's
37
+ * dry-run path emits `{ ok: true, dryRun: true, preview }` uniformly
38
+ * (issue #165), and apply paths emit the domain payload directly.
39
+ * Bearer token redaction in `headers.authorization` is honored by
40
+ * `buildDryRunPreview` in core; the MCP tool is a thin pass-through.
41
+ */
42
+ export function registerProfileBasicUpdateTool(server, ctx) {
43
+ server.registerTool(TOOL_NAME, {
44
+ title: "Update profile basic info",
45
+ description: [
46
+ "Update the signed-in user's profile bio and/or headline. At least one must be supplied.",
47
+ "Pass `dryRun: true` to preview the request without firing the mutation.",
48
+ "",
49
+ "Example user prompts that should map to this tool:",
50
+ ' - "Update my bio to: Senior backend engineer specialising in Go and PostgreSQL."',
51
+ " - \"Change my Toptal headline to 'CTO at AcmeCo'.\"",
52
+ ' - "Set my profile bio and headline."',
53
+ ' - "Show me what would be sent if I changed my bio to X."',
54
+ ].join("\n"),
55
+ inputSchema: {
56
+ bio: z
57
+ .string()
58
+ .optional()
59
+ .describe("Long-form bio paragraph (multi-line). Maps to GraphQL `Profile.about`. Optional. The empty string is a valid value (clears the bio); pass `undefined` to leave the existing bio unchanged."),
60
+ headline: z
61
+ .string()
62
+ .optional()
63
+ .describe("Short tagline shown above the user's photo (single line). Maps to GraphQL `Profile.quote`. Optional."),
64
+ dryRun: z
65
+ .boolean()
66
+ .optional()
67
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview: DryRunPreview }` carrying the `UPDATE_BASIC_INFO` operation + redacted bearer header. No transport (read or write) is invoked. Default: false."),
68
+ },
69
+ outputSchema: profileBasicUpdateOutputSchema.shape,
70
+ }, async (input) => {
71
+ const auth = await ctx.loadTokenForTool(TOOL_NAME);
72
+ if (isToolErrorResponse(auth))
73
+ return auth;
74
+ const changes = {};
75
+ if (input.bio !== undefined)
76
+ changes.bio = input.bio;
77
+ if (input.headline !== undefined)
78
+ changes.headline = input.headline;
79
+ try {
80
+ const outcome = await profile.basic.set(auth.token, changes, { dryRun: input.dryRun ?? false });
81
+ if (outcome.kind === "preview") {
82
+ return dryRunResponse(outcome.preview);
83
+ }
84
+ return jsonResponse(outcome.result);
85
+ }
86
+ catch (err) {
87
+ const typed = ttctlErrorToToolResponseOrNull(err);
88
+ if (typed !== null)
89
+ return typed;
90
+ if (err instanceof profile.basic.ProfileError) {
91
+ return domainErrorResponse(TOOL_NAME, err);
92
+ }
93
+ return genericErrorResponse(TOOL_NAME, err);
94
+ }
95
+ });
96
+ }
97
+ //# sourceMappingURL=profile_basic_update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_basic_update.js","sourceRoot":"","sources":["../../src/tools/profile_basic_update.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,GAEb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAErE,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAAiB,EAAE,GAA4B;IAC5F,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,2BAA2B;QAClC,WAAW,EAAE;YACX,yFAAyF;YACzF,yEAAyE;YACzE,EAAE;YACF,oDAAoD;YACpD,oFAAoF;YACpF,uDAAuD;YACvD,wCAAwC;YACxC,4DAA4D;SAC7D,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE;YACX,GAAG,EAAE,CAAC;iBACH,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,4LAA4L,CAC7L;YACH,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,sGAAsG,CACvG;YACH,MAAM,EAAE,CAAC;iBACN,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CACP,mOAAmO,CACpO;SACJ;QACD,YAAY,EAAE,8BAA8B,CAAC,KAAK;KACnD,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAE3C,MAAM,OAAO,GAAgC,EAAE,CAAC;QAChD,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;QACrD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;YAAE,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAEpE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC,CAAC;YAChG,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC/B,OAAO,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACzC,CAAC;YACD,OAAO,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,GAAG,YAAY,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;gBAC9C,OAAO,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,oBAAoB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_profile_external_advanced_wizard_show` MCP tool.
5
+ * Mirrors the `ttctl profile external advanced-wizard show` CLI leaf —
6
+ * reads the advanced-profile-wizard status plus a summary of the talent's
7
+ * travel-visa list (count + IDs).
8
+ *
9
+ * Visa CRUD lives in the `ttctl_profile_visas_*` sub-domain — surfacing
10
+ * the rich shape here would create a partial duplication that drifts as
11
+ * the visas sub-domain evolves.
12
+ */
13
+ export declare function registerProfileExternalAdvancedWizardShowTool(server: McpServer, ctx: ToolRegistrationContext): void;
14
+ //# sourceMappingURL=profile_external_advanced_wizard_show.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_advanced_wizard_show.d.ts","sourceRoot":"","sources":["../../src/tools/profile_external_advanced_wizard_show.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAWtB;;;;;;;;;GASG;AACH,wBAAgB,6CAA6C,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CA2CnH"}
@@ -0,0 +1,56 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { profile } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { buildMcpDryRunPreview, domainErrorResponse, dryRunResponse, genericErrorResponse, isToolErrorResponse, jsonResponse, } from "./_shared.js";
7
+ const TOOL_NAME = "ttctl_profile_external_advanced_wizard_show";
8
+ const DRY_RUN_FIELD = z
9
+ .boolean()
10
+ .optional()
11
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Default: false.");
12
+ /**
13
+ * Register the `ttctl_profile_external_advanced_wizard_show` MCP tool.
14
+ * Mirrors the `ttctl profile external advanced-wizard show` CLI leaf —
15
+ * reads the advanced-profile-wizard status plus a summary of the talent's
16
+ * travel-visa list (count + IDs).
17
+ *
18
+ * Visa CRUD lives in the `ttctl_profile_visas_*` sub-domain — surfacing
19
+ * the rich shape here would create a partial duplication that drifts as
20
+ * the visas sub-domain evolves.
21
+ */
22
+ export function registerProfileExternalAdvancedWizardShowTool(server, ctx) {
23
+ server.registerTool(TOOL_NAME, {
24
+ title: "Show advanced-profile wizard status",
25
+ description: [
26
+ "Read the advanced-profile-wizard status plus a summary of the talent's travel-visa list (count + IDs).",
27
+ "",
28
+ "Example user prompts that should map to this tool:",
29
+ ' - "What\'s the state of my advanced-profile wizard?"',
30
+ ' - "Have I finished the advanced profile setup?"',
31
+ ' - "Show me my travel-visa summary."',
32
+ ].join("\n"),
33
+ inputSchema: { dryRun: DRY_RUN_FIELD },
34
+ }, async (input) => {
35
+ const auth = await ctx.loadTokenForTool(TOOL_NAME);
36
+ if (isToolErrorResponse(auth))
37
+ return auth;
38
+ if (input.dryRun === true) {
39
+ return dryRunResponse(buildMcpDryRunPreview("getAdvancedProfileData", "talent-profile", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER }, auth.token));
40
+ }
41
+ try {
42
+ const result = await profile.external.advancedWizardShow(auth.token);
43
+ return jsonResponse(result);
44
+ }
45
+ catch (err) {
46
+ const typed = ttctlErrorToToolResponseOrNull(err);
47
+ if (typed !== null)
48
+ return typed;
49
+ if (err instanceof profile.external.ProfileError) {
50
+ return domainErrorResponse(TOOL_NAME, err);
51
+ }
52
+ return genericErrorResponse(TOOL_NAME, err);
53
+ }
54
+ });
55
+ }
56
+ //# sourceMappingURL=profile_external_advanced_wizard_show.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_advanced_wizard_show.js","sourceRoot":"","sources":["../../src/tools/profile_external_advanced_wizard_show.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,GAEb,MAAM,cAAc,CAAC;AAEtB,MAAM,SAAS,GAAG,6CAA6C,CAAC;AAEhE,MAAM,aAAa,GAAG,CAAC;KACpB,OAAO,EAAE;KACT,QAAQ,EAAE;KACV,QAAQ,CACP,+JAA+J,CAChK,CAAC;AAEJ;;;;;;;;;GASG;AACH,MAAM,UAAU,6CAA6C,CAAC,MAAiB,EAAE,GAA4B;IAC3G,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,qCAAqC;QAC5C,WAAW,EAAE;YACX,wGAAwG;YACxG,EAAE;YACF,oDAAoD;YACpD,wDAAwD;YACxD,mDAAmD;YACnD,uCAAuC;SACxC,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE;KACvC,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAE3C,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,cAAc,CACnB,qBAAqB,CACnB,wBAAwB,EACxB,gBAAgB,EAChB,EAAE,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAC3D,IAAI,CAAC,KAAK,CACX,CACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrE,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,GAAG,YAAY,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACjD,OAAO,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,oBAAoB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_profile_external_custom_requirements_set` MCP tool.
5
+ * Mirrors the `ttctl profile external custom-requirements set` CLI leaf —
6
+ * toggles one or more of the three onboarding-readiness booleans.
7
+ *
8
+ * Caller-omitted fields default to the current server state (the
9
+ * underlying mutation has no PATCH semantics — the service layer fetches
10
+ * current state and merges before sending).
11
+ */
12
+ export declare function registerProfileExternalCustomRequirementsSetTool(server: McpServer, ctx: ToolRegistrationContext): void;
13
+ //# sourceMappingURL=profile_external_custom_requirements_set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_custom_requirements_set.d.ts","sourceRoot":"","sources":["../../src/tools/profile_external_custom_requirements_set.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAWtB;;;;;;;;GAQG;AACH,wBAAgB,gDAAgD,CAC9D,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,uBAAuB,GAC3B,IAAI,CA6DN"}
@@ -0,0 +1,75 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { profile } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { buildMcpDryRunPreview, domainErrorResponse, dryRunResponse, genericErrorResponse, isToolErrorResponse, jsonResponse, } from "./_shared.js";
7
+ const TOOL_NAME = "ttctl_profile_external_custom_requirements_set";
8
+ const DRY_RUN_FIELD = z
9
+ .boolean()
10
+ .optional()
11
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Note: the apply path merges with the current server state via a sibling read; the dry-run preview shows only the user-supplied diff in `customRequirements`, not the merged final shape. Default: false.");
12
+ /**
13
+ * Register the `ttctl_profile_external_custom_requirements_set` MCP tool.
14
+ * Mirrors the `ttctl profile external custom-requirements set` CLI leaf —
15
+ * toggles one or more of the three onboarding-readiness booleans.
16
+ *
17
+ * Caller-omitted fields default to the current server state (the
18
+ * underlying mutation has no PATCH semantics — the service layer fetches
19
+ * current state and merges before sending).
20
+ */
21
+ export function registerProfileExternalCustomRequirementsSetTool(server, ctx) {
22
+ server.registerTool(TOOL_NAME, {
23
+ title: "Update custom requirements",
24
+ description: [
25
+ "Toggle one or more of the three onboarding-readiness booleans (background-check, drug-test, time-tracking-tools). Caller-omitted fields default to the current server state. At least one field must be supplied.",
26
+ "",
27
+ "Example user prompts that should map to this tool:",
28
+ ' - "Opt me into background-check screening."',
29
+ ' - "Mark me as willing to use time-tracking tools."',
30
+ ' - "Toggle off the drug-test flag on my profile."',
31
+ ].join("\n"),
32
+ inputSchema: {
33
+ backgroundCheck: z
34
+ .boolean()
35
+ .optional()
36
+ .describe("Willing to undergo a background check (true|false). Optional."),
37
+ drugTest: z.boolean().optional().describe("Willing to undergo a drug test (true|false). Optional."),
38
+ timeTrackingTools: z
39
+ .boolean()
40
+ .optional()
41
+ .describe("Willing to use time-tracking tools (true|false). Optional."),
42
+ dryRun: DRY_RUN_FIELD,
43
+ },
44
+ }, async (input) => {
45
+ const auth = await ctx.loadTokenForTool(TOOL_NAME);
46
+ if (isToolErrorResponse(auth))
47
+ return auth;
48
+ const changes = {};
49
+ if (input.backgroundCheck !== undefined)
50
+ changes.backgroundCheck = input.backgroundCheck;
51
+ if (input.drugTest !== undefined)
52
+ changes.drugTest = input.drugTest;
53
+ if (input.timeTrackingTools !== undefined)
54
+ changes.timeTrackingTools = input.timeTrackingTools;
55
+ if (input.dryRun === true) {
56
+ return dryRunResponse(buildMcpDryRunPreview("updateCustomRequirements", "talent-profile", {
57
+ input: { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER, customRequirements: changes },
58
+ }, auth.token));
59
+ }
60
+ try {
61
+ const result = await profile.external.customRequirementsSet(auth.token, changes);
62
+ return jsonResponse(result);
63
+ }
64
+ catch (err) {
65
+ const typed = ttctlErrorToToolResponseOrNull(err);
66
+ if (typed !== null)
67
+ return typed;
68
+ if (err instanceof profile.external.ProfileError) {
69
+ return domainErrorResponse(TOOL_NAME, err);
70
+ }
71
+ return genericErrorResponse(TOOL_NAME, err);
72
+ }
73
+ });
74
+ }
75
+ //# sourceMappingURL=profile_external_custom_requirements_set.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_custom_requirements_set.js","sourceRoot":"","sources":["../../src/tools/profile_external_custom_requirements_set.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,GAEb,MAAM,cAAc,CAAC;AAEtB,MAAM,SAAS,GAAG,gDAAgD,CAAC;AAEnE,MAAM,aAAa,GAAG,CAAC;KACpB,OAAO,EAAE;KACT,QAAQ,EAAE;KACV,QAAQ,CACP,wVAAwV,CACzV,CAAC;AAEJ;;;;;;;;GAQG;AACH,MAAM,UAAU,gDAAgD,CAC9D,MAAiB,EACjB,GAA4B;IAE5B,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,4BAA4B;QACnC,WAAW,EAAE;YACX,mNAAmN;YACnN,EAAE;YACF,oDAAoD;YACpD,+CAA+C;YAC/C,sDAAsD;YACtD,oDAAoD;SACrD,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE;YACX,eAAe,EAAE,CAAC;iBACf,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CAAC,+DAA+D,CAAC;YAC5E,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;YACnG,iBAAiB,EAAE,CAAC;iBACjB,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CAAC,4DAA4D,CAAC;YACzE,MAAM,EAAE,aAAa;SACtB;KACF,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAE3C,MAAM,OAAO,GAA8C,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS;YAAE,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;QACzF,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;YAAE,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QACpE,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS;YAAE,OAAO,CAAC,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,CAAC;QAE/F,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,cAAc,CACnB,qBAAqB,CACnB,0BAA0B,EAC1B,gBAAgB,EAChB;gBACE,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,kBAAkB,EAAE,OAAO,EAAE;aAChG,EACD,IAAI,CAAC,KAAK,CACX,CACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACjF,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,GAAG,YAAY,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACjD,OAAO,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,oBAAoB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_profile_external_custom_requirements_show` MCP tool.
5
+ * Mirrors the `ttctl profile external custom-requirements show` CLI leaf —
6
+ * reads the three onboarding-readiness toggles (background-check,
7
+ * drug-test, time-tracking-tools).
8
+ *
9
+ * Despite the issue's "free-text" framing, the underlying API is a
10
+ * boolean trio. See the service module top-comment for the spec/API
11
+ * reconciliation.
12
+ */
13
+ export declare function registerProfileExternalCustomRequirementsShowTool(server: McpServer, ctx: ToolRegistrationContext): void;
14
+ //# sourceMappingURL=profile_external_custom_requirements_show.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_custom_requirements_show.d.ts","sourceRoot":"","sources":["../../src/tools/profile_external_custom_requirements_show.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAWtB;;;;;;;;;GASG;AACH,wBAAgB,iDAAiD,CAC/D,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,uBAAuB,GAC3B,IAAI,CA2CN"}
@@ -0,0 +1,56 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { profile } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { buildMcpDryRunPreview, domainErrorResponse, dryRunResponse, genericErrorResponse, isToolErrorResponse, jsonResponse, } from "./_shared.js";
7
+ const TOOL_NAME = "ttctl_profile_external_custom_requirements_show";
8
+ const DRY_RUN_FIELD = z
9
+ .boolean()
10
+ .optional()
11
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Default: false.");
12
+ /**
13
+ * Register the `ttctl_profile_external_custom_requirements_show` MCP tool.
14
+ * Mirrors the `ttctl profile external custom-requirements show` CLI leaf —
15
+ * reads the three onboarding-readiness toggles (background-check,
16
+ * drug-test, time-tracking-tools).
17
+ *
18
+ * Despite the issue's "free-text" framing, the underlying API is a
19
+ * boolean trio. See the service module top-comment for the spec/API
20
+ * reconciliation.
21
+ */
22
+ export function registerProfileExternalCustomRequirementsShowTool(server, ctx) {
23
+ server.registerTool(TOOL_NAME, {
24
+ title: "Show custom requirements",
25
+ description: [
26
+ "Read the three onboarding-readiness toggles (background-check, drug-test, time-tracking-tools) for the signed-in talent.",
27
+ "",
28
+ "Example user prompts that should map to this tool:",
29
+ ' - "Am I opted into background checks?"',
30
+ ' - "What\'s my onboarding-readiness state?"',
31
+ ' - "Show my custom requirements."',
32
+ ].join("\n"),
33
+ inputSchema: { dryRun: DRY_RUN_FIELD },
34
+ }, async (input) => {
35
+ const auth = await ctx.loadTokenForTool(TOOL_NAME);
36
+ if (isToolErrorResponse(auth))
37
+ return auth;
38
+ if (input.dryRun === true) {
39
+ return dryRunResponse(buildMcpDryRunPreview("getCustomRequirements", "talent-profile", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER }, auth.token));
40
+ }
41
+ try {
42
+ const result = await profile.external.customRequirementsShow(auth.token);
43
+ return jsonResponse(result);
44
+ }
45
+ catch (err) {
46
+ const typed = ttctlErrorToToolResponseOrNull(err);
47
+ if (typed !== null)
48
+ return typed;
49
+ if (err instanceof profile.external.ProfileError) {
50
+ return domainErrorResponse(TOOL_NAME, err);
51
+ }
52
+ return genericErrorResponse(TOOL_NAME, err);
53
+ }
54
+ });
55
+ }
56
+ //# sourceMappingURL=profile_external_custom_requirements_show.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_custom_requirements_show.js","sourceRoot":"","sources":["../../src/tools/profile_external_custom_requirements_show.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,GAEb,MAAM,cAAc,CAAC;AAEtB,MAAM,SAAS,GAAG,iDAAiD,CAAC;AAEpE,MAAM,aAAa,GAAG,CAAC;KACpB,OAAO,EAAE;KACT,QAAQ,EAAE;KACV,QAAQ,CACP,+JAA+J,CAChK,CAAC;AAEJ;;;;;;;;;GASG;AACH,MAAM,UAAU,iDAAiD,CAC/D,MAAiB,EACjB,GAA4B;IAE5B,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EAAE;YACX,0HAA0H;YAC1H,EAAE;YACF,oDAAoD;YACpD,0CAA0C;YAC1C,8CAA8C;YAC9C,oCAAoC;SACrC,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE;KACvC,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAE3C,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,cAAc,CACnB,qBAAqB,CACnB,uBAAuB,EACvB,gBAAgB,EAChB,EAAE,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAC3D,IAAI,CAAC,KAAK,CACX,CACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzE,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,GAAG,YAAY,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACjD,OAAO,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,oBAAoB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_profile_external_readiness` MCP tool. Mirrors the
5
+ * `ttctl profile external readiness` CLI leaf — reads the per-section
6
+ * profile-readiness checklist plus the rolled-up `submitAvailable` flag.
7
+ *
8
+ * Used to know which sections still need work before the talent can
9
+ * submit-for-review.
10
+ */
11
+ export declare function registerProfileExternalReadinessTool(server: McpServer, ctx: ToolRegistrationContext): void;
12
+ //# sourceMappingURL=profile_external_readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_readiness.d.ts","sourceRoot":"","sources":["../../src/tools/profile_external_readiness.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAWtB;;;;;;;GAOG;AACH,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CA2C1G"}
@@ -0,0 +1,54 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { profile } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { buildMcpDryRunPreview, domainErrorResponse, dryRunResponse, genericErrorResponse, isToolErrorResponse, jsonResponse, } from "./_shared.js";
7
+ const TOOL_NAME = "ttctl_profile_external_readiness";
8
+ const DRY_RUN_FIELD = z
9
+ .boolean()
10
+ .optional()
11
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Default: false.");
12
+ /**
13
+ * Register the `ttctl_profile_external_readiness` MCP tool. Mirrors the
14
+ * `ttctl profile external readiness` CLI leaf — reads the per-section
15
+ * profile-readiness checklist plus the rolled-up `submitAvailable` flag.
16
+ *
17
+ * Used to know which sections still need work before the talent can
18
+ * submit-for-review.
19
+ */
20
+ export function registerProfileExternalReadinessTool(server, ctx) {
21
+ server.registerTool(TOOL_NAME, {
22
+ title: "Show profile readiness",
23
+ description: [
24
+ "Read the per-section profile-readiness checklist (photo, basic info, skills, employments, portfolio, working hours, etc.) plus the rolled-up `submitAvailable` flag.",
25
+ "",
26
+ "Example user prompts that should map to this tool:",
27
+ ' - "Is my Toptal profile ready to submit?"',
28
+ ' - "Which sections still need work?"',
29
+ ' - "Show me my profile-readiness checklist."',
30
+ ].join("\n"),
31
+ inputSchema: { dryRun: DRY_RUN_FIELD },
32
+ }, async (input) => {
33
+ const auth = await ctx.loadTokenForTool(TOOL_NAME);
34
+ if (isToolErrorResponse(auth))
35
+ return auth;
36
+ if (input.dryRun === true) {
37
+ return dryRunResponse(buildMcpDryRunPreview("getProfileReadiness", "talent-profile", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER }, auth.token));
38
+ }
39
+ try {
40
+ const result = await profile.external.readiness(auth.token);
41
+ return jsonResponse(result);
42
+ }
43
+ catch (err) {
44
+ const typed = ttctlErrorToToolResponseOrNull(err);
45
+ if (typed !== null)
46
+ return typed;
47
+ if (err instanceof profile.external.ProfileError) {
48
+ return domainErrorResponse(TOOL_NAME, err);
49
+ }
50
+ return genericErrorResponse(TOOL_NAME, err);
51
+ }
52
+ });
53
+ }
54
+ //# sourceMappingURL=profile_external_readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_readiness.js","sourceRoot":"","sources":["../../src/tools/profile_external_readiness.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,GAEb,MAAM,cAAc,CAAC;AAEtB,MAAM,SAAS,GAAG,kCAAkC,CAAC;AAErD,MAAM,aAAa,GAAG,CAAC;KACpB,OAAO,EAAE;KACT,QAAQ,EAAE;KACV,QAAQ,CACP,+JAA+J,CAChK,CAAC;AAEJ;;;;;;;GAOG;AACH,MAAM,UAAU,oCAAoC,CAAC,MAAiB,EAAE,GAA4B;IAClG,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE;YACX,sKAAsK;YACtK,EAAE;YACF,oDAAoD;YACpD,6CAA6C;YAC7C,uCAAuC;YACvC,+CAA+C;SAChD,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE;KACvC,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,mBAAmB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAE3C,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,cAAc,CACnB,qBAAqB,CACnB,qBAAqB,EACrB,gBAAgB,EAChB,EAAE,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAC3D,IAAI,CAAC,KAAK,CACX,CACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5D,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,GAAG,YAAY,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACjD,OAAO,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,oBAAoB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_profile_external_recommendations` MCP tool. Mirrors
5
+ * the `ttctl profile external recommendations` CLI leaf — lists the
6
+ * platform's "do this next" recommendations.
7
+ *
8
+ * Each recommendation has a discriminator `type` (e.g.
9
+ * `EmploymentsCountRecommendation`, `ProfileFreshnessRecommendation`)
10
+ * and a small payload of variant-specific scalar fields. Nested entity
11
+ * lists are intentionally trimmed at the GraphQL level — drilling in
12
+ * requires fetching the underlying domain directly.
13
+ */
14
+ export declare function registerProfileExternalRecommendationsTool(server: McpServer, ctx: ToolRegistrationContext): void;
15
+ //# sourceMappingURL=profile_external_recommendations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile_external_recommendations.d.ts","sourceRoot":"","sources":["../../src/tools/profile_external_recommendations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAWtB;;;;;;;;;;GAUG;AACH,wBAAgB,0CAA0C,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CA2ChH"}