findskills-mcp 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.
Files changed (5) hide show
  1. package/README.md +88 -0
  2. package/api.js +36 -0
  3. package/bin.js +3 -0
  4. package/package.json +34 -0
  5. package/server.js +82 -0
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # findskills-mcp
2
+
3
+ MCP Server for [FindSkills](https://findskills.org) — search and discover 15,000+ AI Agent Skills via the [Model Context Protocol](https://modelcontextprotocol.io).
4
+
5
+ ## Quick Start
6
+
7
+ ### Claude Desktop
8
+
9
+ Add to `claude_desktop_config.json`:
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "findskills": {
15
+ "command": "npx",
16
+ "args": ["-y", "findskills-mcp"]
17
+ }
18
+ }
19
+ }
20
+ ```
21
+
22
+ ### Claude Code
23
+
24
+ ```bash
25
+ claude mcp add findskills -- npx -y findskills-mcp
26
+ ```
27
+
28
+ ### Other MCP Clients
29
+
30
+ ```bash
31
+ npx findskills-mcp
32
+ ```
33
+
34
+ The server communicates over stdio using the MCP protocol.
35
+
36
+ ## Tools
37
+
38
+ | Tool | Description |
39
+ |------|-------------|
40
+ | `search_skills` | Search by keyword, ranked by relevance |
41
+ | `list_skills` | Browse/filter by category, source, safety, quality |
42
+ | `get_skill` | Full details for a specific skill |
43
+ | `get_stats` | Dataset overview (total count, distributions) |
44
+ | `list_tags` | All tags with usage counts |
45
+
46
+ ### search_skills
47
+
48
+ | Parameter | Type | Required | Description |
49
+ |-----------|------|----------|-------------|
50
+ | `query` | string | yes | Search keyword |
51
+ | `limit` | number | no | Max results (default 20, max 100) |
52
+
53
+ ### list_skills
54
+
55
+ | Parameter | Type | Required | Description |
56
+ |-----------|------|----------|-------------|
57
+ | `category` | enum | no | One of: search, coding, data, communication, media, automation, security, ai-ml, devops, finance, productivity, integration, other |
58
+ | `source` | enum | no | clawhub, github, manual |
59
+ | `auth_type` | enum | no | none, api_key, oauth2, bearer |
60
+ | `sort` | enum | no | updated, added, stars, quality, safety, name |
61
+ | `min_quality` | number | no | Minimum quality score (0-100) |
62
+ | `min_safety` | number | no | Minimum safety score (0-100) |
63
+ | `limit` | number | no | Results per page (default 20) |
64
+ | `offset` | number | no | Pagination offset |
65
+
66
+ ### get_skill
67
+
68
+ | Parameter | Type | Required | Description |
69
+ |-----------|------|----------|-------------|
70
+ | `id` | string | yes | Skill ID |
71
+
72
+ ### get_stats
73
+
74
+ No parameters.
75
+
76
+ ### list_tags
77
+
78
+ | Parameter | Type | Required | Description |
79
+ |-----------|------|----------|-------------|
80
+ | `limit` | number | no | Max tags (default 50) |
81
+
82
+ ## Requirements
83
+
84
+ - Node.js >= 20.0.0
85
+
86
+ ## License
87
+
88
+ MIT
package/api.js ADDED
@@ -0,0 +1,36 @@
1
+ const BASE = 'https://findskills.org/api/v1';
2
+
3
+ async function request(path) {
4
+ const res = await fetch(`${BASE}${path}`, { redirect: 'follow' });
5
+ if (!res.ok) throw new Error(`FindSkills API error: ${res.status} ${res.statusText}`);
6
+ return res.json();
7
+ }
8
+
9
+ export async function searchSkills(query, limit = 20) {
10
+ return request(`/search?q=${encodeURIComponent(query)}&limit=${limit}`);
11
+ }
12
+
13
+ export async function listSkills({ category, source, auth_type, sort, min_quality, min_safety, limit = 20, offset = 0 } = {}) {
14
+ const params = new URLSearchParams();
15
+ params.set('limit', String(limit));
16
+ params.set('offset', String(offset));
17
+ if (category) params.set('category', category);
18
+ if (source) params.set('source', source);
19
+ if (auth_type) params.set('auth_type', auth_type);
20
+ if (sort) params.set('sort', sort);
21
+ if (min_quality != null) params.set('min_quality', String(min_quality));
22
+ if (min_safety != null) params.set('min_safety', String(min_safety));
23
+ return request(`/skills?${params}`);
24
+ }
25
+
26
+ export async function getSkill(id) {
27
+ return request(`/skills/${encodeURIComponent(id)}`);
28
+ }
29
+
30
+ export async function getStats() {
31
+ return request('/stats');
32
+ }
33
+
34
+ export async function listTags(limit = 50) {
35
+ return request(`/tags?limit=${limit}`);
36
+ }
package/bin.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { startServer } from './server.js';
3
+ startServer();
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "findskills-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP Server for FindSkills — search and discover 15,000+ AI Agent Skills",
5
+ "type": "module",
6
+ "bin": {
7
+ "findskills-mcp": "bin.js"
8
+ },
9
+ "files": [
10
+ "bin.js",
11
+ "server.js",
12
+ "api.js"
13
+ ],
14
+ "engines": {
15
+ "node": ">=20.0.0"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "ai",
20
+ "agent",
21
+ "skills",
22
+ "findskills",
23
+ "model-context-protocol"
24
+ ],
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/shintemy/findskills.git"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.27.0",
32
+ "zod": "^3.24.0"
33
+ }
34
+ }
package/server.js ADDED
@@ -0,0 +1,82 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ import { searchSkills, listSkills, getSkill, getStats, listTags } from './api.js';
5
+
6
+ function text(content) {
7
+ return { content: [{ type: 'text', text: typeof content === 'string' ? content : JSON.stringify(content, null, 2) }] };
8
+ }
9
+
10
+ export function createServer() {
11
+ const server = new McpServer({ name: 'findskills', version: '0.1.0' });
12
+
13
+ server.registerTool('search_skills', {
14
+ title: 'Search Skills',
15
+ description: 'Search FindSkills directory by keyword. Returns skills ranked by relevance.',
16
+ inputSchema: {
17
+ query: z.string().describe('Search keyword (e.g. "web scraping", "slack", "database")'),
18
+ limit: z.number().int().min(1).max(100).default(20).describe('Max results (default 20)'),
19
+ },
20
+ }, async ({ query, limit }) => {
21
+ const data = await searchSkills(query, limit);
22
+ return text(data);
23
+ });
24
+
25
+ server.registerTool('list_skills', {
26
+ title: 'List Skills',
27
+ description: 'Browse and filter skills by category, source, safety tier, and more. Supports pagination.',
28
+ inputSchema: {
29
+ category: z.enum(['search', 'coding', 'data', 'communication', 'media', 'automation', 'security', 'ai-ml', 'devops', 'finance', 'productivity', 'integration', 'other']).optional().describe('Filter by category'),
30
+ source: z.enum(['clawhub', 'github', 'manual']).optional().describe('Filter by data source'),
31
+ auth_type: z.enum(['none', 'api_key', 'oauth2', 'bearer']).optional().describe('Filter by auth requirement'),
32
+ sort: z.enum(['updated', 'added', 'stars', 'quality', 'safety', 'name']).default('updated').describe('Sort order'),
33
+ min_quality: z.number().int().min(0).max(100).optional().describe('Minimum quality score (0-100)'),
34
+ min_safety: z.number().int().min(0).max(100).optional().describe('Minimum safety score (0-100)'),
35
+ limit: z.number().int().min(1).max(100).default(20).describe('Results per page'),
36
+ offset: z.number().int().min(0).default(0).describe('Pagination offset'),
37
+ },
38
+ }, async (params) => {
39
+ const data = await listSkills(params);
40
+ return text(data);
41
+ });
42
+
43
+ server.registerTool('get_skill', {
44
+ title: 'Get Skill Details',
45
+ description: 'Get full details for a specific skill including auth requirements, safety signals, and quality signals.',
46
+ inputSchema: {
47
+ id: z.string().describe('Skill ID (e.g. "clawhub-web-search")'),
48
+ },
49
+ }, async ({ id }) => {
50
+ const data = await getSkill(id);
51
+ return text(data);
52
+ });
53
+
54
+ server.registerTool('get_stats', {
55
+ title: 'Get Dataset Stats',
56
+ description: 'Get FindSkills dataset overview: total skill count, category/source/auth breakdowns, quality and safety distributions. Call this first to understand the dataset.',
57
+ inputSchema: {},
58
+ }, async () => {
59
+ const data = await getStats();
60
+ return text(data);
61
+ });
62
+
63
+ server.registerTool('list_tags', {
64
+ title: 'List Tags',
65
+ description: 'List all skill tags with usage counts, sorted by popularity.',
66
+ inputSchema: {
67
+ limit: z.number().int().min(1).max(500).default(50).describe('Max tags to return'),
68
+ },
69
+ }, async ({ limit }) => {
70
+ const data = await listTags(limit);
71
+ return text(data);
72
+ });
73
+
74
+ return server;
75
+ }
76
+
77
+ export async function startServer() {
78
+ const server = createServer();
79
+ const transport = new StdioServerTransport();
80
+ await server.connect(transport);
81
+ console.error('FindSkills MCP Server running on stdio');
82
+ }