skillsmp-mcp-lite 1.0.0 → 1.0.2

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 CHANGED
@@ -1,114 +1,143 @@
1
- # SkillsMP MCP Server
1
+ # SkillsMP MCP Server (Lite)
2
2
 
3
- An MCP (Model Context Protocol) server that enables AI assistants to search for skills from [SkillsMP](https://skillsmp.com) marketplace before starting any task.
3
+ A lightweight MCP server that enables AI assistants to search for skills from [SkillsMP](https://skillsmp.com) marketplace before starting any task.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - **Keyword Search**: Search skills using specific keywords like "PDF", "web scraper", "SEO"
8
8
  - **AI Semantic Search**: Find skills using natural language descriptions powered by Cloudflare AI
9
9
 
10
- ## Installation
10
+ ## Quick Setup
11
11
 
12
- ```bash
13
- npm install
14
- npm run build
15
- ```
16
-
17
- ## Configuration
12
+ No installation required! Just add the config to your AI client.
18
13
 
19
- ### Environment Variables
14
+ ### VS Code / GitHub Copilot
20
15
 
21
- | Variable | Required | Description |
22
- | ------------------ | -------- | --------------------- |
23
- | `SKILLSMP_API_KEY` | Yes | Your SkillsMP API key |
16
+ Add to your VS Code `mcp.json` (open with: `Ctrl+Shift+P` → "MCP: Open User Configuration"):
24
17
 
25
- Get your API key from: https://skillsmp.com/docs/api
18
+ ```json
19
+ {
20
+ "servers": {
21
+ "skillsmp": {
22
+ "type": "stdio",
23
+ "command": "npx",
24
+ "args": ["-y", "skillsmp-mcp-lite"],
25
+ "env": {
26
+ "SKILLSMP_API_KEY": "YOUR_API_KEY"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ ```
26
32
 
27
- ### VS Code / Cursor Setup
33
+ ### Cursor
28
34
 
29
- Add to your `settings.json`:
35
+ Add to `~/.cursor/mcp.json`:
30
36
 
31
37
  ```json
32
38
  {
33
- "mcp": {
34
- "servers": {
35
- "skillsmp": {
36
- "command": "node",
37
- "args": ["path/to/skillsmp-mcp-server/dist/index.js"],
38
- "env": {
39
- "SKILLSMP_API_KEY": "sk_live_skillsmp_YOUR_API_KEY"
40
- }
39
+ "mcpServers": {
40
+ "skillsmp": {
41
+ "command": "npx",
42
+ "args": ["-y", "skillsmp-mcp-lite"],
43
+ "env": {
44
+ "SKILLSMP_API_KEY": "YOUR_API_KEY"
41
45
  }
42
46
  }
43
47
  }
44
48
  }
45
49
  ```
46
50
 
47
- ### Claude Desktop Setup
51
+ ### Claude Desktop
48
52
 
49
53
  Add to your `claude_desktop_config.json`:
50
54
 
55
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
56
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
57
+
51
58
  ```json
52
59
  {
53
60
  "mcpServers": {
54
61
  "skillsmp": {
55
- "command": "node",
56
- "args": ["/absolute/path/to/skillsmp-mcp-server/dist/index.js"],
62
+ "command": "npx",
63
+ "args": ["-y", "skillsmp-mcp-lite"],
57
64
  "env": {
58
- "SKILLSMP_API_KEY": "sk_live_skillsmp_YOUR_API_KEY"
65
+ "SKILLSMP_API_KEY": "YOUR_API_KEY"
59
66
  }
60
67
  }
61
68
  }
62
69
  }
63
70
  ```
64
71
 
72
+ ### Claude Code
73
+
74
+ ```bash
75
+ claude mcp add skillsmp -- npx -y skillsmp-mcp-lite --env SKILLSMP_API_KEY=YOUR_API_KEY
76
+ ```
77
+
78
+ ## Get Your API Key
79
+
80
+ Get your API key from: https://skillsmp.com/docs/api
81
+
82
+ > **Note**: The API key is optional. Without it, you may encounter rate limits.
83
+
65
84
  ## Available Tools
66
85
 
67
86
  ### `skillsmp_search_skills`
68
87
 
69
88
  Search for skills using keywords.
70
89
 
71
- **Parameters:**
90
+ | Parameter | Type | Required | Description |
91
+ |-----------|------|----------|-------------|
92
+ | `query` | string | Yes | Search keywords |
93
+ | `page` | number | No | Page number (default: 1) |
94
+ | `limit` | number | No | Items per page (default: 20, max: 100) |
95
+ | `sortBy` | string | No | Sort by "stars" or "recent" |
72
96
 
73
- - `query` (string, required): Search keywords
74
- - `page` (number, optional): Page number (default: 1)
75
- - `limit` (number, optional): Items per page (default: 20, max: 100)
76
- - `sortBy` (string, optional): Sort by "stars" or "recent"
97
+ ### `skillsmp_ai_search_skills`
77
98
 
78
- **Example:**
99
+ AI semantic search for skills using natural language.
79
100
 
80
- ```
81
- Search for "PDF manipulation" skills
82
- ```
101
+ | Parameter | Type | Required | Description |
102
+ |-----------|------|----------|-------------|
103
+ | `query` | string | Yes | Natural language description |
83
104
 
84
- ### `skillsmp_ai_search_skills`
105
+ ### `skillsmp_install_and_read_skill`
85
106
 
86
- AI semantic search for skills using natural language.
107
+ Install a skill from GitHub and immediately read its content.
87
108
 
88
- **Parameters:**
109
+ | Parameter | Type | Required | Description |
110
+ |-----------|------|----------|-------------|
111
+ | `repo` | string | Yes | GitHub repository in 'owner/repo' format |
112
+ | `skillName` | string | Yes | Name of the skill to read after installation |
113
+ | `global` | boolean | No | Install globally to ~/.claude/skills/ (default: false) |
114
+ | `universal` | boolean | No | Install to .agent/skills/ for universal usage (default: false) |
89
115
 
90
- - `query` (string, required): Natural language description of what you want to accomplish
116
+ ## Usage Examples
91
117
 
92
- **Example:**
118
+ Ask your AI assistant:
93
119
 
94
- ```
95
- Find skills for "How to create a web scraper that extracts product data"
96
- ```
120
+ - "Search for PDF manipulation skills"
121
+ - "Find skills for building a web scraper"
122
+ - "What skills can help me with SEO optimization?"
123
+ - "Install and load the python-code-review skill from existential-birds/beagle"
97
124
 
98
- ## Usage Workflow
125
+ ## AGENTS.md Integration
99
126
 
100
- The recommended workflow is:
127
+ To enable automatic skill discovery, copy the content from [`AGENTS.example.md`](./AGENTS.example.md) and paste it at the top of your `AGENTS.md` file.
101
128
 
102
- 1. **Before starting any task**, search for relevant skills
103
- 2. If a matching skill is found, use `npx openskills read <skill-name>` to load it
104
- 3. Follow the skill's instructions to complete the task
129
+ ### How It Works
105
130
 
106
- ## API Reference
131
+ 1. AI receives a complex task
132
+ 2. AI searches SkillsMP for relevant skills using `skillsmp_search_skills`
133
+ 3. If keyword search is insufficient, AI tries `skillsmp_ai_search_skills`
134
+ 4. If a relevant skill is found, AI installs and reads it with `skillsmp_install_and_read_skill`
135
+ 5. AI follows the skill's instructions to complete the task
107
136
 
108
- This server uses the SkillsMP REST API:
137
+ ### Search Tips
109
138
 
110
- - `GET /api/v1/skills/search` - Keyword search
111
- - `GET /api/v1/skills/ai-search` - AI semantic search
139
+ - **Keyword search**: Keep queries short (1-3 words). Example: `"code review"`, `"typescript"`, `"pdf"`
140
+ - **Semantic search**: Use natural language. Example: `"how to build a landing page with React"`
112
141
 
113
142
  ## License
114
143
 
package/dist/schemas.d.ts CHANGED
@@ -31,3 +31,20 @@ export declare const AISearchSchema: z.ZodObject<{
31
31
  query: string;
32
32
  }>;
33
33
  export type AISearchInput = z.infer<typeof AISearchSchema>;
34
+ export declare const InstallAndReadSchema: z.ZodObject<{
35
+ repo: z.ZodString;
36
+ skillName: z.ZodString;
37
+ global: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
38
+ universal: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
39
+ }, "strict", z.ZodTypeAny, {
40
+ repo: string;
41
+ skillName: string;
42
+ global: boolean;
43
+ universal: boolean;
44
+ }, {
45
+ repo: string;
46
+ skillName: string;
47
+ global?: boolean | undefined;
48
+ universal?: boolean | undefined;
49
+ }>;
50
+ export type InstallAndReadInput = z.infer<typeof InstallAndReadSchema>;
package/dist/schemas.js CHANGED
@@ -36,3 +36,21 @@ export const AISearchSchema = z.object({
36
36
  .max(500, "Query must not exceed 500 characters")
37
37
  .describe("Natural language description of what you want to accomplish")
38
38
  }).strict();
39
+ // Install and Read Skill Schema
40
+ export const InstallAndReadSchema = z.object({
41
+ repo: z.string()
42
+ .min(1, "Repository is required")
43
+ .regex(/^[^/]+\/[^/]+$/, "Repository must be in 'owner/repo' format")
44
+ .describe("GitHub repository in 'owner/repo' format (e.g., 'existential-birds/beagle')"),
45
+ skillName: z.string()
46
+ .min(1, "Skill name is required")
47
+ .describe("Name of the skill to read after installation"),
48
+ global: z.boolean()
49
+ .optional()
50
+ .default(false)
51
+ .describe("Install globally to ~/.claude/skills/ (default: false, installs to project)"),
52
+ universal: z.boolean()
53
+ .optional()
54
+ .default(false)
55
+ .describe("Install to .agent/skills/ for universal AGENTS.md usage (default: false)")
56
+ }).strict();
@@ -1,5 +1,8 @@
1
+ import { exec } from "child_process";
2
+ import { promisify } from "util";
1
3
  import { makeApiRequest, handleApiError, validateSearchResponse, validateAISearchResponse } from "../api.js";
2
- import { KeywordSearchSchema, AISearchSchema } from "../schemas.js";
4
+ import { KeywordSearchSchema, AISearchSchema, InstallAndReadSchema } from "../schemas.js";
5
+ const execAsync = promisify(exec);
3
6
  /**
4
7
  * Register SkillsMP tools on the MCP server
5
8
  */
@@ -144,6 +147,115 @@ Examples:
144
147
  };
145
148
  }
