note-mcp 1.1.1 → 1.2.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.
Files changed (3) hide show
  1. package/README.md +103 -13
  2. package/dist/index.js +72 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,16 +5,72 @@ Unofficial stdio MCP server for note.com. It uses cookie-based access to note.co
5
5
  > [!WARNING]
6
6
  > This project is unofficial and not affiliated with note.com. Internal APIs can change without notice. Keep cookies local and never commit them to GitHub, npm, logs, or issue reports.
7
7
 
8
- ## Install / run
8
+ ## Quick start
9
+
10
+ ### Local/desktop agents
11
+
12
+ Use browser login first:
9
13
 
10
14
  ```bash
11
- npx note-mcp
15
+ npx note-mcp auth
12
16
  ```
13
17
 
14
- For advanced/server setups, you can still provide a Cookie header through the environment:
18
+ After you log in to note.com in the opened browser, `note-mcp` saves the cookie locally and prints the saved file path:
19
+
20
+ ```json
21
+ {
22
+ "authenticated": true,
23
+ "saved": true,
24
+ "configPath": "/Users/you/.config/note-mcp/config.json",
25
+ "cookiePreview": "fp=b…5948",
26
+ "message": "note.com authentication configured from browser login. Cookie saved to /Users/you/.config/note-mcp/config.json."
27
+ }
28
+ ```
29
+
30
+ Then configure your MCP client without putting cookies in the config:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "note": {
36
+ "command": "npx",
37
+ "args": ["-y", "note-mcp"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ Some MCP clients only load newly added tools when a process or conversation starts. After authentication or config changes, restart the client or open a new thread/session if `note_*` tools do not appear immediately.
44
+
45
+ Quick setup check:
46
+
47
+ 1. `npx note-mcp auth`
48
+ 2. `npx note-mcp auth --status`
49
+ 3. Add `npx -y note-mcp` to your MCP client config
50
+ 4. Restart the client or open a new thread/session
51
+ 5. Run `note_auth_status` from the MCP client
52
+
53
+ ### Servers, containers, and CI
54
+
55
+ Do not rely on browser login in headless/container environments. Provide a cookie through env or a mounted config file instead:
15
56
 
16
57
  ```bash
17
- NOTE_COOKIE='your note.com cookie string' npx note-mcp
58
+ NOTE_COOKIE='your note.com Cookie header' npx note-mcp
59
+ ```
60
+
61
+ Or mount a config file and point `NOTE_MCP_CONFIG` at it:
62
+
63
+ ```bash
64
+ docker run \
65
+ -v ~/.config/note-mcp/config.json:/run/secrets/note-mcp-config.json:ro \
66
+ -e NOTE_MCP_CONFIG=/run/secrets/note-mcp-config.json \
67
+ your-agent-image
68
+ ```
69
+
70
+ ## Install / run
71
+
72
+ ```bash
73
+ npx note-mcp
18
74
  ```
19
75
 
20
76
  For local development:
@@ -27,7 +83,7 @@ node dist/index.js
27
83
 
28
84
  ## MCP client configuration
29
85
 
30
- Desktop/local browser-login friendly setup:
86
+ Recommended desktop setup after `npx note-mcp auth`:
31
87
 
32
88
  ```json
33
89
  {
@@ -49,13 +105,33 @@ Advanced env-based setup:
49
105
  "command": "npx",
50
106
  "args": ["-y", "note-mcp"],
51
107
  "env": {
52
- "NOTE_COOKIE": "your note.com cookie string"
108
+ "NOTE_COOKIE": "your note.com Cookie header"
53
109
  }
54
110
  }
55
111
  }
56
112
  }
57
113
  ```
58
114
 
115
+ ### Codex CLI
116
+
117
+ For Codex, add `note-mcp` as a stdio MCP server with `npx`:
118
+
119
+ ```bash
120
+ codex mcp add note -- npx -y note-mcp
121
+ codex mcp list
122
+ npx -y note-mcp auth --status
123
+ ```
124
+
125
+ Recommended verification flow:
126
+
127
+ 1. `npx note-mcp auth`
128
+ 2. `npx note-mcp auth --status`
129
+ 3. `codex mcp add note -- npx -y note-mcp`
130
+ 4. Restart Codex or create a new thread
131
+ 5. Run `note_auth_status`
132
+
133
+ If the server is listed but `note_*` tools are not available in the current thread, restart Codex or start a new thread so the MCP tools are loaded from the new configuration.
134
+
59
135
  ## Authentication
60
136
 
61
137
  `note-mcp` supports two authentication paths.
@@ -78,6 +154,8 @@ This opens a browser, lets you log in to note.com normally, then stores note.com
78
154
  ~/.config/note-mcp/config.json
79
155
  ```
80
156
 
157
+ The CLI and MCP tool response include the actual `configPath` used.
158
+
81
159
  If the browser executable is not installed yet, install Playwright's Chromium once on the same machine/user account, then retry:
82
160
 
83
161
  ```bash
@@ -92,8 +170,6 @@ npx -p playwright playwright install chromium
92
170
 
93
171
  For remote servers, containers, or CI, prefer the secret/env/config-file path below instead of browser login.
94
172
 
95
- The config file is written with `0600` permissions where supported.
96
-
97
173
  Useful CLI commands:
98
174
 
99
175
  ```bash
@@ -105,7 +181,7 @@ npx note-mcp auth --headed
105
181
 
106
182
  ### 2. Advanced/server/CI: secret, env, or config file
107
183
 
108
- For remote agents, servers, CI, and secret managers, provide a Cookie header via:
184
+ For remote agents, servers, containers, CI, and secret managers, provide a Cookie header via:
109
185
 
110
186
  - `NOTE_COOKIE`
111
187
  - `NOTE_SESSION_COOKIE`
@@ -127,12 +203,24 @@ Cookie lookup priority:
127
203
  2. `NOTE_SESSION_COOKIE`
128
204
  3. config file cookie
129
205
 
206
+ Default config path:
207
+
208
+ ```text
209
+ ~/.config/note-mcp/config.json
210
+ ```
211
+
212
+ Override config path:
213
+
214
+ ```bash
215
+ NOTE_MCP_CONFIG=/path/to/config.json npx note-mcp
216
+ ```
217
+
130
218
  ## Tools
131
219
 
132
220
  Authentication/setup tools:
133
221
 
134
- - `note_auth_status` — inspect whether auth is configured
135
- - `note_auth_login` — open a browser login flow and save cookies locally
222
+ - `note_auth_status` — inspect whether auth is configured and which config path is used
223
+ - `note_auth_login` — open a browser login flow and save cookies locally; response includes `configPath`
136
224
  - `note_set_cookie` — save a Cookie header to the local config file, optionally verifying it first
137
225
  - `note_clear_cookie` — delete the stored config-file cookie
138
226
  - `note_login_help` — explain supported setup paths
@@ -140,7 +228,7 @@ Authentication/setup tools:
140
228
  note.com tools:
141
229
 
142
230
  - `note_auth_check` — verify configured cookie-based access to note.com internal APIs
143
- - `note_list_my_notes` — list notes for the authenticated account
231
+ - `note_list_my_notes` — list creator contents for the authenticated account via `GET /v2/creators/info/contents?kind=note&page={page}`. By default returns the full internal API payload. For LLM-friendly list views, pass `fields: "summary"` or `includeBody: false` to return summary fields such as `title`, `key`, `url`, `publishAt`, `status`, and `likeCount`.
144
232
  - `note_list_drafts` — list drafts for the authenticated account
145
233
  - `note_get_note` — fetch a note by note key, e.g. `n1a0b26f944f4`
146
234
  - `note_create_draft` — create a draft
@@ -158,10 +246,12 @@ Known endpoint basis:
158
246
 
159
247
  - Base URL: `https://note.com/api`
160
248
  - Note detail: `GET /v3/notes/{noteKey}`
161
- - Own contents: `GET /v2/creators/info/contents?kind=note&page=1`
249
+ - Authenticated creator contents: `GET /v2/creators/info/contents?kind=note&page=1`
162
250
  - Draft save: `POST /v1/text_notes/draft_save?id={draftId}`
163
251
  - Auth smoke test: `GET /v3/notice_counts`
164
252
 
253
+ `note_list_my_notes` intentionally exposes the authenticated creator contents endpoint above. The exact visibility and shape are determined by note.com's internal API response for the configured cookie; use the default full response when debugging endpoint behavior, and use summary mode when a compact list is enough.
254
+
165
255
  ## Release
166
256
 
167
257
  Releases are handled by GitHub Actions + semantic-release.
package/dist/index.js CHANGED
@@ -131,8 +131,12 @@ var NoteClient = class {
131
131
  async authCheck() {
132
132
  return this.request("/v3/notice_counts");
133
133
  }
134
- async listMyNotes(page = 1) {
135
- return this.request(`/v2/creators/info/contents?kind=note&page=${page}`);
134
+ async listMyNotes(page = 1, options = {}) {
135
+ const payload = await this.request(`/v2/creators/info/contents?kind=note&page=${page}`);
136
+ if (options.fields === "summary" || options.includeBody === false) {
137
+ return summarizeListPayload(payload);
138
+ }
139
+ return payload;
136
140
  }
137
141
  async listDrafts(page = 1) {
138
142
  return this.request(`/v2/creators/info/contents?kind=draft&page=${page}`);
@@ -181,6 +185,54 @@ var NoteClient = class {
181
185
  return body;
182
186
  }
183
187
  };
188
+ function summarizeListPayload(payload) {
189
+ if (!isJsonObject(payload)) return payload;
190
+ if (isJsonObject(payload.data) && Array.isArray(payload.data.contents)) {
191
+ return {
192
+ ...payload,
193
+ data: {
194
+ ...payload.data,
195
+ contents: payload.data.contents.map(summarizeNoteItem)
196
+ }
197
+ };
198
+ }
199
+ if (Array.isArray(payload.contents)) {
200
+ return {
201
+ ...payload,
202
+ contents: payload.contents.map(summarizeNoteItem)
203
+ };
204
+ }
205
+ return payload;
206
+ }
207
+ function summarizeNoteItem(item) {
208
+ if (!isJsonObject(item)) return item;
209
+ const key = firstString(item.key, item.noteKey, item.id);
210
+ return omitUndefined({
211
+ key,
212
+ title: firstString(item.title, item.name),
213
+ url: firstString(item.url, item.noteUrl, item.note_url, item.path) ?? noteUrl(key),
214
+ publishAt: firstDefined(item.publishAt, item.publish_at, item.publishedAt, item.published_at),
215
+ status: item.status,
216
+ likeCount: firstDefined(item.likeCount, item.like_count)
217
+ });
218
+ }
219
+ function firstDefined(...values) {
220
+ return values.find((value) => value !== void 0);
221
+ }
222
+ function firstString(...values) {
223
+ return values.find((value) => typeof value === "string" && value.length > 0);
224
+ }
225
+ function noteUrl(key) {
226
+ return key ? `https://note.com/notes/${key}` : void 0;
227
+ }
228
+ function omitUndefined(record) {
229
+ return Object.fromEntries(
230
+ Object.entries(record).filter((entry) => entry[1] !== void 0)
231
+ );
232
+ }
233
+ function isJsonObject(value) {
234
+ return typeof value === "object" && value !== null && !Array.isArray(value);
235
+ }
184
236
  async function parseBody(response) {
185
237
  const text = await response.text();
186
238
  if (!text) return null;
@@ -222,15 +274,9 @@ async function runBrowserLogin(options = {}) {
222
274
  const client = new NoteClient({ cookie });
223
275
  try {
224
276
  await client.authCheck();
225
- if (options.save ?? true) {
226
- await saveCookie(cookie);
227
- }
228
- return {
229
- authenticated: true,
230
- saved: options.save ?? true,
231
- cookiePreview: previewCookie2(cookie),
232
- message: "note.com authentication configured from browser login."
233
- };
277
+ const shouldSave = options.save ?? true;
278
+ const saveStatus = shouldSave ? await saveCookie(cookie) : void 0;
279
+ return buildBrowserLoginResult(cookie, shouldSave, saveStatus);
234
280
  } catch {
235
281
  }
236
282
  }
@@ -250,6 +296,16 @@ async function importPlaywright() {
250
296
  );
251
297
  }
252
298
  }
299
+ function buildBrowserLoginResult(cookie, saved, saveStatus) {
300
+ const configPath = saveStatus?.configPath;
301
+ return {
302
+ authenticated: true,
303
+ saved,
304
+ ...configPath ? { configPath } : {},
305
+ cookiePreview: saveStatus?.cookiePreview ?? previewCookie2(cookie),
306
+ message: configPath ? `note.com authentication configured from browser login. Cookie saved to ${configPath}.` : "note.com authentication configured from browser login."
307
+ };
308
+ }
253
309
  function toBrowserLoginError(error) {
254
310
  const message = error instanceof Error ? error.message : String(error);
255
311
  if (message.includes("Executable doesn't exist") || message.includes("Please run the following command to download new browsers") || message.includes("playwright install")) {
@@ -393,12 +449,14 @@ async function runMcpServer() {
393
449
  "note_list_my_notes",
394
450
  {
395
451
  title: "List my note.com notes",
396
- description: "Lists notes for the authenticated note.com account.",
452
+ description: 'Lists creator contents for the authenticated note.com account via GET /v2/creators/info/contents?kind=note. By default returns the full internal API payload; pass fields: "summary" or includeBody: false for a lightweight list with title/key/url/publishAt/status/likeCount.',
397
453
  inputSchema: {
398
- page: z.number().int().positive().default(1)
454
+ page: z.number().int().positive().default(1),
455
+ fields: z.enum(["full", "summary"]).default("full"),
456
+ includeBody: z.boolean().optional()
399
457
  }
400
458
  },
401
- async ({ page }) => withClient((client) => client.listMyNotes(page))
459
+ async ({ page, fields, includeBody }) => withClient((client) => client.listMyNotes(page, { fields, includeBody }))
402
460
  );
403
461
  server.registerTool(
404
462
  "note_list_drafts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "note-mcp",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Unofficial stdio MCP server for note.com using cookie-based internal APIs.",
5
5
  "type": "module",
6
6
  "bin": {