ring-skills-mcp 1.3.2 → 1.3.4
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 +78 -0
- package/dist/index.js +46 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@ An MCP (Model Context Protocol) service for fetching and installing company Skil
|
|
|
7
7
|
- **list_skills** - Fetch company Skills and Skill Groups list, supports search and pagination
|
|
8
8
|
- **install_skill** - Install skill to local project by gitUrl (supports GitHub and GitLab)
|
|
9
9
|
- **install_skill_group** - Install all skills from a skill group to local project
|
|
10
|
+
- **check_gitlab_credentials** - Check if GitLab credentials are configured for a host
|
|
11
|
+
- **setup_gitlab_credentials** - Configure GitLab credentials for private repository access
|
|
10
12
|
|
|
11
13
|
## Installation
|
|
12
14
|
|
|
@@ -110,6 +112,8 @@ Install the specified skill to local project by gitUrl.
|
|
|
110
112
|
- `gitUrl` (required): Git URL of the skill. Supports both GitHub and GitLab URLs.
|
|
111
113
|
- `projectPath` (required): Project path where the skill will be installed. Please provide the project root directory path of the currently opened file in IDE
|
|
112
114
|
- `targetDir` (optional): Installation target directory, default is `.claude/skills`
|
|
115
|
+
- `gitToken` (optional): GitLab Personal Access Token for private repository authentication. If provided, will be saved for future use.
|
|
116
|
+
- `saveCredentials` (optional): Whether to save the token for future use. Default: true
|
|
113
117
|
|
|
114
118
|
**Supported URL Formats:**
|
|
115
119
|
|
|
@@ -131,6 +135,7 @@ https://git.ringcentral.com/ai-testing/aiter-skills/-/tree/main/.agent/skills/no
|
|
|
131
135
|
```
|
|
132
136
|
Install skill from GitHub URL to /Users/xxx/my-project
|
|
133
137
|
Install skill from GitLab URL to /Users/xxx/my-project
|
|
138
|
+
Install skill from private GitLab with token: gitToken=glpat-xxxx
|
|
134
139
|
```
|
|
135
140
|
|
|
136
141
|
### install_skill_group
|
|
@@ -143,6 +148,7 @@ Install all skills from a skill group to local project.
|
|
|
143
148
|
- `token` (optional): Authorization token, can be passed as parameter or set via environment variable `SKILLS_AUTH_TOKEN`
|
|
144
149
|
- `projectPath` (required): Project path where the skills will be installed
|
|
145
150
|
- `targetDir` (optional): Installation target directory, default is `.claude/skills`
|
|
151
|
+
- `gitToken` (optional): GitLab Personal Access Token for private repository authentication
|
|
146
152
|
|
|
147
153
|
**Example usage:**
|
|
148
154
|
```
|
|
@@ -154,6 +160,78 @@ Install all skills from skill group "697190fc88f4e586fb1a7114" to /Users/xxx/my-
|
|
|
154
160
|
- Lists all successfully installed skills
|
|
155
161
|
- Reports any installation errors
|
|
156
162
|
|
|
163
|
+
### check_gitlab_credentials
|
|
164
|
+
|
|
165
|
+
Check if GitLab credentials are already configured for a host.
|
|
166
|
+
|
|
167
|
+
**Parameters:**
|
|
168
|
+
- `host` (required): GitLab host domain to check (e.g., 'git.ringcentral.com')
|
|
169
|
+
|
|
170
|
+
**Example usage:**
|
|
171
|
+
```
|
|
172
|
+
check_gitlab_credentials:
|
|
173
|
+
host: git.ringcentral.com
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Returns:**
|
|
177
|
+
- ✅ Credentials configured - if credentials exist
|
|
178
|
+
- ⚠️ No credentials found - if credentials need to be configured
|
|
179
|
+
|
|
180
|
+
### setup_gitlab_credentials
|
|
181
|
+
|
|
182
|
+
Configure GitLab credentials for private repository access. The token will be saved to your system's git credential store.
|
|
183
|
+
|
|
184
|
+
**Parameters:**
|
|
185
|
+
- `host` (required): GitLab host domain (e.g., 'git.ringcentral.com')
|
|
186
|
+
- `token` (required): GitLab Personal Access Token with 'read_repository' scope
|
|
187
|
+
- `force` (optional): Force overwrite even if credentials already exist. Default: false
|
|
188
|
+
|
|
189
|
+
**How to create a Personal Access Token:**
|
|
190
|
+
1. Open `https://{host}/-/user_settings/personal_access_tokens`
|
|
191
|
+
2. Login to your GitLab account
|
|
192
|
+
3. Create a new Token:
|
|
193
|
+
- Token name: `ring-skills-mcp`
|
|
194
|
+
- Expiration: Select a date (recommended: 1 year)
|
|
195
|
+
- Scopes: Check `read_repository`
|
|
196
|
+
4. Click "Create personal access token"
|
|
197
|
+
5. Copy the generated Token
|
|
198
|
+
|
|
199
|
+
**Example usage:**
|
|
200
|
+
```
|
|
201
|
+
setup_gitlab_credentials:
|
|
202
|
+
host: git.ringcentral.com
|
|
203
|
+
token: glpat-xxxxxxxxxxxx
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## GitLab Private Repository Authentication
|
|
207
|
+
|
|
208
|
+
For private GitLab repositories, you have two options:
|
|
209
|
+
|
|
210
|
+
### Option 1: Pre-configure credentials (Recommended)
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
# First, setup credentials
|
|
214
|
+
setup_gitlab_credentials:
|
|
215
|
+
host: git.ringcentral.com
|
|
216
|
+
token: glpat-xxxxxxxxxxxx
|
|
217
|
+
|
|
218
|
+
# Then install skills without providing token each time
|
|
219
|
+
install_skill:
|
|
220
|
+
gitUrl: https://git.ringcentral.com/...
|
|
221
|
+
projectPath: /path/to/project
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Option 2: Provide token with each installation
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
install_skill:
|
|
228
|
+
gitUrl: https://git.ringcentral.com/...
|
|
229
|
+
projectPath: /path/to/project
|
|
230
|
+
gitToken: glpat-xxxxxxxxxxxx
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The token will be automatically saved for future use.
|
|
234
|
+
|
|
157
235
|
## Development
|
|
158
236
|
|
|
159
237
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { z } from "zod";
|
|
|
5
5
|
import { exec } from "child_process";
|
|
6
6
|
import { promisify } from "util";
|
|
7
7
|
import path from "path";
|
|
8
|
+
import fs from "fs/promises";
|
|
8
9
|
const execAsync = promisify(exec);
|
|
9
10
|
/**
|
|
10
11
|
* Check if error message indicates authentication failure
|
|
@@ -313,6 +314,34 @@ async function installFromGitHub(urlInfo, destPath) {
|
|
|
313
314
|
const output = stdout || stderr || "Installation completed";
|
|
314
315
|
return `✅ Skill "${urlInfo.skillName}" has been successfully installed to ${destPath}\n\nSource: ${sourcePath}\n${output}`;
|
|
315
316
|
}
|
|
317
|
+
/**
|
|
318
|
+
* Recursively remove a directory (cross-platform)
|
|
319
|
+
*/
|
|
320
|
+
async function removeDirectory(dirPath) {
|
|
321
|
+
try {
|
|
322
|
+
await fs.rm(dirPath, { recursive: true, force: true });
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
// Ignore errors if directory doesn't exist
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Recursively copy a directory (cross-platform)
|
|
330
|
+
*/
|
|
331
|
+
async function copyDirectory(src, dest) {
|
|
332
|
+
await fs.mkdir(dest, { recursive: true });
|
|
333
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
334
|
+
for (const entry of entries) {
|
|
335
|
+
const srcPath = path.join(src, entry.name);
|
|
336
|
+
const destPath = path.join(dest, entry.name);
|
|
337
|
+
if (entry.isDirectory()) {
|
|
338
|
+
await copyDirectory(srcPath, destPath);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
await fs.copyFile(srcPath, destPath);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
316
345
|
/**
|
|
317
346
|
* Install Skill from GitLab using git sparse-checkout
|
|
318
347
|
* For private GitLab repositories that degit doesn't support
|
|
@@ -323,7 +352,7 @@ async function installFromGitHub(urlInfo, destPath) {
|
|
|
323
352
|
*/
|
|
324
353
|
async function installFromGitLab(urlInfo, destPath, gitToken, saveCredentials = true) {
|
|
325
354
|
const skillsDir = path.dirname(destPath);
|
|
326
|
-
const tempDir = `temp-${urlInfo.skillName}-${Date.now()}
|
|
355
|
+
const tempDir = path.join(skillsDir, `temp-${urlInfo.skillName}-${Date.now()}`);
|
|
327
356
|
// Build repo URL - if token provided, use authenticated URL with oauth2 username
|
|
328
357
|
let repoUrl;
|
|
329
358
|
let displayUrl;
|
|
@@ -336,25 +365,18 @@ async function installFromGitLab(urlInfo, destPath, gitToken, saveCredentials =
|
|
|
336
365
|
repoUrl = `https://${urlInfo.host}/${urlInfo.owner}/${urlInfo.repo}.git`;
|
|
337
366
|
displayUrl = repoUrl;
|
|
338
367
|
}
|
|
339
|
-
// Build command sequence:
|
|
340
|
-
// 1. Create target directory
|
|
341
|
-
// 2. Clone with sparse checkout
|
|
342
|
-
// 3. Set sparse-checkout path
|
|
343
|
-
// 4. Move skill folder to destination
|
|
344
|
-
// 5. Cleanup temp directory
|
|
345
|
-
const commands = [
|
|
346
|
-
`mkdir -p ${skillsDir}`,
|
|
347
|
-
`cd ${skillsDir}`,
|
|
348
|
-
`git clone --depth 1 --filter=blob:none --sparse ${repoUrl} ${tempDir}`,
|
|
349
|
-
`cd ${tempDir}`,
|
|
350
|
-
`git sparse-checkout set ${urlInfo.skillPath}`,
|
|
351
|
-
`cd ..`,
|
|
352
|
-
`mv ${tempDir}/${urlInfo.skillPath} ${urlInfo.skillName}`,
|
|
353
|
-
`rm -rf ${tempDir}`,
|
|
354
|
-
].join(" && ");
|
|
355
368
|
try {
|
|
356
|
-
|
|
357
|
-
|
|
369
|
+
// Step 1: Create target directory (cross-platform)
|
|
370
|
+
await fs.mkdir(skillsDir, { recursive: true });
|
|
371
|
+
// Step 2: Clone with sparse checkout
|
|
372
|
+
await execAsync(`git clone --depth 1 --filter=blob:none --sparse "${repoUrl}" "${tempDir}"`);
|
|
373
|
+
// Step 3: Set sparse-checkout path
|
|
374
|
+
await execAsync(`git -C "${tempDir}" sparse-checkout set "${urlInfo.skillPath}"`);
|
|
375
|
+
// Step 4: Copy skill folder to destination (cross-platform)
|
|
376
|
+
const sourcePath = path.join(tempDir, urlInfo.skillPath);
|
|
377
|
+
await copyDirectory(sourcePath, destPath);
|
|
378
|
+
// Step 5: Cleanup temp directory (cross-platform)
|
|
379
|
+
await removeDirectory(tempDir);
|
|
358
380
|
// If we used a token and saveCredentials is true, save credentials for future use
|
|
359
381
|
if (gitToken && saveCredentials) {
|
|
360
382
|
try {
|
|
@@ -364,21 +386,18 @@ async function installFromGitLab(urlInfo, destPath, gitToken, saveCredentials =
|
|
|
364
386
|
// Silently fail credential saving - installation was successful
|
|
365
387
|
}
|
|
366
388
|
}
|
|
367
|
-
return `✅ Skill "${urlInfo.skillName}" has been successfully installed to ${destPath}\n\nSource: ${displayUrl} (${urlInfo.skillPath})
|
|
389
|
+
return `✅ Skill "${urlInfo.skillName}" has been successfully installed to ${destPath}\n\nSource: ${displayUrl} (${urlInfo.skillPath})`;
|
|
368
390
|
}
|
|
369
391
|
catch (error) {
|
|
370
392
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
371
393
|
// Check if this is an authentication error
|
|
372
394
|
if (isAuthenticationError(errorMessage)) {
|
|
373
|
-
// Clean up any partial temp directory
|
|
374
|
-
|
|
375
|
-
await execAsync(`rm -rf ${path.join(skillsDir, tempDir)}`);
|
|
376
|
-
}
|
|
377
|
-
catch {
|
|
378
|
-
// Ignore cleanup errors
|
|
379
|
-
}
|
|
395
|
+
// Clean up any partial temp directory (cross-platform)
|
|
396
|
+
await removeDirectory(tempDir);
|
|
380
397
|
throw new Error(generateAuthErrorMessage(urlInfo.host, displayUrl));
|
|
381
398
|
}
|
|
399
|
+
// Clean up on any error
|
|
400
|
+
await removeDirectory(tempDir);
|
|
382
401
|
throw error;
|
|
383
402
|
}
|
|
384
403
|
}
|