@doist/todoist-mcp 13.5.0 → 13.6.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.
@@ -5,6 +5,15 @@ type CreateHttpAppOptions = {
5
5
  /** Hostnames trusted in the Host/Origin headers (DNS-rebinding protection). */
6
6
  allowedHosts: string[];
7
7
  };
8
+ type HttpApp = {
9
+ app: Express;
10
+ /**
11
+ * Ends the open `subscriptions/listen` streams and aborts in-flight MCP
12
+ * exchanges. Call it before closing the HTTP server, otherwise
13
+ * `server.close()` waits for those streams to end on their own.
14
+ */
15
+ close: () => Promise<void>;
16
+ };
8
17
  /**
9
18
  * Build the Express app for the MCP HTTP server.
10
19
  *
@@ -14,6 +23,6 @@ type CreateHttpAppOptions = {
14
23
  * target's private IP in the Host header — keep working; it exposes no account
15
24
  * data.
16
25
  */
17
- declare function createHttpApp({ todoistApiKey, baseUrl, allowedHosts }: CreateHttpAppOptions): Express;
18
- export { createHttpApp, type CreateHttpAppOptions };
26
+ declare function createHttpApp({ todoistApiKey, baseUrl, allowedHosts }: CreateHttpAppOptions): HttpApp;
27
+ export { createHttpApp, type CreateHttpAppOptions, type HttpApp };
19
28
  //# sourceMappingURL=http-app.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-app.d.ts","sourceRoot":"","sources":["../src/http-app.ts"],"names":[],"mappings":"AACA,OAAgB,EAAE,KAAK,OAAO,EAA+B,MAAM,SAAS,CAAA;AAK5E,KAAK,oBAAoB,GAAG;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,EAAE,CAAA;CACzB,CAAA;AAED;;;;;;;;GAQG;AACH,iBAAS,aAAa,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAgD9F;AAED,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,CAAA"}