146
149
  });
150
+ // Tool 3: Install and Read Skill
151
+ server.registerTool("skillsmp_install_and_read_skill", {
152
+ title: "Install and Read Skill",
153
+ description: `Install a skill from GitHub and immediately read its content.
154
+
155
+ This tool first checks if the skill is already installed locally. If found, it skips installation and directly reads the content (faster). If not found, it installs from GitHub first.
156
+
157
+ **IMPORTANT**: Use this to quickly load skill instructions without manual steps.
158
+
159
+ Args:
160
+ - repo (string, required): GitHub repository in 'owner/repo' format
161
+ - skillName (string, required): Name of the skill to read after installation
162
+ - global (boolean, optional): Install globally to ~/.claude/skills/ (default: false)
163
+ - universal (boolean, optional): Install to .agent/skills/ for universal usage (default: false)
164
+
165
+ Returns:
166
+ The full content of the skill's instructions (SKILL.md).
167
+
168
+ Examples:
169
+ - repo: "existential-birds/beagle", skillName: "python-code-review"
170
+ - repo: "LA3D/skillhelper", skillName: "code-reviewer"`,
171
+ inputSchema: InstallAndReadSchema,
172
+ annotations: {
173
+ readOnlyHint: false,
174
+ destructiveHint: false,
175
+ idempotentHint: true,
176
+ openWorldHint: true
177
+ }
178
+ }, async (params) => {
179
+ try {
180
+ const readCmd = `npx -y openskills read ${params.skillName}`;
181
+ // Step 1: Check if skill already exists locally
182
+ let skillExists = false;
183
+ try {
184
+ const { stdout } = await execAsync(readCmd, { timeout: 30000 });
185
+ if (stdout && !stdout.includes("not found") && !stdout.includes("Error")) {
186
+ skillExists = true;
187
+ const output = formatInstallAndReadResponse(params.repo, params.skillName, stdout, true);
188
+ return {
189
+ content: [{ type: "text", text: output }],
190
+ structuredContent: {
191
+ repo: params.repo,
192
+ skillName: params.skillName,
193
+ skillContent: stdout,
194
+ wasAlreadyInstalled: true
195
+ }
196
+ };
197
+ }
198
+ }
199
+ catch {
200
+ // Skill not found locally, proceed with installation
201
+ skillExists = false;
202
+ }
203
+ // Step 2: Install if not exists
204
+ const installFlags = ["-y"];
205
+ if (params.global)
206
+ installFlags.push("--global");
207
+ if (params.universal)
208
+ installFlags.push("--universal");
209
+ const installCmd = `npx -y openskills install ${params.repo} ${installFlags.join(" ")}`;
210
+ let installOutput;
211
+ try {
212
+ const { stdout, stderr } = await execAsync(installCmd, { timeout: 120000 });
213
+ installOutput = stdout || stderr;
214
+ }
215
+ catch (installError) {
216
+ const error = installError;
217
+ return {
218
+ content: [{
219
+ type: "text",
220
+ text: `❌ **Installation Failed**\n\nRepository: ${params.repo}\n\nError:\n${error.stderr || error.message || "Unknown error"}`
221
+ }]
222
+ };
223
+ }
224
+ // Step 3: Read the skill after installation
225
+ let readOutput;
226
+ try {
227
+ const { stdout, stderr } = await execAsync(readCmd, { timeout: 30000 });
228
+ readOutput = stdout || stderr;
229
+ }
230
+ catch (readError) {
231
+ const error = readError;
232
+ return {
233
+ content: [{
234
+ type: "text",
235
+ text: `✅ **Installation Succeeded** but **Read Failed**\n\nRepository: ${params.repo}\nSkill: ${params.skillName}\n\n**Install Output:**\n${installOutput}\n\n**Read Error:**\n${error.stderr || error.message || "Skill not found"}\n\n💡 **Tip**: Check if the skill name is correct. Use \`npx openskills list\` to see installed skills.`
236
+ }]
237
+ };
238
+ }
239
+ const output = formatInstallAndReadResponse(params.repo, params.skillName, readOutput, false);
240
+ return {
241
+ content: [{ type: "text", text: output }],
242
+ structuredContent: {
243
+ repo: params.repo,
244
+ skillName: params.skillName,
245
+ skillContent: readOutput,
246
+ wasAlreadyInstalled: false
247
+ }
248
+ };
249
+ }
250
+ catch (error) {
251
+ return {
252
+ content: [{
253
+ type: "text",
254
+ text: `❌ **Error**: ${error instanceof Error ? error.message : "An unexpected error occurred"}`
255
+ }]
256
+ };
257
+ }
258
+ });
147
259
  }
