Initial commit: KOC LOOP platform

This commit is contained in:
巫凤萍
2026-07-30 12:06:41 +08:00
commit d2cde2c9b2
98 changed files with 44076 additions and 0 deletions

View File

@@ -0,0 +1,510 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
collectXhsMetricsFromMcp,
resolveCollectionMcpConfig,
resolveXhsPublicAccountDetails,
resolveXhsPublicAccountId,
resolveXhsAccountProfileFromMcp,
resolveXhsProfileDetailsFromMcp,
xhsNoteIdFromUrl,
} from "../lib/mcp-collection-client.ts";
function sse(payload, options = {}) {
return new Response(
`event: message\ndata: ${JSON.stringify(payload)}\n\n`,
{
status: 200,
...options,
headers: {
"content-type": "text/event-stream",
...(options.headers ?? {}),
},
},
);
}
function toolEnvelope(payload, isError = false) {
return {
jsonrpc: "2.0",
id: "tool-call",
result: {
isError,
content: [
{
type: "text",
text: JSON.stringify(payload),
},
],
},
};
}
function createFakeMcp(toolResults) {
let toolIndex = 0;
const calls = [];
const fetchImpl = async (url, init) => {
const body = JSON.parse(init.body);
calls.push({ url: String(url), body, headers: new Headers(init.headers) });
if (body.method === "initialize") {
return sse(
{
jsonrpc: "2.0",
id: body.id,
result: {
protocolVersion: "2025-03-26",
capabilities: { tools: { listChanged: false } },
serverInfo: { name: "ai-tool-center", version: "test" },
},
},
{ headers: { "mcp-session-id": "session-test" } },
);
}
if (body.method === "notifications/initialized") {
return new Response("", { status: 202 });
}
if (body.method === "tools/call") {
const result = toolResults[toolIndex];
toolIndex += 1;
return sse(result);
}
throw new Error(`Unexpected MCP method: ${body.method}`);
};
return { calls, fetchImpl };
}
test("collects likes, comments and favorites from the verified MCP shape", async () => {
const { calls, fetchImpl } = createFakeMcp([
toolEnvelope({
http_status: 200,
response: {
code: 200,
success: true,
msg: "获取内容详情成功",
data: {
likes: "483",
comments: "41",
collects: "519",
},
},
}),
]);
const result = await collectXhsMetricsFromMcp(
"https://www.xiaohongshu.com/discovery/item/test?xsec_token=valid",
{
endpoint: "https://collector.example/mcp",
key: "test-key",
},
fetchImpl,
);
assert.deepEqual(result, {
likes: 483,
comments: 41,
collects: 519,
});
assert.equal(calls.length, 3);
assert.equal(calls[2].body.params.name, "fetch_content_detail");
assert.equal(calls[2].body.params.arguments.include_comments, false);
assert.equal(calls[2].headers.get("mcp-session-id"), "session-test");
assert.equal(new URL(calls[0].url).searchParams.get("key"), "test-key");
});
test("resolves the real XHS account profile from a submitted note link", async () => {
const { calls, fetchImpl } = createFakeMcp([
toolEnvelope({
response: {
code: 200,
success: true,
data: {
note_detail: {
products: [
{
content_tags: [
{
notes: [
{
ip_location: "重庆",
note_id: "6a671108000000000f004bef",
user: {
nickname: "N我的麻辣烫好了吗",
profile_url:
"https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
red_id: "94329495984",
user_id: "6905cbca0000000037009f49",
},
},
],
},
],
},
],
},
},
},
}),
toolEnvelope({
response: {
code: 200,
success: true,
data: {
fans_count: "734",
},
},
}),
]);
const profile = await resolveXhsAccountProfileFromMcp(
"https://www.xiaohongshu.com/discovery/item/6a671108000000000f004bef",
"回填昵称",
{
endpoint: "https://collector.example/mcp",
key: "test-key",
},
fetchImpl,
);
assert.deepEqual(profile, {
platformUid: "6905cbca0000000037009f49",
nickname: "N我的麻辣烫好了吗",
profileUrl:
"https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
redId: "94329495984",
ipLocation: "重庆",
followers: 734,
});
assert.equal(calls.length, 4);
assert.equal(
calls[2].body.params.name,
"collect_xhs_wen_note_detail",
);
assert.equal(
calls[2].body.params.arguments.note_id,
"6a671108000000000f004bef",
);
assert.equal(calls[3].body.params.name, "parse_xhs_user_summary");
assert.equal(
calls[3].body.params.arguments.url,
"https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
);
assert.equal(
xhsNoteIdFromUrl(
"https://www.xiaohongshu.com/explore/6a671108000000000f004bef",
),
"6a671108000000000f004bef",
);
});
test("resolves followers directly from the supported XHS user summary tool", async () => {
const { calls, fetchImpl } = createFakeMcp([
toolEnvelope({
response: {
code: 200,
success: true,
msg: "用户摘要解析成功",
data: {
user: {
fansCount: 6,
ipLocation: "福建",
nickname: "555 五",
userId: "1020668113",
},
},
},
}),
]);
const details = await resolveXhsProfileDetailsFromMcp(
"https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
{
endpoint: "https://collector.example/mcp",
key: "test-key",
},
fetchImpl,
);
assert.deepEqual(details, {
followers: 6,
redId: "1020668113",
ipLocation: "福建",
});
assert.equal(calls[2].body.params.name, "parse_xhs_user_summary");
});
test("resolves an xhslink short URL before requesting the author profile", async () => {
const fakeMcp = createFakeMcp([
toolEnvelope({
response: {
code: 200,
success: true,
data: {
note_detail: {
note_id: "6a572da40000000021018bd2",
ip_location: "上海",
user: {
nickname: "短链作者",
user_id: "6905cbca0000000037009f49",
},
},
},
},
}),
toolEnvelope({
response: {
code: 200,
success: true,
data: {
red_id: "1020668113",
followers: "1.2万",
},
},
}),
]);
const fetchImpl = async (url, init) => {
if (String(url) === "http://xhslink.cn/o/AJFyP5dnj7O") {
return new Response(null, {
status: 302,
headers: {
location:
"https://www.xiaohongshu.com/discovery/item/6a572da40000000021018bd2?xsec_token=valid",
},
});
}
return fakeMcp.fetchImpl(url, init);
};
const profile = await resolveXhsAccountProfileFromMcp(
"http://xhslink.cn/o/AJFyP5dnj7O",
"回填昵称",
{
endpoint: "https://collector.example/mcp",
key: "test-key",
},
fetchImpl,
);
assert.equal(profile.nickname, "短链作者");
assert.equal(profile.platformUid, "6905cbca0000000037009f49");
assert.equal(profile.redId, "1020668113");
assert.equal(profile.followers, 12_000);
assert.equal(
profile.profileUrl,
"https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
);
assert.equal(
fakeMcp.calls[2].body.params.arguments.note_id,
"6a572da40000000021018bd2",
);
});
test("uses the public note author when MCP profile lookup fails", async () => {
const fakeMcp = createFakeMcp([
toolEnvelope(
{
response: {
code: 500,
success: false,
msg: "作者详情暂时不可用",
},
},
true,
),
]);
const fetchImpl = async (url, init) => {
if (String(url) === "http://xhslink.cn/o/AJFyP5dnj7O") {
return new Response(
'<script>window.__STATE__={&quot;noteData&quot;:{&quot;desc&quot;:&quot;测试&quot;,&quot;user&quot;:{&quot;userId&quot;:&quot;5fb21d32000000000101c23e&quot;,&quot;nickName&quot;:&quot;555 五&quot;}}}</script>',
{
status: 200,
headers: {
"content-type": "text/html; charset=utf-8",
location:
"https://www.xiaohongshu.com/discovery/item/6a572da40000000021018bd2?xsec_token=valid",
},
},
);
}
if (
String(url) ===
"https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e"
) {
return new Response(
'<script>{"redId":"1020668113","interactions":[{"name":"粉丝","count":"6","i18nCount":"6"}]}</script>',
{ status: 200 },
);
}
return fakeMcp.fetchImpl(url, init);
};
const profile = await resolveXhsAccountProfileFromMcp(
"http://xhslink.cn/o/AJFyP5dnj7O",
"回填昵称",
{
endpoint: "https://collector.example/mcp",
key: "test-key",
},
fetchImpl,
);
assert.deepEqual(profile, {
platformUid: "5fb21d32000000000101c23e",
nickname: "555 五",
profileUrl:
"https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
redId: "1020668113",
ipLocation: "待识别",
followers: 6,
});
assert.equal(
fakeMcp.calls[2].body.params.name,
"collect_xhs_wen_note_detail",
);
});
test("reads the user-visible Xiaohongshu number from a public profile", async () => {
const fetchImpl = async () =>
new Response(
'<div class="redId">小红书号1020668113</div><script>{"redId":"1020668113","interactions":[{"name":"粉丝","count":"10+","i18nCount":"10+"}]}</script>',
{ status: 200 },
);
const accountId = await resolveXhsPublicAccountId(
"https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
fetchImpl,
);
const details = await resolveXhsPublicAccountDetails(
"https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
fetchImpl,
);
assert.equal(accountId, "1020668113");
assert.deepEqual(details, {
redId: "1020668113",
followers: 10,
ipLocation: "",
});
});
test("falls back to parse_xhs_note when the primary tool fails", async () => {
const { calls, fetchImpl } = createFakeMcp([
toolEnvelope(
{
response: {
code: 400,
success: false,
msg: "获取内容详情失败",
data: null,
},
},
true,
),
toolEnvelope({
response: {
code: 200,
success: true,
data: {
likes: "1.2万",
comments: 32,
collects: "2,345",
},
},
}),
]);
const result = await collectXhsMetricsFromMcp(
"https://www.xiaohongshu.com/explore/test",
{
endpoint: "https://collector.example/mcp?key=test-key",
},
fetchImpl,
);
assert.deepEqual(result, {
likes: 12_000,
comments: 32,
collects: 2_345,
});
assert.equal(calls[3].body.params.name, "parse_xhs_note");
});
test("requires the MCP key without sending a network request", async () => {
let requested = false;
await assert.rejects(
collectXhsMetricsFromMcp(
"https://www.xiaohongshu.com/explore/test",
resolveCollectionMcpConfig({}),
async () => {
requested = true;
return new Response();
},
),
/MCP采集密钥未配置/,
);
assert.equal(requested, false);
});
test("rebuilds the MCP session after a gateway session miss", async () => {
let initializeCount = 0;
const fetchImpl = async (_url, init) => {
const body = JSON.parse(init.body);
if (body.method === "initialize") {
initializeCount += 1;
return sse(
{
jsonrpc: "2.0",
id: body.id,
result: {
protocolVersion: "2025-03-26",
capabilities: { tools: { listChanged: false } },
serverInfo: { name: "ai-tool-center", version: "test" },
},
},
{
headers: {
"mcp-session-id": `session-${initializeCount}`,
},
},
);
}
if (
body.method === "notifications/initialized" &&
initializeCount === 1
) {
return Response.json(
{
jsonrpc: "2.0",
id: "server-error",
error: { code: -32600, message: "Session not found" },
},
{ status: 404 },
);
}
if (body.method === "notifications/initialized") {
return new Response("", { status: 202 });
}
if (body.method === "tools/call") {
return sse(
toolEnvelope({
response: {
code: 200,
success: true,
data: { likes: 8, comments: 2, collects: 5 },
},
}),
);
}
throw new Error(`Unexpected MCP method: ${body.method}`);
};
const result = await collectXhsMetricsFromMcp(
"https://www.xiaohongshu.com/explore/test",
{
endpoint: "https://collector.example/mcp",
key: "test-key",
},
fetchImpl,
);
assert.deepEqual(result, { likes: 8, comments: 2, collects: 5 });
assert.equal(initializeCount, 2);
});