@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.
- package/README.md +72 -9
- package/dist/auth.d.ts +40 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +69 -0
- package/dist/auth.js.map +1 -0
- package/dist/data-handling.d.ts +91 -0
- package/dist/data-handling.d.ts.map +1 -0
- package/dist/data-handling.js +129 -0
- package/dist/data-handling.js.map +1 -0
- package/dist/diagnostic.d.ts +262 -0
- package/dist/diagnostic.d.ts.map +1 -0
- package/dist/diagnostic.js +362 -0
- package/dist/diagnostic.js.map +1 -0
- package/dist/errors.d.ts +54 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +48 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/kill-switch-hook.d.ts +67 -0
- package/dist/kill-switch-hook.d.ts.map +1 -0
- package/dist/kill-switch-hook.js +61 -0
- package/dist/kill-switch-hook.js.map +1 -0
- package/dist/server.d.ts +100 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +157 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/_shared.d.ts +227 -0
- package/dist/tools/_shared.d.ts.map +1 -0
- package/dist/tools/_shared.js +238 -0
- package/dist/tools/_shared.js.map +1 -0
- package/dist/tools/applications.d.ts +27 -0
- package/dist/tools/applications.d.ts.map +1 -0
- package/dist/tools/applications.js +192 -0
- package/dist/tools/applications.js.map +1 -0
- package/dist/tools/availability.d.ts +33 -0
- package/dist/tools/availability.d.ts.map +1 -0
- package/dist/tools/availability.js +272 -0
- package/dist/tools/availability.js.map +1 -0
- package/dist/tools/contracts.d.ts +29 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +157 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/engagements.d.ts +36 -0
- package/dist/tools/engagements.d.ts.map +1 -0
- package/dist/tools/engagements.js +408 -0
- package/dist/tools/engagements.js.map +1 -0
- package/dist/tools/file-upload.d.ts +133 -0
- package/dist/tools/file-upload.d.ts.map +1 -0
- package/dist/tools/file-upload.js +247 -0
- package/dist/tools/file-upload.js.map +1 -0
- package/dist/tools/index.d.ts +28 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +133 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/jobs.d.ts +37 -0
- package/dist/tools/jobs.d.ts.map +1 -0
- package/dist/tools/jobs.js +505 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/output-schemas.d.ts +129 -0
- package/dist/tools/output-schemas.d.ts.map +1 -0
- package/dist/tools/output-schemas.js +138 -0
- package/dist/tools/output-schemas.js.map +1 -0
- package/dist/tools/payments.d.ts +36 -0
- package/dist/tools/payments.d.ts.map +1 -0
- package/dist/tools/payments.js +373 -0
- package/dist/tools/payments.js.map +1 -0
- package/dist/tools/profile/certifications.d.ts +18 -0
- package/dist/tools/profile/certifications.d.ts.map +1 -0
- package/dist/tools/profile/certifications.js +219 -0
- package/dist/tools/profile/certifications.js.map +1 -0
- package/dist/tools/profile/education.d.ts +23 -0
- package/dist/tools/profile/education.d.ts.map +1 -0
- package/dist/tools/profile/education.js +222 -0
- package/dist/tools/profile/education.js.map +1 -0
- package/dist/tools/profile/employment.d.ts +23 -0
- package/dist/tools/profile/employment.d.ts.map +1 -0
- package/dist/tools/profile/employment.js +254 -0
- package/dist/tools/profile/employment.js.map +1 -0
- package/dist/tools/profile/industries.d.ts +30 -0
- package/dist/tools/profile/industries.d.ts.map +1 -0
- package/dist/tools/profile/industries.js +196 -0
- package/dist/tools/profile/industries.js.map +1 -0
- package/dist/tools/profile/portfolio.d.ts +22 -0
- package/dist/tools/profile/portfolio.d.ts.map +1 -0
- package/dist/tools/profile/portfolio.js +341 -0
- package/dist/tools/profile/portfolio.js.map +1 -0
- package/dist/tools/profile/resume.d.ts +16 -0
- package/dist/tools/profile/resume.d.ts.map +1 -0
- package/dist/tools/profile/resume.js +107 -0
- package/dist/tools/profile/resume.js.map +1 -0
- package/dist/tools/profile/shared.d.ts +85 -0
- package/dist/tools/profile/shared.d.ts.map +1 -0
- package/dist/tools/profile/shared.js +128 -0
- package/dist/tools/profile/shared.js.map +1 -0
- package/dist/tools/profile/visas.d.ts +15 -0
- package/dist/tools/profile/visas.d.ts.map +1 -0
- package/dist/tools/profile/visas.js +170 -0
- package/dist/tools/profile/visas.js.map +1 -0
- package/dist/tools/profile_basic_photo_show.d.ts +14 -0
- package/dist/tools/profile_basic_photo_show.d.ts.map +1 -0
- package/dist/tools/profile_basic_photo_show.js +59 -0
- package/dist/tools/profile_basic_photo_show.js.map +1 -0
- package/dist/tools/profile_basic_photo_upload.d.ts +24 -0
- package/dist/tools/profile_basic_photo_upload.d.ts.map +1 -0
- package/dist/tools/profile_basic_photo_upload.js +90 -0
- package/dist/tools/profile_basic_photo_upload.js.map +1 -0
- package/dist/tools/profile_basic_show.d.ts +64 -0
- package/dist/tools/profile_basic_show.d.ts.map +1 -0
- package/dist/tools/profile_basic_show.js +108 -0
- package/dist/tools/profile_basic_show.js.map +1 -0
- package/dist/tools/profile_basic_update.d.ts +37 -0
- package/dist/tools/profile_basic_update.d.ts.map +1 -0
- package/dist/tools/profile_basic_update.js +97 -0
- package/dist/tools/profile_basic_update.js.map +1 -0
- package/dist/tools/profile_external_advanced_wizard_show.d.ts +14 -0
- package/dist/tools/profile_external_advanced_wizard_show.d.ts.map +1 -0
- package/dist/tools/profile_external_advanced_wizard_show.js +56 -0
- package/dist/tools/profile_external_advanced_wizard_show.js.map +1 -0
- package/dist/tools/profile_external_custom_requirements_set.d.ts +13 -0
- package/dist/tools/profile_external_custom_requirements_set.d.ts.map +1 -0
- package/dist/tools/profile_external_custom_requirements_set.js +75 -0
- package/dist/tools/profile_external_custom_requirements_set.js.map +1 -0
- package/dist/tools/profile_external_custom_requirements_show.d.ts +14 -0
- package/dist/tools/profile_external_custom_requirements_show.d.ts.map +1 -0
- package/dist/tools/profile_external_custom_requirements_show.js +56 -0
- package/dist/tools/profile_external_custom_requirements_show.js.map +1 -0
- package/dist/tools/profile_external_readiness.d.ts +12 -0
- package/dist/tools/profile_external_readiness.d.ts.map +1 -0
- package/dist/tools/profile_external_readiness.js +54 -0
- package/dist/tools/profile_external_readiness.js.map +1 -0
- package/dist/tools/profile_external_recommendations.d.ts +15 -0
- package/dist/tools/profile_external_recommendations.d.ts.map +1 -0
- package/dist/tools/profile_external_recommendations.js +57 -0
- package/dist/tools/profile_external_recommendations.js.map +1 -0
- package/dist/tools/profile_external_show.d.ts +15 -0
- package/dist/tools/profile_external_show.d.ts.map +1 -0
- package/dist/tools/profile_external_show.js +59 -0
- package/dist/tools/profile_external_show.js.map +1 -0
- package/dist/tools/profile_external_update.d.ts +14 -0
- package/dist/tools/profile_external_update.d.ts.map +1 -0
- package/dist/tools/profile_external_update.js +79 -0
- package/dist/tools/profile_external_update.js.map +1 -0
- package/dist/tools/profile_reviews_approve_item.d.ts +17 -0
- package/dist/tools/profile_reviews_approve_item.d.ts.map +1 -0
- package/dist/tools/profile_reviews_approve_item.js +77 -0
- package/dist/tools/profile_reviews_approve_item.js.map +1 -0
- package/dist/tools/profile_reviews_approve_section.d.ts +15 -0
- package/dist/tools/profile_reviews_approve_section.d.ts.map +1 -0
- package/dist/tools/profile_reviews_approve_section.js +70 -0
- package/dist/tools/profile_reviews_approve_section.js.map +1 -0
- package/dist/tools/profile_reviews_list.d.ts +16 -0
- package/dist/tools/profile_reviews_list.d.ts.map +1 -0
- package/dist/tools/profile_reviews_list.js +58 -0
- package/dist/tools/profile_reviews_list.js.map +1 -0
- package/dist/tools/profile_reviews_submit_for_review.d.ts +14 -0
- package/dist/tools/profile_reviews_submit_for_review.d.ts.map +1 -0
- package/dist/tools/profile_reviews_submit_for_review.js +56 -0
- package/dist/tools/profile_reviews_submit_for_review.js.map +1 -0
- package/dist/tools/profile_skills_add.d.ts +4 -0
- package/dist/tools/profile_skills_add.d.ts.map +1 -0
- package/dist/tools/profile_skills_add.js +52 -0
- package/dist/tools/profile_skills_add.js.map +1 -0
- package/dist/tools/profile_skills_autocomplete.d.ts +4 -0
- package/dist/tools/profile_skills_autocomplete.d.ts.map +1 -0
- package/dist/tools/profile_skills_autocomplete.js +78 -0
- package/dist/tools/profile_skills_autocomplete.js.map +1 -0
- package/dist/tools/profile_skills_list.d.ts +16 -0
- package/dist/tools/profile_skills_list.d.ts.map +1 -0
- package/dist/tools/profile_skills_list.js +65 -0
- package/dist/tools/profile_skills_list.js.map +1 -0
- package/dist/tools/profile_skills_readiness.d.ts +4 -0
- package/dist/tools/profile_skills_readiness.d.ts.map +1 -0
- package/dist/tools/profile_skills_readiness.js +53 -0
- package/dist/tools/profile_skills_readiness.js.map +1 -0
- package/dist/tools/profile_skills_remove.d.ts +4 -0
- package/dist/tools/profile_skills_remove.d.ts.map +1 -0
- package/dist/tools/profile_skills_remove.js +53 -0
- package/dist/tools/profile_skills_remove.js.map +1 -0
- package/dist/tools/profile_skills_show.d.ts +4 -0
- package/dist/tools/profile_skills_show.d.ts.map +1 -0
- package/dist/tools/profile_skills_show.js +51 -0
- package/dist/tools/profile_skills_show.js.map +1 -0
- package/dist/tools/profile_skills_update.d.ts +11 -0
- package/dist/tools/profile_skills_update.d.ts.map +1 -0
- package/dist/tools/profile_skills_update.js +97 -0
- package/dist/tools/profile_skills_update.js.map +1 -0
- package/dist/tools/timesheet.d.ts +29 -0
- package/dist/tools/timesheet.d.ts.map +1 -0
- package/dist/tools/timesheet.js +257 -0
- package/dist/tools/timesheet.js.map +1 -0
- package/package.json +33 -13
- package/index.js +0 -7
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { ConfigError, DateInputError, TtctlError, profile, resolveConfig } from "@ttctl/core";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { emitMcpAuthResolve } from "../../diagnostic.js";
|
|
6
|
+
import { ttctlErrorToToolResponse } from "../../errors.js";
|
|
7
|
+
/**
|
|
8
|
+
* Zod schema for sub-domain `--from` / `--to` / `--issued` / `--expires` /
|
|
9
|
+
* other date-flavored flags. Accepts ISO-8601 (`YYYY-MM-DD`) or year-only
|
|
10
|
+
* (`YYYY`); semantic validation (real calendar dates, year range) happens
|
|
11
|
+
* later inside `parseDateInput` from `@ttctl/core`. Hoisted here so the
|
|
12
|
+
* four sub-domain tool files share a single source of truth.
|
|
13
|
+
*/
|
|
14
|
+
export const dateInput = z
|
|
15
|
+
.string()
|
|
16
|
+
.regex(/^(\d{4}|\d{4}-\d{2}-\d{2})$/, "expected ISO-8601 date (YYYY-MM-DD) or year (YYYY)");
|
|
17
|
+
/**
|
|
18
|
+
* Render a JSON-serialized success response. Tools return structured data
|
|
19
|
+
* as JSON in the `text` content field — MCP-aware LLM clients can parse
|
|
20
|
+
* it; non-aware clients see human-readable JSON. The same payload is
|
|
21
|
+
* mirrored into `structuredContent` so tools declaring an `outputSchema`
|
|
22
|
+
* (#226) get SDK-validated structured output without per-tool plumbing.
|
|
23
|
+
*
|
|
24
|
+
* `structuredContent` is populated only when `payload` is an object —
|
|
25
|
+
* the MCP SDK's `structuredContent` slot expects an object shape, and
|
|
26
|
+
* array / primitive payloads stay in the `text` slot only.
|
|
27
|
+
*/
|
|
28
|
+
export function jsonSuccess(payload) {
|
|
29
|
+
const response = {
|
|
30
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
31
|
+
};
|
|
32
|
+
if (payload !== null && typeof payload === "object" && !Array.isArray(payload)) {
|
|
33
|
+
response.structuredContent = payload;
|
|
34
|
+
}
|
|
35
|
+
return response;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Render a plain-text success response (useful for verbs like `remove` /
|
|
39
|
+
* `highlight` whose output is a confirmation, not structured data). Use
|
|
40
|
+
* {@link textWithStructuredSuccess} when the tool also declares an
|
|
41
|
+
* `outputSchema` requiring a typed acknowledgment.
|
|
42
|
+
*/
|
|
43
|
+
export function textSuccess(text) {
|
|
44
|
+
return { content: [{ type: "text", text }] };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Render a confirmation line as the `text` content slot while also
|
|
48
|
+
* publishing a typed acknowledgment via `structuredContent`. Used by
|
|
49
|
+
* `*_remove` tools (#226) where the human-readable text stays for
|
|
50
|
+
* compatibility and the structured payload matches the tool's declared
|
|
51
|
+
* `outputSchema`.
|
|
52
|
+
*/
|
|
53
|
+
export function textWithStructuredSuccess(text, structuredContent) {
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: "text", text }],
|
|
56
|
+
structuredContent,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Map a domain error from any sub-domain into an MCP tool-error response.
|
|
61
|
+
*
|
|
62
|
+
* Routes through three branches:
|
|
63
|
+
* - `TtctlError` subclasses → uniform Error/Recovery/Code blocks
|
|
64
|
+
* - `profile.basic.ProfileError` → `(<CODE>): <message>` line
|
|
65
|
+
* - anything else → generic `text: <message>`
|
|
66
|
+
*
|
|
67
|
+
* `commandLabel` (e.g. `"profile.education.add"`) prefixes the error
|
|
68
|
+
* line for sub-domain disambiguation.
|
|
69
|
+
*/
|
|
70
|
+
export function presentToolError(commandLabel, err) {
|
|
71
|
+
if (err instanceof TtctlError)
|
|
72
|
+
return ttctlErrorToToolResponse(err);
|
|
73
|
+
if (err instanceof profile.basic.ProfileError) {
|
|
74
|
+
return {
|
|
75
|
+
isError: true,
|
|
76
|
+
content: [{ type: "text", text: `${commandLabel} failed (${err.code}): ${err.message}` }],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (err instanceof DateInputError) {
|
|
80
|
+
return {
|
|
81
|
+
isError: true,
|
|
82
|
+
content: [{ type: "text", text: `${commandLabel} failed (${err.code}): ${err.message}` }],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
86
|
+
return {
|
|
87
|
+
isError: true,
|
|
88
|
+
content: [{ type: "text", text: `${commandLabel} failed: ${message}` }],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function createTokenResolver(configPath) {
|
|
92
|
+
return async function resolveTokenForTool(commandLabel) {
|
|
93
|
+
let token;
|
|
94
|
+
try {
|
|
95
|
+
const { config } = resolveConfig({ path: configPath });
|
|
96
|
+
token = config.auth.token;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
if (err instanceof ConfigError) {
|
|
100
|
+
emitMcpAuthResolve(configPath, "config_error", false);
|
|
101
|
+
return {
|
|
102
|
+
error: {
|
|
103
|
+
isError: true,
|
|
104
|
+
content: [{ type: "text", text: `${commandLabel} failed (${err.code}): ${err.message}` }],
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
if (token === undefined) {
|
|
111
|
+
emitMcpAuthResolve(configPath, "unauthenticated", false);
|
|
112
|
+
return {
|
|
113
|
+
error: {
|
|
114
|
+
isError: true,
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: `${commandLabel} failed (UNAUTHENTICATED): No auth token found. Run \`ttctl auth signin\` to sign in.`,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
emitMcpAuthResolve(configPath, "ok", true);
|
|
125
|
+
return Promise.resolve({ token });
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/tools/profile/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 four `ttctl_profile_visas_*` MCP tools.
|
|
5
|
+
*
|
|
6
|
+
* Tool names use the canonical sub-domain `visas` (no CLI alias). Each
|
|
7
|
+
* tool maps 1:1 to a CLI leaf. Dry-run path (issue #165): every tool
|
|
8
|
+
* accepts `dryRun?: boolean` and emits the uniform `{ ok, dryRun, preview }`
|
|
9
|
+
* envelope via MCP-level preview building when `dryRun: true`.
|
|
10
|
+
* `variables.input.profileId` (list) carries
|
|
11
|
+
* `DRY_RUN_PROFILE_ID_PLACEHOLDER` because the apply path resolves it
|
|
12
|
+
* via a sibling profile read.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerVisasTools(server: McpServer, ctx: ToolRegistrationContext): void;
|
|
15
|
+
//# sourceMappingURL=visas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visas.d.ts","sourceRoot":"","sources":["../../../src/tools/profile/visas.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAAyC,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AASpG;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CAyIxF"}
|
|
@@ -0,0 +1,170 @@
|
|
|
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, 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 four `ttctl_profile_visas_*` MCP tools.
|
|
13
|
+
*
|
|
14
|
+
* Tool names use the canonical sub-domain `visas` (no CLI alias). Each
|
|
15
|
+
* tool maps 1:1 to a CLI leaf. Dry-run path (issue #165): every tool
|
|
16
|
+
* accepts `dryRun?: boolean` and emits the uniform `{ ok, dryRun, preview }`
|
|
17
|
+
* envelope via MCP-level preview building when `dryRun: true`.
|
|
18
|
+
* `variables.input.profileId` (list) carries
|
|
19
|
+
* `DRY_RUN_PROFILE_ID_PLACEHOLDER` because the apply path resolves it
|
|
20
|
+
* via a sibling profile read.
|
|
21
|
+
*/
|
|
22
|
+
export function registerVisasTools(server, ctx) {
|
|
23
|
+
server.registerTool("ttctl_profile_visas_list", {
|
|
24
|
+
title: "List travel visas",
|
|
25
|
+
description: "List the signed-in user's travel-visa records (id, country, type, expiry). Pass `dryRun: true` to preview the request.",
|
|
26
|
+
inputSchema: { dryRun: DRY_RUN_FIELD },
|
|
27
|
+
}, async (args) => {
|
|
28
|
+
const auth = await ctx.resolveToolAuth();
|
|
29
|
+
if (!auth.ok)
|
|
30
|
+
return auth.response;
|
|
31
|
+
if (args.dryRun === true) {
|
|
32
|
+
return dryRunResponse(buildMcpDryRunPreview("getTravelVisas", "mobile-gateway", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER }, auth.token));
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const visas = await profile.visas.list(auth.token);
|
|
36
|
+
return successResponse(visas);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
return mapVisasError(err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
server.registerTool("ttctl_profile_visas_add", {
|
|
43
|
+
title: "Create a travel-visa record",
|
|
44
|
+
description: "Create a new travel-visa record. Both `countryId` and `visaType` are required; `expiryDate` is optional. Pass `dryRun: true` to preview the request.",
|
|
45
|
+
inputSchema: {
|
|
46
|
+
countryId: z.string().describe("Country id (server-issued; query the Toptal travel-visa form for valid ids)"),
|
|
47
|
+
visaType: z.string().describe("Visa type (e.g., Schengen, B1/B2, Tier 5)"),
|
|
48
|
+
expiryDate: z.string().optional().describe("Expiry date in YYYY-MM-DD"),
|
|
49
|
+
dryRun: DRY_RUN_FIELD,
|
|
50
|
+
},
|
|
51
|
+
}, async (args) => {
|
|
52
|
+
const auth = await ctx.resolveToolAuth();
|
|
53
|
+
if (!auth.ok)
|
|
54
|
+
return auth.response;
|
|
55
|
+
const input = {
|
|
56
|
+
countryId: args.countryId,
|
|
57
|
+
visaType: args.visaType,
|
|
58
|
+
};
|
|
59
|
+
if (args.expiryDate !== undefined)
|
|
60
|
+
input.expiryDate = args.expiryDate;
|
|
61
|
+
if (args.dryRun === true) {
|
|
62
|
+
return dryRunResponse(buildMcpDryRunPreview("createTravelVisa", "talent-profile", { input: { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER, travelVisa: input } }, auth.token));
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const visas = await profile.visas.add(auth.token, input);
|
|
66
|
+
return successResponse(visas);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
return mapVisasError(err);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
server.registerTool("ttctl_profile_visas_update", {
|
|
73
|
+
title: "Update a travel-visa record",
|
|
74
|
+
description: "Update fields on a travel-visa record by id. Only supplied fields are updated. Pass `dryRun: true` to preview the request.",
|
|
75
|
+
inputSchema: {
|
|
76
|
+
id: z.string().describe("Id of the travel-visa record"),
|
|
77
|
+
countryId: z.string().optional().describe("Country id"),
|
|
78
|
+
visaType: z.string().optional().describe("Visa type"),
|
|
79
|
+
expiryDate: z.string().optional().describe("Expiry date in YYYY-MM-DD"),
|
|
80
|
+
dryRun: DRY_RUN_FIELD,
|
|
81
|
+
},
|
|
82
|
+
}, async (args) => {
|
|
83
|
+
const auth = await ctx.resolveToolAuth();
|
|
84
|
+
if (!auth.ok)
|
|
85
|
+
return auth.response;
|
|
86
|
+
const changes = {};
|
|
87
|
+
if (args.countryId !== undefined)
|
|
88
|
+
changes.countryId = args.countryId;
|
|
89
|
+
if (args.visaType !== undefined)
|
|
90
|
+
changes.visaType = args.visaType;
|
|
91
|
+
if (args.expiryDate !== undefined)
|
|
92
|
+
changes.expiryDate = args.expiryDate;
|
|
93
|
+
if (args.dryRun === true) {
|
|
94
|
+
return dryRunResponse(buildMcpDryRunPreview("updateTravelVisa", "talent-profile", { input: { travelVisaId: args.id, travelVisa: changes } }, auth.token));
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const visas = await profile.visas.update(auth.token, args.id, changes);
|
|
98
|
+
return successResponse(visas);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return mapVisasError(err);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
server.registerTool("ttctl_profile_visas_remove", {
|
|
105
|
+
title: "Remove a travel-visa record",
|
|
106
|
+
description: "Remove a travel-visa record by id. Pass `dryRun: true` to preview the request.",
|
|
107
|
+
inputSchema: {
|
|
108
|
+
id: z.string().describe("Id of the travel-visa record to remove"),
|
|
109
|
+
dryRun: DRY_RUN_FIELD,
|
|
110
|
+
},
|
|
111
|
+
}, async (args) => {
|
|
112
|
+
const auth = await ctx.resolveToolAuth();
|
|
113
|
+
if (!auth.ok)
|
|
114
|
+
return auth.response;
|
|
115
|
+
if (args.dryRun === true) {
|
|
116
|
+
return dryRunResponse(buildMcpDryRunPreview("removeTravelVisa", "talent-profile", { input: { travelVisaId: args.id } }, auth.token));
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const visas = await profile.visas.remove(auth.token, args.id);
|
|
120
|
+
return successResponse(visas);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
return mapVisasError(err);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function successResponse(data) {
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function mapVisasError(err) {
|
|
133
|
+
const typed = ttctlErrorToToolResponseOrNull(err);
|
|
134
|
+
if (typed !== null)
|
|
135
|
+
return typed;
|
|
136
|
+
if (err instanceof profile.visas.VisasError) {
|
|
137
|
+
return {
|
|
138
|
+
isError: true,
|
|
139
|
+
content: [
|
|
140
|
+
{
|
|
141
|
+
type: "text",
|
|
142
|
+
text: [
|
|
143
|
+
`Error: ${err.message}`,
|
|
144
|
+
"",
|
|
145
|
+
"Recovery: Adjust the tool input or retry; see the code below.",
|
|
146
|
+
"",
|
|
147
|
+
`(Code: ${err.code})`,
|
|
148
|
+
].join("\n"),
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
154
|
+
return {
|
|
155
|
+
isError: true,
|
|
156
|
+
content: [
|
|
157
|
+
{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: [
|
|
160
|
+
`Error: travel-visa request failed: ${message}`,
|
|
161
|
+
"",
|
|
162
|
+
"Recovery: Retry; if the failure persists, file an issue.",
|
|
163
|
+
"",
|
|
164
|
+
"(Code: UNKNOWN)",
|
|
165
|
+
].join("\n"),
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=visas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visas.js","sourceRoot":"","sources":["../../../src/tools/profile/visas.ts"],"names":[],"mappings":"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"}
|
|
@@ -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_basic_photo_show` MCP tool. Read-only.
|
|
5
|
+
*
|
|
6
|
+
* Dry-run path (issue #165): when `dryRun: true`, returns a preview of
|
|
7
|
+
* the `GET_PHOTO` query (talent-profile surface) that WOULD have been
|
|
8
|
+
* sent. The `profileId` variable carries `DRY_RUN_PROFILE_ID_PLACEHOLDER`
|
|
9
|
+
* because the apply path resolves it via a sibling `show()` call at
|
|
10
|
+
* execution time — the dry-run path skips that read entirely so no
|
|
11
|
+
* transport is invoked.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerProfileBasicPhotoShowTool(server: McpServer, ctx: ToolRegistrationContext): void;
|
|
14
|
+
//# sourceMappingURL=profile_basic_photo_show.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile_basic_photo_show.d.ts","sourceRoot":"","sources":["../../src/tools/profile_basic_photo_show.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAItB;;;;;;;;;GASG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CAoDvG"}
|
|
@@ -0,0 +1,59 @@
|
|
|
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_photo_show";
|
|
8
|
+
/**
|
|
9
|
+
* Register the `ttctl_profile_basic_photo_show` MCP tool. Read-only.
|
|
10
|
+
*
|
|
11
|
+
* Dry-run path (issue #165): when `dryRun: true`, returns a preview of
|
|
12
|
+
* the `GET_PHOTO` query (talent-profile surface) that WOULD have been
|
|
13
|
+
* sent. The `profileId` variable carries `DRY_RUN_PROFILE_ID_PLACEHOLDER`
|
|
14
|
+
* because the apply path resolves it via a sibling `show()` call at
|
|
15
|
+
* execution time — the dry-run path skips that read entirely so no
|
|
16
|
+
* transport is invoked.
|
|
17
|
+
*/
|
|
18
|
+
export function registerProfileBasicPhotoShowTool(server, ctx) {
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
20
|
+
title: "Show profile photo URLs",
|
|
21
|
+
description: [
|
|
22
|
+
"Fetch the URLs of the signed-in user's profile photo (default / original / small variants plus the recommended crop rectangle and a `isResolutionSatisfied` flag).",
|
|
23
|
+
"",
|
|
24
|
+
"Pass `dryRun: true` to preview the request without firing the query.",
|
|
25
|
+
"",
|
|
26
|
+
"Example user prompts that should map to this tool:",
|
|
27
|
+
' - "Show me my Toptal profile photo."',
|
|
28
|
+
' - "What are the URLs of my profile photo variants?"',
|
|
29
|
+
' - "Is my profile photo resolution OK?"',
|
|
30
|
+
].join("\n"),
|
|
31
|
+
inputSchema: {
|
|
32
|
+
dryRun: z
|
|
33
|
+
.boolean()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` with the GET_PHOTO operation; `variables.profileId` is a placeholder that the apply path would have resolved via a sibling profile read. Default: false."),
|
|
36
|
+
},
|
|
37
|
+
}, async (input) => {
|
|
38
|
+
const auth = await ctx.loadTokenForTool(TOOL_NAME);
|
|
39
|
+
if (isToolErrorResponse(auth))
|
|
40
|
+
return auth;
|
|
41
|
+
if (input.dryRun === true) {
|
|
42
|
+
return dryRunResponse(buildMcpDryRunPreview("GET_PHOTO", "talent-profile", { profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER }, auth.token));
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const payload = await profile.basic.photoShow(auth.token);
|
|
46
|
+
return jsonResponse(payload);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
const typed = ttctlErrorToToolResponseOrNull(err);
|
|
50
|
+
if (typed !== null)
|
|
51
|
+
return typed;
|
|
52
|
+
if (err instanceof profile.basic.ProfileError) {
|
|
53
|
+
return domainErrorResponse(TOOL_NAME, err);
|
|
54
|
+
}
|
|
55
|
+
return genericErrorResponse(TOOL_NAME, err);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=profile_basic_photo_show.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile_basic_photo_show.js","sourceRoot":"","sources":["../../src/tools/profile_basic_photo_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,gCAAgC,CAAC;AAEnD;;;;;;;;;GASG;AACH,MAAM,UAAU,iCAAiC,CAAC,MAAiB,EAAE,GAA4B;IAC/F,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE;YACX,oKAAoK;YACpK,EAAE;YACF,sEAAsE;YACtE,EAAE;YACF,oDAAoD;YACpD,wCAAwC;YACxC,uDAAuD;YACvD,0CAA0C;SAC3C,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE;YACX,MAAM,EAAE,CAAC;iBACN,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CACP,+OAA+O,CAChP;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,CACnB,qBAAqB,CACnB,WAAW,EACX,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,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1D,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;QAC/B,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,24 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type ToolRegistrationContext } from "./_shared.js";
|
|
3
|
+
/**
|
|
4
|
+
* Register the `ttctl_profile_basic_photo_upload` MCP tool. Mirrors the
|
|
5
|
+
* `ttctl profile basic photo upload <file>` CLI leaf — uploads a new
|
|
6
|
+
* profile photo from a local file path.
|
|
7
|
+
*
|
|
8
|
+
* The tool accepts only a `file` path (string). Buffer input from the CLI
|
|
9
|
+
* surface is not exposed here because MCP transports are JSON-only —
|
|
10
|
+
* passing binary through MCP would require base64 wrapping that's brittle
|
|
11
|
+
* and confusing for LLM clients. Use the CLI leaf if you need to upload
|
|
12
|
+
* a buffer programmatically.
|
|
13
|
+
*
|
|
14
|
+
* Dry-run path (issue #165): when `dryRun: true`, returns a preview of
|
|
15
|
+
* the `UploadProfilePhoto` mutation's GraphQL operations envelope (the
|
|
16
|
+
* top-level fields of the multipart form's `operations` part). The
|
|
17
|
+
* multipart binary payload itself is NOT described — only the GraphQL
|
|
18
|
+
* request shape that would be sent in the `operations` part of the
|
|
19
|
+
* multipart envelope. `variables.input.profileId` is the placeholder
|
|
20
|
+
* `DRY_RUN_PROFILE_ID_PLACEHOLDER` (apply path resolves it via a
|
|
21
|
+
* sibling profile read).
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerProfileBasicPhotoUploadTool(server: McpServer, ctx: ToolRegistrationContext): void;
|
|
24
|
+
//# sourceMappingURL=profile_basic_photo_upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile_basic_photo_upload.d.ts","sourceRoot":"","sources":["../../src/tools/profile_basic_photo_upload.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAMtB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mCAAmC,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CAyEzG"}
|
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
import { UPLOAD_CATEGORIES, validateUploadPath } from "./file-upload.js";
|
|
8
|
+
import { profileBasicPhotoUploadOutputSchema } from "./output-schemas.js";
|
|
9
|
+
const TOOL_NAME = "ttctl_profile_basic_photo_upload";
|
|
10
|
+
/**
|
|
11
|
+
* Register the `ttctl_profile_basic_photo_upload` MCP tool. Mirrors the
|
|
12
|
+
* `ttctl profile basic photo upload <file>` CLI leaf — uploads a new
|
|
13
|
+
* profile photo from a local file path.
|
|
14
|
+
*
|
|
15
|
+
* The tool accepts only a `file` path (string). Buffer input from the CLI
|
|
16
|
+
* surface is not exposed here because MCP transports are JSON-only —
|
|
17
|
+
* passing binary through MCP would require base64 wrapping that's brittle
|
|
18
|
+
* and confusing for LLM clients. Use the CLI leaf if you need to upload
|
|
19
|
+
* a buffer programmatically.
|
|
20
|
+
*
|
|
21
|
+
* Dry-run path (issue #165): when `dryRun: true`, returns a preview of
|
|
22
|
+
* the `UploadProfilePhoto` mutation's GraphQL operations envelope (the
|
|
23
|
+
* top-level fields of the multipart form's `operations` part). The
|
|
24
|
+
* multipart binary payload itself is NOT described — only the GraphQL
|
|
25
|
+
* request shape that would be sent in the `operations` part of the
|
|
26
|
+
* multipart envelope. `variables.input.profileId` is the placeholder
|
|
27
|
+
* `DRY_RUN_PROFILE_ID_PLACEHOLDER` (apply path resolves it via a
|
|
28
|
+
* sibling profile read).
|
|
29
|
+
*/
|
|
30
|
+
export function registerProfileBasicPhotoUploadTool(server, ctx) {
|
|
31
|
+
server.registerTool(TOOL_NAME, {
|
|
32
|
+
title: "Upload profile photo",
|
|
33
|
+
description: [
|
|
34
|
+
"Upload a new profile photo from a local image file (jpg / png / gif / webp). Image content-type is inferred from the file extension.",
|
|
35
|
+
"",
|
|
36
|
+
"Pass `dryRun: true` to preview the request without firing the mutation. The preview describes the GraphQL `operations` envelope only (not the multipart binary body).",
|
|
37
|
+
"",
|
|
38
|
+
"Example user prompts that should map to this tool:",
|
|
39
|
+
' - "Upload /Users/me/Pictures/headshot.jpg as my Toptal profile photo."',
|
|
40
|
+
' - "Set my profile photo to ./avatar.png."',
|
|
41
|
+
].join("\n"),
|
|
42
|
+
inputSchema: {
|
|
43
|
+
file: z
|
|
44
|
+
.string()
|
|
45
|
+
.min(1)
|
|
46
|
+
.describe("Absolute or relative path to the image file to upload. Must be readable by the MCP server process."),
|
|
47
|
+
dryRun: z
|
|
48
|
+
.boolean()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe("Preview the request without executing. Returns `{ ok: true, dryRun: true, preview }` for the UploadProfilePhoto operation; the multipart binary body is NOT enumerated (only the GraphQL operations envelope). Default: false."),
|
|
51
|
+
},
|
|
52
|
+
outputSchema: profileBasicPhotoUploadOutputSchema.shape,
|
|
53
|
+
}, async (input) => {
|
|
54
|
+
const auth = await ctx.loadTokenForTool(TOOL_NAME);
|
|
55
|
+
if (isToolErrorResponse(auth))
|
|
56
|
+
return auth;
|
|
57
|
+
if (input.dryRun === true) {
|
|
58
|
+
// The multipart envelope's `operations` part carries:
|
|
59
|
+
// { operationName, query, variables: { input: <UpdatePhotoInput, file=null> } }
|
|
60
|
+
// — the actual file lives in a separate multipart part referenced
|
|
61
|
+
// via the `map` field. The dry-run preview describes the operations
|
|
62
|
+
// envelope only (mirroring the wire shape that `photoUpload` builds
|
|
63
|
+
// in core/services/profile/basic/index.ts).
|
|
64
|
+
return dryRunResponse(buildMcpDryRunPreview("UploadProfilePhoto", "talent-profile", {
|
|
65
|
+
input: {
|
|
66
|
+
profileId: profile.basic.DRY_RUN_PROFILE_ID_PLACEHOLDER,
|
|
67
|
+
photo: null,
|
|
68
|
+
transformation: { cropped: { x: 0, y: 0, width: 0, height: 0 } },
|
|
69
|
+
},
|
|
70
|
+
}, auth.token));
|
|
71
|
+
}
|
|
72
|
+
const pathError = validateUploadPath(input.file, UPLOAD_CATEGORIES.basicPhoto);
|
|
73
|
+
if (pathError !== null)
|
|
74
|
+
return pathError;
|
|
75
|
+
try {
|
|
76
|
+
const result = await profile.basic.photoUpload(auth.token, { file: input.file });
|
|
77
|
+
return jsonResponse(result);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const typed = ttctlErrorToToolResponseOrNull(err);
|
|
81
|
+
if (typed !== null)
|
|
82
|
+
return typed;
|
|
83
|
+
if (err instanceof profile.basic.ProfileError) {
|
|
84
|
+
return domainErrorResponse(TOOL_NAME, err);
|
|
85
|
+
}
|
|
86
|
+
return genericErrorResponse(TOOL_NAME, err);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=profile_basic_photo_upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile_basic_photo_upload.js","sourceRoot":"","sources":["../../src/tools/profile_basic_photo_upload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { profile } from "@ttctl/core";
|
|
3
|
+
import type { ProfileShowQuery } from "@ttctl/core";
|
|
4
|
+
import { type ToolRegistrationContext } from "./_shared.js";
|
|
5
|
+
/**
|
|
6
|
+
* Merged payload returned by `ttctl_profile_basic_show`. Mirrors the
|
|
7
|
+
* CLI's `BasicShowPayload` shape (`packages/cli/src/commands/profile/
|
|
8
|
+
* basic/show.ts`) so the read surface speaks the same vocabulary across
|
|
9
|
+
* MCP and CLI clients.
|
|
10
|
+
*
|
|
11
|
+
* `profile` carries the mobile-gateway `ProfileShowQuery` (identity, role,
|
|
12
|
+
* vertical, skills, hours, rate); `basicInfo` carries the talent-profile
|
|
13
|
+
* `BasicInfo` projection (`bio`, `headline`, `languages`). The two come
|
|
14
|
+
* from different GraphQL surfaces — the mobile-gateway `Profile` type does
|
|
15
|
+
* NOT publish `about` / `quote`, hence the dedicated `getBasicInfo()`
|
|
16
|
+
* companion shipped in #127.
|
|
17
|
+
*
|
|
18
|
+
* `basicInfo` is `null` when the secondary `getBasicInfo()` call failed in
|
|
19
|
+
* a non-session-level way (network blip, talent-profile `GRAPHQL_ERROR`).
|
|
20
|
+
* Session-level failures (`AuthRevokedError`, `Cf403Error`) propagate as
|
|
21
|
+
* tool errors — they indicate the bearer is no longer accepted, and the
|
|
22
|
+
* primary `show()` call would have hit them too.
|
|
23
|
+
*/
|
|
24
|
+
export interface BasicShowPayload {
|
|
25
|
+
profile: ProfileShowQuery;
|
|
26
|
+
basicInfo: profile.basic.BasicInfo | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Register the `ttctl_profile_basic_show` MCP tool. Mirrors the
|
|
30
|
+
* `ttctl profile basic show` CLI leaf — fetches the signed-in user's
|
|
31
|
+
* profile from both the mobile-gateway and the talent-profile surfaces
|
|
32
|
+
* and returns the merged payload.
|
|
33
|
+
*
|
|
34
|
+
* Two-call read surface (parity with CLI's post-#129 path, closed in
|
|
35
|
+
* this PR for MCP per #340):
|
|
36
|
+
*
|
|
37
|
+
* 1. `profile.basic.show()` → `mobile-gateway` for identity, role,
|
|
38
|
+
* vertical, skills, hours, rate.
|
|
39
|
+
* 2. `profile.basic.getBasicInfo()` → `talent_profile/graphql` for
|
|
40
|
+
* `bio` (`Profile.about`), `headline` (`Profile.quote`), and
|
|
41
|
+
* `languages`.
|
|
42
|
+
*
|
|
43
|
+
* Errors from the secondary `getBasicInfo()` call are non-fatal: the
|
|
44
|
+
* tool swallows non-session failures and renders `basicInfo: null`, so a
|
|
45
|
+
* glitch on the secondary surface doesn't blank the whole show. Session-
|
|
46
|
+
* level errors (`AuthRevokedError`, `Cf403Error`) still propagate — they
|
|
47
|
+
* indicate the bearer is no longer valid; the primary `show()` would
|
|
48
|
+
* have hit them too.
|
|
49
|
+
*
|
|
50
|
+
* Auth token identifies the user. MCP is the LLM-facing surface, so the
|
|
51
|
+
* description includes example user-intent phrases the model can match
|
|
52
|
+
* against, and reflects the bio/headline/languages coverage added in
|
|
53
|
+
* this PR.
|
|
54
|
+
*
|
|
55
|
+
* Dry-run path (issue #165): when `dryRun: true`, the tool returns a
|
|
56
|
+
* structured preview of the primary `ProfileShow` query — no transport
|
|
57
|
+
* call. The preview shows only the mobile-gateway operation; the
|
|
58
|
+
* secondary `GET_BASIC_INFO` call on the talent-profile surface is also
|
|
59
|
+
* dispatched on the apply path but is not part of the preview envelope
|
|
60
|
+
* (single-op envelope is the cross-cutting dry-run contract; the
|
|
61
|
+
* secondary read is an implementation detail of the merged response).
|
|
62
|
+
*/
|
|
63
|
+
export declare function registerProfileBasicShowTool(server: McpServer, ctx: ToolRegistrationContext): void;
|
|
64
|
+
//# sourceMappingURL=profile_basic_show.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile_basic_show.d.ts","sourceRoot":"","sources":["../../src/tools/profile_basic_show.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAItB;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,uBAAuB,GAAG,IAAI,CAqElG"}
|