1
+ {"version":3,"file":"http-app.d.ts","sourceRoot":"","sources":["../src/http-app.ts"],"names":[],"mappings":"AAEA,OAAgB,EAAE,KAAK,OAAO,EAA+B,MAAM,SAAS,CAAA;AAK5E,KAAK,oBAAoB,GAAG;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,EAAE,CAAA;CACzB,CAAA;AAED,KAAK,OAAO,GAAG;IACX,GAAG,EAAE,OAAO,CAAA;IACZ;;;;OAIG;IACH,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B,CAAA;AAED;;;;;;;;GAQG;AACH,iBAAS,aAAa,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAoD9F;AAED,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,OAAO,EAAE,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { t as s } from "./mcp-server-Bi7iBPtS.js";
2
- import { F as r, a as d, b as i, c as n, d as c, e as l, f as m, h as p, i as f, j as T, k as j, l as g, m as k, n as u, o as v, p as P, q as h, r as b, s as S, u as y, v as A, w as C, x as R, y as x, z as F, g as M, A as O, B as E, C as L, D as w, E as H, G as I, H as W, I as q, J as z, K as B, L as D, M as N, N as U, O as V, P as G, Q as J, R as K, S as Q, T as X, U as Y, V as _, W as Z, X as $, Y as ss } from "./mcp-server-Bi7iBPtS.js";
3
- import { r as es, v as ts } from "./require-valid-todoist-token-D4bkOh_N.js";
1
+ import { t as s } from "./mcp-server-DHMEVYZ1.js";
2
+ import { F as r, a as d, b as i, c as n, d as c, e as l, f as m, h as p, i as f, j as T, k as j, l as g, m as k, n as u, o as v, p as P, q as h, r as b, s as S, u as y, v as A, w as C, x as R, y as x, z as F, g as M, A as O, B as E, C as L, D as w, E as H, G as I, H as W, I as q, J as z, K as B, L as D, M as N, N as U, O as V, P as G, Q as J, R as K, S as Q, T as X, U as Y, V as _, W as Z, X as $, Y as ss } from "./mcp-server-DHMEVYZ1.js";
3
+ import { r as es, v as ts } from "./require-valid-todoist-token-ErppL5lQ.js";
4
4
  const e = s;
5
5
  export {
6
6
  r as FEATURE_NAMES,
package/dist/main-http.js CHANGED
@@ -1,130 +1,133 @@
1
1
  #!/usr/bin/env node
2
- import { isIP as p } from "node:net";
3
- import O from "dotenv";
4
- import { NodeStreamableHTTPServerTransport as S } from "@modelcontextprotocol/node";
5
- import m from "express";
6
- import { g as v } from "./mcp-server-Bi7iBPtS.js";
7
- import { r as w } from "./require-valid-todoist-token-D4bkOh_N.js";
8
- function f(t) {
9
- return t.startsWith("[") && t.endsWith("]") ? t.slice(1, -1) : t;
2
+ import { isIP as f } from "node:net";
3
+ import S from "dotenv";
4
+ import { toNodeHandler as w } from "@modelcontextprotocol/node";
5
+ import { createMcpHandler as v } from "@modelcontextprotocol/server";
6
+ import h from "express";
7
+ import { g as I } from "./mcp-server-DHMEVYZ1.js";
8
+ import { r as g } from "./require-valid-todoist-token-ErppL5lQ.js";
9
+ function p(e) {
10
+ return e.startsWith("[") && e.endsWith("]") ? e.slice(1, -1) : e;
10
11
  }
11
- function I(t) {
12
- return t = f(t), t === "localhost" || t === "::1" || t === "0:0:0:0:0:0:0:1" ? !0 : p(t) === 4 ? t.split(".")[0] === "127" : !1;
12
+ function _(e) {
13
+ return e = p(e), e === "localhost" || e === "::1" || e === "0:0:0:0:0:0:0:1" ? !0 : f(e) === 4 ? e.split(".")[0] === "127" : !1;
13
14
  }
14
- const _ = ["localhost", "127.0.0.1", "[::1]"], g = /[@/\\?#\s]/;
15
- function h(t) {
16
- if (!g.test(t))
15
+ const L = ["localhost", "127.0.0.1", "[::1]"], A = /[@/\\?#\s]/;
16
+ function m(e) {
17
+ if (!A.test(e))
17
18
  try {
18
- return new URL(`http://${t}`).hostname.toLowerCase();
19
+ return new URL(`http://${e}`).hostname.toLowerCase();
19
20
  } catch {
20
21
  return;
21
22
  }
22
23
  }
23
- function L(t) {
24
- let r;
24
+ function E(e) {
25
+ let o;
25
26
  try {
26
- r = new URL(t);
27
+ o = new URL(e);
27
28
  } catch {
28
29
  return;
29
30
  }
30
- if (!(r.username || r.password || r.pathname !== "/" || r.search || r.hash))
31
- return r.hostname.toLowerCase();
31
+ if (!(o.username || o.password || o.pathname !== "/" || o.search || o.hash))
32
+ return o.hostname.toLowerCase();
32
33
  }
33
- function A(t, r) {
34
- const o = new Set(_);
35
- for (const s of (r ?? "").split(",")) {
36
- const n = s.trim();
37
- n && o.add(n);
34
+ function P(e, o) {
35
+ const n = new Set(L);
36
+ for (const c of (o ?? "").split(",")) {
37
+ const i = c.trim();
38
+ i && n.add(i);
38
39
  }
39
- const e = f(t);
40
- return e && e !== "0.0.0.0" && e !== "::" && o.add(p(e) === 6 ? `[${e}]` : e), [...o];
40
+ const r = p(e);
41
+ return r && r !== "0.0.0.0" && r !== "::" && n.add(f(r) === 6 ? `[${r}]` : r), [...n];
41
42
  }
42
- function d(t, r) {
43
- t.status(403).json({
43
+ function d(e, o) {
44
+ e.status(403).json({
44
45
  jsonrpc: "2.0",
45
- error: { code: -32e3, message: r },
46
+ error: { code: -32e3, message: o },
46
47
  id: null
47
48
  });
48
49
  }
49
- function b(t) {
50
- const r = /* @__PURE__ */ new Set();
51
- for (const o of t.allowedHosts) {
52
- const e = h(o);
53
- if (!e)
50
+ function $(e) {
51
+ const o = /* @__PURE__ */ new Set();
52
+ for (const n of e.allowedHosts) {
53
+ const r = m(n);
54
+ if (!r)
54
55
  throw new Error(
55
- `Invalid allowed host ${JSON.stringify(o)}: must be a hostname or host:port (IPv6 literals must be bracketed, e.g. [::1])`
56
+ `Invalid allowed host ${JSON.stringify(n)}: must be a hostname or host:port (IPv6 literals must be bracketed, e.g. [::1])`
56
57
  );
57
- r.add(e);
58
+ o.add(r);
58
59
  }
59
- return (o, e, s) => {
60
- const n = o.headers.host;
61
- if (!n) {
62
- d(e, "Missing Host header");
60
+ return (n, r, c) => {
61
+ const i = n.headers.host;
62
+ if (!i) {
63
+ d(r, "Missing Host header");
63
64
  return;
64
65
  }
65
- const i = h(n);
66
- if (!i || !r.has(i)) {
67
- d(e, `Invalid Host: ${n}`);
66
+ const a = m(i);
67
+ if (!a || !o.has(a)) {
68
+ d(r, `Invalid Host: ${i}`);
68
69
  return;
69
70
  }
70
- const a = o.headers.origin;
71
- if (a) {
72
- const l = L(a);
73
- if (!l || !r.has(l)) {
74
- d(e, `Invalid Origin: ${a}`);
71
+ const t = n.headers.origin;
72
+ if (t) {
73
+ const s = E(t);
74
+ if (!s || !o.has(s)) {
75
+ d(r, `Invalid Origin: ${t}`);
75
76
  return;
76
77
  }
77
78
  }
78
- s();
79
+ c();
79
80
  };
80
81
  }
81
- function E({ todoistApiKey: t, baseUrl: r, allowedHosts: o }) {
82
- const e = m(), s = b({ allowedHosts: o });
83
- return e.get("/health", (n, i) => {
84
- i.json({ status: "ok" });
85
- }), e.post(
86
- "/mcp",
87
- s,
88
- m.json(),
89
- w({ type: "static", apiKey: t, baseUrl: r }),
90
- async (n, i) => {
91
- try {
92
- const a = new S({
93
- sessionIdGenerator: void 0
94
- });
95
- await v({ todoistApiKey: t, baseUrl: r }).connect(a), await a.handleRequest(n, i, n.body);
96
- } catch (a) {
97
- console.error("[Error] Request handling failed:", a), i.status(500).json({
98
- jsonrpc: "2.0",
99
- error: {
100
- code: -32603,
101
- message: "Internal server error"
102
- },
103
- id: null
104
- });
105
- }
82
+ function b({ todoistApiKey: e, baseUrl: o, allowedHosts: n }) {
83
+ const r = h(), c = $({ allowedHosts: n });
84
+ r.get("/health", (t, s) => {
85
+ s.json({ status: "ok" });
86
+ });
87
+ const i = v(() => I({ todoistApiKey: e, baseUrl: o }), {
88
+ onerror: (t) => {
89
+ console.error("[Error] MCP request rejected:", t);
90
+ }
91
+ }), a = w(i, {
92
+ onerror: (t) => {
93
+ console.error("[Error] Request handling failed:", t);
106
94
  }
107
- ), e.get("/mcp", s, (n, i) => {
108
- i.status(405).set("Allow", "POST").send("Method Not Allowed");
109
- }), e;
95
+ });
96
+ return r.post(
97
+ "/mcp",
98
+ c,
99
+ h.json(),
100
+ g({ type: "static", apiKey: e, baseUrl: o }),
101
+ (t, s) => a(t, s, t.body)
102
+ ), r.get("/mcp", c, (t, s) => {
103
+ s.status(405).set("Allow", "POST").send("Method Not Allowed");
104
+ }), { app: r, close: i.close };
110
105
  }
111
- O.config({ quiet: !0 });
112
- const c = Number.parseInt(process.env.PORT || "3000", 10), T = process.env.HOST || "127.0.0.1", u = f(T);
113
- function P(t) {
114
- return t === "0.0.0.0" || t === "::" ? "localhost" : H(t);
106
+ S.config({ quiet: !0 });
107
+ const l = Number.parseInt(process.env.PORT || "3000", 10), H = process.env.HOST || "127.0.0.1", u = p(H);
108
+ function R(e) {
109
+ return e === "0.0.0.0" || e === "::" ? "localhost" : T(e);
115
110
  }
116
- function H(t) {
117
- return p(t) === 6 ? `[${t}]` : t;
111
+ function T(e) {
112
+ return f(e) === 6 ? `[${e}]` : e;
118
113
  }
119
- function $() {
120
- const t = process.env.TODOIST_BASE_URL, r = process.env.TODOIST_API_KEY;
121
- r || (console.error("Error: TODOIST_API_KEY environment variable is required"), process.exit(1));
122
- const o = A(T, process.env.ALLOWED_HOSTS);
123
- E({ todoistApiKey: r, baseUrl: t, allowedHosts: o }).listen(c, u, () => {
124
- const s = P(u);
125
- console.error(`Todoist MCP HTTP Server started on ${H(u)}:${c}`), console.error(`MCP endpoint: http://${s}:${c}/mcp`), console.error(`Health check: http://${s}:${c}/health`), I(u) || console.error(
114
+ function y() {
115
+ const e = process.env.TODOIST_BASE_URL, o = process.env.TODOIST_API_KEY;
116
+ o || (console.error("Error: TODOIST_API_KEY environment variable is required"), process.exit(1));
117
+ const n = P(H, process.env.ALLOWED_HOSTS), { app: r, close: c } = b({ todoistApiKey: o, baseUrl: e, allowedHosts: n }), i = r.listen(l, u, () => {
118
+ const s = R(u);
119
+ console.error(`Todoist MCP HTTP Server started on ${T(u)}:${l}`), console.error(`MCP endpoint: http://${s}:${l}/mcp`), console.error(`Health check: http://${s}:${l}/health`), _(u) || console.error(
126
120
  "Warning: todoist-mcp-http is reachable from other hosts. Set ALLOWED_HOSTS to the hostnames clients use and protect this service with trusted network/auth controls because requests run with TODOIST_API_KEY."
127
121
  );
128
122
  });
123
+ let a = !1;
124
+ const t = (s) => {
125
+ a || (a = !0, console.error(`Received ${s}, shutting down`), c().catch((O) => {
126
+ console.error("Error closing MCP handler:", O);
127
+ }).finally(() => {
128
+ i.close(() => process.exit(0)), i.closeIdleConnections();
129
+ }));
130
+ };
131
+ process.once("SIGTERM", t), process.once("SIGINT", t);
129
132
  }
130
- $();
133
+ y();
package/dist/main.js CHANGED
@@ -1,17 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { StdioServerTransport as s } from "@modelcontextprotocol/server/stdio";
3
- import c from "dotenv";
4
- import { g as i } from "./mcp-server-Bi7iBPtS.js";
5
- function p() {
6
- const e = process.env.TODOIST_BASE_URL, r = process.env.TODOIST_API_KEY;
2
+ import { serveStdio as t } from "@modelcontextprotocol/server/stdio";
3
+ import s from "dotenv";
4
+ import { g as n } from "./mcp-server-DHMEVYZ1.js";
5
+ function i() {
6
+ const o = process.env.TODOIST_BASE_URL, r = process.env.TODOIST_API_KEY;
7
7
  if (!r)
8
8
  throw new Error("TODOIST_API_KEY is not set");
9
- const o = i({ todoistApiKey: r, baseUrl: e }), t = new s();
10
- o.connect(t).then(() => {
11
- console.error("Server started");
12
- }).catch((n) => {
13
- console.error("Error starting the Todoist MCP server:", n), process.exit(1);
14
- });
9
+ t(() => n({ todoistApiKey: r, baseUrl: o }), {
10
+ onerror: (e) => {
11
+ console.error("Todoist MCP server error:", e);
12
+ }
13
+ }), console.error("Server started");
15
14
  }
16
- c.config({ quiet: !0 });
17
- p();
15
+ s.config({ quiet: !0 });
16
+ i();