@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.
- package/.github/ISSUE_TEMPLATE/add-api.yml +123 -0
- package/BRIEFING.md +30 -0
- package/CONCEPT.md +494 -0
- package/README.md +272 -0
- package/backend/convex/README.md +90 -0
- package/backend/convex/_generated/api.d.ts +55 -0
- package/backend/convex/_generated/api.js +23 -0
- package/backend/convex/_generated/dataModel.d.ts +60 -0
- package/backend/convex/_generated/server.d.ts +143 -0
- package/backend/convex/_generated/server.js +93 -0
- package/backend/convex/apiKeys.ts +75 -0
- package/backend/convex/purchases.ts +74 -0
- package/backend/convex/schema.ts +45 -0
- package/backend/convex/transactions.ts +57 -0
- package/backend/convex/tsconfig.json +25 -0
- package/backend/convex/users.ts +94 -0
- package/backend/package-lock.json +521 -0
- package/backend/package.json +15 -0
- package/dist/credits.d.ts +54 -0
- package/dist/credits.d.ts.map +1 -0
- package/dist/credits.js +209 -0
- package/dist/credits.js.map +1 -0
- package/dist/discovery.d.ts +37 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +109 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +355 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/apis.json +20894 -0
- package/dist/registry/parse_apis.py +146 -0
- package/dist/revenuecat.d.ts +61 -0
- package/dist/revenuecat.d.ts.map +1 -0
- package/dist/revenuecat.js +166 -0
- package/dist/revenuecat.js.map +1 -0
- package/dist/test.d.ts +6 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +81 -0
- package/dist/test.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/webhooks/revenuecat.d.ts +48 -0
- package/dist/webhooks/revenuecat.d.ts.map +1 -0
- package/dist/webhooks/revenuecat.js +119 -0
- package/dist/webhooks/revenuecat.js.map +1 -0
- package/docs/revenuecat-setup.md +89 -0
- package/landing/next-env.d.ts +5 -0
- package/landing/next.config.mjs +6 -0
- package/landing/package-lock.json +1666 -0
- package/landing/package.json +27 -0
- package/landing/postcss.config.js +6 -0
- package/landing/src/app/api/keys/route.ts +71 -0
- package/landing/src/app/api/log/route.ts +37 -0
- package/landing/src/app/api/stats/route.ts +37 -0
- package/landing/src/app/globals.css +261 -0
- package/landing/src/app/layout.tsx +37 -0
- package/landing/src/app/page.tsx +753 -0
- package/landing/src/app/page.tsx.bak +567 -0
- package/landing/src/components/AddKeyModal.tsx +159 -0
- package/landing/tailwind.config.ts +34 -0
- package/landing/tsconfig.json +20 -0
- package/newsletter-template.html +71 -0
- package/outreach/OUTREACH-SYSTEM.md +211 -0
- package/outreach/email-template.html +179 -0
- package/outreach/targets.md +133 -0
- package/package.json +39 -0
- package/src/credits.ts +261 -0
- package/src/discovery.ts +147 -0
- package/src/index.ts +396 -0
- package/src/registry/apis.json +20894 -0
- package/src/registry/parse_apis.py +146 -0
- package/src/revenuecat.ts +239 -0
- package/src/test.ts +97 -0
- package/src/types.ts +110 -0
- package/src/webhooks/revenuecat.ts +187 -0
- 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);
|