@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,192 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { applications } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { buildMcpDryRunPreview, dryRunMultiResponse, dryRunResponse } from "./_shared.js";
7
+ const DRY_RUN_FIELD = z
8
+ .boolean()
9
+ .optional()
10
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Default: false.");
11
+ /**
12
+ * Register the three `ttctl_applications_*` MCP tools per the #15 spec.
13
+ * Tool names use the `ttctl_` prefix and the canonical CLI path joined
14
+ * with `_` per project naming policy:
15
+ *
16
+ * - `ttctl_applications_list`
17
+ * - `ttctl_applications_show`
18
+ * - `ttctl_applications_stats`
19
+ *
20
+ * Each tool maps 1:1 to a CLI leaf — the schemas describe the same set
21
+ * of fields. The list tool's `keywords` and `statusGroups` mirror the
22
+ * `--keywords` / `--status-group` CLI flags.
23
+ *
24
+ * **Read-only** — per project non-goals (#15), no apply / withdraw /
25
+ * edit tools are exposed. `applications` is intentionally a smaller
26
+ * surface than the profile sub-domains.
27
+ *
28
+ * Dry-run path (issue #165): every tool accepts `dryRun?: boolean`.
29
+ * `list` and `show` emit the singular `{ preview }` envelope (one
30
+ * operation per call); `stats` emits the plural `{ previews: [...] }`
31
+ * envelope because the apply path fires 5 parallel `JobActivityItems`
32
+ * calls (one per STATUS_GROUPS member) — see {@link dryRunMultiResponse}.
33
+ */
34
+ export function registerApplicationsTools(server, ctx) {
35
+ server.registerTool("ttctl_applications_list", {
36
+ title: "List activity items",
37
+ description: [
38
+ "List the signed-in user's Toptal Talent activity items.",
39
+ "Each row represents an application, availability request, interview, or engagement —",
40
+ "Toptal collapses these into a single 'TalentJobActivityItem' resource.",
41
+ "",
42
+ "Optional filters:",
43
+ " - `keywords`: free-text search against indexed job fields",
44
+ " - `statusGroups`: restrict to one or more JobActivityItemStatusGroupEnum values",
45
+ "",
46
+ "Example user prompts:",
47
+ ' - "Show me my recent Toptal applications."',
48
+ ' - "What active engagements do I have on Toptal?"',
49
+ ' - "List my archived Toptal job activity."',
50
+ ].join("\n"),
51
+ inputSchema: {
52
+ keywords: z.array(z.string()).optional().describe("Free-text keyword filter (AND across multiple)"),
53
+ statusGroups: z
54
+ .array(z.enum([...applications.STATUS_GROUPS]))
55
+ .optional()
56
+ .describe("Restrict to one or more JobActivityItemStatusGroupEnum values: ACTIVE_ENGAGEMENT, ARCHIVED, CLOSED_ENGAGEMENT, ON_CLIENT_REVIEW, ON_RECRUITER_REVIEW"),
57
+ dryRun: DRY_RUN_FIELD,
58
+ },
59
+ }, async (args) => {
60
+ const auth = await ctx.resolveToolAuth();
61
+ if (!auth.ok)
62
+ return auth.response;
63
+ const opts = {};
64
+ if (args.keywords !== undefined)
65
+ opts.keywords = args.keywords;
66
+ if (args.statusGroups !== undefined)
67
+ opts.statusGroups = args.statusGroups;
68
+ if (args.dryRun === true) {
69
+ const variables = {};
70
+ if (opts.keywords !== undefined)
71
+ variables["keywords"] = opts.keywords;
72
+ if (opts.statusGroups !== undefined)
73
+ variables["onlyStatusGroupFilter"] = opts.statusGroups;
74
+ return dryRunResponse(buildMcpDryRunPreview("JobActivityItems", "mobile-gateway", variables, auth.token));
75
+ }
76
+ try {
77
+ const items = await applications.list(auth.token, opts);
78
+ return successResponse(items);
79
+ }
80
+ catch (err) {
81
+ return mapApplicationsError(err);
82
+ }
83
+ });
84
+ server.registerTool("ttctl_applications_show", {
85
+ title: "Show one activity item",
86
+ description: [
87
+ "Fetch a single activity item by id (the row id, not the underlying job id).",
88
+ "Returns the full detail view: status, job metadata (title, description, commitment),",
89
+ "application info (id, requested rate), and engagement info (start date, commitment) where present.",
90
+ "",
91
+ "Example user prompts:",
92
+ ' - "Show me the details of activity item act_abc123."',
93
+ ' - "What does my application app_xyz look like?" (use the activity id, not the application id)',
94
+ ].join("\n"),
95
+ inputSchema: {
96
+ id: z.string().describe("Activity item id (the TalentJobActivityItem id)"),
97
+ dryRun: DRY_RUN_FIELD,
98
+ },
99
+ }, async (args) => {
100
+ const auth = await ctx.resolveToolAuth();
101
+ if (!auth.ok)
102
+ return auth.response;
103
+ if (args.dryRun === true) {
104
+ return dryRunResponse(buildMcpDryRunPreview("JobActivityItem", "mobile-gateway", { id: args.id }, auth.token));
105
+ }
106
+ try {
107
+ const item = await applications.show(auth.token, args.id);
108
+ return successResponse(item);
109
+ }
110
+ catch (err) {
111
+ return mapApplicationsError(err);
112
+ }
113
+ });
114
+ server.registerTool("ttctl_applications_stats", {
115
+ title: "Per-status-group activity counts",
116
+ description: [
117
+ "Aggregate activity-item counts: returns per-status-group totals plus the overall sum.",
118
+ "",
119
+ "Issues 5 server calls in parallel (one per JobActivityItemStatusGroupEnum value).",
120
+ "Each count is server-provided (totalCount on JobActivityList) — no client-side aggregation.",
121
+ "",
122
+ "Example user prompts:",
123
+ ' - "How many Toptal applications do I have in each status?"',
124
+ ' - "Give me a breakdown of my Toptal activity by status group."',
125
+ ' - "What\'s my total activity count on Toptal?"',
126
+ "",
127
+ "Dry-run note: returns `{ ok: true, dryRun: true, previews: [...] }` (plural `previews`) — one `JobActivityItems` preview per status group (5 total), matching the 5 parallel calls the apply path fires.",
128
+ ].join("\n"),
129
+ inputSchema: { dryRun: DRY_RUN_FIELD },
130
+ }, async (args) => {
131
+ const auth = await ctx.resolveToolAuth();
132
+ if (!auth.ok)
133
+ return auth.response;
134
+ if (args.dryRun === true) {
135
+ const previews = applications.STATUS_GROUPS.map((group) => buildMcpDryRunPreview("JobActivityItems", "mobile-gateway", { onlyStatusGroupFilter: [group] }, auth.token));
136
+ return dryRunMultiResponse(previews);
137
+ }
138
+ try {
139
+ const stats = await applications.stats(auth.token);
140
+ return successResponse(stats);
141
+ }
142
+ catch (err) {
143
+ return mapApplicationsError(err);
144
+ }
145
+ });
146
+ }
147
+ function successResponse(data) {
148
+ return {
149
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
150
+ };
151
+ }
152
+ function mapApplicationsError(err) {
153
+ const typed = ttctlErrorToToolResponseOrNull(err);
154
+ if (typed !== null)
155
+ return typed;
156
+ if (err instanceof applications.ApplicationsError) {
157
+ return {
158
+ isError: true,
159
+ content: [
160
+ {
161
+ type: "text",
162
+ text: [
163
+ `Error: ${err.message}`,
164
+ "",
165
+ err.code === "NOT_FOUND"
166
+ ? "Recovery: Verify the activity id (use ttctl_applications_list to discover it)."
167
+ : "Recovery: Adjust the tool input or retry; see the code below.",
168
+ "",
169
+ `(Code: ${err.code})`,
170
+ ].join("\n"),
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ const message = err instanceof Error ? err.message : String(err);
176
+ return {
177
+ isError: true,
178
+ content: [
179
+ {
180
+ type: "text",
181
+ text: [
182
+ `Error: applications request failed: ${message}`,
183
+ "",
184
+ "Recovery: Retry; if the failure persists, file an issue.",
185
+ "",
186
+ "(Code: UNKNOWN)",
187
+ ].join("\n"),
188
+ },
189
+ ],
190
+ };
191
+ }
192
+ //# sourceMappingURL=applications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applications.js","sourceRoot":"","sources":["../../src/tools/applications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_availability_*` MCP tools per the #146 amended
5
+ * spec. Tool names use the `ttctl_` prefix and the canonical CLI path
6
+ * joined with `_`:
7
+ *
8
+ * - `ttctl_availability_show`
9
+ * - `ttctl_availability_working_hours_show`
10
+ * - `ttctl_availability_working_hours_set`
11
+ * - `ttctl_availability_allocated_hours_show`
12
+ * - `ttctl_availability_allocated_hours_set`
13
+ *
14
+ * Each tool maps 1:1 to a CLI leaf — the schemas describe the same set
15
+ * of fields.
16
+ *
17
+ * **Vocabulary note** (parallel to the CLI surface): per-engagement
18
+ * "time off" is exposed via `ttctl_engagements_breaks_*` — there is no
19
+ * `ttctl_availability_time_off_*` surface (the underlying API is
20
+ * engagement-scoped and would only duplicate the engagements tools).
21
+ * "Lead time" / "minimum scheduling notice" is for booking pages
22
+ * (consultations), a separate surface not exposed in v1.
23
+ *
24
+ * Dry-run path (issue #165): every tool accepts `dryRun?: boolean`.
25
+ * Read tools build the `GetAvailability` preview at the MCP layer
26
+ * (same query underlies show + the two `*_show` filters, which apply
27
+ * client-side narrowing). The two `*_set` tools passthrough-forward
28
+ * `{ dryRun: true }` to the core (#164 already wired it through) and
29
+ * reformat the `{ kind: "preview", preview }` outcome as the uniform
30
+ * envelope.
31
+ */
32
+ export declare function registerAvailabilityTools(server: McpServer, ctx: ToolRegistrationContext): void;
33
+ //# sourceMappingURL=availability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../../src/tools/availability.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,OAAO,EAAyC,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AASnG;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CA+L/F"}
@@ -0,0 +1,272 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { availability } from "@ttctl/core";
4
+ import { z } from "zod";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ import { buildMcpDryRunPreview, dryRunResponse } from "./_shared.js";
7
+ const DRY_RUN_FIELD = z
8
+ .boolean()
9
+ .optional()
10
+ .describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with operationName + variables + redacted bearer header. Default: false.");
11
+ /**
12
+ * Register the `ttctl_availability_*` MCP tools per the #146 amended
13
+ * spec. Tool names use the `ttctl_` prefix and the canonical CLI path
14
+ * joined with `_`:
15
+ *
16
+ * - `ttctl_availability_show`
17
+ * - `ttctl_availability_working_hours_show`
18
+ * - `ttctl_availability_working_hours_set`
19
+ * - `ttctl_availability_allocated_hours_show`
20
+ * - `ttctl_availability_allocated_hours_set`
21
+ *
22
+ * Each tool maps 1:1 to a CLI leaf — the schemas describe the same set
23
+ * of fields.
24
+ *
25
+ * **Vocabulary note** (parallel to the CLI surface): per-engagement
26
+ * "time off" is exposed via `ttctl_engagements_breaks_*` — there is no
27
+ * `ttctl_availability_time_off_*` surface (the underlying API is
28
+ * engagement-scoped and would only duplicate the engagements tools).
29
+ * "Lead time" / "minimum scheduling notice" is for booking pages
30
+ * (consultations), a separate surface not exposed in v1.
31
+ *
32
+ * Dry-run path (issue #165): every tool accepts `dryRun?: boolean`.
33
+ * Read tools build the `GetAvailability` preview at the MCP layer
34
+ * (same query underlies show + the two `*_show` filters, which apply
35
+ * client-side narrowing). The two `*_set` tools passthrough-forward
36
+ * `{ dryRun: true }` to the core (#164 already wired it through) and
37
+ * reformat the `{ kind: "preview", preview }` outcome as the uniform
38
+ * envelope.
39
+ */
40
+ export function registerAvailabilityTools(server, ctx) {
41
+ server.registerTool("ttctl_availability_show", {
42
+ title: "Show availability snapshot",
43
+ description: [
44
+ "Show the signed-in user's full availability snapshot — time zone,",
45
+ "daily working-hours window, flexible shift range, and viewer-scoped",
46
+ "allocated hours per week.",
47
+ "",
48
+ "Per-engagement time off (= engagement breaks) is NOT included; use",
49
+ "`ttctl_engagements_breaks_list` for that.",
50
+ "",
51
+ "Example user prompts:",
52
+ ' - "What is my current Toptal availability?"',
53
+ ' - "Show me my working hours and time zone."',
54
+ ' - "How many hours have I allocated for Toptal engagements?"',
55
+ ].join("\n"),
56
+ inputSchema: { dryRun: DRY_RUN_FIELD },
57
+ }, async (args) => {
58
+ const auth = await ctx.resolveToolAuth();
59
+ if (!auth.ok)
60
+ return auth.response;
61
+ if (args.dryRun === true) {
62
+ return dryRunResponse(buildMcpDryRunPreview("GetAvailability", "mobile-gateway", {}, auth.token));
63
+ }
64
+ try {
65
+ const snap = await availability.show(auth.token);
66
+ return successResponse(snap);
67
+ }
68
+ catch (err) {
69
+ return mapAvailabilityError(err);
70
+ }
71
+ });
72
+ server.registerTool("ttctl_availability_working_hours_show", {
73
+ title: "Show working-hours subset",
74
+ description: [
75
+ "Show just the working-hours subset of availability — time zone +",
76
+ "daily window (workingTimeFrom/To) + flexible shift range",
77
+ "(availableShiftRangeFrom/To). Drops the allocatedHours field.",
78
+ "",
79
+ "Example user prompts:",
80
+ ' - "What are my Toptal working hours?"',
81
+ ' - "Show me my time-zone configuration."',
82
+ "",
83
+ "Dry-run note: the apply path issues `GetAvailability` (same query as `availability_show`) and narrows the result client-side — the preview reflects the wire call accordingly.",
84
+ ].join("\n"),
85
+ inputSchema: { dryRun: DRY_RUN_FIELD },
86
+ }, async (args) => {
87
+ const auth = await ctx.resolveToolAuth();
88
+ if (!auth.ok)
89
+ return auth.response;
90
+ if (args.dryRun === true) {
91
+ return dryRunResponse(buildMcpDryRunPreview("GetAvailability", "mobile-gateway", {}, auth.token));
92
+ }
93
+ try {
94
+ const data = await availability.workingHours.show(auth.token);
95
+ return successResponse(data);
96
+ }
97
+ catch (err) {
98
+ return mapAvailabilityError(err);
99
+ }
100
+ });
101
+ server.registerTool("ttctl_availability_working_hours_set", {
102
+ title: "Update working hours",
103
+ description: [
104
+ "Update working hours: any subset of (time zone, daily window,",
105
+ "flexible shift range) via the UpdateWorkingHours mutation.",
106
+ "",
107
+ "All time fields are `HH:MM:SS` strings (e.g., `09:00:00`).",
108
+ "`timeZone` is an IANA zone identifier (e.g., `Europe/Berlin`).",
109
+ "",
110
+ "At least one field MUST be provided — empty change sets are",
111
+ "rejected pre-flight.",
112
+ "",
113
+ "**This is a write operation**: it modifies the user's availability",
114
+ "settings on the live Toptal Talent platform. Confirm with the user",
115
+ "before invoking.",
116
+ "",
117
+ "Example user prompts:",
118
+ ' - "Set my Toptal working hours to 9 AM through 5 PM."',
119
+ ' - "Change my time zone to Europe/Berlin."',
120
+ ' - "Update my flexible shift range to 7 AM - 7 PM."',
121
+ ].join("\n"),
122
+ inputSchema: {
123
+ timeZone: z
124
+ .string()
125
+ .optional()
126
+ .describe("IANA time-zone identifier (e.g., `Europe/Berlin`, `America/New_York`)"),
127
+ workingTimeFrom: z
128
+ .string()
129
+ .optional()
130
+ .describe("Daily working-hours window start, `HH:MM:SS` (e.g., `09:00:00`)"),
131
+ workingTimeTo: z.string().optional().describe("Daily working-hours window end, `HH:MM:SS` (e.g., `17:00:00`)"),
132
+ availableShiftRangeFrom: z.string().optional().describe("Flexible shift-range start, `HH:MM:SS`"),
133
+ availableShiftRangeTo: z.string().optional().describe("Flexible shift-range end, `HH:MM:SS`"),
134
+ dryRun: DRY_RUN_FIELD,
135
+ },
136
+ }, async (args) => {
137
+ const auth = await ctx.resolveToolAuth();
138
+ if (!auth.ok)
139
+ return auth.response;
140
+ try {
141
+ const input = {};
142
+ if (args.timeZone !== undefined)
143
+ input.timeZone = args.timeZone;
144
+ if (args.workingTimeFrom !== undefined)
145
+ input.workingTimeFrom = args.workingTimeFrom;
146
+ if (args.workingTimeTo !== undefined)
147
+ input.workingTimeTo = args.workingTimeTo;
148
+ if (args.availableShiftRangeFrom !== undefined)
149
+ input.availableShiftRangeFrom = args.availableShiftRangeFrom;
150
+ if (args.availableShiftRangeTo !== undefined)
151
+ input.availableShiftRangeTo = args.availableShiftRangeTo;
152
+ const outcome = await availability.workingHours.set(auth.token, input, { dryRun: args.dryRun ?? false });
153
+ if (outcome.kind === "preview")
154
+ return dryRunResponse(outcome.preview);
155
+ return successResponse(outcome.result);
156
+ }
157
+ catch (err) {
158
+ return mapAvailabilityError(err);
159
+ }
160
+ });
161
+ server.registerTool("ttctl_availability_allocated_hours_show", {
162
+ title: "Show allocated hours",
163
+ description: [
164
+ "Show the signed-in user's viewer-scoped allocated hours per week.",
165
+ "",
166
+ "Example user prompts:",
167
+ ' - "How many hours have I allocated for Toptal work?"',
168
+ ' - "Show my Toptal availability in hours per week."',
169
+ "",
170
+ "Dry-run note: the apply path issues `GetAvailability` and narrows the result client-side — the preview reflects the wire call accordingly.",
171
+ ].join("\n"),
172
+ inputSchema: { dryRun: DRY_RUN_FIELD },
173
+ }, async (args) => {
174
+ const auth = await ctx.resolveToolAuth();
175
+ if (!auth.ok)
176
+ return auth.response;
177
+ if (args.dryRun === true) {
178
+ return dryRunResponse(buildMcpDryRunPreview("GetAvailability", "mobile-gateway", {}, auth.token));
179
+ }
180
+ try {
181
+ const data = await availability.allocatedHours.show(auth.token);
182
+ return successResponse(data);
183
+ }
184
+ catch (err) {
185
+ return mapAvailabilityError(err);
186
+ }
187
+ });
188
+ server.registerTool("ttctl_availability_allocated_hours_set", {
189
+ title: "Set allocated hours",
190
+ description: [
191
+ "Set the viewer-scoped allocated hours per week (non-negative",
192
+ "integer; the portal UI caps at 80 and the server validator",
193
+ "enforces the same range).",
194
+ "",
195
+ "This is a VIEWER-scoped value — it applies across all of the",
196
+ "viewer's active engagements, NOT per-engagement.",
197
+ "",
198
+ "**This is a write operation**: it modifies the user's availability",
199
+ "settings on the live Toptal Talent platform. Confirm with the user",
200
+ "before invoking.",
201
+ "",
202
+ "Example user prompts:",
203
+ ' - "Set my allocated Toptal hours to 40 per week."',
204
+ ' - "Update my Toptal allocated hours to 20."',
205
+ ].join("\n"),
206
+ inputSchema: {
207
+ hours: z.number().int().nonnegative().describe("Non-negative integer hours per week (portal UI caps at 80)"),
208
+ dryRun: DRY_RUN_FIELD,
209
+ },
210
+ }, async (args) => {
211
+ const auth = await ctx.resolveToolAuth();
212
+ if (!auth.ok)
213
+ return auth.response;
214
+ try {
215
+ const outcome = await availability.allocatedHours.set(auth.token, args.hours, { dryRun: args.dryRun ?? false });
216
+ if (outcome.kind === "preview")
217
+ return dryRunResponse(outcome.preview);
218
+ return successResponse(outcome.result);
219
+ }
220
+ catch (err) {
221
+ return mapAvailabilityError(err);
222
+ }
223
+ });
224
+ }
225
+ function successResponse(data) {
226
+ return {
227
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
228
+ };
229
+ }
230
+ function mapAvailabilityError(err) {
231
+ const typed = ttctlErrorToToolResponseOrNull(err);
232
+ if (typed !== null)
233
+ return typed;
234
+ if (err instanceof availability.AvailabilityError) {
235
+ return {
236
+ isError: true,
237
+ content: [
238
+ {
239
+ type: "text",
240
+ text: [`Error: ${err.message}`, "", recoveryForCode(err.code), "", `(Code: ${err.code})`].join("\n"),
241
+ },
242
+ ],
243
+ };
244
+ }
245
+ const message = err instanceof Error ? err.message : String(err);
246
+ return {
247
+ isError: true,
248
+ content: [
249
+ {
250
+ type: "text",
251
+ text: [
252
+ `Error: availability request failed: ${message}`,
253
+ "",
254
+ "Recovery: Retry; if the failure persists, file an issue.",
255
+ "",
256
+ "(Code: UNKNOWN)",
257
+ ].join("\n"),
258
+ },
259
+ ],
260
+ };
261
+ }
262
+ function recoveryForCode(code) {
263
+ switch (code) {
264
+ case "NO_VIEWER_ROLE":
265
+ return "Recovery: Sign in as a Toptal Talent (the availability surface is talent-side).";
266
+ case "MUTATION_ERROR":
267
+ return "Recovery: The mutation was rejected by the server (often: malformed time string, unknown time-zone identifier, or out-of-range allocated hours). Check the message above and adjust the input.";
268
+ default:
269
+ return "Recovery: Adjust the tool input or retry; see the code below.";
270
+ }
271
+ }
272
+ //# sourceMappingURL=availability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.js","sourceRoot":"","sources":["../../src/tools/availability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the `ttctl_contracts_*` MCP tools (#195). Two read-only tools:
5
+ *
6
+ * - `ttctl_contracts_list` — list talent-level contracts
7
+ * - `ttctl_contracts_show` — show one contract by id
8
+ *
9
+ * The `<id>` argument is the `Contract.id` from `ttctl_contracts_list`.
10
+ *
11
+ * **Domain distinction**: this group surfaces talent-level legal
12
+ * documents (Toptal Direct, Master Service Agreement) via
13
+ * `viewer.contracts` on the portal surface. Engagement-attached
14
+ * commercial agreements (rates, hours, period for one project) live
15
+ * on a different surface — use `ttctl_engagements_show <engagement-id>`.
16
+ *
17
+ * **Dry-run path** (issue #165): both tools accept `dryRun?: boolean`.
18
+ * Read-only tools build the preview at the MCP layer via
19
+ * `buildMcpDryRunPreview` — `show` previews the same `GetContracts`
20
+ * operation as `list` (the apply path fetches the list and filters
21
+ * client-side; the dry-run reflects that wire call accurately).
22
+ *
23
+ * **Per CLAUDE.md schema/contract validation rule**: `GetContracts`
24
+ * is hand-authored against the portal surface; every projected field
25
+ * is `Unknown`-typed in the SDL → INFERRED. Live E2E coverage
26
+ * (`packages/e2e/src/35-contracts.e2e.test.ts`) is mandatory pre-merge.
27
+ */
28
+ export declare function registerContractsTools(server: McpServer, ctx: ToolRegistrationContext): void;
29
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/tools/contracts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,OAAO,EAAyC,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AASnG;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CAgF5F"}