@pipeworx/mcp-ai-briefing 0.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/LICENSE +21 -0
- package/README.md +42 -0
- package/package.json +20 -0
- package/server.json +18 -0
- package/src/index.ts +427 -0
- package/tsconfig.json +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pipeworx
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# mcp-ai-briefing
|
|
2
|
+
|
|
3
|
+
AI Briefing MCP — Keep AI models current on industry developments
|
|
4
|
+
|
|
5
|
+
Part of the [Pipeworx](https://pipeworx.io) open MCP gateway.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
|------|-------------|
|
|
11
|
+
| `get_briefing` | Get today\'s AI tools briefing — new MCP servers, APIs, SDKs, agent frameworks, and developer tools released in the last 24 hours. Call this at the start of any session to discover new tools you can use. |
|
|
12
|
+
| `search_developments` | Search for new tools, APIs, MCP servers, and frameworks by keyword. Returns matching developments across HN, GitHub, HuggingFace, and AI company blogs. Use for queries like "new MCP servers", "vector database tools", or "Claude integrations". |
|
|
13
|
+
| `get_recent` | Get recent tool and API releases filtered by category, source, or timeframe. Categories: mcp, tool, agent_framework, open_source, model_release, integration, infrastructure, product, paper. Sources: hackernews, arxiv, github, huggingface, openai_blog, anthropic_blog, google_ai_blog, meta_ai_blog. |
|
|
14
|
+
| `get_model_landscape` | Get recent AI model releases — what models shipped, from which companies, what they can do. Useful for knowing what\'s available to build with right now. |
|
|
15
|
+
| `get_timeline` | Get a chronological timeline of AI developments between two dates. Useful for understanding what happened during a specific period. |
|
|
16
|
+
| `get_ai_toolbelt` | Get the latest tools, features, and capabilities you can use RIGHT NOW. Returns new Claude Code features, MCP servers, SDK updates, CLI tools, and integrations. Call this to discover what new tools are in your toolbelt since your training cutoff. |
|
|
17
|
+
| `get_ai_news` | Get AI industry news — model releases, funding rounds, acquisitions, policy changes, benchmark results. Separate from toolbelt; this is about what happened in the AI industry, not tools you can use. |
|
|
18
|
+
| `what_happened` | Natural language query about recent tools and developments. Ask "any new MCP servers this week", "latest Claude tools", "new open source frameworks", "what APIs launched recently". Returns the most relevant tool-related developments. |
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
Add to your MCP client config:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"ai-briefing": {
|
|
28
|
+
"url": "https://gateway.pipeworx.io/ai-briefing/mcp"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or use the CLI:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx pipeworx use ai-briefing
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pipeworx/mcp-ai-briefing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI Briefing MCP — Keep AI models current on industry developments",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"keywords": ["mcp", "mcp-server", "model-context-protocol", "pipeworx", "ai-briefing"],
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/pipeworx-io/mcp-ai-briefing"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"typecheck": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.7.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.pipeworx-io/ai-briefing",
|
|
4
|
+
"title": "ai uriefing",
|
|
5
|
+
"description": "AI Briefing MCP — Keep AI models current on industry developments",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"websiteUrl": "https://pipeworx.io/packs/ai-briefing",
|
|
8
|
+
"repository": {
|
|
9
|
+
"url": "https://github.com/pipeworx-io/mcp-ai-briefing",
|
|
10
|
+
"source": "github"
|
|
11
|
+
},
|
|
12
|
+
"remotes": [
|
|
13
|
+
{
|
|
14
|
+
"type": "streamable-http",
|
|
15
|
+
"url": "https://gateway.pipeworx.io/ai-briefing/mcp"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
interface McpToolDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: 'object';
|
|
6
|
+
properties: Record<string, unknown>;
|
|
7
|
+
required?: string[];
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface McpToolExport {
|
|
12
|
+
tools: McpToolDefinition[];
|
|
13
|
+
callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* AI Briefing MCP — Keep AI models current on industry developments
|
|
18
|
+
*
|
|
19
|
+
* Provides daily-updated intelligence on AI model releases, papers,
|
|
20
|
+
* funding, products, and industry news sourced from HN, ArXiv,
|
|
21
|
+
* GitHub, Hugging Face, and official AI company blogs.
|
|
22
|
+
*
|
|
23
|
+
* Tools:
|
|
24
|
+
* - get_briefing: Today's AI digest — top stories, model releases, papers
|
|
25
|
+
* - search_developments: Semantic search across all tracked developments
|
|
26
|
+
* - get_recent: Recent developments filtered by category, source, or timeframe
|
|
27
|
+
* - get_model_landscape: Current state of model releases
|
|
28
|
+
* - get_timeline: Chronological event log between dates
|
|
29
|
+
* - what_happened: Natural language query — "what happened with Claude this month"
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
const SUPABASE_URL = 'https://pqauisounztsgdgfkhke.supabase.co';
|
|
34
|
+
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBxYXVpc291bnp0c2dkZ2ZraGtlIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc3NDM3MDMxMSwiZXhwIjoyMDg5OTQ2MzExfQ.gciWwNdmss8ko0ThAeUjQiFgwlMWxEP6LSucyyjTfcA';
|
|
35
|
+
|
|
36
|
+
async function querySupabase(path: string): Promise<unknown> {
|
|
37
|
+
const url = `${SUPABASE_URL}/rest/v1/${path}`;
|
|
38
|
+
const res = await fetch(url, {
|
|
39
|
+
headers: {
|
|
40
|
+
apikey: SUPABASE_KEY,
|
|
41
|
+
Authorization: `Bearer ${SUPABASE_KEY}`,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
const body = await res.text().catch(() => '');
|
|
46
|
+
throw new Error(`Supabase ${res.status}: ${body.slice(0, 200)}`);
|
|
47
|
+
}
|
|
48
|
+
return res.json();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const tools: McpToolExport['tools'] = [
|
|
52
|
+
{
|
|
53
|
+
name: 'get_briefing',
|
|
54
|
+
description: 'Get today\'s AI tools briefing — new MCP servers, APIs, SDKs, agent frameworks, and developer tools released in the last 24 hours. Call this at the start of any session to discover new tools you can use.',
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: 'object' as const,
|
|
57
|
+
properties: {
|
|
58
|
+
date: { type: 'string', description: 'Date in YYYY-MM-DD format (default: today)' },
|
|
59
|
+
},
|
|
60
|
+
required: [],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'search_developments',
|
|
65
|
+
description: 'Search for new tools, APIs, MCP servers, and frameworks by keyword. Returns matching developments across HN, GitHub, HuggingFace, and AI company blogs. Use for queries like "new MCP servers", "vector database tools", or "Claude integrations".',
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: 'object' as const,
|
|
68
|
+
properties: {
|
|
69
|
+
query: { type: 'string', description: 'Search query' },
|
|
70
|
+
limit: { type: 'number', description: 'Max results (default 10)' },
|
|
71
|
+
},
|
|
72
|
+
required: ['query'],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'get_recent',
|
|
77
|
+
description: 'Get recent tool and API releases filtered by category, source, or timeframe. Categories: mcp, tool, agent_framework, open_source, model_release, integration, infrastructure, product, paper. Sources: hackernews, arxiv, github, huggingface, openai_blog, anthropic_blog, google_ai_blog, meta_ai_blog.',
|
|
78
|
+
inputSchema: {
|
|
79
|
+
type: 'object' as const,
|
|
80
|
+
properties: {
|
|
81
|
+
category: { type: 'string', description: 'Filter by category (e.g., model_release, paper, funding)' },
|
|
82
|
+
source: { type: 'string', description: 'Filter by source (e.g., arxiv, hackernews, github)' },
|
|
83
|
+
days: { type: 'number', description: 'Look back N days (default 7)' },
|
|
84
|
+
importance: { type: 'string', description: 'Filter by importance: low, normal, high, breaking' },
|
|
85
|
+
limit: { type: 'number', description: 'Max results (default 20)' },
|
|
86
|
+
},
|
|
87
|
+
required: [],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'get_model_landscape',
|
|
92
|
+
description: 'Get recent AI model releases — what models shipped, from which companies, what they can do. Useful for knowing what\'s available to build with right now.',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: 'object' as const,
|
|
95
|
+
properties: {
|
|
96
|
+
days: { type: 'number', description: 'Look back N days (default 30)' },
|
|
97
|
+
},
|
|
98
|
+
required: [],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'get_timeline',
|
|
103
|
+
description: 'Get a chronological timeline of AI developments between two dates. Useful for understanding what happened during a specific period.',
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: 'object' as const,
|
|
106
|
+
properties: {
|
|
107
|
+
start_date: { type: 'string', description: 'Start date YYYY-MM-DD' },
|
|
108
|
+
end_date: { type: 'string', description: 'End date YYYY-MM-DD (default: today)' },
|
|
109
|
+
category: { type: 'string', description: 'Optional category filter' },
|
|
110
|
+
limit: { type: 'number', description: 'Max results (default 50)' },
|
|
111
|
+
},
|
|
112
|
+
required: ['start_date'],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'get_ai_toolbelt',
|
|
117
|
+
description: 'Get the latest tools, features, and capabilities you can use RIGHT NOW. Returns new Claude Code features, MCP servers, SDK updates, CLI tools, and integrations. Call this to discover what new tools are in your toolbelt since your training cutoff.',
|
|
118
|
+
inputSchema: {
|
|
119
|
+
type: 'object' as const,
|
|
120
|
+
properties: {
|
|
121
|
+
days: { type: 'number', description: 'Look back N days (default 7)' },
|
|
122
|
+
limit: { type: 'number', description: 'Max results (default 15)' },
|
|
123
|
+
},
|
|
124
|
+
required: [],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'get_ai_news',
|
|
129
|
+
description: 'Get AI industry news — model releases, funding rounds, acquisitions, policy changes, benchmark results. Separate from toolbelt; this is about what happened in the AI industry, not tools you can use.',
|
|
130
|
+
inputSchema: {
|
|
131
|
+
type: 'object' as const,
|
|
132
|
+
properties: {
|
|
133
|
+
days: { type: 'number', description: 'Look back N days (default 7)' },
|
|
134
|
+
limit: { type: 'number', description: 'Max results (default 15)' },
|
|
135
|
+
},
|
|
136
|
+
required: [],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'what_happened',
|
|
141
|
+
description: 'Natural language query about recent tools and developments. Ask "any new MCP servers this week", "latest Claude tools", "new open source frameworks", "what APIs launched recently". Returns the most relevant tool-related developments.',
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: 'object' as const,
|
|
144
|
+
properties: {
|
|
145
|
+
question: { type: 'string', description: 'Your question about recent AI developments' },
|
|
146
|
+
days: { type: 'number', description: 'Look back N days (default 30)' },
|
|
147
|
+
},
|
|
148
|
+
required: ['question'],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
async function callTool(name: string, args: Record<string, unknown>): Promise<unknown> {
|
|
154
|
+
switch (name) {
|
|
155
|
+
case 'get_briefing':
|
|
156
|
+
return getBriefing(args.date as string | undefined);
|
|
157
|
+
case 'search_developments':
|
|
158
|
+
return searchDevelopments(args.query as string, (args.limit as number) ?? 10);
|
|
159
|
+
case 'get_recent':
|
|
160
|
+
return getRecent(args);
|
|
161
|
+
case 'get_model_landscape':
|
|
162
|
+
return getModelLandscape((args.days as number) ?? 30);
|
|
163
|
+
case 'get_timeline':
|
|
164
|
+
return getTimeline(args);
|
|
165
|
+
case 'get_ai_toolbelt':
|
|
166
|
+
return getToolbelt((args.days as number) ?? 7, (args.limit as number) ?? 15);
|
|
167
|
+
case 'get_ai_news':
|
|
168
|
+
return getAiNews((args.days as number) ?? 7, (args.limit as number) ?? 15);
|
|
169
|
+
case 'what_happened':
|
|
170
|
+
return whatHappened(args.question as string, (args.days as number) ?? 30);
|
|
171
|
+
default:
|
|
172
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function getBriefing(date?: string): Promise<unknown> {
|
|
177
|
+
const targetDate = date ?? new Date().toISOString().slice(0, 10);
|
|
178
|
+
|
|
179
|
+
// Try digest first
|
|
180
|
+
const digests = await querySupabase(
|
|
181
|
+
`ai_digests?date=eq.${targetDate}&limit=1`
|
|
182
|
+
) as Array<Record<string, unknown>>;
|
|
183
|
+
|
|
184
|
+
if (digests.length > 0) {
|
|
185
|
+
const d = digests[0];
|
|
186
|
+
return {
|
|
187
|
+
date: d.date,
|
|
188
|
+
summary: d.summary,
|
|
189
|
+
top_stories: typeof d.top_stories === 'string' ? JSON.parse(d.top_stories as string) : d.top_stories,
|
|
190
|
+
model_updates: typeof d.model_updates === 'string' ? JSON.parse(d.model_updates as string) : d.model_updates,
|
|
191
|
+
paper_highlights: typeof d.paper_highlights === 'string' ? JSON.parse(d.paper_highlights as string) : d.paper_highlights,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// No digest yet — build one from raw developments
|
|
196
|
+
const since = new Date(new Date(targetDate).getTime() - 24 * 60 * 60 * 1000).toISOString();
|
|
197
|
+
const devs = await querySupabase(
|
|
198
|
+
`ai_developments?published_at=gte.${since}&order=published_at.desc&limit=30`
|
|
199
|
+
) as Array<Record<string, unknown>>;
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
date: targetDate,
|
|
203
|
+
note: 'Live query (no cached digest available)',
|
|
204
|
+
total_developments: devs.length,
|
|
205
|
+
developments: devs.map((d) => ({
|
|
206
|
+
title: d.title,
|
|
207
|
+
summary: d.summary,
|
|
208
|
+
url: d.url,
|
|
209
|
+
source: d.source,
|
|
210
|
+
category: d.category,
|
|
211
|
+
importance: d.importance,
|
|
212
|
+
published_at: d.published_at,
|
|
213
|
+
})),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function searchDevelopments(query: string, limit: number): Promise<unknown> {
|
|
218
|
+
const encoded = encodeURIComponent(query);
|
|
219
|
+
const devs = await querySupabase(
|
|
220
|
+
`ai_developments?or=(title.ilike.*${encoded}*,summary.ilike.*${encoded}*,tags.cs.{${encoded.toLowerCase()}})&order=published_at.desc&limit=${limit}`
|
|
221
|
+
) as Array<Record<string, unknown>>;
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
query,
|
|
225
|
+
total: devs.length,
|
|
226
|
+
results: devs.map((d) => ({
|
|
227
|
+
title: d.title,
|
|
228
|
+
summary: d.summary,
|
|
229
|
+
url: d.url,
|
|
230
|
+
source: d.source,
|
|
231
|
+
category: d.category,
|
|
232
|
+
importance: d.importance,
|
|
233
|
+
published_at: d.published_at,
|
|
234
|
+
})),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function getRecent(args: Record<string, unknown>): Promise<unknown> {
|
|
239
|
+
const days = (args.days as number) ?? 7;
|
|
240
|
+
const limit = (args.limit as number) ?? 20;
|
|
241
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
242
|
+
|
|
243
|
+
const filters = [`published_at=gte.${since}`];
|
|
244
|
+
if (args.category) filters.push(`category=eq.${args.category}`);
|
|
245
|
+
if (args.source) filters.push(`source=eq.${args.source}`);
|
|
246
|
+
if (args.importance) filters.push(`importance=eq.${args.importance}`);
|
|
247
|
+
|
|
248
|
+
const devs = await querySupabase(
|
|
249
|
+
`ai_developments?${filters.join('&')}&order=published_at.desc&limit=${limit}`
|
|
250
|
+
) as Array<Record<string, unknown>>;
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
period: `last ${days} days`,
|
|
254
|
+
total: devs.length,
|
|
255
|
+
developments: devs.map((d) => ({
|
|
256
|
+
title: d.title,
|
|
257
|
+
summary: d.summary,
|
|
258
|
+
url: d.url,
|
|
259
|
+
source: d.source,
|
|
260
|
+
category: d.category,
|
|
261
|
+
importance: d.importance,
|
|
262
|
+
published_at: d.published_at,
|
|
263
|
+
})),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function getModelLandscape(days: number): Promise<unknown> {
|
|
268
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
269
|
+
const devs = await querySupabase(
|
|
270
|
+
`ai_developments?category=eq.model_release&published_at=gte.${since}&order=published_at.desc&limit=30`
|
|
271
|
+
) as Array<Record<string, unknown>>;
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
period: `last ${days} days`,
|
|
275
|
+
model_releases: devs.length,
|
|
276
|
+
models: devs.map((d) => ({
|
|
277
|
+
title: d.title,
|
|
278
|
+
summary: d.summary,
|
|
279
|
+
url: d.url,
|
|
280
|
+
source: d.source,
|
|
281
|
+
importance: d.importance,
|
|
282
|
+
published_at: d.published_at,
|
|
283
|
+
tags: d.tags,
|
|
284
|
+
})),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async function getTimeline(args: Record<string, unknown>): Promise<unknown> {
|
|
289
|
+
const startDate = args.start_date as string;
|
|
290
|
+
const endDate = (args.end_date as string) ?? new Date().toISOString().slice(0, 10);
|
|
291
|
+
const limit = (args.limit as number) ?? 50;
|
|
292
|
+
|
|
293
|
+
const filters = [`published_at=gte.${startDate}T00:00:00Z`, `published_at=lte.${endDate}T23:59:59Z`];
|
|
294
|
+
if (args.category) filters.push(`category=eq.${args.category}`);
|
|
295
|
+
|
|
296
|
+
const devs = await querySupabase(
|
|
297
|
+
`ai_developments?${filters.join('&')}&order=published_at.asc&limit=${limit}`
|
|
298
|
+
) as Array<Record<string, unknown>>;
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
start_date: startDate,
|
|
302
|
+
end_date: endDate,
|
|
303
|
+
total: devs.length,
|
|
304
|
+
timeline: devs.map((d) => ({
|
|
305
|
+
date: (d.published_at as string)?.slice(0, 10),
|
|
306
|
+
title: d.title,
|
|
307
|
+
summary: d.summary,
|
|
308
|
+
url: d.url,
|
|
309
|
+
source: d.source,
|
|
310
|
+
category: d.category,
|
|
311
|
+
importance: d.importance,
|
|
312
|
+
})),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function getToolbelt(days: number, limit: number): Promise<unknown> {
|
|
317
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
318
|
+
const toolCategories = ['mcp', 'tool', 'toolbelt', 'agent_framework', 'integration', 'infrastructure', 'open_source'];
|
|
319
|
+
const catFilter = toolCategories.map((c) => `category.eq.${c}`).join(',');
|
|
320
|
+
|
|
321
|
+
const devs = await querySupabase(
|
|
322
|
+
`ai_developments?or=(${catFilter})&published_at=gte.${since}&order=published_at.desc&limit=${limit}`
|
|
323
|
+
) as Array<Record<string, unknown>>;
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
feed: 'toolbelt',
|
|
327
|
+
period: `last ${days} days`,
|
|
328
|
+
description: 'Tools, features, and capabilities you can use right now',
|
|
329
|
+
total: devs.length,
|
|
330
|
+
items: devs.map((d) => ({
|
|
331
|
+
title: d.title,
|
|
332
|
+
summary: d.summary,
|
|
333
|
+
url: d.url,
|
|
334
|
+
source: d.source,
|
|
335
|
+
category: d.category,
|
|
336
|
+
importance: d.importance,
|
|
337
|
+
published_at: d.published_at,
|
|
338
|
+
})),
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function getAiNews(days: number, limit: number): Promise<unknown> {
|
|
343
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
344
|
+
const newsCategories = ['model_release', 'claude_update', 'funding', 'acquisition', 'policy', 'benchmark', 'news', 'paper'];
|
|
345
|
+
const catFilter = newsCategories.map((c) => `category.eq.${c}`).join(',');
|
|
346
|
+
|
|
347
|
+
const devs = await querySupabase(
|
|
348
|
+
`ai_developments?or=(${catFilter})&published_at=gte.${since}&order=published_at.desc&limit=${limit}`
|
|
349
|
+
) as Array<Record<string, unknown>>;
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
feed: 'ai_news',
|
|
353
|
+
period: `last ${days} days`,
|
|
354
|
+
description: 'AI industry developments — models, funding, policy, research',
|
|
355
|
+
total: devs.length,
|
|
356
|
+
items: devs.map((d) => ({
|
|
357
|
+
title: d.title,
|
|
358
|
+
summary: d.summary,
|
|
359
|
+
url: d.url,
|
|
360
|
+
source: d.source,
|
|
361
|
+
category: d.category,
|
|
362
|
+
importance: d.importance,
|
|
363
|
+
published_at: d.published_at,
|
|
364
|
+
})),
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function whatHappened(question: string, days: number): Promise<unknown> {
|
|
369
|
+
// Extract keywords from the question for search
|
|
370
|
+
const keywords = question
|
|
371
|
+
.toLowerCase()
|
|
372
|
+
.replace(/[^a-z0-9\s]/g, '')
|
|
373
|
+
.split(/\s+/)
|
|
374
|
+
.filter((w) => w.length > 2 && !['what', 'the', 'any', 'new', 'latest', 'recent', 'happened', 'with', 'about', 'has', 'have', 'been', 'there'].includes(w));
|
|
375
|
+
|
|
376
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
377
|
+
|
|
378
|
+
if (keywords.length === 0) {
|
|
379
|
+
// No specific keywords — return top recent items
|
|
380
|
+
return getRecent({ days, limit: 15, importance: 'high' });
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Search for each keyword and merge results
|
|
384
|
+
const allDevs: Array<Record<string, unknown>> = [];
|
|
385
|
+
const seen = new Set<string>();
|
|
386
|
+
|
|
387
|
+
for (const kw of keywords.slice(0, 3)) {
|
|
388
|
+
const devs = await querySupabase(
|
|
389
|
+
`ai_developments?or=(title.ilike.*${encodeURIComponent(kw)}*,summary.ilike.*${encodeURIComponent(kw)}*)&published_at=gte.${since}&order=published_at.desc&limit=10`
|
|
390
|
+
) as Array<Record<string, unknown>>;
|
|
391
|
+
|
|
392
|
+
for (const d of devs) {
|
|
393
|
+
const id = d.id as string;
|
|
394
|
+
if (!seen.has(id)) {
|
|
395
|
+
seen.add(id);
|
|
396
|
+
allDevs.push(d);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Sort by importance then date
|
|
402
|
+
allDevs.sort((a, b) => {
|
|
403
|
+
const impOrder = { breaking: 0, high: 1, normal: 2, low: 3 };
|
|
404
|
+
const ai = impOrder[(a.importance as string) as keyof typeof impOrder] ?? 2;
|
|
405
|
+
const bi = impOrder[(b.importance as string) as keyof typeof impOrder] ?? 2;
|
|
406
|
+
if (ai !== bi) return ai - bi;
|
|
407
|
+
return new Date(b.published_at as string).getTime() - new Date(a.published_at as string).getTime();
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
question,
|
|
412
|
+
keywords_used: keywords,
|
|
413
|
+
period: `last ${days} days`,
|
|
414
|
+
total: allDevs.length,
|
|
415
|
+
developments: allDevs.slice(0, 15).map((d) => ({
|
|
416
|
+
title: d.title,
|
|
417
|
+
summary: d.summary,
|
|
418
|
+
url: d.url,
|
|
419
|
+
source: d.source,
|
|
420
|
+
category: d.category,
|
|
421
|
+
importance: d.importance,
|
|
422
|
+
published_at: d.published_at,
|
|
423
|
+
})),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export default { tools, callTool } satisfies McpToolExport;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"rootDir": "src",
|
|
11
|
+
"declaration": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"]
|
|
14
|
+
}
|