@nordsym/apiclaw 1.3.8 → 1.3.9

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.
@@ -0,0 +1,291 @@
1
+ /**
2
+ * MCP Install Command
3
+ * Simple, focused command to install APIClaw into MCP config files
4
+ * Supports Claude Desktop and Claude Code
5
+ */
6
+
7
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
8
+ import { dirname, join } from 'path';
9
+ import { platform, homedir } from 'os';
10
+ import chalk from 'chalk';
11
+
12
+ export interface MCPInstallOptions {
13
+ client?: string;
14
+ dryRun?: boolean;
15
+ }
16
+
17
+ type Platform = 'mac' | 'win' | 'linux';
18
+
19
+ interface ClientConfig {
20
+ name: string;
21
+ displayName: string;
22
+ getConfigPath: () => string;
23
+ configKey: string; // Key path in config (e.g., "mcpServers" or root level)
24
+ }
25
+
26
+ /**
27
+ * Detect operating system
28
+ */
29
+ function detectOS(): Platform {
30
+ const os = platform();
31
+ switch (os) {
32
+ case 'darwin': return 'mac';
33
+ case 'win32': return 'win';
34
+ default: return 'linux';
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Get home directory
40
+ */
41
+ function getHome(): string {
42
+ return homedir();
43
+ }
44
+
45
+ /**
46
+ * Get config paths for supported clients
47
+ */
48
+ function getClientConfigs(): ClientConfig[] {
49
+ const os = detectOS();
50
+ const home = getHome();
51
+
52
+ const clients: ClientConfig[] = [
53
+ {
54
+ name: 'claude-desktop',
55
+ displayName: 'Claude Desktop',
56
+ configKey: 'mcpServers',
57
+ getConfigPath: () => {
58
+ switch (os) {
59
+ case 'mac':
60
+ return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
61
+ case 'win':
62
+ return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
63
+ case 'linux':
64
+ return join(home, '.config', 'Claude', 'claude_desktop_config.json');
65
+ }
66
+ },
67
+ },
68
+ {
69
+ name: 'claude-code',
70
+ displayName: 'Claude Code',
71
+ configKey: 'mcpServers',
72
+ getConfigPath: () => {
73
+ // Claude Code uses ~/.claude.json on all platforms
74
+ return join(home, '.claude.json');
75
+ },
76
+ },
77
+ ];
78
+
79
+ return clients;
80
+ }
81
+
82
+ /**
83
+ * APIClaw MCP server configuration
84
+ */
85
+ const APICLAW_CONFIG = {
86
+ command: 'npx',
87
+ args: ['-y', '@nordsym/apiclaw', 'serve'],
88
+ };
89
+
90
+ /**
91
+ * Read JSON config file
92
+ */
93
+ function readConfig(path: string): { success: boolean; config: any; error?: string; isNew?: boolean } {
94
+ try {
95
+ if (!existsSync(path)) {
96
+ return { success: true, config: {}, isNew: true };
97
+ }
98
+
99
+ const content = readFileSync(path, 'utf-8');
100
+ if (!content.trim()) {
101
+ return { success: true, config: {}, isNew: true };
102
+ }
103
+
104
+ return { success: true, config: JSON.parse(content), isNew: false };
105
+ } catch (error) {
106
+ return {
107
+ success: false,
108
+ config: null,
109
+ error: error instanceof Error ? error.message : 'Unknown error'
110
+ };
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Write JSON config file with backup
116
+ */
117
+ function writeConfig(path: string, config: any, createBackup = true): { success: boolean; error?: string } {
118
+ try {
119
+ const dir = dirname(path);
120
+ if (!existsSync(dir)) {
121
+ mkdirSync(dir, { recursive: true });
122
+ }
123
+
124
+ // Create backup if file exists
125
+ if (createBackup && existsSync(path)) {
126
+ const backupPath = `${path}.backup.${Date.now()}.json`;
127
+ const existing = readFileSync(path, 'utf-8');
128
+ writeFileSync(backupPath, existing, 'utf-8');
129
+ }
130
+
131
+ writeFileSync(path, JSON.stringify(config, null, 2), 'utf-8');
132
+ return { success: true };
133
+ } catch (error) {
134
+ return {
135
+ success: false,
136
+ error: error instanceof Error ? error.message : 'Unknown error'
137
+ };
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Install APIClaw into a client config
143
+ */
144
+ function installToClient(client: ClientConfig, dryRun: boolean): { success: boolean; message: string; skipped?: boolean } {
145
+ const configPath = client.getConfigPath();
146
+
147
+ // Read existing config
148
+ const readResult = readConfig(configPath);
149
+ if (!readResult.success) {
150
+ return { success: false, message: `Failed to read config: ${readResult.error}` };
151
+ }
152
+
153
+ const config = readResult.config;
154
+
155
+ // Initialize mcpServers if not present
156
+ if (!config.mcpServers) {
157
+ config.mcpServers = {};
158
+ }
159
+
160
+ // Check if already installed
161
+ if (config.mcpServers.apiclaw) {
162
+ return { success: true, message: 'Already installed', skipped: true };
163
+ }
164
+
165
+ // Add APIClaw config
166
+ config.mcpServers.apiclaw = APICLAW_CONFIG;
167
+
168
+ if (dryRun) {
169
+ console.log(chalk.cyan(`\n Would add to ${configPath}:`));
170
+ console.log(chalk.gray(JSON.stringify({ apiclaw: APICLAW_CONFIG }, null, 4)));
171
+ return { success: true, message: 'Dry run - no changes made', skipped: true };
172
+ }
173
+
174
+ // Write config
175
+ const writeResult = writeConfig(configPath, config);
176
+ if (!writeResult.success) {
177
+ return { success: false, message: `Failed to write config: ${writeResult.error}` };
178
+ }
179
+
180
+ return {
181
+ success: true,
182
+ message: readResult.isNew ? 'Created new config' : 'Updated config'
183
+ };
184
+ }
185
+
186
+ /**
187
+ * Main mcp-install command handler
188
+ */
189
+ export async function mcpInstallCommand(options: MCPInstallOptions): Promise<void> {
190
+ const os = detectOS();
191
+ const osName = os === 'mac' ? 'macOS' : os === 'win' ? 'Windows' : 'Linux';
192
+
193
+ console.log(chalk.bold('\n🦞 APIClaw MCP Install\n'));
194
+ console.log(`Platform: ${osName}\n`);
195
+
196
+ const clients = getClientConfigs();
197
+ let targetClients = clients;
198
+
199
+ // Filter to specific client if requested
200
+ if (options.client) {
201
+ const normalizedClient = options.client.toLowerCase().replace(/[_\s]/g, '-');
202
+ const aliases: Record<string, string> = {
203
+ 'claude': 'claude-desktop',
204
+ 'claude-desktop': 'claude-desktop',
205
+ 'claudedesktop': 'claude-desktop',
206
+ 'desktop': 'claude-desktop',
207
+ 'code': 'claude-code',
208
+ 'claude-code': 'claude-code',
209
+ 'claudecode': 'claude-code',
210
+ };
211
+
212
+ const targetName = aliases[normalizedClient];
213
+ if (!targetName) {
214
+ console.log(chalk.red(`❌ Unknown client: ${options.client}`));
215
+ console.log(' Supported: claude-desktop, claude-code');
216
+ process.exit(1);
217
+ }
218
+
219
+ targetClients = clients.filter(c => c.name === targetName);
220
+ }
221
+
222
+ // Detect which clients exist
223
+ console.log('🔍 Detecting MCP clients...\n');
224
+
225
+ const detectedClients: ClientConfig[] = [];
226
+ for (const client of targetClients) {
227
+ const configPath = client.getConfigPath();
228
+ const configDir = dirname(configPath);
229
+ const exists = existsSync(configPath) || existsSync(configDir);
230
+
231
+ const icon = exists ? chalk.green('✓') : chalk.gray('✗');
232
+ const status = exists ? 'found' : 'not found';
233
+ console.log(` ${icon} ${client.displayName} ${status}`);
234
+
235
+ if (exists) {
236
+ detectedClients.push(client);
237
+ }
238
+ }
239
+
240
+ console.log('');
241
+
242
+ if (detectedClients.length === 0) {
243
+ console.log(chalk.yellow('⚠️ No MCP clients detected.'));
244
+ console.log(' Install Claude Desktop or Claude Code first.\n');
245
+ process.exit(0);
246
+ }
247
+
248
+ // Install to each detected client
249
+ let successCount = 0;
250
+ let skipCount = 0;
251
+ let failCount = 0;
252
+
253
+ for (const client of detectedClients) {
254
+ const result = installToClient(client, options.dryRun || false);
255
+
256
+ if (result.success) {
257
+ if (result.skipped) {
258
+ skipCount++;
259
+ console.log(chalk.yellow(`⏭️ ${client.displayName}: ${result.message}`));
260
+ } else {
261
+ successCount++;
262
+ console.log(chalk.green(`✓ ${client.displayName}: ${result.message}`));
263
+ }
264
+ } else {
265
+ failCount++;
266
+ console.log(chalk.red(`✗ ${client.displayName}: ${result.message}`));
267
+ }
268
+ }
269
+
270
+ // Summary
271
+ console.log('\n' + '═'.repeat(50));
272
+
273
+ if (failCount === 0) {
274
+ if (options.dryRun) {
275
+ console.log(chalk.cyan('\n✅ Dry run complete! Run without --dry-run to apply changes.\n'));
276
+ } else if (successCount > 0) {
277
+ console.log(chalk.green('\n✅ APIClaw installed successfully!\n'));
278
+ console.log('Next steps:');
279
+ console.log(' 1. Restart your MCP client (Claude Desktop/Code)');
280
+ console.log(' 2. Ask: "List available APIs"');
281
+ console.log('');
282
+ console.log('Need help? https://apiclaw.com/docs\n');
283
+ } else {
284
+ console.log(chalk.yellow('\n✅ APIClaw already installed in all clients.\n'));
285
+ console.log('Run with --force to reinstall (coming soon).\n');
286
+ }
287
+ } else {
288
+ console.log(chalk.red(`\n⚠️ Installation completed with ${failCount} error(s).\n`));
289
+ process.exit(1);
290
+ }
291
+ }
package/src/cli/index.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  import { Command } from 'commander';
8
8
  import { writeFileSync } from 'fs';
9
9
  import { setupCommand } from './commands/setup.js';
10
+ import { mcpInstallCommand } from './commands/mcp-install.js';
10
11
  import { doctorCommand } from './commands/doctor.js';
11
12
  import { restoreCommand } from './commands/restore.js';
12
13
  import { uninstallCommand } from './commands/uninstall.js';
@@ -68,6 +69,14 @@ program
68
69
  await setupCommand(options);
69
70
  });
70
71
 
72
+ // MCP Install command - simple focused installation
73
+ program
74
+ .command('mcp-install')
75
+ .description('Install APIClaw into Claude Desktop or Claude Code MCP config')
76
+ .option('-c, --client <client>', 'Target specific client (claude-desktop, claude-code)')
77
+ .option('--dry-run', 'Show what would happen without making changes')
78
+ .action(mcpInstallCommand);
79
+
71
80
  // Doctor command - health check
72
81
  program
73
82
  .command('doctor')
package/STATUS.md DELETED
@@ -1,160 +0,0 @@
1
- # APIClaw Status — Verifierad 26 Feb 2026, 18:50 CET
2
-
3
- > **Denna fil är source of truth.** Uppdatera vid varje deploy/ändring.
4
-
5
- ---
6
-
7
- ## 🚀 SENASTE NYTT
8
-
9
- ### Launch Meeting (26 feb 2026)
10
- - **Pitch till Ismael från Launch** — gick bra!
11
- - **Live demo fungerade perfekt:**
12
- - Skapade NordSym Echo API live i browsern
13
- - Konfigurerade Direct Call med Vercel endpoint
14
- - Whisper-transkribering via Replicate bevisade proxy-konceptet
15
- - **Key reactions:**
16
- - "Wow" när vi visade tillväxt från 1,400 → 16,000 APIs
17
- - Ismael log när Gustav sa "building for agents"
18
- - Enades om att "API is the missing piece" för agenter
19
- - **Mötet filmades** — demo med Symbot dokumenterad
20
- - **Väntar på respons nästa vecka**
21
-
22
- ---
23
-
24
- ## 📊 Snabbstatus
25
-
26
- | Komponent | Status | Detaljer |
27
- |-----------|--------|----------|
28
- | **npm** | ✅ Live | `@nordsym/apiclaw` |
29
- | **Landing** | ✅ Live | https://apiclaw.nordsym.com |
30
- | **Convex** | ✅ Deployat | `adventurous-avocet-799` |
31
- | **API Registry** | ✅ 5,616 | Live-data från landing |
32
- | **Direct Call** | ✅ 11 providers | Replicate, OpenRouter, ElevenLabs, m.fl. |
33
- | **Provider Dashboard** | ✅ Live | Self-service onboarding fungerar |
34
-
35
- ---
36
-
37
- ## ⚡ Direct Call Providers (11 st)
38
-
39
- | Provider | Capability | Status |
40
- |----------|-----------|--------|
41
- | Replicate | Whisper, Stable Diffusion, 1000+ ML models | ✅ Live |
42
- | OpenRouter | GPT-4, Claude, Llama, 100+ LLMs | ✅ Live |
43
- | ElevenLabs | Text-to-speech i 29 språk | ✅ Live |
44
- | 46elks | SMS i Sverige och globalt | ✅ Live |
45
- | Twilio | Enterprise SMS och voice | ✅ Live |
46
- | Resend | Modern email API | ✅ Live |
47
- | Brave Search | Privacy-focused web search | ✅ Live |
48
- | Firecrawl | Web scraping till LLM-ready markdown | ✅ Live |
49
- | E2B | Secure cloud sandboxes för kod | ✅ Live |
50
- | GitHub | Repos, issues, PRs | ✅ Live |
51
- | CoinGecko | Crypto priser och market data | ✅ Live |
52
-
53
- ---
54
-
55
- ## 🎯 Pitch Points (för samtal med investerare/partners)
56
-
57
- **One-liner:** "The API layer for AI agents"
58
-
59
- **Problem:**
60
- - Agenter har inget ställe att hitta, jämföra och utvärdera API:er
61
- - Providers kan inte nå agenter snabbt nog — allt gammalt är byggt för människor
62
-
63
- **Solution:**
64
- - MCP server som ger agenter instant access till API-lagret
65
- - 5,600+ APIs indexerade för discovery
66
- - Direct Call — vi proxar requests så agenter slipper hantera API-nycklar
67
-
68
- **Traction:**
69
- - 16,980 APIs indexerade
70
- - 865 open APIs
71
- - 11 Direct Call providers
72
- - 2 partnerships signerade (46elks, CoAccept)
73
-
74
- **Business model:**
75
- - Free discovery
76
- - Direct Call är pay-per-use — vi tar marginal på proxade requests
77
-
78
- ---
79
-
80
- ## 🔧 Provider Dashboard
81
-
82
- **URL:** https://apiclaw.nordsym.com/providers/dashboard
83
-
84
- **Fungerar:**
85
- - Email magic link login
86
- - Skapa provider-konto
87
- - Lista nya API:er (4-stegs wizard)
88
- - Konfigurera Direct Call (base URL, auth, rate limits)
89
- - Se analytics (preview)
90
-
91
- **Demo-flow (bevisat live):**
92
- 1. Logga in som NordSym AB
93
- 2. Klicka "Add API"
94
- 3. Fyll i namn, beskrivning, kategori, pricing
95
- 4. Submit → "You're Listed!"
96
- 5. Gå till Direct Call tab
97
- 6. Konfigurera endpoint + auth
98
- 7. Sätt status till Live
99
- 8. Verifiera med curl
100
-
101
- ---
102
-
103
- ## 📁 Projektstruktur
104
-
105
- ```
106
- apiclaw/
107
- ├── src/ # MCP Server (TypeScript)
108
- │ ├── index.ts # Huvudfil, MCP tool definitions
109
- │ ├── discovery.ts # Söklogik
110
- │ ├── execute.ts # Direct Call handlers
111
- │ └── registry/
112
- │ └── apis.json # API registry
113
-
114
- ├── landing/ # Next.js frontend
115
- │ └── src/app/
116
- │ ├── page.tsx # Homepage
117
- │ ├── providers/ # Provider-portal
118
- │ └── admin/ # Admin-panel
119
-
120
- ├── convex/ # Backend
121
- │ ├── schema.ts # Databasschema
122
- │ ├── providers.ts # Provider CRUD
123
- │ └── credits.ts # Credits
124
-
125
- ├── dist/ # Kompilerad JS
126
- └── STATUS.md # DENNA FIL
127
- ```
128
-
129
- ---
130
-
131
- ## 📈 Roadmap
132
-
133
- **Nu (Q1 2026):**
134
- - ✅ 16k+ APIs
135
- - ✅ Direct Call fungerar
136
- - ✅ Provider self-service
137
- - ⏳ Launch respons (nästa vecka)
138
-
139
- **Nästa:**
140
- - Fler Direct Call partnerships
141
- - Stripe payments live
142
- - Usage analytics för providers
143
-
144
- ---
145
-
146
- ## 📝 Ändringslogg
147
-
148
- | Datum | Ändring |
149
- |-------|---------|
150
- | 2026-02-26 | 🎉 **Launch pitch genomförd!** Demo fungerade perfekt |
151
- | 2026-02-26 | NordSym Echo API skapad + Direct Call konfigurerat live |
152
- | 2026-02-26 | Whisper-transkribering via Replicate bevisade proxy-konceptet |
153
- | 2026-02-26 | Provider dashboard delete-funktion tillagd |
154
- | 2026-02-26 | Direct Call modal på landningssidan (klicka på "11" för att se alla) |
155
- | 2026-02-22 | 15,000 APIs milestone |
156
- | 2026-02-16 | npm v1.0.0 publicerad |
157
-
158
- ---
159
-
160
- *Senast verifierad: 26 Feb 2026, kl 18:50 CET*