148
260
  /**
149
261
  * Render a single skill as markdown lines
@@ -205,6 +317,24 @@ function formatAISearchResponse(skills, query) {
205
317
  ""
206
318
  ];
207
319
  skills.forEach((skill, i) => lines.push(...renderSkill(skill, i)));
208
- lines.push("💡 **Tip**: Use `npx openskills read <skill-name>` to load a skill's detailed instructions.");
320
+ lines.push("💡 **Tip**: Use `skillsmp_install_and_read_skill` to install and load a skill's instructions.");
321
+ return lines.join("\n");
322
+ }
323
+ /**
324
+ * Format install and read response as markdown
325
+ */
326
+ function formatInstallAndReadResponse(repo, skillName, skillContent, wasAlreadyInstalled) {
327
+ const statusIcon = wasAlreadyInstalled ? "📖" : "📦";
328
+ const statusText = wasAlreadyInstalled ? "Skill Loaded (already installed)" : "Skill Installed & Loaded";
329
+ const lines = [
330
+ `# ${statusIcon} ${statusText}: ${skillName}`,
331
+ "",
332
+ `**Repository**: ${repo}`,
333
+ wasAlreadyInstalled ? "**Status**: ⚡ Loaded from local cache (skipped installation)" : "**Status**: ✅ Freshly installed",
334
+ "",
335
+ "---",
336
+ "",
337
+ skillContent
338
+ ];
209
339
  return lines.join("\n");
210
340
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillsmp-mcp-lite",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Lightweight MCP server for searching AI skills from SkillsMP before starting any task",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",