tokrepo-mcp-server 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/README.md +88 -0
- package/bin/server.js +323 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# TokRepo MCP Server
|
|
2
|
+
|
|
3
|
+
> Search, browse, and install AI assets from [TokRepo](https://tokrepo.com) — the open registry for AI skills, prompts, MCP configs, scripts, and workflows.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@tokrepo/mcp-server)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
### Claude Code
|
|
11
|
+
```bash
|
|
12
|
+
claude mcp add tokrepo -- npx @tokrepo/mcp-server
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Cursor / Windsurf
|
|
16
|
+
Add to your MCP config (`~/.cursor/mcp.json`):
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"tokrepo": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["@tokrepo/mcp-server"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### OpenAI Codex / Gemini CLI
|
|
29
|
+
```bash
|
|
30
|
+
codex --mcp-server tokrepo -- npx @tokrepo/mcp-server
|
|
31
|
+
gemini settings mcp add tokrepo -- npx @tokrepo/mcp-server
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What It Does
|
|
35
|
+
|
|
36
|
+
Once connected, your AI assistant can:
|
|
37
|
+
|
|
38
|
+
- **Search** 200+ curated AI assets by keyword or category
|
|
39
|
+
- **Browse** trending assets, filter by type (MCP, Skill, Prompt, Agent, Script)
|
|
40
|
+
- **Get details** — full documentation, install instructions, and metadata
|
|
41
|
+
- **Install** — get raw content ready to save or execute
|
|
42
|
+
|
|
43
|
+
## Available Tools
|
|
44
|
+
|
|
45
|
+
| Tool | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `tokrepo_search` | Search assets by keyword and tag |
|
|
48
|
+
| `tokrepo_detail` | Get full asset details by UUID |
|
|
49
|
+
| `tokrepo_install` | Get raw installable content |
|
|
50
|
+
| `tokrepo_trending` | Browse popular/latest assets |
|
|
51
|
+
|
|
52
|
+
## Example Conversations
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
You: "Find me a good MCP server for databases"
|
|
56
|
+
AI: [calls tokrepo_search] → Shows DBHub, Supabase MCP, PostgreSQL MCP with install commands
|
|
57
|
+
|
|
58
|
+
You: "What's trending on TokRepo?"
|
|
59
|
+
AI: [calls tokrepo_trending] → Shows top assets by popularity
|
|
60
|
+
|
|
61
|
+
You: "Install that cursor rules asset"
|
|
62
|
+
AI: [calls tokrepo_install] → Returns raw content ready to save
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Why TokRepo?
|
|
66
|
+
|
|
67
|
+
TokRepo is the **open registry for AI assets** — like npm for packages, but for AI skills, prompts, MCP configs, and workflows.
|
|
68
|
+
|
|
69
|
+
- **200+ curated assets** — quality-reviewed, not a dump
|
|
70
|
+
- **Agent-native** — every asset has machine-readable install contracts
|
|
71
|
+
- **Universal** — works with Claude Code, Cursor, Codex, Gemini CLI, and any MCP client
|
|
72
|
+
- **CLI available** — `npx tokrepo search "query"` / `npx tokrepo install <uuid>`
|
|
73
|
+
|
|
74
|
+
## Requirements
|
|
75
|
+
|
|
76
|
+
- Node.js >= 18
|
|
77
|
+
- Internet connection (queries tokrepo.com API)
|
|
78
|
+
|
|
79
|
+
## Links
|
|
80
|
+
|
|
81
|
+
- **Website**: [tokrepo.com](https://tokrepo.com)
|
|
82
|
+
- **CLI**: [npm: tokrepo](https://www.npmjs.com/package/tokrepo)
|
|
83
|
+
- **GitHub**: [tokrepo/mcp-server](https://github.com/tokrepo/mcp-server)
|
|
84
|
+
- **API**: [tokrepo.com/.well-known/tokrepo.json](https://tokrepo.com/.well-known/tokrepo.json)
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT
|
package/bin/server.js
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TokRepo MCP Server
|
|
5
|
+
*
|
|
6
|
+
* Search, browse, and install AI assets from TokRepo via the Model Context Protocol.
|
|
7
|
+
* Works with Claude Code, Cursor, Codex, Gemini CLI, and any MCP client.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* claude mcp add tokrepo -- npx @tokrepo/mcp-server
|
|
11
|
+
* npx @tokrepo/mcp-server
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const https = require('https');
|
|
15
|
+
const readline = require('readline');
|
|
16
|
+
|
|
17
|
+
const API_BASE = 'https://api.tokrepo.com';
|
|
18
|
+
const TOKREPO_URL = 'https://tokrepo.com';
|
|
19
|
+
|
|
20
|
+
// ─── MCP Protocol (JSON-RPC over stdio) ───
|
|
21
|
+
|
|
22
|
+
const SERVER_INFO = {
|
|
23
|
+
name: 'tokrepo',
|
|
24
|
+
version: '1.0.0',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const CAPABILITIES = {
|
|
28
|
+
tools: {},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const TOOLS = [
|
|
32
|
+
{
|
|
33
|
+
name: 'tokrepo_search',
|
|
34
|
+
description: 'Search TokRepo for AI assets (skills, prompts, MCP configs, scripts, workflows). Returns matching assets with titles, descriptions, tags, stars, and install commands. Use this when the user asks to find AI tools, MCP servers, Claude skills, prompts, or workflows.',
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
query: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Search keywords (e.g. "cursor rules", "mcp database", "claude skill code review")',
|
|
41
|
+
},
|
|
42
|
+
tag: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'Optional tag filter: agent, coding, efficiency, cost-saving, methodology, data-analysis, writing, marketing, learning, research',
|
|
45
|
+
enum: ['agent', 'coding', 'efficiency', 'cost-saving', 'methodology', 'data-analysis', 'writing', 'marketing', 'learning', 'research'],
|
|
46
|
+
},
|
|
47
|
+
limit: {
|
|
48
|
+
type: 'number',
|
|
49
|
+
description: 'Max results (default 10, max 20)',
|
|
50
|
+
default: 10,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
required: ['query'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'tokrepo_detail',
|
|
58
|
+
description: 'Get full details of a TokRepo asset by UUID, including description, content, tags, install instructions, and metadata.',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
uuid: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Asset UUID (from search results)',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
required: ['uuid'],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'tokrepo_install',
|
|
72
|
+
description: 'Get the install command and raw content for a TokRepo asset. Returns the content ready to be saved to a file or executed.',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
uuid: {
|
|
77
|
+
type: 'string',
|
|
78
|
+
description: 'Asset UUID',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ['uuid'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'tokrepo_trending',
|
|
86
|
+
description: 'Get trending/popular AI assets on TokRepo. Use when user asks for recommended or popular AI tools.',
|
|
87
|
+
inputSchema: {
|
|
88
|
+
type: 'object',
|
|
89
|
+
properties: {
|
|
90
|
+
sort: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Sort order',
|
|
93
|
+
enum: ['popular', 'latest', 'views', 'stars'],
|
|
94
|
+
default: 'popular',
|
|
95
|
+
},
|
|
96
|
+
limit: {
|
|
97
|
+
type: 'number',
|
|
98
|
+
description: 'Max results (default 10)',
|
|
99
|
+
default: 10,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
// ─── HTTP Helper ───
|
|
107
|
+
|
|
108
|
+
function apiGet(path) {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
const url = `${API_BASE}${path}`;
|
|
111
|
+
const req = https.get(url, { headers: { Accept: 'application/json' }, timeout: 10000 }, (res) => {
|
|
112
|
+
let body = '';
|
|
113
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
114
|
+
res.on('end', () => {
|
|
115
|
+
try {
|
|
116
|
+
const data = JSON.parse(body);
|
|
117
|
+
resolve(data);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
reject(new Error(`Invalid JSON from ${path}`));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
req.on('error', reject);
|
|
124
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function apiGetText(path) {
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
const url = `${API_BASE}${path}`;
|
|
131
|
+
const req = https.get(url, { headers: { Accept: 'text/plain' }, timeout: 10000 }, (res) => {
|
|
132
|
+
let body = '';
|
|
133
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
134
|
+
res.on('end', () => resolve(body));
|
|
135
|
+
});
|
|
136
|
+
req.on('error', reject);
|
|
137
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── Tool Handlers ───
|
|
142
|
+
|
|
143
|
+
async function handleSearch(args) {
|
|
144
|
+
const { query, tag, limit = 10 } = args;
|
|
145
|
+
const params = new URLSearchParams({
|
|
146
|
+
keyword: query,
|
|
147
|
+
page: '1',
|
|
148
|
+
page_size: String(Math.min(limit, 20)),
|
|
149
|
+
sort_by: 'popular',
|
|
150
|
+
});
|
|
151
|
+
if (tag) {
|
|
152
|
+
// Map tag name to tag_id (approximate)
|
|
153
|
+
const tagMap = { agent: 11, coding: 7, efficiency: 10, 'cost-saving': 12, methodology: 15, 'data-analysis': 14, writing: 1, marketing: 16, learning: 17, research: 8 };
|
|
154
|
+
if (tagMap[tag]) params.set('tag_id', String(tagMap[tag]));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const res = await apiGet(`/api/v1/tokenboard/workflows/list?${params}`);
|
|
158
|
+
if (res.code !== 200 || !res.data?.list?.length) {
|
|
159
|
+
return { content: [{ type: 'text', text: `No assets found for "${query}". Try broader keywords.` }] };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const items = res.data.list.slice(0, limit);
|
|
163
|
+
const lines = items.map((item, i) => {
|
|
164
|
+
const tags = (item.tags || []).map(t => t.name || t.slug).join(', ');
|
|
165
|
+
return [
|
|
166
|
+
`${i + 1}. **${item.title}**`,
|
|
167
|
+
` ${item.description || ''}`,
|
|
168
|
+
` Tags: ${tags || 'general'} | ★ ${item.vote_count || 0} | 👁 ${item.view_count || 0}`,
|
|
169
|
+
` Install: \`tokrepo install ${item.uuid}\``,
|
|
170
|
+
` URL: ${TOKREPO_URL}/en/workflows/${item.uuid}`,
|
|
171
|
+
].join('\n');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const text = `Found ${res.data.total} assets for "${query}" (showing ${items.length}):\n\n${lines.join('\n\n')}`;
|
|
175
|
+
return { content: [{ type: 'text', text }] };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function handleDetail(args) {
|
|
179
|
+
const { uuid } = args;
|
|
180
|
+
const res = await apiGet(`/api/v1/tokenboard/workflows/detail?uuid=${encodeURIComponent(uuid)}`);
|
|
181
|
+
if (res.code !== 200 || !res.data?.workflow) {
|
|
182
|
+
return { content: [{ type: 'text', text: `Asset not found: ${uuid}` }] };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const w = res.data.workflow;
|
|
186
|
+
const tags = (w.tags || []).map(t => t.name || t.slug).join(', ');
|
|
187
|
+
const steps = (w.steps || []).map((s, i) => {
|
|
188
|
+
const content = s.prompt_template || s.description || '';
|
|
189
|
+
return `### Step ${i + 1}: ${s.title}\n${content.substring(0, 500)}${content.length > 500 ? '...' : ''}`;
|
|
190
|
+
}).join('\n\n');
|
|
191
|
+
|
|
192
|
+
const text = [
|
|
193
|
+
`# ${w.title}`,
|
|
194
|
+
``,
|
|
195
|
+
`**Description**: ${w.description}`,
|
|
196
|
+
`**Tags**: ${tags}`,
|
|
197
|
+
`**Stars**: ${w.vote_count || 0} | **Views**: ${w.view_count || 0} | **Forks**: ${w.fork_count || 0}`,
|
|
198
|
+
`**Author**: ${w.author_name || 'Anonymous'}`,
|
|
199
|
+
`**URL**: ${TOKREPO_URL}/en/workflows/${w.uuid}`,
|
|
200
|
+
`**Install**: \`tokrepo install ${w.uuid}\``,
|
|
201
|
+
``,
|
|
202
|
+
steps,
|
|
203
|
+
].join('\n');
|
|
204
|
+
|
|
205
|
+
return { content: [{ type: 'text', text }] };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function handleInstall(args) {
|
|
209
|
+
const { uuid } = args;
|
|
210
|
+
try {
|
|
211
|
+
const raw = await apiGetText(`/api/v1/tokenboard/workflows/raw?uuid=${encodeURIComponent(uuid)}`);
|
|
212
|
+
if (!raw || raw.includes('"code":')) {
|
|
213
|
+
return { content: [{ type: 'text', text: `Could not fetch raw content for ${uuid}. Try: tokrepo install ${uuid}` }] };
|
|
214
|
+
}
|
|
215
|
+
return { content: [{ type: 'text', text: `# Raw content for asset ${uuid}\n\nInstall via CLI: \`npx tokrepo install ${uuid}\`\n\n---\n\n${raw}` }] };
|
|
216
|
+
} catch (e) {
|
|
217
|
+
return { content: [{ type: 'text', text: `Error fetching asset: ${e.message}. Try: tokrepo install ${uuid}` }] };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function handleTrending(args) {
|
|
222
|
+
const { sort = 'popular', limit = 10 } = args;
|
|
223
|
+
const params = new URLSearchParams({
|
|
224
|
+
page: '1',
|
|
225
|
+
page_size: String(Math.min(limit, 20)),
|
|
226
|
+
sort_by: sort,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const res = await apiGet(`/api/v1/tokenboard/workflows/list?${params}`);
|
|
230
|
+
if (res.code !== 200 || !res.data?.list?.length) {
|
|
231
|
+
return { content: [{ type: 'text', text: 'No trending assets found.' }] };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const items = res.data.list.slice(0, limit);
|
|
235
|
+
const lines = items.map((item, i) => {
|
|
236
|
+
const tags = (item.tags || []).map(t => t.name || t.slug).join(', ');
|
|
237
|
+
return `${i + 1}. **${item.title}** — ${item.description || ''}\n ${tags} | ★ ${item.vote_count || 0} | 👁 ${item.view_count || 0} | Install: \`tokrepo install ${item.uuid}\``;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const text = `Trending AI assets on TokRepo (${sort}):\n\n${lines.join('\n\n')}\n\nBrowse more: ${TOKREPO_URL}`;
|
|
241
|
+
return { content: [{ type: 'text', text }] };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ─── MCP JSON-RPC Handler ───
|
|
245
|
+
|
|
246
|
+
async function handleRequest(msg) {
|
|
247
|
+
const { id, method, params } = msg;
|
|
248
|
+
|
|
249
|
+
switch (method) {
|
|
250
|
+
case 'initialize':
|
|
251
|
+
return { jsonrpc: '2.0', id, result: { protocolVersion: '2024-11-05', capabilities: CAPABILITIES, serverInfo: SERVER_INFO } };
|
|
252
|
+
|
|
253
|
+
case 'notifications/initialized':
|
|
254
|
+
return null; // no response for notifications
|
|
255
|
+
|
|
256
|
+
case 'tools/list':
|
|
257
|
+
return { jsonrpc: '2.0', id, result: { tools: TOOLS } };
|
|
258
|
+
|
|
259
|
+
case 'tools/call': {
|
|
260
|
+
const { name, arguments: args } = params || {};
|
|
261
|
+
let result;
|
|
262
|
+
try {
|
|
263
|
+
switch (name) {
|
|
264
|
+
case 'tokrepo_search': result = await handleSearch(args || {}); break;
|
|
265
|
+
case 'tokrepo_detail': result = await handleDetail(args || {}); break;
|
|
266
|
+
case 'tokrepo_install': result = await handleInstall(args || {}); break;
|
|
267
|
+
case 'tokrepo_trending': result = await handleTrending(args || {}); break;
|
|
268
|
+
default: result = { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
|
|
269
|
+
}
|
|
270
|
+
} catch (e) {
|
|
271
|
+
result = { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
|
|
272
|
+
}
|
|
273
|
+
return { jsonrpc: '2.0', id, result };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
case 'ping':
|
|
277
|
+
return { jsonrpc: '2.0', id, result: {} };
|
|
278
|
+
|
|
279
|
+
default:
|
|
280
|
+
return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ─── Stdio Transport ───
|
|
285
|
+
|
|
286
|
+
function main() {
|
|
287
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
288
|
+
let buffer = '';
|
|
289
|
+
|
|
290
|
+
process.stdin.on('data', (chunk) => {
|
|
291
|
+
buffer += chunk.toString();
|
|
292
|
+
// Process complete JSON-RPC messages (newline-delimited)
|
|
293
|
+
const lines = buffer.split('\n');
|
|
294
|
+
buffer = lines.pop() || '';
|
|
295
|
+
for (const line of lines) {
|
|
296
|
+
const trimmed = line.trim();
|
|
297
|
+
if (!trimmed) continue;
|
|
298
|
+
try {
|
|
299
|
+
const msg = JSON.parse(trimmed);
|
|
300
|
+
handleRequest(msg).then((response) => {
|
|
301
|
+
if (response) {
|
|
302
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
303
|
+
}
|
|
304
|
+
}).catch((e) => {
|
|
305
|
+
process.stdout.write(JSON.stringify({
|
|
306
|
+
jsonrpc: '2.0',
|
|
307
|
+
id: msg.id || null,
|
|
308
|
+
error: { code: -32603, message: e.message },
|
|
309
|
+
}) + '\n');
|
|
310
|
+
});
|
|
311
|
+
} catch (e) {
|
|
312
|
+
// Skip malformed JSON
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
process.stdin.on('end', () => process.exit(0));
|
|
318
|
+
|
|
319
|
+
// Log to stderr (not stdout, which is the MCP transport)
|
|
320
|
+
process.stderr.write('TokRepo MCP Server v1.0.0 started\n');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tokrepo-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for TokRepo — search, browse, and install AI assets from any MCP client (Claude Code, Cursor, Codex, Gemini CLI).",
|
|
5
|
+
"bin": {
|
|
6
|
+
"tokrepo-mcp-server": "bin/server.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/tokrepo/mcp-server.git"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://tokrepo.com",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"mcp-server",
|
|
20
|
+
"tokrepo",
|
|
21
|
+
"ai-assets",
|
|
22
|
+
"claude",
|
|
23
|
+
"cursor",
|
|
24
|
+
"codex",
|
|
25
|
+
"gemini",
|
|
26
|
+
"skills",
|
|
27
|
+
"prompts",
|
|
28
|
+
"workflows",
|
|
29
|
+
"agent"
|
|
30
|
+
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
}
|
|
34
|
+
}
|