todogether-mcp 1.0.1 → 1.0.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 (2) hide show
  1. package/dist/index.js +89 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -260,6 +260,79 @@ async function getTodayTodos() {
260
260
  });
261
261
  return `오늘 할 일 ${todos.length}개:\n${lines.join("\n")}`;
262
262
  }
263
+ // ── 오늘 할 일 세부 조회 ─────────────────────────────────────────
264
+ async function getPledgeDetail(id) {
265
+ const res = await api(`/api/pledges/${id}`);
266
+ if (!res.ok)
267
+ return null;
268
+ const data = (await res.json().catch(() => null));
269
+ if (!data)
270
+ return null;
271
+ // API가 { pledge: ... } 또는 직접 Pledge 객체를 반환할 수 있음
272
+ return data.pledge ?? data;
273
+ }
274
+ async function getTodayTodosDetail() {
275
+ if (!isLoggedIn()) {
276
+ return "로그인이 필요합니다. 먼저 `todogether_login` 도구로 로그인해 주세요.";
277
+ }
278
+ const { start, end } = kstToday();
279
+ const [doingRes, expiredRes] = await Promise.all([
280
+ api("/api/pledges?type=doing&limit=50"),
281
+ api("/api/pledges?type=expired&limit=50"),
282
+ ]);
283
+ if (doingRes.status === 401 || doingRes.status === 403) {
284
+ return "세션이 만료되었습니다. 다시 로그인해 주세요.";
285
+ }
286
+ const doing = (await doingRes.json().catch(() => ({ pledges: [] }))).pledges ?? [];
287
+ const expired = expiredRes.ok
288
+ ? ((await expiredRes.json().catch(() => ({ pledges: [] }))).pledges ?? [])
289
+ : [];
290
+ const todayDoing = doing.filter((p) => {
291
+ if (p.isEveryday)
292
+ return true;
293
+ if (!p.startAt)
294
+ return true;
295
+ return new Date(p.startAt) <= end;
296
+ });
297
+ const overdue = expired.filter((p) => !p.isEveryday && p.isSuccess !== true);
298
+ const seen = new Set();
299
+ const todos = [...todayDoing, ...overdue].filter((p) => {
300
+ if (seen.has(p.id))
301
+ return false;
302
+ seen.add(p.id);
303
+ return true;
304
+ });
305
+ if (todos.length === 0)
306
+ return "오늘 할 일이 없습니다. 🎉";
307
+ // 각 할 일의 세부 정보를 병렬로 가져옴
308
+ const details = await Promise.all(todos.map((p) => getPledgeDetail(p.id)));
309
+ const lines = [];
310
+ for (let i = 0; i < todos.length; i++) {
311
+ const p = details[i] ?? todos[i];
312
+ const project = p.channelPledges?.[0]?.channel?.title;
313
+ const badges = [
314
+ p.isEveryday ? "매일" : null,
315
+ project ? `📁 ${project}` : p.category && p.category !== "미지정" ? p.category : null,
316
+ ]
317
+ .filter(Boolean)
318
+ .join(" · ");
319
+ const doneCount = p.subTodos?.filter((s) => s.isDone).length ?? 0;
320
+ const totalCount = p.subTodos?.length ?? 0;
321
+ const progress = totalCount > 0 ? ` (${doneCount}/${totalCount})` : "";
322
+ const deadline = p.endAt ? ` · 마감: ${p.endAt.slice(0, 10)}` : "";
323
+ lines.push(`\n${i + 1}. ${p.title}${badges ? ` [${badges}]` : ""}${progress}${deadline}`);
324
+ if (p.memo) {
325
+ lines.push(` 메모: ${p.memo}`);
326
+ }
327
+ if (p.subTodos && p.subTodos.length > 0) {
328
+ for (const sub of p.subTodos) {
329
+ const check = sub.isDone ? "✅" : "⬜";
330
+ lines.push(` ${check} ${sub.title}${sub.memo ? ` (${sub.memo})` : ""}`);
331
+ }
332
+ }
333
+ }
334
+ return `오늘 할 일 ${todos.length}개:${lines.join("\n")}`;
335
+ }
263
336
  // ── MCP 서버 ─────────────────────────────────────────────────────
264
337
  const server = new McpServer({ name: "todogether", version: "1.0.0" });
265
338
  server.registerTool("todogether_login", {
@@ -362,5 +435,21 @@ server.registerTool("todogether_today_todos", {
362
435
  };
363
436
  }
364
437
  });
438
+ server.registerTool("todogether_today_todos_detail", {
439
+ title: "오늘 할 일 세부 내용 가져오기",
440
+ description: "로그인된 투두게더 계정의 오늘 할 일 목록을 세부 내용(서브태스크 제목·완료 여부·메모, 마감일 등)까지 포함해 가져옵니다.",
441
+ inputSchema: {},
442
+ }, async () => {
443
+ try {
444
+ const text = await getTodayTodosDetail();
445
+ return { content: [{ type: "text", text }] };
446
+ }
447
+ catch (e) {
448
+ return {
449
+ content: [{ type: "text", text: `❌ 조회 실패: ${e.message}` }],
450
+ isError: true,
451
+ };
452
+ }
453
+ });
365
454
  const transport = new StdioServerTransport();
366
455
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "todogether-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "투두게더(todogether) MCP 서버 — 로그인 후 오늘 할 일 조회",
5
5
  "type": "module",
6
6
  "license": "MIT",