@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,227 @@
1
+ import { ConfigError } from "@ttctl/core";
2
+ import type { DryRunPreview, ToptalSurface } from "@ttctl/core";
3
+ import type { AuthResult } from "../auth.js";
4
+ import type { ToolErrorResponse } from "../errors.js";
5
+ /**
6
+ * Shared MCP-tool helpers — auth-token loading, response shaping, error
7
+ * mapping. Kept in one module so each `profile_basic_*` / `profile_skills_*`
8
+ * tool file stays small and focused on its own input shape.
9
+ *
10
+ * **Auth**: tools load the token per-call rather than caching it at server
11
+ * startup. The MCP server is a long-lived process; the user may re-run
12
+ * `ttctl auth signin` while the server is up, and the next tool call should
13
+ * pick up the new token without restarting the server.
14
+ *
15
+ * Post-#113: the per-call read targets the config path captured at
16
+ * `buildServer()` time, NOT a fresh per-invocation `resolveConfig()` call.
17
+ * Tools receive the bound `loadTokenForTool` closure via the registration
18
+ * context, not as a free import. Env-var shifts mid-session do not
19
+ * retarget reads or writes — the captured path is canonical for the
20
+ * session's lifetime.
21
+ *
22
+ * **Error contract**: domain failures (`ProfileError`, `SkillsError`) and
23
+ * typed `TtctlError` subclasses both render as MCP `isError: true` tool
24
+ * responses. Untyped throws bubble up to the SDK's default error path.
25
+ */
26
+ /**
27
+ * MCP tool-success response shape. Mirrors the SDK's `CallToolResult`
28
+ * happy-path: a text-content array carrying the rendered payload.
29
+ *
30
+ * The `[key: string]: unknown` index signature keeps the type
31
+ * structurally compatible with the SDK's `CallToolResult` (whose own type
32
+ * carries the same signature for forward-compatibility with new optional
33
+ * fields). The `structuredContent` field is populated by
34
+ * {@link jsonResponse} so tools that declare an `outputSchema` (#226) get
35
+ * SDK-validated structured payload alongside the `text` slot.
36
+ * `structuredContent` is harmless metadata for tools without
37
+ * `outputSchema` — the SDK skips validation when `outputSchema` is
38
+ * absent.
39
+ */
40
+ export interface ToolSuccessResponse {
41
+ content: [{
42
+ type: "text";
43
+ text: string;
44
+ }];
45
+ structuredContent?: Record<string, unknown>;
46
+ [key: string]: unknown;
47
+ }
48
+ /**
49
+ * Render a JSON-shaped payload as a tool-success response. Stringifies
50
+ * with two-space indentation so LLM clients see an easy-to-read response,
51
+ * and mirrors the payload into `structuredContent` so tools that declare
52
+ * an `outputSchema` (#226) get SDK-validated structured output without
53
+ * each tool having to plumb the field manually.
54
+ *
55
+ * `structuredContent` is only populated when `payload` is an object — the
56
+ * MCP SDK's `structuredContent` slot expects an object shape per
57
+ * `CallToolResult`, and arrays / primitives are encoded only via the
58
+ * `text` slot (callers that emit array payloads can still validate the
59
+ * JSON-decoded `text` field client-side).
60
+ */
61
+ export declare function jsonResponse(payload: unknown): ToolSuccessResponse;
62
+ /**
63
+ * Render a plain string as a tool-success response (e.g., for tools that
64
+ * return a confirmation rather than structured data). Use
65
+ * {@link textWithStructuredResponse} when both a human-readable line and
66
+ * a typed acknowledgment are desired (e.g., `*_remove` tools per #226).
67
+ */
68
+ export declare function textResponse(text: string): ToolSuccessResponse;
69
+ /**
70
+ * Render a confirmation line as the `text` content slot while also
71
+ * publishing a typed acknowledgment via `structuredContent`. Used by
72
+ * `*_remove` tools (#226) where the human-readable text stays for
73
+ * compatibility and the structured payload is `{ id, removed: true }`
74
+ * matching the tool's declared `outputSchema`.
75
+ */
76
+ export declare function textWithStructuredResponse(text: string, structuredContent: Record<string, unknown>): ToolSuccessResponse;
77
+ /**
78
+ * Uniform MCP dry-run response envelope (issue #165). Every tool's
79
+ * `dryRun: true` branch renders through this so MCP clients can treat
80
+ * `dryRun` as a universal "preview" affordance without per-tool envelope
81
+ * knowledge. The shape is `{ ok: true, dryRun: true, preview }` where
82
+ * `preview` is the canonical {@link DryRunPreview} carrying surface,
83
+ * transport, endpoint, operationName, variables, and (bearer-redacted)
84
+ * headers. The same envelope is emitted whether the preview was
85
+ * constructed at the MCP layer (via {@link buildMcpDryRunPreview}) or
86
+ * received from a core service whose `dryRun` option is supported
87
+ * (`profile.basic.set`, `jobs.*`, `engagements.breaks.*`,
88
+ * `availability.*Set`).
89
+ */
90
+ export declare function dryRunResponse(preview: DryRunPreview): ToolSuccessResponse;
91
+ /**
92
+ * Sibling envelope for multi-mutation tools (issue #165). Some tools fire
93
+ * MORE than one wire operation per invocation — `profile.skills.update`
94
+ * fires one mutation per supplied field (rating, experience, publicity).
95
+ * Single-preview envelope would lie: a caller previewing
96
+ * `update({id, rating, experience})` with the singular envelope would see
97
+ * one mutation while the apply path would actually fire two.
98
+ *
99
+ * The plural form preserves honesty without diverging from the dry-run
100
+ * contract: same `{ ok: true, dryRun: true, ... }` shape, but the `preview`
101
+ * key is replaced by `previews` (array). Tools using this helper MUST
102
+ * document the plural form on the tool description so MCP clients can
103
+ * branch on shape. The cross-cutting dry-run smoke test (#165 AC)
104
+ * accepts EITHER `preview` (single) OR `previews` (array).
105
+ */
106
+ export declare function dryRunMultiResponse(previews: DryRunPreview[]): ToolSuccessResponse;
107
+ /**
108
+ * Build a {@link DryRunPreview} at the MCP layer for tools whose core
109
+ * service does NOT carry its own `dryRun` option — i.e. read-only tools
110
+ * across every group and the profile sub-domains beyond `profile.basic`
111
+ * (`skills`, `industries`, `education`, `certifications`, `employment`,
112
+ * `portfolio`, `visas`, `resume`, `external`, `reviews`). The MCP tool
113
+ * supplies the operation's metadata + would-be variables; the helper
114
+ * constructs the preview via the public {@link buildDryRunPreview}
115
+ * primitive without invoking any transport (read or write).
116
+ *
117
+ * For mutating tools whose core supports `dryRun` (the four exceptions
118
+ * listed above), prefer passing `{ dryRun: true }` through to the core
119
+ * call and branching on the returned `{ kind: "preview", preview }`
120
+ * outcome — that path reuses the canonical variable-construction
121
+ * (including placeholder substitution for fields like `profileId` that
122
+ * would otherwise be resolved via a sibling read) and avoids drift
123
+ * between MCP-built variables and what core would actually send.
124
+ *
125
+ * The `token` is forwarded as `authToken` on the synthesised
126
+ * {@link TransportRequest} so {@link buildDryRunPreview} sets the
127
+ * `authorization` header to {@link DRY_RUN_REDACTED_AUTHORIZATION}
128
+ * (i.e. `Token token=<redacted>`) without ever placing the live bearer
129
+ * in the preview payload.
130
+ */
131
+ export declare function buildMcpDryRunPreview(operationName: string, surface: ToptalSurface, variables: Record<string, unknown>, token: string): DryRunPreview;
132
+ /**
133
+ * Build a tool-error response for a missing / unreadable auth token. The
134
+ * MCP equivalent of the CLI's `(UNAUTHENTICATED): No auth token found`
135
+ * branch.
136
+ */
137
+ export declare function unauthenticatedResponse(toolName: string): ToolErrorResponse;
138
+ /**
139
+ * Build a tool-error response for a config-resolution or write-back
140
+ * failure. The `ConfigError.code` discriminator (`NO_CREDS` / `PARSE` /
141
+ * `VALIDATION` / `PERMISSION` / `LOCKED`) is surfaced verbatim as the
142
+ * wire-format code so MCP clients can branch on it without string-matching
143
+ * the prose message. `LOCKED` indicates another ttctl process holds the
144
+ * config write-back lock — the MCP client should retry after a brief delay.
145
+ */
146
+ export declare function configErrorResponse(toolName: string, err: ConfigError): ToolErrorResponse;
147
+ /**
148
+ * Build a tool-error response for a domain error carrying a `code` +
149
+ * `message`. Used for `ProfileError` and `SkillsError` — both expose the
150
+ * same shape (`{code, message}`) but live in different modules.
151
+ */
152
+ export declare function domainErrorResponse(toolName: string, err: {
153
+ code: string;
154
+ message: string;
155
+ }): ToolErrorResponse;
156
+ /**
157
+ * Build a tool-error response for an unexpected exception (anything that
158
+ * isn't a `TtctlError` or domain error). Surfaced so the LLM client gets
159
+ * a structured response rather than the SDK's untyped error fallback.
160
+ */
161
+ export declare function genericErrorResponse(toolName: string, err: unknown): ToolErrorResponse;
162
+ /**
163
+ * Shared auth-token loader. Returns either the token (string) or a
164
+ * tool-error response that the caller should return verbatim.
165
+ *
166
+ * Routes via `ttctlErrorToToolResponseOrNull` first so any `TtctlError`
167
+ * thrown by the resolver chain (rare but possible) gets the uniform
168
+ * Error/Recovery/Code rendering.
169
+ *
170
+ * The loader is a factory closure over the MCP session's canonical config
171
+ * path captured at startup (#113). Per-call reads always target that path;
172
+ * env-var shifts during the session do NOT retarget the read.
173
+ */
174
+ export type TokenLoader = (toolName: string) => Promise<{
175
+ token: string;
176
+ } | ToolErrorResponse>;
177
+ export declare function createTokenLoader(configPath: string): TokenLoader;
178
+ /**
179
+ * Type guard: true when `value` is one of our tool responses (success or
180
+ * error). Used by tool handlers to decide whether to short-circuit on a
181
+ * failed token load.
182
+ */
183
+ export declare function isToolErrorResponse(value: unknown): value is ToolErrorResponse;
184
+ /**
185
+ * Resolver-shape used by `tools/profile/shared.ts` (`commandLabel`-flavored
186
+ * auth resolution returning `{token} | {error}`). Defined here so the
187
+ * `ToolRegistrationContext` can carry it without `_shared.ts` having to
188
+ * import from `tools/profile/`.
189
+ */
190
+ export type TokenResolver = (commandLabel: string) => Promise<{
191
+ token: string;
192
+ } | {
193
+ error: ToolErrorResponse;
194
+ }>;
195
+ /**
196
+ * Dependency-injection context threaded through `registerAllTools` (#113).
197
+ *
198
+ * `buildServer({configPath})` calls `resolveConfig` ONCE at startup and
199
+ * uses the resulting absolute path to construct each resolver. The
200
+ * context is then handed to `registerAllTools`, which forwards it to each
201
+ * per-tool registrar so per-tool callbacks invoke `ctx.resolveToolAuth()`
202
+ * / `ctx.loadTokenForTool(toolName)` / `ctx.resolveTokenForTool(label)`
203
+ * instead of free-importing module-scoped functions that would re-resolve
204
+ * config (and re-read env) on each call.
205
+ *
206
+ * Three resolver shapes co-exist because the existing tool surface uses
207
+ * three different conventions:
208
+ *
209
+ * - `resolveToolAuth` — discriminated-union `AuthResult`
210
+ * (`{ok: true, token} | {ok: false, response}`) consumed by
211
+ * `tools/profile/portfolio|resume|visas.ts`.
212
+ * - `loadTokenForTool(toolName)` — toolName-aware error path that
213
+ * includes the tool name in the rendered `Error: <toolName> failed
214
+ * (...)` text. Used by every per-file `profile_*_*.ts` tool.
215
+ * - `resolveTokenForTool(commandLabel)` — `commandLabel`-prefixed errors
216
+ * (`{token} | {error}` shape) used by sub-domain registrars in
217
+ * `tools/profile/certifications|education|employment|industries.ts`.
218
+ *
219
+ * All three target the captured configPath; mid-session env shifts do
220
+ * NOT retarget reads or writes for any of the three.
221
+ */
222
+ export interface ToolRegistrationContext {
223
+ resolveToolAuth: () => Promise<AuthResult>;
224
+ loadTokenForTool: TokenLoader;
225
+ resolveTokenForTool: TokenResolver;
226
+ }
227
+ //# sourceMappingURL=_shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAiD,MAAM,aAAa,CAAC;AACzF,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAQlE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAE9D;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACzC,mBAAmB,CAKrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,mBAAmB,CAc1E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,mBAAmB,CAQlF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,KAAK,EAAE,MAAM,GACZ,aAAa,CAMf;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAU3E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,iBAAiB,CAUzF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAU/G;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAWtF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAAC,CAAC;AAE/F,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CA2BjE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAE9E;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAAC;AAEhH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,gBAAgB,EAAE,WAAW,CAAC;IAC9B,mBAAmB,EAAE,aAAa,CAAC;CACpC"}
@@ -0,0 +1,238 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ import { ConfigError, TtctlError, buildDryRunPreview, resolveConfig } from "@ttctl/core";
4
+ import { emitMcpAuthResolve } from "../diagnostic.js";
5
+ import { ttctlErrorToToolResponseOrNull } from "../errors.js";
6
+ /**
7
+ * Render a JSON-shaped payload as a tool-success response. Stringifies
8
+ * with two-space indentation so LLM clients see an easy-to-read response,
9
+ * and mirrors the payload into `structuredContent` so tools that declare
10
+ * an `outputSchema` (#226) get SDK-validated structured output without
11
+ * each tool having to plumb the field manually.
12
+ *
13
+ * `structuredContent` is only populated when `payload` is an object — the
14
+ * MCP SDK's `structuredContent` slot expects an object shape per
15
+ * `CallToolResult`, and arrays / primitives are encoded only via the
16
+ * `text` slot (callers that emit array payloads can still validate the
17
+ * JSON-decoded `text` field client-side).
18
+ */
19
+ export function jsonResponse(payload) {
20
+ const response = {
21
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
22
+ };
23
+ if (payload !== null && typeof payload === "object" && !Array.isArray(payload)) {
24
+ response.structuredContent = payload;
25
+ }
26
+ return response;
27
+ }
28
+ /**
29
+ * Render a plain string as a tool-success response (e.g., for tools that
30
+ * return a confirmation rather than structured data). Use
31
+ * {@link textWithStructuredResponse} when both a human-readable line and
32
+ * a typed acknowledgment are desired (e.g., `*_remove` tools per #226).
33
+ */
34
+ export function textResponse(text) {
35
+ return { content: [{ type: "text", text }] };
36
+ }
37
+ /**
38
+ * Render a confirmation line as the `text` content slot while also
39
+ * publishing a typed acknowledgment via `structuredContent`. Used by
40
+ * `*_remove` tools (#226) where the human-readable text stays for
41
+ * compatibility and the structured payload is `{ id, removed: true }`
42
+ * matching the tool's declared `outputSchema`.
43
+ */
44
+ export function textWithStructuredResponse(text, structuredContent) {
45
+ return {
46
+ content: [{ type: "text", text }],
47
+ structuredContent,
48
+ };
49
+ }
50
+ /**
51
+ * Uniform MCP dry-run response envelope (issue #165). Every tool's
52
+ * `dryRun: true` branch renders through this so MCP clients can treat
53
+ * `dryRun` as a universal "preview" affordance without per-tool envelope
54
+ * knowledge. The shape is `{ ok: true, dryRun: true, preview }` where
55
+ * `preview` is the canonical {@link DryRunPreview} carrying surface,
56
+ * transport, endpoint, operationName, variables, and (bearer-redacted)
57
+ * headers. The same envelope is emitted whether the preview was
58
+ * constructed at the MCP layer (via {@link buildMcpDryRunPreview}) or
59
+ * received from a core service whose `dryRun` option is supported
60
+ * (`profile.basic.set`, `jobs.*`, `engagements.breaks.*`,
61
+ * `availability.*Set`).
62
+ */
63
+ export function dryRunResponse(preview) {
64
+ // Intentionally emits ONLY the `text` content slot — no
65
+ // `structuredContent`. The dry-run envelope shape does NOT match the
66
+ // success-path `outputSchema` declared by #226 tools, and the MCP SDK
67
+ // validates `structuredContent` against `outputSchema` when both are
68
+ // present. Leaving `structuredContent` absent lets the SDK skip
69
+ // validation for dry-run responses (per `_validateOutput`: "if
70
+ // `!result.structuredContent` return"), preserving the universal
71
+ // `{ ok, dryRun, preview }` envelope contract without forcing every
72
+ // tool's `outputSchema` to absorb the dry-run shape.
73
+ const envelope = { ok: true, dryRun: true, preview };
74
+ return {
75
+ content: [{ type: "text", text: JSON.stringify(envelope, null, 2) }],
76
+ };
77
+ }
78
+ /**
79
+ * Sibling envelope for multi-mutation tools (issue #165). Some tools fire
80
+ * MORE than one wire operation per invocation — `profile.skills.update`
81
+ * fires one mutation per supplied field (rating, experience, publicity).
82
+ * Single-preview envelope would lie: a caller previewing
83
+ * `update({id, rating, experience})` with the singular envelope would see
84
+ * one mutation while the apply path would actually fire two.
85
+ *
86
+ * The plural form preserves honesty without diverging from the dry-run
87
+ * contract: same `{ ok: true, dryRun: true, ... }` shape, but the `preview`
88
+ * key is replaced by `previews` (array). Tools using this helper MUST
89
+ * document the plural form on the tool description so MCP clients can
90
+ * branch on shape. The cross-cutting dry-run smoke test (#165 AC)
91
+ * accepts EITHER `preview` (single) OR `previews` (array).
92
+ */
93
+ export function dryRunMultiResponse(previews) {
94
+ // Same rationale as `dryRunResponse` — emits ONLY `content`, no
95
+ // `structuredContent`, so #226 tools with declared `outputSchema`
96
+ // don't fail validation on the dry-run shape.
97
+ const envelope = { ok: true, dryRun: true, previews };
98
+ return {
99
+ content: [{ type: "text", text: JSON.stringify(envelope, null, 2) }],
100
+ };
101
+ }
102
+ /**
103
+ * Build a {@link DryRunPreview} at the MCP layer for tools whose core
104
+ * service does NOT carry its own `dryRun` option — i.e. read-only tools
105
+ * across every group and the profile sub-domains beyond `profile.basic`
106
+ * (`skills`, `industries`, `education`, `certifications`, `employment`,
107
+ * `portfolio`, `visas`, `resume`, `external`, `reviews`). The MCP tool
108
+ * supplies the operation's metadata + would-be variables; the helper
109
+ * constructs the preview via the public {@link buildDryRunPreview}
110
+ * primitive without invoking any transport (read or write).
111
+ *
112
+ * For mutating tools whose core supports `dryRun` (the four exceptions
113
+ * listed above), prefer passing `{ dryRun: true }` through to the core
114
+ * call and branching on the returned `{ kind: "preview", preview }`
115
+ * outcome — that path reuses the canonical variable-construction
116
+ * (including placeholder substitution for fields like `profileId` that
117
+ * would otherwise be resolved via a sibling read) and avoids drift
118
+ * between MCP-built variables and what core would actually send.
119
+ *
120
+ * The `token` is forwarded as `authToken` on the synthesised
121
+ * {@link TransportRequest} so {@link buildDryRunPreview} sets the
122
+ * `authorization` header to {@link DRY_RUN_REDACTED_AUTHORIZATION}
123
+ * (i.e. `Token token=<redacted>`) without ever placing the live bearer
124
+ * in the preview payload.
125
+ */
126
+ export function buildMcpDryRunPreview(operationName, surface, variables, token) {
127
+ return buildDryRunPreview({
128
+ surface,
129
+ body: { operationName, variables },
130
+ authToken: token,
131
+ });
132
+ }
133
+ /**
134
+ * Build a tool-error response for a missing / unreadable auth token. The
135
+ * MCP equivalent of the CLI's `(UNAUTHENTICATED): No auth token found`
136
+ * branch.
137
+ */
138
+ export function unauthenticatedResponse(toolName) {
139
+ return {
140
+ isError: true,
141
+ content: [
142
+ {
143
+ type: "text",
144
+ text: `Error: ${toolName} failed (UNAUTHENTICATED): No auth token found.\n\nRecovery: Run \`ttctl auth signin\` to sign in.\n\n(Code: UNAUTHENTICATED)`,
145
+ },
146
+ ],
147
+ };
148
+ }
149
+ /**
150
+ * Build a tool-error response for a config-resolution or write-back
151
+ * failure. The `ConfigError.code` discriminator (`NO_CREDS` / `PARSE` /
152
+ * `VALIDATION` / `PERMISSION` / `LOCKED`) is surfaced verbatim as the
153
+ * wire-format code so MCP clients can branch on it without string-matching
154
+ * the prose message. `LOCKED` indicates another ttctl process holds the
155
+ * config write-back lock — the MCP client should retry after a brief delay.
156
+ */
157
+ export function configErrorResponse(toolName, err) {
158
+ return {
159
+ isError: true,
160
+ content: [
161
+ {
162
+ type: "text",
163
+ text: `Error: ${toolName} failed (${err.code}): ${err.message}\n\n(Code: ${err.code})`,
164
+ },
165
+ ],
166
+ };
167
+ }
168
+ /**
169
+ * Build a tool-error response for a domain error carrying a `code` +
170
+ * `message`. Used for `ProfileError` and `SkillsError` — both expose the
171
+ * same shape (`{code, message}`) but live in different modules.
172
+ */
173
+ export function domainErrorResponse(toolName, err) {
174
+ return {
175
+ isError: true,
176
+ content: [
177
+ {
178
+ type: "text",
179
+ text: `Error: ${toolName} failed (${err.code}): ${err.message}\n\n(Code: ${err.code})`,
180
+ },
181
+ ],
182
+ };
183
+ }
184
+ /**
185
+ * Build a tool-error response for an unexpected exception (anything that
186
+ * isn't a `TtctlError` or domain error). Surfaced so the LLM client gets
187
+ * a structured response rather than the SDK's untyped error fallback.
188
+ */
189
+ export function genericErrorResponse(toolName, err) {
190
+ const message = err instanceof Error ? err.message : String(err);
191
+ return {
192
+ isError: true,
193
+ content: [
194
+ {
195
+ type: "text",
196
+ text: `Error: ${toolName} failed: ${message}\n\n(Code: UNKNOWN)`,
197
+ },
198
+ ],
199
+ };
200
+ }
201
+ export function createTokenLoader(configPath) {
202
+ return async function loadTokenForTool(toolName) {
203
+ let token;
204
+ try {
205
+ const { config } = resolveConfig({ path: configPath });
206
+ token = config.auth.token;
207
+ }
208
+ catch (err) {
209
+ if (err instanceof ConfigError) {
210
+ emitMcpAuthResolve(configPath, "config_error", false);
211
+ return configErrorResponse(toolName, err);
212
+ }
213
+ if (err instanceof TtctlError) {
214
+ const typed = ttctlErrorToToolResponseOrNull(err);
215
+ if (typed !== null) {
216
+ emitMcpAuthResolve(configPath, "config_error", false);
217
+ return typed;
218
+ }
219
+ }
220
+ throw err;
221
+ }
222
+ if (token === undefined) {
223
+ emitMcpAuthResolve(configPath, "unauthenticated", false);
224
+ return unauthenticatedResponse(toolName);
225
+ }
226
+ emitMcpAuthResolve(configPath, "ok", true);
227
+ return Promise.resolve({ token });
228
+ };
229
+ }
230
+ /**
231
+ * Type guard: true when `value` is one of our tool responses (success or
232
+ * error). Used by tool handlers to decide whether to short-circuit on a
233
+ * failed token load.
234
+ */
235
+ export function isToolErrorResponse(value) {
236
+ return typeof value === "object" && value !== null && "isError" in value && value.isError === true;
237
+ }
238
+ //# sourceMappingURL=_shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_shared.js","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type ToolRegistrationContext } from "./_shared.js";
3
+ /**
4
+ * Register the three `ttctl_applications_*` MCP tools per the #15 spec.
5
+ * Tool names use the `ttctl_` prefix and the canonical CLI path joined
6
+ * with `_` per project naming policy:
7
+ *
8
+ * - `ttctl_applications_list`
9
+ * - `ttctl_applications_show`
10
+ * - `ttctl_applications_stats`
11
+ *
12
+ * Each tool maps 1:1 to a CLI leaf — the schemas describe the same set
13
+ * of fields. The list tool's `keywords` and `statusGroups` mirror the
14
+ * `--keywords` / `--status-group` CLI flags.
15
+ *
16
+ * **Read-only** — per project non-goals (#15), no apply / withdraw /
17
+ * edit tools are exposed. `applications` is intentionally a smaller
18
+ * surface than the profile sub-domains.
19
+ *
20
+ * Dry-run path (issue #165): every tool accepts `dryRun?: boolean`.
21
+ * `list` and `show` emit the singular `{ preview }` envelope (one
22
+ * operation per call); `stats` emits the plural `{ previews: [...] }`
23
+ * envelope because the apply path fires 5 parallel `JobActivityItems`
24
+ * calls (one per STATUS_GROUPS member) — see {@link dryRunMultiResponse}.
25
+ */
26
+ export declare function registerApplicationsTools(server: McpServer, ctx: ToolRegistrationContext): void;
27
+ //# sourceMappingURL=applications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applications.d.ts","sourceRoot":"","sources":["../../src/tools/applications.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,OAAO,EAA8D,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AASxH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CAwH/F"}