@nordsym/apiclaw 1.0.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 (79) hide show
  1. package/.github/ISSUE_TEMPLATE/add-api.yml +123 -0
  2. package/BRIEFING.md +30 -0
  3. package/CONCEPT.md +494 -0
  4. package/README.md +272 -0
  5. package/backend/convex/README.md +90 -0
  6. package/backend/convex/_generated/api.d.ts +55 -0
  7. package/backend/convex/_generated/api.js +23 -0
  8. package/backend/convex/_generated/dataModel.d.ts +60 -0
  9. package/backend/convex/_generated/server.d.ts +143 -0
  10. package/backend/convex/_generated/server.js +93 -0
  11. package/backend/convex/apiKeys.ts +75 -0
  12. package/backend/convex/purchases.ts +74 -0
  13. package/backend/convex/schema.ts +45 -0
  14. package/backend/convex/transactions.ts +57 -0
  15. package/backend/convex/tsconfig.json +25 -0
  16. package/backend/convex/users.ts +94 -0
  17. package/backend/package-lock.json +521 -0
  18. package/backend/package.json +15 -0
  19. package/dist/credits.d.ts +54 -0
  20. package/dist/credits.d.ts.map +1 -0
  21. package/dist/credits.js +209 -0
  22. package/dist/credits.js.map +1 -0
  23. package/dist/discovery.d.ts +37 -0
  24. package/dist/discovery.d.ts.map +1 -0
  25. package/dist/discovery.js +109 -0
  26. package/dist/discovery.js.map +1 -0
  27. package/dist/index.d.ts +13 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +355 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/registry/apis.json +20894 -0
  32. package/dist/registry/parse_apis.py +146 -0
  33. package/dist/revenuecat.d.ts +61 -0
  34. package/dist/revenuecat.d.ts.map +1 -0
  35. package/dist/revenuecat.js +166 -0
  36. package/dist/revenuecat.js.map +1 -0
  37. package/dist/test.d.ts +6 -0
  38. package/dist/test.d.ts.map +1 -0
  39. package/dist/test.js +81 -0
  40. package/dist/test.js.map +1 -0
  41. package/dist/types.d.ts +96 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +3 -0
  44. package/dist/types.js.map +1 -0
  45. package/dist/webhooks/revenuecat.d.ts +48 -0
  46. package/dist/webhooks/revenuecat.d.ts.map +1 -0
  47. package/dist/webhooks/revenuecat.js +119 -0
  48. package/dist/webhooks/revenuecat.js.map +1 -0
  49. package/docs/revenuecat-setup.md +89 -0
  50. package/landing/next-env.d.ts +5 -0
  51. package/landing/next.config.mjs +6 -0
  52. package/landing/package-lock.json +1666 -0
  53. package/landing/package.json +27 -0
  54. package/landing/postcss.config.js +6 -0
  55. package/landing/src/app/api/keys/route.ts +71 -0
  56. package/landing/src/app/api/log/route.ts +37 -0
  57. package/landing/src/app/api/stats/route.ts +37 -0
  58. package/landing/src/app/globals.css +261 -0
  59. package/landing/src/app/layout.tsx +37 -0
  60. package/landing/src/app/page.tsx +753 -0
  61. package/landing/src/app/page.tsx.bak +567 -0
  62. package/landing/src/components/AddKeyModal.tsx +159 -0
  63. package/landing/tailwind.config.ts +34 -0
  64. package/landing/tsconfig.json +20 -0
  65. package/newsletter-template.html +71 -0
  66. package/outreach/OUTREACH-SYSTEM.md +211 -0
  67. package/outreach/email-template.html +179 -0
  68. package/outreach/targets.md +133 -0
  69. package/package.json +39 -0
  70. package/src/credits.ts +261 -0
  71. package/src/discovery.ts +147 -0
  72. package/src/index.ts +396 -0
  73. package/src/registry/apis.json +20894 -0
  74. package/src/registry/parse_apis.py +146 -0
  75. package/src/revenuecat.ts +239 -0
  76. package/src/test.ts +97 -0
  77. package/src/types.ts +110 -0
  78. package/src/webhooks/revenuecat.ts +187 -0
  79. package/tsconfig.json +20 -0
