openskills-cli 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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/dist/bin/cli.d.ts +10 -0
  4. package/dist/bin/cli.d.ts.map +1 -0
  5. package/dist/bin/cli.js +133 -0
  6. package/dist/bin/cli.js.map +1 -0
  7. package/dist/src/modes/install.d.ts +32 -0
  8. package/dist/src/modes/install.d.ts.map +1 -0
  9. package/dist/src/modes/install.js +215 -0
  10. package/dist/src/modes/install.js.map +1 -0
  11. package/dist/src/modes/mcp-proxy.d.ts +16 -0
  12. package/dist/src/modes/mcp-proxy.d.ts.map +1 -0
  13. package/dist/src/modes/mcp-proxy.js +117 -0
  14. package/dist/src/modes/mcp-proxy.js.map +1 -0
  15. package/dist/src/services/downloader.d.ts +32 -0
  16. package/dist/src/services/downloader.d.ts.map +1 -0
  17. package/dist/src/services/downloader.js +125 -0
  18. package/dist/src/services/downloader.js.map +1 -0
  19. package/dist/src/services/extractor.d.ts +38 -0
  20. package/dist/src/services/extractor.d.ts.map +1 -0
  21. package/dist/src/services/extractor.js +82 -0
  22. package/dist/src/services/extractor.js.map +1 -0
  23. package/dist/src/services/symlink.d.ts +64 -0
  24. package/dist/src/services/symlink.d.ts.map +1 -0
  25. package/dist/src/services/symlink.js +153 -0
  26. package/dist/src/services/symlink.js.map +1 -0
  27. package/dist/src/types/index.d.ts +75 -0
  28. package/dist/src/types/index.d.ts.map +1 -0
  29. package/dist/src/types/index.js +5 -0
  30. package/dist/src/types/index.js.map +1 -0
  31. package/dist/src/utils/agent-dirs.d.ts +49 -0
  32. package/dist/src/utils/agent-dirs.d.ts.map +1 -0
  33. package/dist/src/utils/agent-dirs.js +116 -0
  34. package/dist/src/utils/agent-dirs.js.map +1 -0
  35. package/dist/src/utils/constants.d.ts +16 -0
  36. package/dist/src/utils/constants.d.ts.map +1 -0
  37. package/dist/src/utils/constants.js +21 -0
  38. package/dist/src/utils/constants.js.map +1 -0
  39. package/dist/src/utils/errors.d.ts +72 -0
  40. package/dist/src/utils/errors.d.ts.map +1 -0
  41. package/dist/src/utils/errors.js +108 -0
  42. package/dist/src/utils/errors.js.map +1 -0
  43. package/dist/src/utils/logger.d.ts +41 -0
  44. package/dist/src/utils/logger.d.ts.map +1 -0
  45. package/dist/src/utils/logger.js +85 -0
  46. package/dist/src/utils/logger.js.map +1 -0
  47. package/dist/src/utils/mode-detector.d.ts +74 -0
  48. package/dist/src/utils/mode-detector.d.ts.map +1 -0
  49. package/dist/src/utils/mode-detector.js +156 -0
  50. package/dist/src/utils/mode-detector.js.map +1 -0
  51. package/dist/src/utils/prompts.d.ts +22 -0
  52. package/dist/src/utils/prompts.d.ts.map +1 -0
  53. package/dist/src/utils/prompts.js +69 -0
  54. package/dist/src/utils/prompts.js.map +1 -0
  55. package/package.json +53 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenSkills
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # openskills-mcp
2
+
3
+ Discover and install AI agent skills via the [Model Context Protocol](https://modelcontextprotocol.io/).
4
+
5
+ OpenSkills indexes skills from trusted GitHub repositories and makes them searchable through MCP tools. This package connects your AI agent to the hosted OpenSkills server.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npx openskills-mcp --api-key osk_your_key_here
11
+ ```
12
+
13
+ Get your API key at [openskills.dev/dashboard](https://openskills.dev/dashboard).
14
+
15
+ ## MCP Configuration
16
+
17
+ ### Claude Desktop / Claude Code
18
+
19
+ Add to your `claude_desktop_config.json` or `.claude/settings.json`:
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "openskills": {
25
+ "command": "npx",
26
+ "args": [
27
+ "-y",
28
+ "openskills-mcp",
29
+ "--api-key",
30
+ "osk_your_key_here"
31
+ ]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### Cursor
38
+
39
+ Add to your MCP settings:
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "openskills": {
45
+ "command": "npx",
46
+ "args": [
47
+ "-y",
48
+ "openskills-mcp",
49
+ "--api-key",
50
+ "osk_your_key_here"
51
+ ]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Available Tools
58
+
59
+ ### search_skills
60
+
61
+ Search for skills using natural language.
62
+
63
+ ```
64
+ search_skills("process PDF files", max_results=5, verified_only=true)
65
+ ```
66
+
67
+ Returns skill metadata: name, description, tags, stars, verified status, relevance score.
68
+
69
+ ### get_skill
70
+
71
+ Get installation command for a skill.
72
+
73
+ ```
74
+ get_skill(skill="pdf-processing", agent="claude-code", global_install=false)
75
+ ```
76
+
77
+ Returns a simple installation command:
78
+ ```bash
79
+ npx openskills pdf-processing -a claude-code
80
+ ```
81
+
82
+ The openskills CLI handles downloading, extracting, and symlinking automatically.
83
+
84
+ ## How It Works
85
+
86
+ This package runs a local MCP server (stdio transport) that proxies requests to the hosted OpenSkills server (HTTP transport) with your API key for authentication.
87
+
88
+ ```
89
+ Your AI Agent <--stdio--> openskills-mcp <--HTTP--> OpenSkills Server
90
+ ```
91
+
92
+ ## Requirements
93
+
94
+ - Node.js >= 18.0.0
95
+ - An OpenSkills API key
96
+
97
+ ## License
98
+
99
+ MIT
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenSkills CLI - Main entry point
4
+ *
5
+ * Dual-mode CLI:
6
+ * 1. Installation mode: npx openskills <skill> [options]
7
+ * 2. MCP proxy mode: npx openskills --api-key <key>
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG"}
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenSkills CLI - Main entry point
4
+ *
5
+ * Dual-mode CLI:
6
+ * 1. Installation mode: npx openskills <skill> [options]
7
+ * 2. MCP proxy mode: npx openskills --api-key <key>
8
+ */
9
+ import { detectMode, parseInstallOptions, parseApiKey } from '../src/utils/mode-detector.js';
10
+ import { install } from '../src/modes/install.js';
11
+ import { userError, ExitCode } from '../src/utils/errors.js';
12
+ import { readFileSync } from 'fs';
13
+ import { fileURLToPath } from 'url';
14
+ import { dirname, join } from 'path';
15
+ // Get package.json for version
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = dirname(__filename);
18
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../..', 'package.json'), 'utf-8'));
19
+ const args = process.argv.slice(2);
20
+ const mode = detectMode(args);
21
+ /**
22
+ * Show help message.
23
+ */
24
+ function showHelp() {
25
+ console.log(`
26
+ OpenSkills CLI v${packageJson.version}
27
+
28
+ Install AI agent skills locally or discover via MCP protocol.
29
+
30
+ INSTALLATION MODE:
31
+ npx openskills <skill> [options]
32
+
33
+ Positional:
34
+ <skill> Skill identifier (e.g., pdf-processing)
35
+
36
+ Options:
37
+ -a, --agent <name> Agent name (e.g., claude-code, cursor)
38
+ -g, --global Install globally to ~/.agents/skills/
39
+ -p, --project Install to project ./agents/skills/ (default if no flag)
40
+ -y Install for multiple agents (claude-code, codex, cursor, gemini-cli, qwen-code)
41
+ --force Overwrite existing installation
42
+
43
+ Examples:
44
+ npx openskills pdf-processing -a claude-code -g
45
+ npx openskills pdf-processing -a claude-code -p
46
+ npx openskills pdf-processing -y
47
+ npx openskills pdf-processing
48
+ (Interactive: prompts for agent and scope)
49
+
50
+ Legacy syntax (still supported):
51
+ npx openskills -s pdf-processing -a claude-code
52
+
53
+ MCP PROXY MODE:
54
+ npx openskills --api-key <key>
55
+
56
+ Required:
57
+ --api-key <key> OpenSkills API key (format: osk_...)
58
+
59
+ Environment:
60
+ OPENSKILLS_BACKEND_URL Backend server URL (default: https://openskills-mcp.hf.space)
61
+
62
+ Example:
63
+ npx openskills --api-key osk_abc123def456
64
+
65
+ OTHER:
66
+ -h, --help Show this help message
67
+ -v, --version Show version number
68
+
69
+ SUPPORTED AGENTS:
70
+ claude-code, openclaw, cursor, windsurf, codex, cody, aider, continue,
71
+ gemini-cli, qwen-code, and 15+ more
72
+
73
+ For more information, visit: https://github.com/nadeemsangrasi/openskills-mcp
74
+ `);
75
+ }
76
+ /**
77
+ * Show version.
78
+ */
79
+ function showVersion() {
80
+ console.log(`openskills v${packageJson.version}`);
81
+ }
82
+ /**
83
+ * Main entry point.
84
+ */
85
+ async function main() {
86
+ try {
87
+ switch (mode) {
88
+ case 'help':
89
+ showHelp();
90
+ process.exit(ExitCode.SUCCESS);
91
+ break;
92
+ case 'version':
93
+ showVersion();
94
+ process.exit(ExitCode.SUCCESS);
95
+ break;
96
+ case 'install': {
97
+ const options = parseInstallOptions(args);
98
+ // Validate that at least skill name is provided
99
+ if (!options.skill) {
100
+ userError('Skill name is required', [
101
+ 'Usage: npx openskills <skill> [options]',
102
+ 'Example: npx openskills pdf-processing -a claude-code',
103
+ ]);
104
+ }
105
+ // Pass options to install (may have null agent for interactive mode)
106
+ await install(options);
107
+ break;
108
+ }
109
+ case 'mcp': {
110
+ const apiKey = parseApiKey(args);
111
+ if (!apiKey) {
112
+ userError('Missing required flag: --api-key', ['Usage: npx openskills --api-key <your-key>']);
113
+ }
114
+ if (!apiKey.startsWith('osk_')) {
115
+ userError("Invalid API key format. Keys start with 'osk_'", ['Get a valid key at: https://openskills.dev/dashboard']);
116
+ }
117
+ // Import and start MCP proxy
118
+ const { startProxy } = await import('../src/modes/mcp-proxy.js');
119
+ await startProxy(apiKey);
120
+ break;
121
+ }
122
+ default:
123
+ showHelp();
124
+ process.exit(ExitCode.SUCCESS);
125
+ }
126
+ }
127
+ catch (error) {
128
+ console.error(`✗ Error: ${error.message}`);
129
+ process.exit(ExitCode.SYSTEM_ERROR);
130
+ }
131
+ }
132
+ main();
133
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Installation mode handler.
3
+ *
4
+ * Orchestrates the complete skill installation flow:
5
+ * 1. Validate arguments or prompt for missing options
6
+ * 2. Check existing installation
7
+ * 3. Download skill zip from server (server does sparse checkout)
8
+ * 4. Extract to .agents/skills/
9
+ * 5. Create symlink(s) to agent directory(ies)
10
+ * 6. Log installation events
11
+ *
12
+ * Server handles sparse checkout - no git required on client.
13
+ *
14
+ * Supports:
15
+ * - Single-agent installation: npx openskills pdf-processing -a claude-code
16
+ * - Multi-agent installation: npx openskills pdf-processing -y
17
+ * - Interactive prompts: npx openskills pdf-processing
18
+ */
19
+ /**
20
+ * Execute installation flow.
21
+ *
22
+ * @param options - Installation options (may have null agent for interactive mode)
23
+ */
24
+ export declare function install(options: {
25
+ skill: string | null;
26
+ agent: string | null;
27
+ global: boolean;
28
+ force: boolean;
29
+ multiAgent: boolean;
30
+ scopeExplicit: boolean;
31
+ }): Promise<void>;
32
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/modes/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAgFH;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE;IACrC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+ChB"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Installation mode handler.
3
+ *
4
+ * Orchestrates the complete skill installation flow:
5
+ * 1. Validate arguments or prompt for missing options
6
+ * 2. Check existing installation
7
+ * 3. Download skill zip from server (server does sparse checkout)
8
+ * 4. Extract to .agents/skills/
9
+ * 5. Create symlink(s) to agent directory(ies)
10
+ * 6. Log installation events
11
+ *
12
+ * Server handles sparse checkout - no git required on client.
13
+ *
14
+ * Supports:
15
+ * - Single-agent installation: npx openskills pdf-processing -a claude-code
16
+ * - Multi-agent installation: npx openskills pdf-processing -y
17
+ * - Interactive prompts: npx openskills pdf-processing
18
+ */
19
+ import * as fs from 'fs';
20
+ import * as path from 'path';
21
+ import * as os from 'os';
22
+ import { fetchSkillZip } from '../services/downloader.js';
23
+ import { extractSkill, validateSkillMd, cleanup } from '../services/extractor.js';
24
+ import { createSymlink, resolveHome } from '../services/symlink.js';
25
+ import { getAgentDir } from '../utils/agent-dirs.js';
26
+ import { createInstallLogger } from '../utils/logger.js';
27
+ import { promptAgent, promptScope, showMultiAgentInfo } from '../utils/prompts.js';
28
+ import { DEFAULT_AGENTS } from '../utils/constants.js';
29
+ import { validateSkillSlug, validateAgentName, networkError, systemError, success, step, info, ExitCode, } from '../utils/errors.js';
30
+ /**
31
+ * Get installation base directory.
32
+ *
33
+ * @param isGlobal - Whether global or project installation
34
+ * @returns Base directory path
35
+ */
36
+ function getBaseDir(isGlobal) {
37
+ if (isGlobal) {
38
+ return path.join(os.homedir(), '.agents', 'skills');
39
+ }
40
+ else {
41
+ return path.join(process.cwd(), '.agents', 'skills');
42
+ }
43
+ }
44
+ /**
45
+ * Check if skill already exists in .agents/skills/.
46
+ *
47
+ * @param skillSlug - Skill identifier
48
+ * @param isGlobal - Whether global or project installation
49
+ * @returns True if skill exists
50
+ */
51
+ function skillExists(skillSlug, isGlobal) {
52
+ const baseDir = getBaseDir(isGlobal);
53
+ const skillDir = path.join(baseDir, skillSlug);
54
+ return fs.existsSync(skillDir) && fs.existsSync(path.join(skillDir, 'SKILL.md'));
55
+ }
56
+ /**
57
+ * Create symlink for a single agent.
58
+ *
59
+ * @param skillDir - Source skill directory
60
+ * @param agent - Agent name
61
+ * @param isGlobal - Whether global installation
62
+ * @param log - Logger function
63
+ */
64
+ async function createAgentSymlink(skillDir, agent, isGlobal, log) {
65
+ const agentDir = getAgentDir(agent, isGlobal);
66
+ const agentPath = isGlobal ? resolveHome(`~/${agentDir}`) : agentDir;
67
+ const symlinkPath = path.join(agentPath, path.basename(skillDir));
68
+ step(`Creating symlink for ${agent} at ${symlinkPath}`);
69
+ try {
70
+ await createSymlink(skillDir, symlinkPath);
71
+ log('symlink_created', { agent, symlink_path: symlinkPath });
72
+ }
73
+ catch (error) {
74
+ log('error', { agent, error: error.message });
75
+ systemError(`Symlink creation failed for ${agent}: ${error.message}`);
76
+ }
77
+ }
78
+ /**
79
+ * Execute installation flow.
80
+ *
81
+ * @param options - Installation options (may have null agent for interactive mode)
82
+ */
83
+ export async function install(options) {
84
+ const startTime = Date.now();
85
+ // Validate skill name
86
+ if (!options.skill) {
87
+ systemError('Skill name is required');
88
+ }
89
+ validateSkillSlug(options.skill);
90
+ // Handle multi-agent installation (-y flag)
91
+ if (options.multiAgent) {
92
+ showMultiAgentInfo(options.skill);
93
+ const installOpts = {
94
+ skill: options.skill,
95
+ agent: DEFAULT_AGENTS,
96
+ global: true, // -y always installs globally
97
+ force: options.force,
98
+ multiAgent: true,
99
+ };
100
+ await executeInstall(installOpts, startTime);
101
+ return;
102
+ }
103
+ // Interactive mode: prompt for missing options
104
+ let agent = options.agent;
105
+ let isGlobal = options.global;
106
+ if (!agent) {
107
+ agent = await promptAgent();
108
+ }
109
+ // If scope was not explicitly set (no -g or -p flag), prompt for scope
110
+ if (!options.scopeExplicit) {
111
+ isGlobal = await promptScope();
112
+ }
113
+ const installOpts = {
114
+ skill: options.skill,
115
+ agent: agent,
116
+ global: isGlobal,
117
+ force: options.force,
118
+ multiAgent: false,
119
+ };
120
+ await executeInstall(installOpts, startTime);
121
+ }
122
+ /**
123
+ * Execute the actual installation process.
124
+ *
125
+ * @param options - Validated installation options
126
+ * @param startTime - Installation start timestamp
127
+ */
128
+ async function executeInstall(options, startTime) {
129
+ const agents = Array.isArray(options.agent) ? options.agent : [options.agent];
130
+ const installScope = options.global ? 'global' : 'project';
131
+ // Use first agent for logging (or 'multi' for multi-agent)
132
+ const logAgent = options.multiAgent ? 'multi-agent' : agents[0];
133
+ const log = createInstallLogger(options.skill, logAgent, installScope);
134
+ try {
135
+ log('start');
136
+ // Determine installation paths
137
+ const baseDir = getBaseDir(options.global);
138
+ const skillDir = path.join(baseDir, options.skill);
139
+ // Check existing installation
140
+ const exists = skillExists(options.skill, options.global);
141
+ if (exists && !options.force) {
142
+ // Skill exists, reuse files and create symlinks
143
+ info(`Skill ${options.skill} already exists, reusing files`);
144
+ for (const agent of agents) {
145
+ const validAgent = validateAgentName(agent);
146
+ await createAgentSymlink(skillDir, validAgent, options.global, log);
147
+ }
148
+ const duration = Date.now() - startTime;
149
+ success('Installation complete', duration);
150
+ log('complete', { duration_ms: duration });
151
+ process.exit(ExitCode.SUCCESS);
152
+ return;
153
+ }
154
+ if (exists && options.force) {
155
+ // Force reinstall: delete existing
156
+ step('Removing existing installation...');
157
+ fs.rmSync(skillDir, { recursive: true, force: true });
158
+ }
159
+ // Download skill zip from server (server does sparse checkout)
160
+ step(`Downloading ${options.skill}...`);
161
+ log('download_begin');
162
+ // Create temp directory for zip
163
+ const tmpDir = path.join(os.tmpdir(), 'openskills');
164
+ if (!fs.existsSync(tmpDir)) {
165
+ fs.mkdirSync(tmpDir, { recursive: true });
166
+ }
167
+ let zipPath;
168
+ try {
169
+ zipPath = await fetchSkillZip(options.skill, tmpDir);
170
+ log('download_complete', { duration_ms: Date.now() - startTime });
171
+ }
172
+ catch (error) {
173
+ log('error', { error: error.message });
174
+ networkError(error.message);
175
+ }
176
+ // Extract to .agents/skills/
177
+ step(`Extracting to ${skillDir}`);
178
+ log('extract_begin');
179
+ try {
180
+ await extractSkill(zipPath, skillDir);
181
+ log('extract_complete', { target_path: skillDir, duration_ms: Date.now() - startTime });
182
+ }
183
+ catch (error) {
184
+ cleanup(zipPath, skillDir);
185
+ log('error', { error: error.message });
186
+ systemError(`Extraction failed: ${error.message}`);
187
+ }
188
+ // Validate SKILL.md
189
+ try {
190
+ validateSkillMd(skillDir);
191
+ }
192
+ catch (error) {
193
+ cleanup(zipPath, skillDir);
194
+ log('error', { error: error.message });
195
+ systemError(`Skill validation failed: ${error.message}`);
196
+ }
197
+ // Clean up zip file
198
+ cleanup(zipPath);
199
+ // Create symlinks for all agents
200
+ for (const agent of agents) {
201
+ const validAgent = validateAgentName(agent);
202
+ await createAgentSymlink(skillDir, validAgent, options.global, log);
203
+ }
204
+ // Success
205
+ const duration = Date.now() - startTime;
206
+ success('Installation complete', duration);
207
+ log('complete', { duration_ms: duration, agents: agents.length });
208
+ process.exit(ExitCode.SUCCESS);
209
+ }
210
+ catch (error) {
211
+ log('error', { error: error.message });
212
+ throw error;
213
+ }
214
+ }
215
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/modes/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * MCP proxy mode handler.
3
+ *
4
+ * Creates a local stdio MCP server that proxies all tool calls
5
+ * to the hosted OpenSkills MCP server with X-API-Key auth.
6
+ *
7
+ * Architecture:
8
+ * AI Agent <--stdio--> this proxy <--HTTP+X-API-Key--> hosted server
9
+ */
10
+ /**
11
+ * Start the stdio-to-HTTP MCP proxy.
12
+ *
13
+ * @param apiKey - OpenSkills API key (osk_xxx)
14
+ */
15
+ export declare function startProxy(apiKey: string): Promise<void>;
16
+ //# sourceMappingURL=mcp-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-proxy.d.ts","sourceRoot":"","sources":["../../../src/modes/mcp-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+G9D"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * MCP proxy mode handler.
3
+ *
4
+ * Creates a local stdio MCP server that proxies all tool calls
5
+ * to the hosted OpenSkills MCP server with X-API-Key auth.
6
+ *
7
+ * Architecture:
8
+ * AI Agent <--stdio--> this proxy <--HTTP+X-API-Key--> hosted server
9
+ */
10
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
11
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
12
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
13
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
14
+ const BACKEND_URL = 'https://sangrasi-openskills-mcp.hf.space';
15
+ /**
16
+ * Start the stdio-to-HTTP MCP proxy.
17
+ *
18
+ * @param apiKey - OpenSkills API key (osk_xxx)
19
+ */
20
+ export async function startProxy(apiKey) {
21
+ const remoteUrl = `${BACKEND_URL}/mcp`;
22
+ // 1. Connect to remote OpenSkills MCP server as a client
23
+ const remoteClient = new Client({
24
+ name: 'openskills-proxy',
25
+ version: '1.0.0',
26
+ });
27
+ const remoteTransport = new StreamableHTTPClientTransport(new URL(remoteUrl), {
28
+ requestInit: {
29
+ headers: {
30
+ 'X-API-Key': apiKey,
31
+ 'Accept': 'application/json, text/event-stream',
32
+ },
33
+ },
34
+ });
35
+ try {
36
+ await remoteClient.connect(remoteTransport);
37
+ }
38
+ catch (err) {
39
+ const msg = err.message || String(err);
40
+ if (msg.includes('401') || msg.includes('Unauthorized')) {
41
+ console.error('Error: Invalid API key. Check your key at https://openskills.dev/dashboard');
42
+ process.exit(2);
43
+ }
44
+ console.error(`Error: Failed to connect to OpenSkills server: ${msg}`);
45
+ process.exit(3);
46
+ }
47
+ // 2. Discover remote tools
48
+ let tools;
49
+ try {
50
+ const result = await remoteClient.listTools();
51
+ tools = result.tools;
52
+ }
53
+ catch (err) {
54
+ console.error(`Error: Failed to list remote tools: ${err.message}`);
55
+ process.exit(3);
56
+ }
57
+ // Log to stderr (stdout is reserved for MCP stdio protocol)
58
+ console.error(`OpenSkills: Connected to ${BACKEND_URL}. ${tools.length} tools available: ${tools.map((t) => t.name).join(', ')}`);
59
+ // 3. Create local stdio MCP server
60
+ const localServer = new McpServer({
61
+ name: 'openskills',
62
+ version: '1.0.0',
63
+ });
64
+ // 4. Register each remote tool as a local proxy tool
65
+ for (const tool of tools) {
66
+ localServer.tool(tool.name, tool.description || `Proxy to remote tool: ${tool.name}`, {}, async (args) => {
67
+ try {
68
+ const result = await remoteClient.callTool({
69
+ name: tool.name,
70
+ arguments: args,
71
+ });
72
+ // Return result directly - MCP SDK handles the response format
73
+ return result;
74
+ }
75
+ catch (err) {
76
+ const msg = err.message || String(err);
77
+ if (msg.includes('401') || msg.includes('Unauthorized')) {
78
+ return {
79
+ content: [
80
+ {
81
+ type: 'text',
82
+ text: 'Error: Invalid API key. Check your key at https://openskills.dev/dashboard',
83
+ },
84
+ ],
85
+ isError: true,
86
+ };
87
+ }
88
+ return {
89
+ content: [
90
+ {
91
+ type: 'text',
92
+ text: `Error calling ${tool.name}: ${msg}`,
93
+ },
94
+ ],
95
+ isError: true,
96
+ };
97
+ }
98
+ });
99
+ }
100
+ // 5. Start local stdio transport
101
+ const stdioTransport = new StdioServerTransport();
102
+ await localServer.connect(stdioTransport);
103
+ console.error('OpenSkills MCP proxy running (stdio -> remote)');
104
+ // Handle graceful shutdown
105
+ process.on('SIGINT', async () => {
106
+ console.error('OpenSkills: Shutting down...');
107
+ await localServer.close();
108
+ await remoteClient.close();
109
+ process.exit(0);
110
+ });
111
+ process.on('SIGTERM', async () => {
112
+ await localServer.close();
113
+ await remoteClient.close();
114
+ process.exit(0);
115
+ });
116
+ }
117
+ //# sourceMappingURL=mcp-proxy.js.map