senq-mcp 1.4.0 → 1.4.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/dist/index.js CHANGED
@@ -9,7 +9,7 @@ if (process.argv[2] === "setup") {
9
9
  await runSetup();
10
10
  process.exit(0);
11
11
  }
12
- const server = new Server({ name: "senq-mcp", version: "1.4.0" }, { capabilities: { tools: {}, prompts: {} } });
12
+ const server = new Server({ name: "senq-mcp", version: "1.4.2" }, { capabilities: { tools: {}, prompts: {} } });
13
13
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
14
14
  tools: [
15
15
  {
@@ -205,7 +205,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
205
205
  });
206
206
  if (!found.length)
207
207
  return { content: [{ type: "text", text: `Сотрудник «${args?.name}» не найден` }] };
208
- const result = found.map((e) => ({ id: e.id, displayName: e.displayName, email: e.email }));
208
+ const result = found.map((e) => ({ id: e.id, displayName: e.displayName, email: e.email, profileUrl: `${BASE_URL}/#/team/${e.id}` }));
209
209
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
210
210
  }
211
211
  if (name === "propose_task_change") {
@@ -327,12 +327,17 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
327
327
  if (args?.offset)
328
328
  params.offset = String(args.offset);
329
329
  const data = await apiGet("/api/tasks/team", params);
330
- const tasks = withUrls(data.tasks ?? []);
330
+ const tasks = withUrls(data.tasks ?? []).map((t) => {
331
+ if (typeof t.assigneeId === "string") {
332
+ return { ...t, assigneeUrl: `${BASE_URL}/#/team/${t.assigneeId}` };
333
+ }
334
+ return t;
335
+ });
331
336
  const total = data.total ?? tasks.length;
332
337
  return {
333
338
  content: [{
334
339
  type: "text",
335
- text: `Найдено задач: ${total}\n\n${JSON.stringify(tasks, null, 2)}`,
340
+ text: `Найдено задач: ${total}\n\nПри отображении форматируй названия задач как markdown-ссылки [название](url), имена исполнителей — как [имя](assigneeUrl).\n\n${JSON.stringify(tasks, null, 2)}`,
336
341
  }],
337
342
  };
338
343
  }
@@ -363,7 +368,18 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
363
368
  const completedLate = filtered.filter((t) => t.status === "completed" && t.dueDate && t.completedAt && t.completedAt.slice(0, 10) > t.dueDate);
364
369
  const overdue = filtered.filter((t) => t.status === "open" && t.dueDate && t.dueDate < today);
365
370
  const inProgress = filtered.filter((t) => t.status === "open" && t.dueDate && t.dueDate >= today);
366
- const fmt = (list) => list.map((t) => ` • ${t.title} (срок: ${t.dueDate ?? "—"}${t.completedAt ? `, выполнена: ${t.completedAt.slice(0, 10)}` : ""}${t.projectName ? `, проект: ${t.projectName}` : ""})`).join("\n");
371
+ const fmt = (list) => list.map((t) => {
372
+ const taskUrl = `${BASE_URL}/#/tasks/${t.id}`;
373
+ const assigneePart = t.assigneeName
374
+ ? `, [${t.assigneeName}](${BASE_URL}/#/team/${assigneeId})`
375
+ : "";
376
+ const parts = [`срок: ${t.dueDate ?? "—"}`];
377
+ if (t.completedAt)
378
+ parts.push(`выполнена: ${t.completedAt.slice(0, 10)}`);
379
+ if (t.projectName)
380
+ parts.push(`проект: ${t.projectName}`);
381
+ return ` • [${t.title}](${taskUrl}) (${parts.join(", ")}${assigneePart})`;
382
+ }).join("\n");
367
383
  const period = dateFrom || dateTo ? ` (период: ${dateFrom ?? "..."} — ${dateTo ?? "..."})` : "";
368
384
  const lines = [
369
385
  `Отчёт по сотруднику${period}`,
package/dist/setup.js CHANGED
@@ -78,7 +78,7 @@ function mergeConfig(configPath, apiKey) {
78
78
  catch { /* corrupt — start fresh */ }
79
79
  }
80
80
  const mcpServers = config["mcpServers"] ?? {};
81
- mcpServers["senq"] = { command: "npx", args: ["senq-mcp"], env: { SENQ_API_KEY: apiKey } };
81
+ mcpServers["senq"] = { command: "npx", args: ["senq-mcp@latest"], env: { SENQ_API_KEY: apiKey } };
82
82
  config["mcpServers"] = mcpServers;
83
83
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
84
84
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
@@ -89,7 +89,7 @@ function mergeCodexConfig(configPath, apiKey) {
89
89
  if (fs.existsSync(configPath)) {
90
90
  existing = fs.readFileSync(configPath, "utf8");
91
91
  }
92
- const senqBlock = `[mcp_servers.senq]\ncommand = "npx"\nargs = ["senq-mcp"]\n\n[mcp_servers.senq.env]\nSENQ_API_KEY = "${apiKey}"`;
92
+ const senqBlock = `[mcp_servers.senq]\ncommand = "npx"\nargs = ["senq-mcp@latest"]\n\n[mcp_servers.senq.env]\nSENQ_API_KEY = "${apiKey}"`;
93
93
  if (existing.includes("[mcp_servers.senq]")) {
94
94
  // Replace existing senq block
95
95
  const updated = existing.replace(/\[mcp_servers\.senq\][\s\S]*?SENQ_API_KEY\s*=\s*"[^"]*"/, senqBlock);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "senq-mcp",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "MCP server for Senq — connect your AI to tasks and knowledge",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -17,7 +17,7 @@ if (process.argv[2] === "setup") {
17
17
  }
18
18
 
19
19
  const server = new Server(
20
- { name: "senq-mcp", version: "1.4.0" },
20
+ { name: "senq-mcp", version: "1.4.2" },
21
21
  { capabilities: { tools: {}, prompts: {} } },
22
22
  );
23
23
 
@@ -218,7 +218,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
218
218
  return name.includes(query) || email.includes(query);
219
219
  });
