@techsnif/mcp-server 1.0.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/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # @techsnif/mcp-server
2
+
3
+ MCP server for [TechSnif](https://techsnif.com) — access tech news articles from AI assistants like Claude Desktop, Cursor, and any MCP-compatible client.
4
+
5
+ ## What it does
6
+
7
+ This server gives your AI assistant access to TechSnif's tech news feed. It can:
8
+
9
+ - **Get latest articles** — optionally filtered by category (AI, Startups, Venture, Robotics) or tag (Crypto, Space, EVs, etc.)
10
+ - **Read full articles** — get the complete text of any article
11
+ - **Get trending stories** — see what's hot in the last 48 hours
12
+ - **Search articles** — find articles by keyword
13
+
14
+ ## Setup
15
+
16
+ ### Claude Desktop
17
+
18
+ Add this to your Claude Desktop config file:
19
+
20
+ **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
21
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "techsnif": {
27
+ "command": "npx",
28
+ "args": ["-y", "@techsnif/mcp-server"]
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### Cursor
35
+
36
+ Add this to `.cursor/mcp.json` in your project (or globally):
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "techsnif": {
42
+ "command": "npx",
43
+ "args": ["-y", "@techsnif/mcp-server"]
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Other MCP clients
50
+
51
+ Run the server directly:
52
+
53
+ ```bash
54
+ npx @techsnif/mcp-server
55
+ ```
56
+
57
+ The server uses stdio transport, compatible with any MCP client.
58
+
59
+ ## Available tools
60
+
61
+ | Tool | Description |
62
+ |------|-------------|
63
+ | `get_latest_articles` | Get latest articles with optional category/tag filters |
64
+ | `get_article` | Get full article content by slug |
65
+ | `get_trending_articles` | Get trending articles from the last 48 hours |
66
+ | `search_articles` | Search articles by keyword |
67
+
68
+ ## Available resources
69
+
70
+ | Resource | Description |
71
+ |----------|-------------|
72
+ | `techsnif://categories` | List of all categories with descriptions |
73
+ | `techsnif://tags` | List of all tags with descriptions |
74
+
75
+ ## Example prompts
76
+
77
+ Once connected, try asking your AI assistant:
78
+
79
+ - "What's the latest AI news on TechSnif?"
80
+ - "Search TechSnif for articles about OpenAI"
81
+ - "What's trending in tech right now?"
82
+ - "Get me the full article about [topic]"
83
+ - "Summarize the latest robotics news from TechSnif"
84
+
85
+ ## Configuration
86
+
87
+ Set `TECHSNIF_API_URL` to override the default API base URL (defaults to `https://techsnif.com`):
88
+
89
+ ```json
90
+ {
91
+ "mcpServers": {
92
+ "techsnif": {
93
+ "command": "npx",
94
+ "args": ["-y", "@techsnif/mcp-server"],
95
+ "env": {
96
+ "TECHSNIF_API_URL": "http://localhost:4321"
97
+ }
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ ## License
104
+
105
+ MIT
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * TechSnif MCP Server
4
+ *
5
+ * Exposes TechSnif tech news articles to AI assistants via the
6
+ * Model Context Protocol. Connects to the public techsnif.com API.
7
+ *
8
+ * Tools:
9
+ * - get_latest_articles — fetch latest articles, optionally filtered by category or tag
10
+ * - get_article — get full article content by slug
11
+ * - get_trending_articles — get trending articles from the last 48 hours
12
+ * - search_articles — search articles by keyword
13
+ *
14
+ * Resources:
15
+ * - techsnif://categories — list of all article categories
16
+ * - techsnif://tags — list of all article tags
17
+ */
18
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * TechSnif MCP Server
4
+ *
5
+ * Exposes TechSnif tech news articles to AI assistants via the
6
+ * Model Context Protocol. Connects to the public techsnif.com API.
7
+ *
8
+ * Tools:
9
+ * - get_latest_articles — fetch latest articles, optionally filtered by category or tag
10
+ * - get_article — get full article content by slug
11
+ * - get_trending_articles — get trending articles from the last 48 hours
12
+ * - search_articles — search articles by keyword
13
+ *
14
+ * Resources:
15
+ * - techsnif://categories — list of all article categories
16
+ * - techsnif://tags — list of all article tags
17
+ */
18
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
19
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
20
+ import { z } from 'zod';
21
+ import { CATEGORIES, CATEGORY_NAMES, TAGS, TAG_NAMES } from '@techsnif/shared';
22
+ const BASE_URL = process.env.TECHSNIF_API_URL || 'https://techsnif.com';
23
+ async function apiFetch(path, params) {
24
+ const url = new URL(`${BASE_URL}${path}`);
25
+ if (params) {
26
+ for (const [key, value] of Object.entries(params)) {
27
+ if (value)
28
+ url.searchParams.set(key, value);
29
+ }
30
+ }
31
+ const response = await fetch(url.toString(), {
32
+ headers: { Accept: 'application/json' },
33
+ });
34
+ if (!response.ok) {
35
+ const body = await response.text().catch(() => '');
36
+ throw new Error(`API request failed: ${response.status} ${response.statusText} — ${body}`);
37
+ }
38
+ return response.json();
39
+ }
40
+ /**
41
+ * Strip HTML tags for cleaner AI consumption.
42
+ * Preserves paragraph breaks as double newlines.
43
+ */
44
+ function stripHtml(html) {
45
+ return html
46
+ .replace(/<br\s*\/?>/gi, '\n')
47
+ .replace(/<\/p>/gi, '\n\n')
48
+ .replace(/<[^>]+>/g, '')
49
+ .replace(/&amp;/g, '&')
50
+ .replace(/&lt;/g, '<')
51
+ .replace(/&gt;/g, '>')
52
+ .replace(/&quot;/g, '"')
53
+ .replace(/&#39;/g, "'")
54
+ .replace(/&nbsp;/g, ' ')
55
+ .replace(/\n{3,}/g, '\n\n')
56
+ .trim();
57
+ }
58
+ function formatDate(iso) {
59
+ const d = new Date(iso);
60
+ return d.toLocaleDateString('en-US', {
61
+ weekday: 'short',
62
+ year: 'numeric',
63
+ month: 'short',
64
+ day: 'numeric',
65
+ });
66
+ }
67
+ function articleUrl(article) {
68
+ const d = new Date(article.publishedAt);
69
+ const year = d.getUTCFullYear();
70
+ const month = String(d.getUTCMonth() + 1).padStart(2, '0');
71
+ const day = String(d.getUTCDate()).padStart(2, '0');
72
+ return `${BASE_URL}/${year}/${month}/${day}/${article.slug}`;
73
+ }
74
+ function formatArticleSummary(article) {
75
+ const lines = [
76
+ `## ${article.title}`,
77
+ '',
78
+ article.excerpt,
79
+ '',
80
+ `- **Category:** ${article.category}`,
81
+ ];
82
+ if (article.tags?.length) {
83
+ lines.push(`- **Tags:** ${article.tags.join(', ')}`);
84
+ }
85
+ if (article.sources?.length) {
86
+ lines.push(`- **Sources:** ${article.sources.join(', ')}`);
87
+ }
88
+ lines.push(`- **Published:** ${formatDate(article.publishedAt)}`);
89
+ lines.push(`- **URL:** ${articleUrl(article)}`);
90
+ lines.push(`- **Slug:** ${article.slug}`);
91
+ return lines.join('\n');
92
+ }
93
+ function formatArticleFull(article) {
94
+ const lines = [
95
+ `# ${article.title}`,
96
+ '',
97
+ `> ${article.excerpt}`,
98
+ '',
99
+ stripHtml(article.content),
100
+ '',
101
+ '---',
102
+ '',
103
+ `- **Category:** ${article.category}`,
104
+ ];
105
+ if (article.tags?.length) {
106
+ lines.push(`- **Tags:** ${article.tags.join(', ')}`);
107
+ }
108
+ if (article.sources?.length) {
109
+ lines.push(`- **Sources:** ${article.sources.join(', ')}`);
110
+ }
111
+ if (article.sourceLinks?.length) {
112
+ const links = article.sourceLinks.map(l => `[${l.name}](${l.url})`).join(', ');
113
+ lines.push(`- **Source links:** ${links}`);
114
+ }
115
+ lines.push(`- **Published:** ${formatDate(article.publishedAt)}`);
116
+ lines.push(`- **URL:** ${article.url}`);
117
+ if (article.isSponsored) {
118
+ lines.push(`- **Sponsored:** Yes`);
119
+ }
120
+ return lines.join('\n');
121
+ }
122
+ // ─── MCP Server ──────────────────────────────────────────────
123
+ const server = new McpServer({
124
+ name: 'techsnif',
125
+ version: '1.0.0',
126
+ });
127
+ // ─── Tools ───────────────────────────────────────────────────
128
+ server.tool('get_latest_articles', 'Get the latest tech news articles from TechSnif. Optionally filter by category (AI, Startups, Venture, Robotics) or tag (Crypto, Space, EVs, Biotech, etc.).', {
129
+ category: z.string().optional().describe('Filter by category: AI, Startups, Venture, or Robotics'),
130
+ tag: z.string().optional().describe('Filter by tag (e.g. Crypto, Space, EVs, Biotech, Cloud Computing)'),
131
+ limit: z.number().min(1).max(50).default(10).describe('Number of articles to return (default 10, max 50)'),
132
+ }, async ({ category, tag, limit }) => {
133
+ const params = { limit: String(limit) };
134
+ if (category)
135
+ params.category = category;
136
+ if (tag)
137
+ params.tag = tag;
138
+ const data = await apiFetch('/api/articles', params);
139
+ if (!data.articles.length) {
140
+ const filter = category ? ` in category "${category}"` : tag ? ` tagged "${tag}"` : '';
141
+ return {
142
+ content: [{ type: 'text', text: `No articles found${filter}.` }],
143
+ };
144
+ }
145
+ const header = `Found ${data.total} article${data.total === 1 ? '' : 's'}${category ? ` in ${category}` : tag ? ` tagged ${tag}` : ''}. Showing ${data.articles.length}:\n\n`;
146
+ const formatted = data.articles.map(formatArticleSummary).join('\n\n---\n\n');
147
+ return {
148
+ content: [{ type: 'text', text: header + formatted }],
149
+ };
150
+ });
151
+ server.tool('get_article', 'Get the full content of a specific TechSnif article by its slug. Use this to read the complete article text.', {
152
+ slug: z.string().describe('The article slug (e.g. "openai-announces-gpt-5")'),
153
+ }, async ({ slug }) => {
154
+ const data = await apiFetch(`/api/articles/${encodeURIComponent(slug)}`);
155
+ return {
156
+ content: [{ type: 'text', text: formatArticleFull(data.article) }],
157
+ };
158
+ });
159
+ server.tool('get_trending_articles', 'Get trending tech news articles from the last 48 hours, ranked by how many sources covered the story.', {
160
+ limit: z.number().min(1).max(20).default(5).describe('Number of articles to return (default 5, max 20)'),
161
+ }, async ({ limit }) => {
162
+ const data = await apiFetch('/api/articles/trending', { limit: String(limit) });
163
+ if (!data.articles.length) {
164
+ return {
165
+ content: [{ type: 'text', text: 'No trending articles found in the last 48 hours.' }],
166
+ };
167
+ }
168
+ const header = `Top ${data.articles.length} trending article${data.articles.length === 1 ? '' : 's'}:\n\n`;
169
+ const formatted = data.articles.map((a, i) => `### #${i + 1}\n\n${formatArticleSummary(a)}`).join('\n\n---\n\n');
170
+ return {
171
+ content: [{ type: 'text', text: header + formatted }],
172
+ };
173
+ });
174
+ server.tool('search_articles', 'Search TechSnif articles by keyword. Matches against article titles and excerpts.', {
175
+ query: z.string().min(2).describe('Search query (min 2 characters)'),
176
+ limit: z.number().min(1).max(50).default(10).describe('Max results to return (default 10, max 50)'),
177
+ }, async ({ query, limit }) => {
178
+ const data = await apiFetch('/api/articles/search', { q: query, limit: String(limit) });
179
+ if (!data.articles.length) {
180
+ return {
181
+ content: [{ type: 'text', text: `No articles found matching "${query}".` }],
182
+ };
183
+ }
184
+ const header = `Found ${data.total} article${data.total === 1 ? '' : 's'} matching "${query}":\n\n`;
185
+ const formatted = data.articles
186
+ .map(a => {
187
+ const lines = [
188
+ `## ${a.title}`,
189
+ '',
190
+ a.excerpt,
191
+ '',
192
+ `- **Category:** ${a.category}`,
193
+ `- **Published:** ${formatDate(a.publishedAt)}`,
194
+ `- **URL:** ${articleUrl(a)}`,
195
+ `- **Slug:** ${a.slug}`,
196
+ ];
197
+ return lines.join('\n');
198
+ })
199
+ .join('\n\n---\n\n');
200
+ return {
201
+ content: [{ type: 'text', text: header + formatted }],
202
+ };
203
+ });
204
+ // ─── Resources ───────────────────────────────────────────────
205
+ server.resource('categories', 'techsnif://categories', { description: 'List of all TechSnif article categories with descriptions' }, async () => {
206
+ const lines = CATEGORY_NAMES.map(key => {
207
+ const cat = CATEGORIES[key];
208
+ return [
209
+ `## ${cat.label}`,
210
+ '',
211
+ cat.description,
212
+ '',
213
+ `- **Slug:** ${cat.slug}`,
214
+ `- **URL:** ${BASE_URL}/category/${cat.slug}`,
215
+ ].join('\n');
216
+ });
217
+ return {
218
+ contents: [{
219
+ uri: 'techsnif://categories',
220
+ mimeType: 'text/plain',
221
+ text: `# TechSnif Categories\n\n${lines.join('\n\n---\n\n')}`,
222
+ }],
223
+ };
224
+ });
225
+ server.resource('tags', 'techsnif://tags', { description: 'List of all TechSnif article tags with descriptions' }, async () => {
226
+ const lines = TAG_NAMES.map(key => {
227
+ const tag = TAGS[key];
228
+ return `- **${tag.label}:** ${tag.description}`;
229
+ });
230
+ return {
231
+ contents: [{
232
+ uri: 'techsnif://tags',
233
+ mimeType: 'text/plain',
234
+ text: `# TechSnif Tags\n\n${lines.join('\n')}`,
235
+ }],
236
+ };
237
+ });
238
+ // ─── Start ───────────────────────────────────────────────────
239
+ async function main() {
240
+ const transport = new StdioServerTransport();
241
+ await server.connect(transport);
242
+ }
243
+ main().catch((error) => {
244
+ console.error('Failed to start TechSnif MCP server:', error);
245
+ process.exit(1);
246
+ });
247
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@techsnif/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for TechSnif — access tech news articles from AI assistants like Claude Desktop and Cursor.",
5
+ "type": "module",
6
+ "bin": {
7
+ "techsnif-mcp": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "start": "node dist/index.js"
16
+ },
17
+ "dependencies": {
18
+ "@modelcontextprotocol/sdk": "^1.26.0",
19
+ "@techsnif/shared": "workspace:*",
20
+ "zod": "^3.23.0"
21
+ },
22
+ "devDependencies": {
23
+ "typescript": "^5.7.0"
24
+ },
25
+ "engines": {
26
+ "node": ">=20"
27
+ },
28
+ "license": "MIT",
29
+ "keywords": [
30
+ "mcp",
31
+ "model-context-protocol",
32
+ "techsnif",
33
+ "tech-news",
34
+ "ai",
35
+ "claude",
36
+ "cursor"
37
+ ]
38
+ }