@codegame.dev/careerflow-mcp 1.1.0
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/LICENSE +21 -0
- package/README.md +398 -0
- package/dist/client.js +110 -0
- package/dist/client.js.map +1 -0
- package/dist/config.js +37 -0
- package/dist/config.js.map +1 -0
- package/dist/helpers.js +192 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.js +194 -0
- package/dist/index.js.map +1 -0
- package/dist/setup.js +296 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/admin.js +232 -0
- package/dist/tools/admin.js.map +1 -0
- package/dist/tools/benefit-funds.js +243 -0
- package/dist/tools/benefit-funds.js.map +1 -0
- package/dist/tools/chat-extra.js +172 -0
- package/dist/tools/chat-extra.js.map +1 -0
- package/dist/tools/chat.js +125 -0
- package/dist/tools/chat.js.map +1 -0
- package/dist/tools/cms.js +145 -0
- package/dist/tools/cms.js.map +1 -0
- package/dist/tools/crm-admin.js +269 -0
- package/dist/tools/crm-admin.js.map +1 -0
- package/dist/tools/crm.js +632 -0
- package/dist/tools/crm.js.map +1 -0
- package/dist/tools/dev-tickets.js +94 -0
- package/dist/tools/dev-tickets.js.map +1 -0
- package/dist/tools/forms.js +105 -0
- package/dist/tools/forms.js.map +1 -0
- package/dist/tools/hr.js +517 -0
- package/dist/tools/hr.js.map +1 -0
- package/dist/tools/kanban-extra.js +403 -0
- package/dist/tools/kanban-extra.js.map +1 -0
- package/dist/tools/misc.js +159 -0
- package/dist/tools/misc.js.map +1 -0
- package/dist/tools/projects.js +138 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/tasks.js +342 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/time.js +129 -0
- package/dist/tools/time.js.map +1 -0
- package/dist/tools/workplace.js +110 -0
- package/dist/tools/workplace.js.map +1 -0
- package/dist/tools/workspace.js +199 -0
- package/dist/tools/workspace.js.map +1 -0
- package/package.json +61 -0
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ApiError } from "./client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Shared shapes and formatting used across tool modules.
|
|
5
|
+
*/
|
|
6
|
+
export const companyIdSchema = z
|
|
7
|
+
.number()
|
|
8
|
+
.int()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe("Company id. Optional when the server is configured with CAREERFLOW_COMPANY_ID; " +
|
|
11
|
+
"required otherwise, or to act in a different company.");
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the company for a call. Kept in one place so every tool behaves the
|
|
14
|
+
* same way when the id is omitted, and so the error names the fix.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveCompanyId(client, provided) {
|
|
17
|
+
const companyId = provided ?? client.defaultCompanyId;
|
|
18
|
+
if (companyId === undefined) {
|
|
19
|
+
throw new Error("No company id given and CAREERFLOW_COMPANY_ID is not set. " +
|
|
20
|
+
"Pass company_id, or set CAREERFLOW_COMPANY_ID on the server.");
|
|
21
|
+
}
|
|
22
|
+
return companyId;
|
|
23
|
+
}
|
|
24
|
+
export function textResult(value) {
|
|
25
|
+
const text = typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
26
|
+
return { content: [{ type: "text", text }] };
|
|
27
|
+
}
|
|
28
|
+
export function errorResult(error) {
|
|
29
|
+
const message = error instanceof ApiError ? error.message : error instanceof Error ? error.message : String(error);
|
|
30
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Wraps a tool handler so a thrown error becomes a readable tool result rather
|
|
34
|
+
* than a transport-level failure the model cannot interpret or recover from.
|
|
35
|
+
*/
|
|
36
|
+
export function safeHandler(handler) {
|
|
37
|
+
return async (args) => {
|
|
38
|
+
try {
|
|
39
|
+
return await handler(args);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return errorResult(error);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Trims a task down to the fields an assistant actually reasons about. The raw
|
|
48
|
+
* rows carry ~40 columns of bookkeeping (activity flags, snapshot ids, ordering
|
|
49
|
+
* numbers) that would otherwise crowd out the useful content of a result.
|
|
50
|
+
*/
|
|
51
|
+
export function summariseTask(task) {
|
|
52
|
+
return {
|
|
53
|
+
id: task.id,
|
|
54
|
+
title: task.title,
|
|
55
|
+
description: task.description || undefined,
|
|
56
|
+
project_id: task.project_id,
|
|
57
|
+
project_title: task.project_title || task.project_name || undefined,
|
|
58
|
+
board_id: task.board_id,
|
|
59
|
+
board_name: task.board_name || undefined,
|
|
60
|
+
is_completed: Boolean(task.is_completed),
|
|
61
|
+
priority: task.priority,
|
|
62
|
+
start_date: task.start_date || undefined,
|
|
63
|
+
due_date: task.due_date || undefined,
|
|
64
|
+
completion_date: task.completion_date || undefined,
|
|
65
|
+
time_estimate_minutes: task.time_estimate_minutes ?? undefined,
|
|
66
|
+
time_minutes: task.time_minutes ?? undefined,
|
|
67
|
+
review_status: task.review_status || undefined,
|
|
68
|
+
review_score: task.review_score ?? undefined,
|
|
69
|
+
is_archived: Boolean(task.is_archived),
|
|
70
|
+
members: Array.isArray(task.members)
|
|
71
|
+
? task.members.map((m) => ({
|
|
72
|
+
user_id: m.user_id ?? m.id,
|
|
73
|
+
name: [m.firstname, m.lastname].filter(Boolean).join(" ") || m.staff_number_with_prefix
|
|
74
|
+
}))
|
|
75
|
+
: undefined,
|
|
76
|
+
labels: Array.isArray(task.labels)
|
|
77
|
+
? task.labels.map((l) => ({ id: l.id, title: l.title }))
|
|
78
|
+
: undefined
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function summariseUser(user) {
|
|
82
|
+
return {
|
|
83
|
+
id: user.id,
|
|
84
|
+
name: [user.firstname, user.lastname].filter(Boolean).join(" ") || undefined,
|
|
85
|
+
staff_number: user.staff_number_with_prefix || user.staff_number || undefined,
|
|
86
|
+
email: user.email || undefined,
|
|
87
|
+
mobile: user.mobile || undefined,
|
|
88
|
+
type: user.type,
|
|
89
|
+
company_id: user.company_id ?? undefined,
|
|
90
|
+
position: user.position || user.job_title || undefined
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Fetches a single task by id alone.
|
|
95
|
+
*
|
|
96
|
+
* `kanbans/tasks/get` needs project_id and board_id alongside the task id, which
|
|
97
|
+
* a caller working from a task number will not have. Task search accepts a bare
|
|
98
|
+
* id and returns the same row plus its project/board, so it is used as the
|
|
99
|
+
* lookup and the ids come back with the task.
|
|
100
|
+
*
|
|
101
|
+
* The read matters for more than convenience: `kanbans/tasks/edit` replaces the
|
|
102
|
+
* whole row, so any field omitted falls back to a default (is_completed -> false,
|
|
103
|
+
* priority -> "medium"). Every edit reads the task first and merges onto it — see
|
|
104
|
+
* `mergeTaskEdit` — so a partial change cannot silently clear untouched fields.
|
|
105
|
+
*/
|
|
106
|
+
export async function fetchTask(client, companyId, taskId) {
|
|
107
|
+
const response = await client.get("kanbans/tasks/search", {
|
|
108
|
+
company_id: companyId,
|
|
109
|
+
task_id: taskId,
|
|
110
|
+
limit: 1
|
|
111
|
+
});
|
|
112
|
+
const { items: tasks } = extractList(response.data, "tasks");
|
|
113
|
+
const task = tasks.find((t) => Number(t.id) === Number(taskId)) ?? tasks[0];
|
|
114
|
+
if (!task || task.id === undefined) {
|
|
115
|
+
throw new Error(`Task ${taskId} was not found, or is not visible to this token.`);
|
|
116
|
+
}
|
|
117
|
+
return task;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Builds the full body for `kanbans/tasks/edit` by layering the requested
|
|
121
|
+
* changes over the task's current values, so unmentioned fields survive.
|
|
122
|
+
*/
|
|
123
|
+
export function mergeTaskEdit(current, companyId, changes) {
|
|
124
|
+
const labelIds = Array.isArray(current.labels)
|
|
125
|
+
? current.labels.map((l) => l.id).join(",")
|
|
126
|
+
: undefined;
|
|
127
|
+
const base = {
|
|
128
|
+
company_id: companyId,
|
|
129
|
+
project_id: current.project_id,
|
|
130
|
+
board_id: current.board_id,
|
|
131
|
+
task_id: current.id,
|
|
132
|
+
title: current.title,
|
|
133
|
+
description: current.description ?? "",
|
|
134
|
+
is_completed: Boolean(current.is_completed),
|
|
135
|
+
start_date: current.start_date ?? null,
|
|
136
|
+
due_date: current.due_date ?? null,
|
|
137
|
+
priority: current.priority ?? "medium",
|
|
138
|
+
time_estimate_minutes: current.time_estimate_minutes ?? null,
|
|
139
|
+
label_ids: labelIds
|
|
140
|
+
};
|
|
141
|
+
for (const [key, value] of Object.entries(changes)) {
|
|
142
|
+
if (value !== undefined) {
|
|
143
|
+
base[key] = value;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return base;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The authenticated user's id, cached for the process lifetime.
|
|
150
|
+
*
|
|
151
|
+
* Several endpoints scope a read to one user and reject an unscoped
|
|
152
|
+
* company-wide query unless the caller holds an admin role, so tools pass this
|
|
153
|
+
* to mean "mine". The token maps to a fixed user, so the lookup is done once.
|
|
154
|
+
*/
|
|
155
|
+
let cachedUserId;
|
|
156
|
+
export async function currentUserId(client) {
|
|
157
|
+
if (cachedUserId !== undefined) {
|
|
158
|
+
return cachedUserId;
|
|
159
|
+
}
|
|
160
|
+
const response = await client.get("users/profile", {});
|
|
161
|
+
const id = response.data?.id;
|
|
162
|
+
if (id !== undefined) {
|
|
163
|
+
cachedUserId = Number(id);
|
|
164
|
+
}
|
|
165
|
+
return cachedUserId;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Pulls a list and its total out of a response payload.
|
|
169
|
+
*
|
|
170
|
+
* The API nests both inside `data` — the rows under an endpoint-specific key and
|
|
171
|
+
* the count under `total` — rather than putting a count on the envelope, so the
|
|
172
|
+
* key is named per call site and the total read from beside it.
|
|
173
|
+
*/
|
|
174
|
+
export function extractList(data, key) {
|
|
175
|
+
if (Array.isArray(data)) {
|
|
176
|
+
return { items: data };
|
|
177
|
+
}
|
|
178
|
+
if (data && typeof data === "object") {
|
|
179
|
+
const record = data;
|
|
180
|
+
const items = Array.isArray(record[key]) ? record[key] : [];
|
|
181
|
+
const total = typeof record.total === "number" ? record.total : undefined;
|
|
182
|
+
return { items, total };
|
|
183
|
+
}
|
|
184
|
+
return { items: [] };
|
|
185
|
+
}
|
|
186
|
+
/** The API takes booleans as 1/0 in form fields. */
|
|
187
|
+
export function boolParam(value) {
|
|
188
|
+
if (value === undefined)
|
|
189
|
+
return undefined;
|
|
190
|
+
return value ? 1 : 0;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { loadConfig } from "./config.js";
|
|
6
|
+
import { CareerFlowClient } from "./client.js";
|
|
7
|
+
import { registerTaskTools } from "./tools/tasks.js";
|
|
8
|
+
import { registerWorkspaceTools } from "./tools/workspace.js";
|
|
9
|
+
import { registerTimeTools } from "./tools/time.js";
|
|
10
|
+
import { registerChatTools } from "./tools/chat.js";
|
|
11
|
+
import { registerChatExtraTools } from "./tools/chat-extra.js";
|
|
12
|
+
import { registerWorkplaceTools } from "./tools/workplace.js";
|
|
13
|
+
import { registerKanbanExtraTools } from "./tools/kanban-extra.js";
|
|
14
|
+
import { registerProjectTools } from "./tools/projects.js";
|
|
15
|
+
import { registerAdminTools } from "./tools/admin.js";
|
|
16
|
+
import { registerCrmTools } from "./tools/crm.js";
|
|
17
|
+
import { registerCrmAdminTools } from "./tools/crm-admin.js";
|
|
18
|
+
import { registerHrTools } from "./tools/hr.js";
|
|
19
|
+
import { registerBenefitFundTools } from "./tools/benefit-funds.js";
|
|
20
|
+
import { registerFormTools } from "./tools/forms.js";
|
|
21
|
+
import { registerCmsTools } from "./tools/cms.js";
|
|
22
|
+
import { registerDevTicketTools } from "./tools/dev-tickets.js";
|
|
23
|
+
import { registerMiscTools } from "./tools/misc.js";
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
let version = "unknown";
|
|
26
|
+
try {
|
|
27
|
+
version = require("../package.json").version;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// package.json sits outside dist/; missing it only affects the reported version
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Tool groups, in registration order. Each entry may hold several modules that
|
|
34
|
+
* belong to one user-facing group — e.g. `crm` spans contacts/deals/activities
|
|
35
|
+
* and CRM configuration.
|
|
36
|
+
*
|
|
37
|
+
* CAREERFLOW_GROUPS (allowlist) and CAREERFLOW_EXCLUDE_GROUPS (denylist) take
|
|
38
|
+
* comma-separated names from here. Useful in clients that load every tool's
|
|
39
|
+
* schema into the model's context: a token scoped to one domain can register
|
|
40
|
+
* only that domain's tools.
|
|
41
|
+
*/
|
|
42
|
+
const toolGroups = [
|
|
43
|
+
{ name: "workspace", description: "whoami, companies, users", register: registerWorkspaceTools },
|
|
44
|
+
{ name: "tasks", description: "tasks and comments", register: registerTaskTools },
|
|
45
|
+
{ name: "kanban", description: "boards, labels, checklists, attachments", register: registerKanbanExtraTools },
|
|
46
|
+
{ name: "projects", description: "projects and membership", register: registerProjectTools },
|
|
47
|
+
{ name: "time", description: "timers and time entries", register: registerTimeTools },
|
|
48
|
+
{
|
|
49
|
+
name: "chat",
|
|
50
|
+
description: "chats, groups, messages",
|
|
51
|
+
register: (server, client) => {
|
|
52
|
+
registerChatTools(server, client);
|
|
53
|
+
registerChatExtraTools(server, client);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{ name: "workplace", description: "announcements, surveys, attendance", register: registerWorkplaceTools },
|
|
57
|
+
{ name: "admin", description: "company and user administration", register: registerAdminTools },
|
|
58
|
+
{
|
|
59
|
+
name: "crm",
|
|
60
|
+
description: "contacts, deals, activities, pipelines",
|
|
61
|
+
register: (server, client) => {
|
|
62
|
+
registerCrmTools(server, client);
|
|
63
|
+
registerCrmAdminTools(server, client);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{ name: "hr", description: "payroll, reviews, notes, careers, onboarding, cafeteria", register: registerHrTools },
|
|
67
|
+
{ name: "benefit-funds", description: "loans, lotteries, membership", register: registerBenefitFundTools },
|
|
68
|
+
{ name: "forms", description: "forms and submissions", register: registerFormTools },
|
|
69
|
+
{ name: "cms", description: "posts and custom pages", register: registerCmsTools },
|
|
70
|
+
{ name: "dev-tickets", description: "support tickets", register: registerDevTicketTools },
|
|
71
|
+
{ name: "misc", description: "addresses, surveys, announcements, billing", register: registerMiscTools }
|
|
72
|
+
];
|
|
73
|
+
const USAGE = `CareerFlow MCP server — connects an AI assistant to CareerFlow.
|
|
74
|
+
|
|
75
|
+
Usage:
|
|
76
|
+
npx @codegame.dev/careerflow-mcp Start the MCP server over stdio (what a client runs)
|
|
77
|
+
npx @codegame.dev/careerflow-mcp init Guided setup: asks for your token, then wires up your client
|
|
78
|
+
npx @codegame.dev/careerflow-mcp --help Show this help
|
|
79
|
+
npx @codegame.dev/careerflow-mcp --version Show the version
|
|
80
|
+
|
|
81
|
+
init options (all optional; safe to share — the token is always prompted for
|
|
82
|
+
separately, hidden, and never read from the command line):
|
|
83
|
+
--base-url <url> CareerFlow host, e.g. https://app.example.com
|
|
84
|
+
--name <name> Server name in the client config (default: careerflow)
|
|
85
|
+
--company-id <id> Default company, so tools need no company_id
|
|
86
|
+
--client <id> claude-code, claude-desktop, zcode, cursor, or other
|
|
87
|
+
|
|
88
|
+
Example one-liner for onboarding pages:
|
|
89
|
+
npx @codegame.dev/careerflow-mcp init --base-url https://app.example.com --name acme --client claude-code
|
|
90
|
+
|
|
91
|
+
Environment:
|
|
92
|
+
CAREERFLOW_TOKEN Required. Personal access token (Settings > Access Tokens)
|
|
93
|
+
CAREERFLOW_BASE_URL Required. Your CareerFlow API root
|
|
94
|
+
CAREERFLOW_COMPANY_ID Optional. Default company, so tools need no company_id
|
|
95
|
+
CAREERFLOW_TIMEOUT_MS Optional. Request timeout, default 30000
|
|
96
|
+
CAREERFLOW_GROUPS Optional. Comma-separated tool groups to register
|
|
97
|
+
(${toolGroups.map((g) => g.name).join(", ")})
|
|
98
|
+
CAREERFLOW_EXCLUDE_GROUPS Optional. Comma-separated groups to leave out
|
|
99
|
+
|
|
100
|
+
Docs: https://www.npmjs.com/package/@codegame.dev/careerflow-mcp`;
|
|
101
|
+
/** Parses CAREERFLOW_GROUPS / CAREERFLOW_EXCLUDE_GROUPS into a group allowlist, or dies naming the valid groups. */
|
|
102
|
+
function selectGroups(env) {
|
|
103
|
+
const parse = (raw) => (raw ?? "")
|
|
104
|
+
.split(",")
|
|
105
|
+
.map((name) => name.trim().toLowerCase())
|
|
106
|
+
.filter(Boolean);
|
|
107
|
+
const include = parse(env.CAREERFLOW_GROUPS);
|
|
108
|
+
const exclude = parse(env.CAREERFLOW_EXCLUDE_GROUPS);
|
|
109
|
+
const valid = new Set(toolGroups.map((g) => g.name));
|
|
110
|
+
const unknown = [...include, ...exclude].filter((name) => !valid.has(name));
|
|
111
|
+
if (unknown.length) {
|
|
112
|
+
throw new Error(`Unknown tool group(s): ${unknown.join(", ")}. Valid groups: ${[...valid].join(", ")}.`);
|
|
113
|
+
}
|
|
114
|
+
let selected = toolGroups;
|
|
115
|
+
if (include.length) {
|
|
116
|
+
const allow = new Set(include);
|
|
117
|
+
selected = selected.filter((g) => allow.has(g.name));
|
|
118
|
+
if (!selected.length) {
|
|
119
|
+
throw new Error("CAREERFLOW_GROUPS left no tool groups to register.");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (exclude.length) {
|
|
123
|
+
const deny = new Set(exclude);
|
|
124
|
+
selected = selected.filter((g) => !deny.has(g.name));
|
|
125
|
+
if (!selected.length) {
|
|
126
|
+
throw new Error("CAREERFLOW_EXCLUDE_GROUPS left no tool groups to register.");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return selected;
|
|
130
|
+
}
|
|
131
|
+
async function serve() {
|
|
132
|
+
const config = loadConfig();
|
|
133
|
+
const client = new CareerFlowClient(config);
|
|
134
|
+
const groups = selectGroups(process.env);
|
|
135
|
+
const server = new McpServer({
|
|
136
|
+
name: "careerflow",
|
|
137
|
+
version
|
|
138
|
+
}, {
|
|
139
|
+
instructions: "Tools for CareerFlow, a workplace platform: tasks and kanban boards, projects, time " +
|
|
140
|
+
"tracking, chat, CRM (contacts/deals/activities), HR (payroll, disciplinary and " +
|
|
141
|
+
"administrative notes, careers, onboarding), the benefit fund (loans and lotteries), " +
|
|
142
|
+
"forms, CMS, and company/user administration.\n\n" +
|
|
143
|
+
"Guidance:\n" +
|
|
144
|
+
"- Call whoami first when a request depends on who 'I' or 'me' is, or before any tool " +
|
|
145
|
+
"that takes company_id — whoami's response already includes every company the user " +
|
|
146
|
+
"belongs to (and resolves company_id outright if there's only one), so don't call a " +
|
|
147
|
+
"company-scoped tool without a company_id and wait for it to fail first.\n" +
|
|
148
|
+
"- Task writes need project and board ids: resolve them with list_projects and list_boards.\n" +
|
|
149
|
+
"- CRM writes need pipeline and stage ids: resolve them with crm_list_pipelines and crm_list_stages.\n" +
|
|
150
|
+
"- Resolve people to user ids with find_user or list_project_members before assigning work.\n" +
|
|
151
|
+
"- Some tools have a real, hard-to-undo effect and say so in their own description — " +
|
|
152
|
+
"send_message, create_administrative_note, and message_form_submission deliver to real " +
|
|
153
|
+
"people; create_user, set_user_status, and set_user_role change real accounts; " +
|
|
154
|
+
"request_benefit_fund_loan, update_benefit_fund_loan_status, " +
|
|
155
|
+
"pay_benefit_fund_loan_installment, and respond_to_lottery_win touch real money. Confirm " +
|
|
156
|
+
"details with the user before calling any of these.\n" +
|
|
157
|
+
"- A 403 means the token lacks a scope; tell the user which scope to add in " +
|
|
158
|
+
"Settings > Access Tokens rather than retrying."
|
|
159
|
+
});
|
|
160
|
+
for (const group of groups) {
|
|
161
|
+
group.register(server, client);
|
|
162
|
+
}
|
|
163
|
+
const transport = new StdioServerTransport();
|
|
164
|
+
await server.connect(transport);
|
|
165
|
+
// stdout carries the MCP protocol stream, so anything human-facing must go to
|
|
166
|
+
// stderr or it corrupts the transport
|
|
167
|
+
console.error(`careerflow-mcp connected (api: ${config.baseUrl}, groups: ${groups.map((g) => g.name).join(", ")})`);
|
|
168
|
+
}
|
|
169
|
+
const [, , command] = process.argv;
|
|
170
|
+
if (command === "--help" || command === "-h") {
|
|
171
|
+
console.log(USAGE);
|
|
172
|
+
}
|
|
173
|
+
else if (command === "--version" || command === "-v") {
|
|
174
|
+
console.log(version);
|
|
175
|
+
}
|
|
176
|
+
else if (command === "init") {
|
|
177
|
+
import("./setup.js")
|
|
178
|
+
.then(({ runSetup }) => runSetup(process.argv.slice(3)))
|
|
179
|
+
.catch((error) => {
|
|
180
|
+
console.error(`careerflow-mcp init failed: ${error.message}`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else if (command === undefined) {
|
|
185
|
+
serve().catch((error) => {
|
|
186
|
+
console.error(`careerflow-mcp failed to start: ${error.message}`);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.error(`Unknown command: ${command}\n\n${USAGE}`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|