220
220
  if (!found.length) return { content: [{ type: "text", text: `Сотрудник «${args?.name}» не найден` }] };
221
- const result = found.map((e) => ({ id: e.id, displayName: e.displayName, email: e.email }));
221
+ const result = found.map((e) => ({ id: e.id, displayName: e.displayName, email: e.email, profileUrl: `${BASE_URL}/#/team/${e.id}` }));
222
222
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
223
223
  }
224
224
 
@@ -309,12 +309,17 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
309
309
  if (args?.limit) params.limit = String(args.limit);
310
310
  if (args?.offset) params.offset = String(args.offset);
311
311
  const data = await apiGet<{ tasks?: unknown[]; total?: number }>("/api/tasks/team", params);
312
- const tasks = withUrls(data.tasks ?? []);
312
+ const tasks = withUrls(data.tasks ?? []).map((t) => {
313
+ if (typeof t.assigneeId === "string") {
314
+ return { ...t, assigneeUrl: `${BASE_URL}/#/team/${t.assigneeId}` };
315
+ }
316
+ return t;
317
+ });
313
318
  const total = data.total ?? tasks.length;
314
319
  return {
315
320
  content: [{
316
321
  type: "text",
317
- text: `Найдено задач: ${total}\n\n${JSON.stringify(tasks, null, 2)}`,
322
+ text: `Найдено задач: ${total}\n\nПри отображении форматируй названия задач как markdown-ссылки [название](url), имена исполнителей — как [имя](assigneeUrl).\n\n${JSON.stringify(tasks, null, 2)}`,
318
323
  }],
319
324
  };
320
325
  }
@@ -352,7 +357,16 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
352
357
  const inProgress = filtered.filter((t) => t.status === "open" && t.dueDate && t.dueDate >= today);
353
358
 
354
359
  const fmt = (list: typeof filtered) =>
355
- list.map((t) => ` • ${t.title} (срок: ${t.dueDate ?? "—"}${t.completedAt ? `, выполнена: ${t.completedAt.slice(0, 10)}` : ""}${t.projectName ? `, проект: ${t.projectName}` : ""})`).join("\n");
360
+ list.map((t) => {
361
+ const taskUrl = `${BASE_URL}/#/tasks/${t.id}`;
362
+ const assigneePart = t.assigneeName
363
+ ? `, [${t.assigneeName}](${BASE_URL}/#/team/${assigneeId})`
364
+ : "";
365
+ const parts = [`срок: ${t.dueDate ?? "—"}`];
366
+ if (t.completedAt) parts.push(`выполнена: ${t.completedAt.slice(0, 10)}`);
367
+ if (t.projectName) parts.push(`проект: ${t.projectName}`);
368
+ return ` • [${t.title}](${taskUrl}) (${parts.join(", ")}${assigneePart})`;
369
+ }).join("\n");
356
370
 
357
371
  const period = dateFrom || dateTo ? ` (период: ${dateFrom ?? "..."} — ${dateTo ?? "..."})` : "";
358
372
  const lines = [
package/src/setup.ts CHANGED
@@ -82,7 +82,7 @@ function mergeConfig(configPath: string, apiKey: string): void {
82
82
  try { config = JSON.parse(fs.readFileSync(configPath, "utf8")); } catch { /* corrupt — start fresh */ }
83
83
  }
84
84
  const mcpServers = (config["mcpServers"] as Record<string, unknown>) ?? {};
85
- mcpServers["senq"] = { command: "npx", args: ["senq-mcp"], env: { SENQ_API_KEY: apiKey } };
85
+ mcpServers["senq"] = { command: "npx", args: ["senq-mcp@latest"], env: { SENQ_API_KEY: apiKey } };
86
86
  config["mcpServers"] = mcpServers;
87
87
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
88
88
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
@@ -95,7 +95,7 @@ function mergeCodexConfig(configPath: string, apiKey: string): void {
95
95
  existing = fs.readFileSync(configPath, "utf8");
96
96
  }
97
97
 
98
- const senqBlock = `[mcp_servers.senq]\ncommand = "npx"\nargs = ["senq-mcp"]\n\n[mcp_servers.senq.env]\nSENQ_API_KEY = "${apiKey}"`;
98
+ const senqBlock = `[mcp_servers.senq]\ncommand = "npx"\nargs = ["senq-mcp@latest"]\n\n[mcp_servers.senq.env]\nSENQ_API_KEY = "${apiKey}"`;
99
99
 
100
100
  if (existing.includes("[mcp_servers.senq]")) {
101
101
  // Replace existing senq block