ring-skills-mcp 1.0.4 → 1.0.6

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 (2) hide show
  1. package/dist/index.js +74 -56
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8,7 +8,6 @@ import path from "path";
8
8
  const execAsync = promisify(exec);
9
9
  // Configuration
10
10
  const DEFAULT_API_HOST = process.env.SKILLS_API_HOST || "";
11
- const DEFAULT_SKILLS_REPO = process.env.SKILLS_REPO || "anthropics/skills";
12
11
  const DEFAULT_AUTH_TOKEN = process.env.SKILLS_AUTH_TOKEN || "";
13
12
  // Create MCP server
14
13
  const server = new McpServer({
@@ -52,30 +51,85 @@ async function fetchSkills(host, search = "", pageSize = 5000, token = "") {
52
51
  throw new Error("Failed to fetch Skills list: Unknown error");
53
52
  }
54
53
  }
54
+ function parseGitUrl(gitUrl) {
55
+ // GitHub URL pattern: https://github.com/{owner}/{repo}/tree/{branch}/{path}
56
+ const githubMatch = gitUrl.match(/https?:\/\/github\.com\/([^\/]+)\/([^\/]+)\/tree\/([^\/]+)\/(.+)/);
57
+ if (githubMatch) {
58
+ const skillPath = githubMatch[4];
59
+ const skillName = skillPath.split("/").pop() || "";
60
+ return {
61
+ type: "github",
62
+ host: "github.com",
63
+ owner: githubMatch[1],
64
+ repo: githubMatch[2],
65
+ branch: githubMatch[3],
66
+ skillPath,
67
+ skillName: skillName.toLowerCase(),
68
+ };
69
+ }
70
+ // GitLab URL pattern: https://{host}/{owner}/{repo}/-/tree/{branch}/{path}
71
+ const gitlabMatch = gitUrl.match(/https?:\/\/([^\/]+)\/([^\/]+)\/([^\/]+)\/-\/tree\/([^\/]+)\/(.+)/);
72
+ if (gitlabMatch) {
73
+ const skillPath = gitlabMatch[5];
74
+ const skillName = skillPath.split("/").pop() || "";
75
+ return {
76
+ type: "gitlab",
77
+ host: gitlabMatch[1],
78
+ owner: gitlabMatch[2],
79
+ repo: gitlabMatch[3],
80
+ branch: gitlabMatch[4],
81
+ skillPath,
82
+ skillName: skillName.toLowerCase(),
83
+ };
84
+ }
85
+ // Fallback: try to extract skill name from URL
86
+ const skillMatch = gitUrl.match(/\/skills\/([^\/\s]+)/);
87
+ if (skillMatch) {
88
+ return {
89
+ type: "unknown",
90
+ host: "",
91
+ owner: "",
92
+ repo: "",
93
+ branch: "main",
94
+ skillPath: "",
95
+ skillName: skillMatch[1].toLowerCase(),
96
+ };
97
+ }
98
+ return null;
99
+ }
55
100
  /**
56
- * Extract skill name from gitUrl
57
- * Example: "https://github.com/anthropics/skills/tree/main/skills/webapp-testing" -> "webapp-testing"
101
+ * Build degit source path from git URL info
58
102
  */
59
- function extractSkillNameFromGitUrl(gitUrl) {
60
- // Match pattern: .../skills/{skill-name} or .../skills/{skill-name}/...
61
- const match = gitUrl.match(/\/skills\/([^\/\s]+)/);
62
- return match ? match[1].toLowerCase() : null;
103
+ function buildDegitSource(urlInfo) {
104
+ if (urlInfo.type === "github") {
105
+ // GitHub: owner/repo/path#branch
106
+ return `${urlInfo.owner}/${urlInfo.repo}/${urlInfo.skillPath}#${urlInfo.branch}`;
107
+ }
108
+ else if (urlInfo.type === "gitlab") {
109
+ // GitLab (self-hosted): host:owner/repo/path#branch
110
+ return `${urlInfo.host}:${urlInfo.owner}/${urlInfo.repo}/${urlInfo.skillPath}#${urlInfo.branch}`;
111
+ }
112
+ return "";
63
113
  }
64
114
  /**
65
- * Install Skill to specified project
115
+ * Install Skill to specified project using gitUrl
66
116
  */
67
- async function installSkill(skillName, projectPath, targetDir = ".claude/skills", repo = DEFAULT_SKILLS_REPO) {
68
- // Convert skill name to lowercase
69
- const normalizedName = skillName.toLowerCase();
70
- // Build full installation path
71
- const destPath = path.join(projectPath, targetDir, normalizedName);
72
- // Build degit command
73
- const sourcePath = `${repo}/skills/${normalizedName}`;
117
+ async function installSkillFromGitUrl(gitUrl, projectPath, targetDir = ".claude/skills") {
118
+ const urlInfo = parseGitUrl(gitUrl);
119
+ if (!urlInfo) {
120
+ throw new Error(`Could not parse git URL: ${gitUrl}`);
121
+ }
122
+ const skillName = urlInfo.skillName;
123
+ const destPath = path.join(projectPath, targetDir, skillName);
124
+ const sourcePath = buildDegitSource(urlInfo);
125
+ if (!sourcePath) {
126
+ throw new Error(`Could not build degit source from URL: ${gitUrl}`);
127
+ }
74
128
  const command = `npx degit ${sourcePath} ${destPath}`;
75
129
  try {
76
130
  const { stdout, stderr } = await execAsync(command);
77
131
  const output = stdout || stderr || "Installation completed";
78
- return `✅ Skill "${normalizedName}" has been successfully installed to ${destPath}\n${output}`;
132
+ return `✅ Skill "${skillName}" has been successfully installed to ${destPath}\n\nSource: ${sourcePath}\n${output}`;
79
133
  }
80
134
  catch (error) {
81
135
  if (error instanceof Error) {
@@ -154,9 +208,8 @@ server.tool("list_skills", "Fetch company Skills list. You can search for specif
154
208
  }
155
209
  });
156
210
  // Register tool: Install Skill
157
- server.tool("install_skill", "Install skill to local project by skill name or gitUrl. Uses npx degit to download skill template from remote repository. Project path is required, which can be the project path of the currently opened file in IDE.", {
158
- skillName: z.string().optional().describe("Name of the skill to install (e.g., 'webapp-testing'). Either skillName or gitUrl must be provided."),
159
- gitUrl: z.string().optional().describe("Git URL of the skill (e.g., 'https://github.com/anthropics/skills/tree/main/skills/webapp-testing'). The skill name will be extracted from this URL. Either skillName or gitUrl must be provided."),
211
+ server.tool("install_skill", "Install skill to local project by gitUrl. Uses npx degit to download skill template from remote repository. Project path is required, which can be the project path of the currently opened file in IDE.", {
212
+ gitUrl: z.string().describe("Git URL of the skill (e.g., 'https://github.com/anthropics/skills/tree/main/skills/webapp-testing'). The skill name will be extracted from this URL."),
160
213
  projectPath: z
161
214
  .string()
162
215
  .optional()
@@ -165,11 +218,7 @@ server.tool("install_skill", "Install skill to local project by skill name or gi
165
218
  .string()
166
219
  .optional()
167
220
  .describe("Installation target directory, default: .claude/skills"),
168
- repo: z
169
- .string()
170
- .optional()
171
- .describe(`Skills repository path, default: ${DEFAULT_SKILLS_REPO}`),
172
- }, async ({ skillName, gitUrl, projectPath, targetDir, repo }) => {
221
+ }, async ({ gitUrl, projectPath, targetDir }) => {
173
222
  // Check if project path is provided
174
223
  if (!projectPath) {
175
224
  return {
@@ -182,39 +231,8 @@ server.tool("install_skill", "Install skill to local project by skill name or gi
182
231
  isError: true,
183
232
  };
184
233
  }
185
- // Determine the actual skill name to use
186
- let actualSkillName = null;
187
- // Priority: gitUrl > skillName
188
- if (gitUrl) {
189
- actualSkillName = extractSkillNameFromGitUrl(gitUrl);
190
- if (!actualSkillName) {
191
- return {
192
- content: [
193
- {
194
- type: "text",
195
- text: `❌ Error: Could not extract skill name from gitUrl: ${gitUrl}\n\nExpected format: https://github.com/org/repo/tree/main/skills/{skill-name}`,
196
- },
197
- ],
198
- isError: true,
199
- };
200
- }
201
- }
202
- else if (skillName) {
203
- actualSkillName = skillName;
204
- }
205
- if (!actualSkillName) {
206
- return {
207
- content: [
208
- {
209
- type: "text",
210
- text: "❌ Error: Either skillName or gitUrl must be provided.",
211
- },
212
- ],
213
- isError: true,
214
- };
215
- }
216
234
  try {
217
- const result = await installSkill(actualSkillName, projectPath, targetDir || ".claude/skills", repo || DEFAULT_SKILLS_REPO);
235
+ const result = await installSkillFromGitUrl(gitUrl, projectPath, targetDir || ".claude/skills");
218
236
  return {
219
237
  content: [
220
238
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ring-skills-mcp",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "MCP service for fetching and installing company Skills",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",