package/src/index.ts ADDED
@@ -0,0 +1,396 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * APIvault - Agent-Native API Discovery MCP Server
4
+ *
5
+ * Tools:
6
+ * - discover_apis: Search for APIs by capability
7
+ * - get_api_details: Get full info about an API
8
+ * - purchase_access: Buy API access with credits
9
+ * - check_balance: Check credits and active purchases
10
+ * - add_credits: Add credits to account (for testing)
11
+ */
12
+
13
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
14
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
15
+ import {
16
+ CallToolRequestSchema,
17
+ ListToolsRequestSchema,
18
+ Tool,
19
+ } from '@modelcontextprotocol/sdk/types.js';
20
+
21
+ import { discoverAPIs, getAPIDetails, getCategories, getAllAPIs, getAPICount } from './discovery.js';
22
+ import {
23
+ getAgentCredits,
24
+ addCredits,
25
+ purchaseAPIAccess,
26
+ getBalanceSummary,
27
+ getAgentPurchases
28
+ } from './credits.js';
29
+
30
+ // Default agent ID for MVP (in production, this would come from auth)
31
+ const DEFAULT_AGENT_ID = 'agent_default';
32
+
33
+ // Tool definitions
34
+ const tools: Tool[] = [
35
+ {
36
+ name: 'discover_apis',
37
+ description: 'Search 1400+ APIs based on what you need to do. Describe your use case naturally.',
38
+ inputSchema: {
39
+ type: 'object',
40
+ properties: {
41
+ query: {
42
+ type: 'string',
43
+ description: 'Natural language query describing what you need (e.g., "send SMS", "weather data", "payment processing", "text to speech")'
44
+ },
45
+ category: {
46
+ type: 'string',
47
+ description: 'Filter by category (use list_categories to see all)'
48
+ },
49
+ max_results: {
50
+ type: 'number',
51
+ description: 'Maximum number of results to return (default: 10)',
52
+ default: 10
53
+ }
54
+ },
55
+ required: ['query']
56
+ }
57
+ },
58
+ {
59
+ name: 'get_api_details',
60
+ description: 'Get detailed information about a specific API provider, including endpoints, pricing, and features.',
61
+ inputSchema: {
62
+ type: 'object',
63
+ properties: {
64
+ api_id: {
65
+ type: 'string',
66
+ description: 'The API provider ID (e.g., "46elks", "resend", "openrouter")'
67
+ }
68
+ },
69
+ required: ['api_id']
70
+ }
71
+ },
72
+ {
73
+ name: 'purchase_access',
74
+ description: 'Purchase access to an API using your credit balance. Returns API credentials on success.',
75
+ inputSchema: {
76
+ type: 'object',
77
+ properties: {
78
+ api_id: {
79
+ type: 'string',
80
+ description: 'The API provider ID to purchase access to'
81
+ },
82
+ amount_usd: {
83
+ type: 'number',
84
+ description: 'Amount in USD to spend on this API'
85
+ },
86
+ agent_id: {
87
+ type: 'string',
88
+ description: 'Your agent identifier (optional, uses default if not provided)'
89
+ }
90
+ },
91
+ required: ['api_id', 'amount_usd']
92
+ }
93
+ },
94
+ {
95
+ name: 'check_balance',
96
+ description: 'Check your credit balance and list active API purchases.',
97
+ inputSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ agent_id: {
101
+ type: 'string',
102
+ description: 'Your agent identifier (optional, uses default if not provided)'
103
+ }
104
+ }
105
+ }
106
+ },
107
+ {
108
+ name: 'add_credits',
109
+ description: 'Add credits to your account. (For testing/demo purposes)',
110
+ inputSchema: {
111
+ type: 'object',
112
+ properties: {
113
+ amount_usd: {
114
+ type: 'number',
115
+ description: 'Amount in USD to add to your balance'
116
+ },
117
+ agent_id: {
118
+ type: 'string',
119
+ description: 'Your agent identifier (optional, uses default if not provided)'
120
+ }
121
+ },
122
+ required: ['amount_usd']
123
+ }
124
+ },
125
+ {
126
+ name: 'list_categories',
127
+ description: 'List all available API categories.',
128
+ inputSchema: {
129
+ type: 'object',
130
+ properties: {}
131
+ }
132
+ }
133
+ ];
134
+
135
+ // Create server
136
+ const server = new Server(
137
+ {
138
+ name: 'apivault',
139
+ version: '0.1.0',
140
+ },
141
+ {
142
+ capabilities: {
143
+ tools: {},
144
+ },
145
+ }
146
+ );
147
+
148
+ // Handle list tools
149
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
150
+ return { tools };
151
+ });
152
+
153
+ // Handle tool calls
154
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
155
+ const { name, arguments: args } = request.params;
156
+
157
+ try {
158
+ switch (name) {
159
+ case 'discover_apis': {
160
+ const query = args?.query as string;
161
+ const category = args?.category as string | undefined;
162
+ const maxResults = (args?.max_results as number) || 10;
163
+
164
+ const results = discoverAPIs(query, { category, maxResults });
165
+
166
+ if (results.length === 0) {
167
+ return {
168
+ content: [
169
+ {
170
+ type: 'text',
171
+ text: JSON.stringify({
172
+ status: 'no_results',
173
+ message: `No APIs found matching "${query}". Try broader terms or check available categories with list_categories.`,
174
+ total_apis: getAPICount(),
175
+ available_categories: getCategories().slice(0, 20)
176
+ }, null, 2)
177
+ }
178
+ ]
179
+ };
180
+ }
181
+
182
+ return {
183
+ content: [
184
+ {
185
+ type: 'text',
186
+ text: JSON.stringify({
187
+ status: 'success',
188
+ query,
189
+ results_count: results.length,
190
+ total_apis: getAPICount(),
191
+ results: results.map(r => ({
192
+ id: r.api.id,
193
+ name: r.api.name,
194
+ description: r.api.description,
195
+ category: r.api.category,
196
+ auth: r.api.auth,
197
+ https: r.api.https,
198
+ link: r.api.link,
199
+ pricing: r.api.pricing,
200
+ keywords: r.api.keywords,
201
+ relevance_score: r.relevance_score,
202
+ match_reasons: r.match_reasons
203
+ }))
204
+ }, null, 2)
205
+ }
206
+ ]
207
+ };
208
+ }
209
+
210
+ case 'get_api_details': {
211
+ const apiId = args?.api_id as string;
212
+ const api = getAPIDetails(apiId);
213
+
214
+ if (!api) {
215
+ return {
216
+ content: [
217
+ {
218
+ type: 'text',
219
+ text: JSON.stringify({
220
+ status: 'error',
221
+ message: `API not found: ${apiId}`,
222
+ available_apis: getAllAPIs().map(a => a.id)
223
+ }, null, 2)
224
+ }
225
+ ]
226
+ };
227
+ }
228
+
229
+ return {
230
+ content: [
231
+ {
232
+ type: 'text',
233
+ text: JSON.stringify({
234
+ status: 'success',
235
+ api
236
+ }, null, 2)
237
+ }
238
+ ]
239
+ };
240
+ }
241
+
242
+ case 'purchase_access': {
243
+ const apiId = args?.api_id as string;
244
+ const amountUsd = args?.amount_usd as number;
245
+ const agentId = (args?.agent_id as string) || DEFAULT_AGENT_ID;
246
+
247
+ const result = purchaseAPIAccess(agentId, apiId, amountUsd);
248
+
249
+ if (!result.success) {
250
+ return {
251
+ content: [
252
+ {
253
+ type: 'text',
254
+ text: JSON.stringify({
255
+ status: 'error',
256
+ message: result.error
257
+ }, null, 2)
258
+ }
259
+ ]
260
+ };
261
+ }
262
+
263
+ const api = getAPIDetails(apiId);
264
+
265
+ return {
266
+ content: [
267
+ {
268
+ type: 'text',
269
+ text: JSON.stringify({
270
+ status: 'success',
271
+ message: `Successfully purchased access to ${apiId}`,
272
+ purchase: {
273
+ id: result.purchase!.id,
274
+ provider: apiId,
275
+ amount_paid_usd: amountUsd,
276
+ credits_received: result.purchase!.credits_purchased,
277
+ status: result.purchase!.status
278
+ },
279
+ credentials: result.purchase!.credentials,
280
+ access: {
281
+ link: api?.link,
282
+ auth: api?.auth
283
+ }
284
+ }, null, 2)
285
+ }
286
+ ]
287
+ };
288
+ }
289
+
290
+ case 'check_balance': {
291
+ const agentId = (args?.agent_id as string) || DEFAULT_AGENT_ID;
292
+ const summary = getBalanceSummary(agentId);
293
+
294
+ return {
295
+ content: [
296
+ {
297
+ type: 'text',
298
+ text: JSON.stringify({
299
+ status: 'success',
300
+ agent_id: agentId,
301
+ balance_usd: summary.credits.balance_usd,
302
+ currency: summary.credits.currency,
303
+ total_spent_usd: summary.total_spent_usd,
304
+ active_purchases: summary.active_purchases.map(p => ({
305
+ id: p.id,
306
+ provider: p.provider_id,
307
+ credits_remaining: p.credits_purchased, // Would track actual usage in production
308
+ status: p.status
309
+ }))
310
+ }, null, 2)
311
+ }
312
+ ]
313
+ };
314
+ }
315
+
316
+ case 'add_credits': {
317
+ const amountUsd = args?.amount_usd as number;
318
+ const agentId = (args?.agent_id as string) || DEFAULT_AGENT_ID;
319
+
320
+ const credits = addCredits(agentId, amountUsd);
321
+
322
+ return {
323
+ content: [
324
+ {
325
+ type: 'text',
326
+ text: JSON.stringify({
327
+ status: 'success',
328
+ message: `Added $${amountUsd.toFixed(2)} to your account`,
329
+ new_balance_usd: credits.balance_usd
330
+ }, null, 2)
331
+ }
332
+ ]
333
+ };
334
+ }
335
+
336
+ case 'list_categories': {
337
+ const categories = getCategories();
338
+ const categoryCounts: Record<string, number> = {};
339
+
340
+ for (const cat of categories) {
341
+ categoryCounts[cat] = getAllAPIs().filter(a => a.category === cat).length;
342
+ }
343
+
344
+ return {
345
+ content: [
346
+ {
347
+ type: 'text',
348
+ text: JSON.stringify({
349
+ status: 'success',
350
+ total_apis: getAPICount(),
351
+ category_count: categories.length,
352
+ categories: categoryCounts
353
+ }, null, 2)
354
+ }
355
+ ]
356
+ };
357
+ }
358
+
359
+ default:
360
+ return {
361
+ content: [
362
+ {
363
+ type: 'text',
364
+ text: JSON.stringify({
365
+ status: 'error',
366
+ message: `Unknown tool: ${name}`
367
+ }, null, 2)
368
+ }
369
+ ],
370
+ isError: true
371
+ };
372
+ }
373
+ } catch (error) {
374
+ return {
375
+ content: [
376
+ {
377
+ type: 'text',
378
+ text: JSON.stringify({
379
+ status: 'error',
380
+ message: error instanceof Error ? error.message : 'Unknown error'
381
+ }, null, 2)
382
+ }
383
+ ],
384
+ isError: true
385
+ };
386
+ }
387
+ });
388
+
389
+ // Start server
390
+ async function main() {
391
+ const transport = new StdioServerTransport();
392
+ await server.connect(transport);
393
+ console.error('APIvault MCP server running on stdio');
394
+ }
395
+
396
+ main().catch(console.error);