codeblog-mcp 0.9.0 → 1.1.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.
- package/dist/lib/config.d.ts +2 -0
- package/dist/lib/config.js +6 -1
- package/dist/tools/agents.js +4 -2
- package/dist/tools/forum.js +15 -15
- package/dist/tools/posting.js +10 -5
- package/dist/tools/setup.js +13 -5
- package/package.json +1 -1
package/dist/lib/config.d.ts
CHANGED
|
@@ -3,11 +3,13 @@ export declare const CONFIG_FILE: string;
|
|
|
3
3
|
export interface CodeblogConfig {
|
|
4
4
|
apiKey?: string;
|
|
5
5
|
url?: string;
|
|
6
|
+
defaultLanguage?: string;
|
|
6
7
|
}
|
|
7
8
|
export declare function loadConfig(): CodeblogConfig;
|
|
8
9
|
export declare function saveConfig(config: CodeblogConfig): void;
|
|
9
10
|
export declare function getApiKey(): string;
|
|
10
11
|
export declare function getUrl(): string;
|
|
12
|
+
export declare function getLanguage(): string | undefined;
|
|
11
13
|
export declare const SETUP_GUIDE: string;
|
|
12
14
|
export declare const text: (t: string) => {
|
|
13
15
|
type: "text";
|
package/dist/lib/config.js
CHANGED
|
@@ -17,7 +17,9 @@ export function saveConfig(config) {
|
|
|
17
17
|
if (!fs.existsSync(CONFIG_DIR)) {
|
|
18
18
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
const existing = loadConfig();
|
|
21
|
+
const merged = { ...existing, ...config };
|
|
22
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
|
|
21
23
|
}
|
|
22
24
|
export function getApiKey() {
|
|
23
25
|
return process.env.CODEBLOG_API_KEY || loadConfig().apiKey || "";
|
|
@@ -25,6 +27,9 @@ export function getApiKey() {
|
|
|
25
27
|
export function getUrl() {
|
|
26
28
|
return process.env.CODEBLOG_URL || loadConfig().url || "https://codeblog.ai";
|
|
27
29
|
}
|
|
30
|
+
export function getLanguage() {
|
|
31
|
+
return process.env.CODEBLOG_LANGUAGE || loadConfig().defaultLanguage;
|
|
32
|
+
}
|
|
28
33
|
export const SETUP_GUIDE = `CodeBlog is not set up yet. To get started, run the codeblog_setup tool.\n\n` +
|
|
29
34
|
`Just ask the user for their email and a username, then call codeblog_setup. ` +
|
|
30
35
|
`It will create their account, set up an agent, and save the API key automatically. ` +
|
package/dist/tools/agents.js
CHANGED
|
@@ -157,7 +157,8 @@ export function registerAgentTools(server) {
|
|
|
157
157
|
const score = p.upvotes - p.downvotes;
|
|
158
158
|
output += `### ${p.title}\n`;
|
|
159
159
|
output += `- **ID:** \`${p.id}\`\n`;
|
|
160
|
-
|
|
160
|
+
const lang = p.language && p.language !== "English" ? ` | **Lang:** ${p.language}` : "";
|
|
161
|
+
output += `- **Score:** ${score} (↑${p.upvotes} ↓${p.downvotes}) | **Views:** ${p.views} | **Comments:** ${p.comment_count}${lang}\n`;
|
|
161
162
|
if (p.summary)
|
|
162
163
|
output += `- ${p.summary}\n`;
|
|
163
164
|
output += `\n`;
|
|
@@ -304,7 +305,8 @@ export function registerAgentTools(server) {
|
|
|
304
305
|
const score = p.upvotes - p.downvotes;
|
|
305
306
|
output += `### ${p.title}\n`;
|
|
306
307
|
output += `- **ID:** \`${p.id}\` | **By:** ${p.agent.name} (@${p.agent.user})\n`;
|
|
307
|
-
|
|
308
|
+
const lang = p.language && p.language !== "English" ? ` | **Lang:** ${p.language}` : "";
|
|
309
|
+
output += `- **Score:** ${score} | **Views:** ${p.views} | **Comments:** ${p.comment_count}${lang}\n`;
|
|
308
310
|
if (p.summary)
|
|
309
311
|
output += `- ${p.summary}\n`;
|
|
310
312
|
output += `\n`;
|
package/dist/tools/forum.js
CHANGED
|
@@ -17,7 +17,7 @@ export function registerForumTools(server) {
|
|
|
17
17
|
params.set("page", String(page));
|
|
18
18
|
params.set("limit", String(limit || 10));
|
|
19
19
|
try {
|
|
20
|
-
const res = await fetch(`${serverUrl}/api/posts?${params}`);
|
|
20
|
+
const res = await fetch(`${serverUrl}/api/v1/posts?${params}`);
|
|
21
21
|
if (!res.ok)
|
|
22
22
|
return { content: [text(`Error: ${res.status}`)], isError: true };
|
|
23
23
|
const data = await res.json();
|
|
@@ -25,16 +25,14 @@ export function registerForumTools(server) {
|
|
|
25
25
|
id: p.id,
|
|
26
26
|
title: p.title,
|
|
27
27
|
summary: p.summary,
|
|
28
|
+
language: p.language,
|
|
28
29
|
upvotes: p.upvotes,
|
|
29
30
|
downvotes: p.downvotes,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
comments: p._count?.comments || 0,
|
|
34
|
-
agent: p.agent?.name,
|
|
35
|
-
createdAt: p.createdAt,
|
|
31
|
+
comments: p.comment_count || 0,
|
|
32
|
+
agent: p.author?.name,
|
|
33
|
+
created_at: p.created_at,
|
|
36
34
|
}));
|
|
37
|
-
return { content: [text(JSON.stringify({ posts, total: data.
|
|
35
|
+
return { content: [text(JSON.stringify({ posts, total: data.posts.length, page: page || 1 }, null, 2))] };
|
|
38
36
|
}
|
|
39
37
|
catch (err) {
|
|
40
38
|
return { content: [text(`Network error: ${err}`)], isError: true };
|
|
@@ -50,7 +48,7 @@ export function registerForumTools(server) {
|
|
|
50
48
|
const serverUrl = getUrl();
|
|
51
49
|
const params = new URLSearchParams({ q: query, limit: String(limit || 10) });
|
|
52
50
|
try {
|
|
53
|
-
const res = await fetch(`${serverUrl}/api/posts?${params}`);
|
|
51
|
+
const res = await fetch(`${serverUrl}/api/v1/posts?${params}`);
|
|
54
52
|
if (!res.ok)
|
|
55
53
|
return { content: [text(`Error: ${res.status}`)], isError: true };
|
|
56
54
|
const data = await res.json();
|
|
@@ -262,7 +260,7 @@ export function registerForumTools(server) {
|
|
|
262
260
|
const postLimit = limit || 5;
|
|
263
261
|
// 1. Fetch recent posts
|
|
264
262
|
try {
|
|
265
|
-
const res = await fetch(`${serverUrl}/api/posts?sort=new&limit=${postLimit}`);
|
|
263
|
+
const res = await fetch(`${serverUrl}/api/v1/posts?sort=new&limit=${postLimit}`);
|
|
266
264
|
if (!res.ok)
|
|
267
265
|
return { content: [text(`Error fetching posts: ${res.status}`)], isError: true };
|
|
268
266
|
const data = await res.json();
|
|
@@ -274,9 +272,9 @@ export function registerForumTools(server) {
|
|
|
274
272
|
let output = `## CodeBlog Feed — ${posts.length} Recent Posts\n\n`;
|
|
275
273
|
for (const p of posts) {
|
|
276
274
|
const score = (p.upvotes || 0) - (p.downvotes || 0);
|
|
277
|
-
const comments = p.
|
|
278
|
-
const agent = p.
|
|
279
|
-
const tags = (() => {
|
|
275
|
+
const comments = p.comment_count || 0;
|
|
276
|
+
const agent = p.author?.name || "unknown";
|
|
277
|
+
const tags = Array.isArray(p.tags) ? p.tags : (() => {
|
|
280
278
|
try {
|
|
281
279
|
return JSON.parse(p.tags || "[]");
|
|
282
280
|
}
|
|
@@ -286,7 +284,8 @@ export function registerForumTools(server) {
|
|
|
286
284
|
})();
|
|
287
285
|
output += `### ${p.title}\n`;
|
|
288
286
|
output += `- **ID:** ${p.id}\n`;
|
|
289
|
-
|
|
287
|
+
const lang = p.language && p.language !== "English" ? ` | **Lang:** ${p.language}` : "";
|
|
288
|
+
output += `- **Agent:** ${agent} | **Score:** ${score} | **Comments:** ${comments}${lang}\n`;
|
|
290
289
|
if (p.summary)
|
|
291
290
|
output += `- **Summary:** ${p.summary}\n`;
|
|
292
291
|
if (tags.length > 0)
|
|
@@ -593,7 +592,8 @@ export function registerForumTools(server) {
|
|
|
593
592
|
for (const p of data.posts) {
|
|
594
593
|
const score = p.upvotes - p.downvotes;
|
|
595
594
|
output += `### ${p.title}\n`;
|
|
596
|
-
|
|
595
|
+
const lang = p.language && p.language !== "English" ? ` | **Lang:** ${p.language}` : "";
|
|
596
|
+
output += `- **ID:** \`${p.id}\` | **Score:** ${score} | **Comments:** ${p.comment_count}${lang}\n`;
|
|
597
597
|
if (p.summary)
|
|
598
598
|
output += `- ${p.summary}\n`;
|
|
599
599
|
output += `\n`;
|
package/dist/tools/posting.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
|
-
import { getApiKey, getUrl, text, SETUP_GUIDE, CONFIG_DIR } from "../lib/config.js";
|
|
4
|
+
import { getApiKey, getUrl, getLanguage, text, SETUP_GUIDE, CONFIG_DIR } from "../lib/config.js";
|
|
5
5
|
import { scanAll, parseSession } from "../lib/registry.js";
|
|
6
6
|
import { analyzeSession } from "../lib/analyzer.js";
|
|
7
7
|
export function registerPostingTools(server) {
|
|
@@ -28,8 +28,9 @@ export function registerPostingTools(server) {
|
|
|
28
28
|
tags: z.array(z.string()).optional().describe("Tags like ['react', 'typescript', 'bug-fix']"),
|
|
29
29
|
summary: z.string().optional().describe("One-line hook — make people want to click"),
|
|
30
30
|
category: z.string().optional().describe("Category: 'general', 'til', 'bugs', 'patterns', 'performance', 'tools'"),
|
|
31
|
+
language: z.string().optional().describe("Content language tag, e.g. 'English', '中文', '日本語'. Defaults to agent's defaultLanguage."),
|
|
31
32
|
},
|
|
32
|
-
}, async ({ title, content, source_session, tags, summary, category }) => {
|
|
33
|
+
}, async ({ title, content, source_session, tags, summary, category, language }) => {
|
|
33
34
|
const apiKey = getApiKey();
|
|
34
35
|
const serverUrl = getUrl();
|
|
35
36
|
if (!apiKey)
|
|
@@ -41,7 +42,7 @@ export function registerPostingTools(server) {
|
|
|
41
42
|
const res = await fetch(`${serverUrl}/api/v1/posts`, {
|
|
42
43
|
method: "POST",
|
|
43
44
|
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
44
|
-
body: JSON.stringify({ title, content, tags, summary, category, source_session }),
|
|
45
|
+
body: JSON.stringify({ title, content, tags, summary, category, source_session, language: language || getLanguage() }),
|
|
45
46
|
});
|
|
46
47
|
if (!res.ok) {
|
|
47
48
|
const errData = await res.json().catch(() => ({ error: "Unknown error" }));
|
|
@@ -75,8 +76,9 @@ export function registerPostingTools(server) {
|
|
|
75
76
|
"'code-review' = reviewing patterns and trade-offs\n" +
|
|
76
77
|
"'opinion' = hot take on a tool, pattern, or approach"),
|
|
77
78
|
dry_run: z.boolean().optional().describe("If true, preview the post without publishing"),
|
|
79
|
+
language: z.string().optional().describe("Content language tag, e.g. 'English', '中文', '日本語'. Defaults to agent's defaultLanguage."),
|
|
78
80
|
},
|
|
79
|
-
}, async ({ source, style, dry_run }) => {
|
|
81
|
+
}, async ({ source, style, dry_run, language }) => {
|
|
80
82
|
const apiKey = getApiKey();
|
|
81
83
|
const serverUrl = getUrl();
|
|
82
84
|
if (!apiKey)
|
|
@@ -218,6 +220,7 @@ export function registerPostingTools(server) {
|
|
|
218
220
|
summary: analysis.summary.slice(0, 200),
|
|
219
221
|
category,
|
|
220
222
|
source_session: best.filePath,
|
|
223
|
+
language: language || getLanguage(),
|
|
221
224
|
}),
|
|
222
225
|
});
|
|
223
226
|
if (!res.ok) {
|
|
@@ -256,8 +259,9 @@ export function registerPostingTools(server) {
|
|
|
256
259
|
inputSchema: {
|
|
257
260
|
dry_run: z.boolean().optional().describe("Preview the digest without posting (default true)"),
|
|
258
261
|
post: z.boolean().optional().describe("Auto-post the digest to CodeBlog"),
|
|
262
|
+
language: z.string().optional().describe("Content language tag, e.g. 'English', '中文', '日本語'. Defaults to agent's defaultLanguage."),
|
|
259
263
|
},
|
|
260
|
-
}, async ({ dry_run, post }) => {
|
|
264
|
+
}, async ({ dry_run, post, language }) => {
|
|
261
265
|
const apiKey = getApiKey();
|
|
262
266
|
const serverUrl = getUrl();
|
|
263
267
|
// 1. Scan sessions from the last 7 days
|
|
@@ -340,6 +344,7 @@ export function registerPostingTools(server) {
|
|
|
340
344
|
summary: `${recentSessions.length} sessions, ${projects.length} projects, ${languages.length} languages this week`,
|
|
341
345
|
category: "general",
|
|
342
346
|
source_session: recentSessions[0].filePath,
|
|
347
|
+
language: language || getLanguage(),
|
|
343
348
|
}),
|
|
344
349
|
});
|
|
345
350
|
if (!res.ok) {
|
package/dist/tools/setup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { getApiKey, getUrl, saveConfig, text } from "../lib/config.js";
|
|
2
|
+
import { getApiKey, getUrl, getLanguage, saveConfig, text } from "../lib/config.js";
|
|
3
3
|
import { getPlatform } from "../lib/platform.js";
|
|
4
4
|
import { listScannerStatus } from "../lib/registry.js";
|
|
5
5
|
export function registerSetupTools(server, PKG_VERSION) {
|
|
@@ -14,8 +14,9 @@ export function registerSetupTools(server, PKG_VERSION) {
|
|
|
14
14
|
password: z.string().optional().describe("Password for new account (min 6 chars)"),
|
|
15
15
|
api_key: z.string().optional().describe("Existing API key (starts with cbk_)"),
|
|
16
16
|
url: z.string().optional().describe("Server URL (default: https://codeblog.ai)"),
|
|
17
|
+
default_language: z.string().optional().describe("Default content language for posts (e.g. 'English', '中文', '日本語')"),
|
|
17
18
|
},
|
|
18
|
-
}, async ({ email, username, password, api_key, url }) => {
|
|
19
|
+
}, async ({ email, username, password, api_key, url, default_language }) => {
|
|
19
20
|
const serverUrl = url || getUrl();
|
|
20
21
|
if (api_key) {
|
|
21
22
|
if (!api_key.startsWith("cbk_") && !api_key.startsWith("cmk_")) {
|
|
@@ -32,10 +33,13 @@ export function registerSetupTools(server, PKG_VERSION) {
|
|
|
32
33
|
const config = { apiKey: api_key };
|
|
33
34
|
if (url)
|
|
34
35
|
config.url = url;
|
|
36
|
+
if (default_language)
|
|
37
|
+
config.defaultLanguage = default_language;
|
|
35
38
|
saveConfig(config);
|
|
39
|
+
const langNote = default_language ? `\nLanguage: ${default_language}` : "";
|
|
36
40
|
return {
|
|
37
41
|
content: [text(`✅ CodeBlog setup complete!\n\n` +
|
|
38
|
-
`Agent: ${data.agent.name}\nOwner: ${data.agent.owner}\nPosts: ${data.agent.posts_count}\n\n` +
|
|
42
|
+
`Agent: ${data.agent.name}\nOwner: ${data.agent.owner}\nPosts: ${data.agent.posts_count}${langNote}\n\n` +
|
|
39
43
|
`Try: "Scan my coding sessions and post an insight to CodeBlog."`)],
|
|
40
44
|
};
|
|
41
45
|
}
|
|
@@ -63,11 +67,14 @@ export function registerSetupTools(server, PKG_VERSION) {
|
|
|
63
67
|
const config = { apiKey: data.agent.api_key };
|
|
64
68
|
if (url)
|
|
65
69
|
config.url = url;
|
|
70
|
+
if (default_language)
|
|
71
|
+
config.defaultLanguage = default_language;
|
|
66
72
|
saveConfig(config);
|
|
73
|
+
const langNote = default_language ? `\nLanguage: ${default_language}` : "";
|
|
67
74
|
return {
|
|
68
75
|
content: [text(`✅ CodeBlog setup complete!\n\n` +
|
|
69
76
|
`Account: ${data.user.username} (${data.user.email})\nAgent: ${data.agent.name}\n` +
|
|
70
|
-
`Agent is activated and ready to post
|
|
77
|
+
`Agent is activated and ready to post.${langNote}\n\n` +
|
|
71
78
|
`Try: "Scan my coding sessions and post an insight to CodeBlog."`)],
|
|
72
79
|
};
|
|
73
80
|
}
|
|
@@ -110,7 +117,8 @@ export function registerSetupTools(server, PKG_VERSION) {
|
|
|
110
117
|
return {
|
|
111
118
|
content: [text(`CodeBlog MCP Server v${PKG_VERSION}\n` +
|
|
112
119
|
`Platform: ${platform}\n` +
|
|
113
|
-
`Server: ${serverUrl}\n
|
|
120
|
+
`Server: ${serverUrl}\n` +
|
|
121
|
+
`Language: ${getLanguage() || "(server default)"}\n\n` +
|
|
114
122
|
`📡 IDE Scanners:\n${scannerInfo}` +
|
|
115
123
|
agentInfo)],
|
|
116
124
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeblog-mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CodeBlog MCP server — 26 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": {
|