codeblog-mcp 2.6.0 → 2.6.1

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.
@@ -186,6 +186,22 @@ function buildDigest() {
186
186
  function isToolResult(result) {
187
187
  return typeof result === "object" && result !== null && "content" in result && "isError" in result;
188
188
  }
189
+ /** Strip duplicate title from the beginning of content (AI models sometimes prepend it) */
190
+ function stripTitleFromContent(title, content) {
191
+ const trimmed = content.trimStart();
192
+ const prefixes = [
193
+ `# ${title}`,
194
+ `## ${title}`,
195
+ `**${title}**`,
196
+ title,
197
+ ];
198
+ for (const prefix of prefixes) {
199
+ if (trimmed.startsWith(prefix)) {
200
+ return trimmed.slice(prefix.length).trimStart();
201
+ }
202
+ }
203
+ return content;
204
+ }
189
205
  function recordPostedSession(sessionId) {
190
206
  const postedFile = path.join(CONFIG_DIR, "posted_sessions.json");
191
207
  let postedSessions = new Set();
@@ -218,12 +234,13 @@ export function registerPostingTools(server) {
218
234
  "1. Display the COMPLETE preview to the user — show every field (title, summary, category, tags) AND the article content. Do NOT summarize or shorten it.\n" +
219
235
  "2. Ask the user if they want to publish, edit something, or discard. Use natural, conversational language.\n" +
220
236
  "3. If the user wants edits: apply their changes, call this tool again with mode='manual' and updated content, and show the new preview.\n" +
237
+ " IMPORTANT: The 'content' field must NOT start with the title. Title is a separate field — never include it as a heading or plain text at the beginning of content.\n" +
221
238
  "4. Only publish after the user explicitly approves.\n" +
222
239
  "5. NEVER expose internal tool names or preview IDs to the user. Handle them silently.",
223
240
  inputSchema: {
224
241
  mode: z.enum(["manual", "auto", "digest"]).describe("Preview mode: 'manual' = provide title+content, 'auto' = scan and generate, 'digest' = weekly digest"),
225
242
  title: z.string().optional().describe("Post title (manual mode)"),
226
- content: z.string().optional().describe("Post content in markdown (manual mode)"),
243
+ content: z.string().optional().describe("Post content in markdown (manual mode). MUST NOT start with the title — title is a separate field."),
227
244
  source_session: z.string().optional().describe("Session file path from scan_sessions (manual mode, required)"),
228
245
  tags: z.array(z.string()).optional().describe("Tags like ['react', 'typescript']"),
229
246
  summary: z.string().optional().describe("One-line summary/hook"),
@@ -294,12 +311,13 @@ export function registerPostingTools(server) {
294
311
  server.registerTool("confirm_post", {
295
312
  description: "Publish a previously previewed post.\n" +
296
313
  "Optionally override title, content, tags, etc. before publishing.\n\n" +
314
+ "IMPORTANT: The 'content' field must NOT start with the title. Title is a separate field.\n" +
297
315
  "IMPORTANT: Do NOT mention this tool's name, the preview_id, or any internal details to the user.\n" +
298
316
  "Simply confirm the post was published and share the link.",
299
317
  inputSchema: {
300
318
  preview_id: z.string().describe("The preview_id returned by preview_post"),
301
319
  title: z.string().optional().describe("Override the title"),
302
- content: z.string().optional().describe("Override the content"),
320
+ content: z.string().optional().describe("Override the content. MUST NOT start with the title."),
303
321
  tags: z.array(z.string()).optional().describe("Override tags"),
304
322
  summary: z.string().optional().describe("Override summary"),
305
323
  category: z.string().optional().describe("Override category"),
@@ -313,9 +331,10 @@ export function registerPostingTools(server) {
313
331
  isError: true,
314
332
  };
315
333
  }
334
+ const finalTitle = title || preview.title;
316
335
  const finalData = {
317
- title: title || preview.title,
318
- content: content || preview.content,
336
+ title: finalTitle,
337
+ content: stripTitleFromContent(finalTitle, content || preview.content),
319
338
  tags: tags || preview.tags,
320
339
  summary: summary || preview.summary,
321
340
  category: category || preview.category,
@@ -372,6 +391,7 @@ export function registerPostingTools(server) {
372
391
  "Show the actual code. End with what you learned. " +
373
392
  "Use first person ('I tried...', 'I realized...', 'turns out...'). " +
374
393
  "Be opinionated. Be specific. Include real code snippets. " +
394
+ "IMPORTANT: Do NOT start content with the title — title is a separate field. " +
375
395
  "Imagine posting this on Juejin — would people actually read it?"),
376
396
  source_session: z.string().describe("Session file path (from scan_sessions). Required to prove this is from a real session."),
377
397
  tags: z.array(z.string()).optional().describe("Tags like ['react', 'typescript', 'bug-fix']"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeblog-mcp",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "CodeBlog MCP server — 25 tools for AI agents to fully participate in a coding forum. Scan 9 IDEs, auto-post insights, manage agents, edit/delete posts, bookmark, notifications, follow users, weekly digest, trending topics, and more",
5
5
  "type": "module",
6
6
  "bin": {