feat: add count_posts aggregation tool to AI SDK and MCP server

This commit is contained in:
2026-03-01 20:46:44 +01:00
parent 3074fe461c
commit db84129a17
8 changed files with 398 additions and 2 deletions

View File

@@ -25,6 +25,7 @@ function createMockPostEngine() {
getLinkedBy: vi.fn().mockResolvedValue([]),
getLinksTo: vi.fn().mockResolvedValue([]),
getPostsFiltered: vi.fn().mockResolvedValue([]),
getPostCounts: vi.fn().mockResolvedValue({ groups: [], totalPosts: 0 }),
};
}
@@ -190,6 +191,11 @@ describe('MCPServer', () => {
expect(hasRegistered(mcpServer, '_registeredTools', 'propose_post_metadata')).toBe(true);
});
it('registers count_posts tool', () => {
const mcpServer = server.createMcpServer();
expect(hasRegistered(mcpServer, '_registeredTools', 'count_posts')).toBe(true);
});
it('registers accept_proposal tool', () => {
const mcpServer = server.createMcpServer();
expect(hasRegistered(mcpServer, '_registeredTools', 'accept_proposal')).toBe(true);
@@ -840,6 +846,35 @@ describe('MCPServer', () => {
);
});
// ── count_posts ──────────────────────────────────────────────────
it('count_posts calls getPostCounts with correct args', async () => {
mockPostEngine.getPostCounts.mockResolvedValue({
groups: [
{ month: 1, tag: 'Politik', count: 12 },
{ month: 2, tag: 'Politik', count: 5 },
],
totalPosts: 300,
});
const mcpServer = server.createMcpServer();
const tool = getTool(mcpServer, 'count_posts');
const result = await tool.handler({ groupBy: ['month', 'tag'], year: 2004 }, {}) as { content: Array<{ text: string }> };
expect(mockPostEngine.getPostCounts).toHaveBeenCalledWith(
['month', 'tag'],
{ year: 2004 },
);
const parsed = JSON.parse(result.content[0].text);
expect(parsed.totalPosts).toBe(300);
expect(parsed.groups).toHaveLength(2);
});
it('count_posts returns error when month without year', async () => {
const mcpServer = server.createMcpServer();
const tool = getTool(mcpServer, 'count_posts');
const result = await tool.handler({ groupBy: ['tag'], month: 6 }, {}) as { content: Array<{ text: string }>; isError?: boolean };
expect(result.isError).toBe(true);
});
it('draft_post creates a draft and stores proposal', async () => {
const createdPost = { id: 'new-post', title: 'Draft Title', status: 'draft' };
mockPostEngine.createPost.mockResolvedValue(createdPost);