eigen-skills 2.0.3 → 2.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.
- package/README.md +55 -4
- package/bin/eigen-mcp.js +3 -0
- package/index.js +5 -14
- package/package.json +16 -8
- package/src/mcp-server.js +321 -0
- package/skills/eigen-avs/SKILL.md +0 -92
- package/skills/eigen-avs/scripts/avs-api.js +0 -117
- package/skills/eigen-da/SKILL.md +0 -148
- package/skills/eigen-da/scripts/da-api.js +0 -128
- package/skills/eigen-delegation/SKILL.md +0 -98
- package/skills/eigen-delegation/scripts/delegation-api.js +0 -102
- package/skills/eigen-restaking/SKILL.md +0 -92
- package/skills/eigen-restaking/scripts/eigen-api.js +0 -196
- package/skills/eigen-rewards/SKILL.md +0 -83
- package/skills/eigen-rewards/scripts/rewards-api.js +0 -73
package/README.md
CHANGED
|
@@ -1,22 +1,73 @@
|
|
|
1
1
|
# eigen-skills
|
|
2
2
|
|
|
3
|
-
**EigenCompute Agent Skill — Deploy and manage apps in Trusted Execution Environments (TEE)
|
|
3
|
+
**EigenCompute MCP Server & Agent Skill — Deploy and manage apps in Trusted Execution Environments (TEE)**
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## What is this?
|
|
8
8
|
|
|
9
|
-
**eigen-skills** gives AI agents
|
|
9
|
+
**eigen-skills** gives AI agents the ability to deploy and manage apps on [EigenCompute](https://eigencloud.xyz) — hardware-isolated TEEs powered by Intel TDX with encrypted secrets and cryptographic attestation.
|
|
10
|
+
|
|
11
|
+
Works with:
|
|
12
|
+
- **MCP Clients** — Cursor, Claude Desktop, Antigravity, Cline, etc.
|
|
13
|
+
- **Claude Code** — via SKILL.md standard
|
|
10
14
|
|
|
11
15
|
```bash
|
|
12
16
|
npm install -g eigen-skills@latest
|
|
13
17
|
```
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## MCP Server Setup (Cursor, Claude Desktop, etc.)
|
|
22
|
+
|
|
23
|
+
### 1. Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g eigen-skills
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Configure your MCP client
|
|
30
|
+
|
|
31
|
+
**Cursor** (`~/.cursor/mcp.json`):
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"eigencompute": {
|
|
36
|
+
"command": "eigen-mcp"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"eigencompute": {
|
|
47
|
+
"command": "eigen-mcp"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Available MCP Tools
|
|
54
|
+
|
|
55
|
+
| Tool | Description |
|
|
56
|
+
|------|-------------|
|
|
57
|
+
| `eigencompute_deploy` | Deploy Docker image to TEE |
|
|
58
|
+
| `eigencompute_list` | List all deployed apps |
|
|
59
|
+
| `eigencompute_info` | Get app status, IP, details |
|
|
60
|
+
| `eigencompute_logs` | View app logs |
|
|
61
|
+
| `eigencompute_start` | Start stopped app |
|
|
62
|
+
| `eigencompute_stop` | Stop running app |
|
|
63
|
+
| `eigencompute_terminate` | Destroy app permanently |
|
|
64
|
+
| `eigencompute_whoami` | Check CLI auth status |
|
|
65
|
+
| `eigencompute_env_set` | Set sealed secrets |
|
|
66
|
+
| `eigencompute_upgrade` | Upgrade running app |
|
|
16
67
|
|
|
17
68
|
---
|
|
18
69
|
|
|
19
|
-
##
|
|
70
|
+
## Prerequisites
|
|
20
71
|
|
|
21
72
|
```bash
|
|
22
73
|
npm install -g @layr-labs/ecloud-cli@latest # minimum v0.4.3
|
package/bin/eigen-mcp.js
ADDED
package/index.js
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* eigen-skills —
|
|
2
|
+
* eigen-skills — EigenCompute TEE deployment for AI agents
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* MCP Server: eigen-mcp (for Cursor, Claude Desktop, etc.)
|
|
5
|
+
* Claude Code: Discovers SKILL.md automatically
|
|
6
|
+
* Programmatic: require('eigen-skills')
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const EigenAPI = require('./skills/eigen-restaking/scripts/eigen-api');
|
|
10
|
-
const AVSAPI = require('./skills/eigen-avs/scripts/avs-api');
|
|
11
|
-
const RewardsAPI = require('./skills/eigen-rewards/scripts/rewards-api');
|
|
12
|
-
const DelegationAPI = require('./skills/eigen-delegation/scripts/delegation-api');
|
|
13
9
|
const EigenCompute = require('./skills/eigen-compute/scripts/compute-api');
|
|
14
|
-
const EigenDA = require('./skills/eigen-da/scripts/da-api');
|
|
15
10
|
|
|
16
11
|
module.exports = {
|
|
17
|
-
EigenAPI,
|
|
18
|
-
AVSAPI,
|
|
19
|
-
RewardsAPI,
|
|
20
|
-
DelegationAPI,
|
|
21
12
|
EigenCompute,
|
|
22
|
-
|
|
13
|
+
default: EigenCompute,
|
|
23
14
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eigen-skills",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "Deploy and manage apps on EigenCompute TEE — trusted execution environments with hardware-level isolation, encrypted secrets, and attestation",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Deploy and manage apps on EigenCompute TEE — trusted execution environments with hardware-level isolation, encrypted secrets, and attestation. Works as MCP server for Cursor/Claude Desktop or as Claude Code skill.",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"eigen-mcp": "./bin/eigen-mcp.js",
|
|
8
|
+
"eigencompute": "./bin/eigen-mcp.js"
|
|
9
|
+
},
|
|
6
10
|
"agents": {
|
|
7
11
|
"skills": "skills/"
|
|
8
12
|
},
|
|
@@ -10,22 +14,26 @@
|
|
|
10
14
|
"postinstall": "node scripts/postinstall.js",
|
|
11
15
|
"test": "node scripts/test-all.js",
|
|
12
16
|
"demo": "node scripts/demo.js",
|
|
13
|
-
"ui": "node server.js"
|
|
17
|
+
"ui": "node server.js",
|
|
18
|
+
"mcp": "node src/mcp-server.js"
|
|
14
19
|
},
|
|
15
20
|
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"mcp-server",
|
|
23
|
+
"model-context-protocol",
|
|
16
24
|
"eigenlayer",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"avs",
|
|
25
|
+
"eigencompute",
|
|
26
|
+
"tee",
|
|
20
27
|
"agent-skills",
|
|
21
28
|
"ai-agent",
|
|
22
29
|
"claude",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
30
|
+
"cursor",
|
|
31
|
+
"antigravity"
|
|
25
32
|
],
|
|
26
33
|
"author": "zeeshan8281",
|
|
27
34
|
"license": "MIT",
|
|
28
35
|
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
37
|
"axios": "^1.7.0",
|
|
30
38
|
"dotenv": "^17.3.1",
|
|
31
39
|
"express": "^5.2.1",
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
4
|
+
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
5
|
+
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
|
6
|
+
const { execSync, exec } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const INSTANCE_TYPES = [
|
|
9
|
+
'g1-micro-1v',
|
|
10
|
+
'g1-medium-1v',
|
|
11
|
+
'g1-custom-2-4096s',
|
|
12
|
+
'g1-standard-2s',
|
|
13
|
+
'g1-standard-4t',
|
|
14
|
+
'g1-standard-8t'
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
function checkCLI() {
|
|
18
|
+
try {
|
|
19
|
+
execSync('ecloud --version', { stdio: 'pipe' });
|
|
20
|
+
return true;
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function runCommand(cmd, timeout = 60000) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
exec(`ecloud ${cmd}`, { encoding: 'utf-8', timeout }, (error, stdout, stderr) => {
|
|
29
|
+
if (error) {
|
|
30
|
+
reject(new Error(stderr || error.message));
|
|
31
|
+
} else {
|
|
32
|
+
resolve(stdout.trim());
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function runDeploy(args) {
|
|
39
|
+
const { name, image, instanceType = 'g1-standard-4t', envFile } = args;
|
|
40
|
+
|
|
41
|
+
let cmd = `compute app deploy --name "${name}" --image-ref "${image}" --skip-profile --instance-type ${instanceType} --log-visibility public --resource-usage-monitoring enable --verbose`;
|
|
42
|
+
|
|
43
|
+
if (envFile) {
|
|
44
|
+
cmd += ` --env-file "${envFile}"`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
exec(`echo "n" | ecloud ${cmd}`, { encoding: 'utf-8', timeout: 300000 }, (error, stdout, stderr) => {
|
|
49
|
+
if (error) {
|
|
50
|
+
reject(new Error(stderr || error.message));
|
|
51
|
+
} else {
|
|
52
|
+
resolve(stdout.trim());
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const TOOLS = [
|
|
59
|
+
{
|
|
60
|
+
name: 'eigencompute_whoami',
|
|
61
|
+
description: 'Check which address the ecloud CLI is authenticated as',
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: 'object',
|
|
64
|
+
properties: {},
|
|
65
|
+
required: []
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'eigencompute_list',
|
|
70
|
+
description: 'List all deployed EigenCompute apps',
|
|
71
|
+
inputSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {},
|
|
74
|
+
required: []
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'eigencompute_info',
|
|
79
|
+
description: 'Get detailed info for a specific app including status and IP',
|
|
80
|
+
inputSchema: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
appId: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'The app ID to get info for'
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
required: ['appId']
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'eigencompute_logs',
|
|
93
|
+
description: 'View logs for a specific app',
|
|
94
|
+
inputSchema: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
properties: {
|
|
97
|
+
appId: {
|
|
98
|
+
type: 'string',
|
|
99
|
+
description: 'The app ID to get logs for'
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
required: ['appId']
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'eigencompute_start',
|
|
107
|
+
description: 'Start a stopped app',
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: 'object',
|
|
110
|
+
properties: {
|
|
111
|
+
appId: {
|
|
112
|
+
type: 'string',
|
|
113
|
+
description: 'The app ID to start'
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
required: ['appId']
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'eigencompute_stop',
|
|
121
|
+
description: 'Stop a running app',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
appId: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
description: 'The app ID to stop'
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
required: ['appId']
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'eigencompute_terminate',
|
|
135
|
+
description: 'Permanently terminate and destroy an app. This cannot be undone.',
|
|
136
|
+
inputSchema: {
|
|
137
|
+
type: 'object',
|
|
138
|
+
properties: {
|
|
139
|
+
appId: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
description: 'The app ID to terminate'
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
required: ['appId']
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'eigencompute_deploy',
|
|
149
|
+
description: 'Deploy a Docker image to EigenCompute TEE. Image must be linux/amd64 and pushed to a public registry.',
|
|
150
|
+
inputSchema: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: {
|
|
153
|
+
name: {
|
|
154
|
+
type: 'string',
|
|
155
|
+
description: 'App name for the deployment'
|
|
156
|
+
},
|
|
157
|
+
image: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
description: 'Docker image reference (e.g., user/app:latest)'
|
|
160
|
+
},
|
|
161
|
+
instanceType: {
|
|
162
|
+
type: 'string',
|
|
163
|
+
description: 'Instance type. Recommended: g1-standard-4t',
|
|
164
|
+
enum: INSTANCE_TYPES,
|
|
165
|
+
default: 'g1-standard-4t'
|
|
166
|
+
},
|
|
167
|
+
envFile: {
|
|
168
|
+
type: 'string',
|
|
169
|
+
description: 'Path to .env file for sealed secrets (optional)'
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
required: ['name', 'image']
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'eigencompute_env_set',
|
|
177
|
+
description: 'Set sealed environment variables for an app. Secrets are encrypted and only decryptable inside the TEE.',
|
|
178
|
+
inputSchema: {
|
|
179
|
+
type: 'object',
|
|
180
|
+
properties: {
|
|
181
|
+
appId: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
description: 'The app ID to set env vars for'
|
|
184
|
+
},
|
|
185
|
+
secrets: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
description: 'Key-value pairs of secrets to set',
|
|
188
|
+
additionalProperties: { type: 'string' }
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
required: ['appId', 'secrets']
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'eigencompute_upgrade',
|
|
196
|
+
description: 'Upgrade a running app to a new image version',
|
|
197
|
+
inputSchema: {
|
|
198
|
+
type: 'object',
|
|
199
|
+
properties: {
|
|
200
|
+
appId: {
|
|
201
|
+
type: 'string',
|
|
202
|
+
description: 'The app ID to upgrade'
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
required: ['appId']
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
async function handleToolCall(name, args) {
|
|
211
|
+
if (!checkCLI()) {
|
|
212
|
+
return {
|
|
213
|
+
content: [{
|
|
214
|
+
type: 'text',
|
|
215
|
+
text: 'Error: ecloud CLI not installed. Run: npm install -g @layr-labs/ecloud-cli@latest'
|
|
216
|
+
}],
|
|
217
|
+
isError: true
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
let result;
|
|
223
|
+
|
|
224
|
+
switch (name) {
|
|
225
|
+
case 'eigencompute_whoami':
|
|
226
|
+
result = await runCommand('auth whoami');
|
|
227
|
+
break;
|
|
228
|
+
|
|
229
|
+
case 'eigencompute_list':
|
|
230
|
+
result = await runCommand('compute app list');
|
|
231
|
+
break;
|
|
232
|
+
|
|
233
|
+
case 'eigencompute_info':
|
|
234
|
+
result = await runCommand(`compute app info ${args.appId}`);
|
|
235
|
+
break;
|
|
236
|
+
|
|
237
|
+
case 'eigencompute_logs':
|
|
238
|
+
result = await runCommand(`compute app logs ${args.appId}`, 120000);
|
|
239
|
+
break;
|
|
240
|
+
|
|
241
|
+
case 'eigencompute_start':
|
|
242
|
+
result = await runCommand(`compute app start ${args.appId}`);
|
|
243
|
+
break;
|
|
244
|
+
|
|
245
|
+
case 'eigencompute_stop':
|
|
246
|
+
result = await runCommand(`compute app stop ${args.appId}`);
|
|
247
|
+
break;
|
|
248
|
+
|
|
249
|
+
case 'eigencompute_terminate':
|
|
250
|
+
result = await new Promise((resolve, reject) => {
|
|
251
|
+
exec(`echo "y" | ecloud compute app terminate ${args.appId}`,
|
|
252
|
+
{ encoding: 'utf-8', timeout: 60000 },
|
|
253
|
+
(error, stdout, stderr) => {
|
|
254
|
+
if (error) reject(new Error(stderr || error.message));
|
|
255
|
+
else resolve(stdout.trim());
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
break;
|
|
259
|
+
|
|
260
|
+
case 'eigencompute_deploy':
|
|
261
|
+
result = await runDeploy(args);
|
|
262
|
+
break;
|
|
263
|
+
|
|
264
|
+
case 'eigencompute_env_set':
|
|
265
|
+
const secretPairs = Object.entries(args.secrets)
|
|
266
|
+
.map(([k, v]) => `${k}="${v}"`)
|
|
267
|
+
.join(' ');
|
|
268
|
+
result = await runCommand(`compute app env set ${secretPairs}`, 120000);
|
|
269
|
+
break;
|
|
270
|
+
|
|
271
|
+
case 'eigencompute_upgrade':
|
|
272
|
+
result = await runCommand(`compute app upgrade ${args.appId}`, 300000);
|
|
273
|
+
break;
|
|
274
|
+
|
|
275
|
+
default:
|
|
276
|
+
return {
|
|
277
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
278
|
+
isError: true
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
content: [{ type: 'text', text: result || 'Command completed successfully' }]
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
} catch (error) {
|
|
287
|
+
return {
|
|
288
|
+
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
289
|
+
isError: true
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function main() {
|
|
295
|
+
const server = new Server(
|
|
296
|
+
{
|
|
297
|
+
name: 'eigencompute',
|
|
298
|
+
version: '2.1.0'
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
capabilities: {
|
|
302
|
+
tools: {}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
308
|
+
return { tools: TOOLS };
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
312
|
+
const { name, arguments: args } = request.params;
|
|
313
|
+
return handleToolCall(name, args || {});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const transport = new StdioServerTransport();
|
|
317
|
+
await server.connect(transport);
|
|
318
|
+
console.error('EigenCompute MCP server running on stdio');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
main().catch(console.error);
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: eigen-avs
|
|
3
|
-
description: "Query EigenLayer AVS (Actively Validated Services) — list services, operators per AVS, stakers per AVS, registration events, and operator-sets"
|
|
4
|
-
version: 1.0.0
|
|
5
|
-
metadata:
|
|
6
|
-
emoji: "🛡️"
|
|
7
|
-
tags: ["eigenlayer", "avs", "services", "operators", "security"]
|
|
8
|
-
user-invocable: true
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# EigenLayer AVS Skill
|
|
12
|
-
|
|
13
|
-
Query live data about Actively Validated Services (AVS) on EigenLayer: service listings, operators securing each AVS, staker delegations, registration events, and operator-sets.
|
|
14
|
-
|
|
15
|
-
## Data Source
|
|
16
|
-
|
|
17
|
-
**EigenExplorer API** — `https://api.eigenexplorer.com`
|
|
18
|
-
- Auth: `x-api-token` header (free key at https://developer.eigenexplorer.com)
|
|
19
|
-
|
|
20
|
-
## When to use this skill
|
|
21
|
-
|
|
22
|
-
Use when the user asks about:
|
|
23
|
-
- AVS (Actively Validated Services) on EigenLayer
|
|
24
|
-
- Which operators are securing a specific AVS
|
|
25
|
-
- Stakers delegated to a specific AVS
|
|
26
|
-
- AVS registration/deregistration events
|
|
27
|
-
- Operator-sets for an AVS
|
|
28
|
-
- Comparing AVS by TVL, staker count, or APY
|
|
29
|
-
|
|
30
|
-
## How to query
|
|
31
|
-
|
|
32
|
-
### Get all AVS (sorted by TVL)
|
|
33
|
-
```bash
|
|
34
|
-
curl -s "https://api.eigenexplorer.com/avs?withTvl=true&sortByTvl=desc&take=10" -H "x-api-token: $EIGEN_API_KEY"
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Search AVS by name
|
|
38
|
-
```bash
|
|
39
|
-
curl -s "https://api.eigenexplorer.com/avs?searchByText=eigenda&withTvl=true" -H "x-api-token: $EIGEN_API_KEY"
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Get a specific AVS
|
|
43
|
-
```bash
|
|
44
|
-
curl -s "https://api.eigenexplorer.com/avs/0xAVS_ADDRESS?withTvl=true" -H "x-api-token: $EIGEN_API_KEY"
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Get operators registered to an AVS
|
|
48
|
-
```bash
|
|
49
|
-
curl -s "https://api.eigenexplorer.com/avs/0xAVS_ADDRESS/operators?take=20" -H "x-api-token: $EIGEN_API_KEY"
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Get stakers for an AVS
|
|
53
|
-
```bash
|
|
54
|
-
curl -s "https://api.eigenexplorer.com/avs/0xAVS_ADDRESS/stakers?take=20" -H "x-api-token: $EIGEN_API_KEY"
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Get registration events for an AVS
|
|
58
|
-
```bash
|
|
59
|
-
curl -s "https://api.eigenexplorer.com/avs/0xAVS_ADDRESS/events/registration?take=20" -H "x-api-token: $EIGEN_API_KEY"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Get operator-sets for an AVS
|
|
63
|
-
```bash
|
|
64
|
-
curl -s "https://api.eigenexplorer.com/avs/0xAVS_ADDRESS/operator-sets?take=20" -H "x-api-token: $EIGEN_API_KEY"
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Get all AVS addresses (lightweight)
|
|
68
|
-
```bash
|
|
69
|
-
curl -s "https://api.eigenexplorer.com/avs/addresses" -H "x-api-token: $EIGEN_API_KEY"
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Response Format
|
|
73
|
-
|
|
74
|
-
Format results for the user with:
|
|
75
|
-
- **Bold AVS names** and abbreviated addresses
|
|
76
|
-
- TVL in human-readable form (e.g., "$500M")
|
|
77
|
-
- Number of operators securing the AVS
|
|
78
|
-
- Number of stakers
|
|
79
|
-
- APY if available
|
|
80
|
-
- Active/inactive status for operator registrations
|
|
81
|
-
- Use bullet points, never tables in chat
|
|
82
|
-
|
|
83
|
-
## Programmatic Usage
|
|
84
|
-
|
|
85
|
-
```javascript
|
|
86
|
-
const AVSAPI = require('eigen-agent-skills/skills/eigen-avs/scripts/avs-api');
|
|
87
|
-
const api = new AVSAPI('YOUR_API_KEY');
|
|
88
|
-
|
|
89
|
-
const allAVS = await api.getAllAVS({ sortByTvl: 'desc', take: 10 });
|
|
90
|
-
const operators = await api.getAVSOperators('0xAVS_ADDRESS');
|
|
91
|
-
const stakers = await api.getAVSStakers('0xAVS_ADDRESS');
|
|
92
|
-
```
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EigenLayer AVS (Actively Validated Services) API Client
|
|
3
|
-
*
|
|
4
|
-
* Data source: EigenExplorer REST API
|
|
5
|
-
* Covers: AVS listing, detail, operators per AVS, stakers per AVS, registration events
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const axios = require('axios');
|
|
9
|
-
|
|
10
|
-
const MAINNET = 'https://api.eigenexplorer.com';
|
|
11
|
-
const HOLESKY = 'https://api-holesky.eigenexplorer.com';
|
|
12
|
-
|
|
13
|
-
class AVSAPI {
|
|
14
|
-
constructor(apiKey, { network = 'mainnet' } = {}) {
|
|
15
|
-
if (!apiKey) throw new Error('EigenExplorer API key required. Get one free at https://developer.eigenexplorer.com');
|
|
16
|
-
this.client = axios.create({
|
|
17
|
-
baseURL: network === 'holesky' ? HOLESKY : MAINNET,
|
|
18
|
-
headers: {
|
|
19
|
-
'x-api-token': apiKey,
|
|
20
|
-
'Content-Type': 'application/json',
|
|
21
|
-
},
|
|
22
|
-
timeout: 30000,
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ─── AVS Listing ──────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get all AVS with optional filtering and sorting.
|
|
30
|
-
* @param {object} opts
|
|
31
|
-
* @param {boolean} [opts.withTvl=true]
|
|
32
|
-
* @param {string} [opts.searchByText] - search AVS by name
|
|
33
|
-
* @param {'asc'|'desc'} [opts.sortByTvl]
|
|
34
|
-
* @param {'asc'|'desc'} [opts.sortByApy]
|
|
35
|
-
* @param {'asc'|'desc'} [opts.sortByTotalStakers]
|
|
36
|
-
* @param {number} [opts.skip=0]
|
|
37
|
-
* @param {number} [opts.take=12]
|
|
38
|
-
*/
|
|
39
|
-
async getAllAVS(opts = {}) {
|
|
40
|
-
const params = {
|
|
41
|
-
withTvl: opts.withTvl !== false ? 'true' : 'false',
|
|
42
|
-
skip: opts.skip || 0,
|
|
43
|
-
take: opts.take || 12,
|
|
44
|
-
};
|
|
45
|
-
if (opts.searchByText) params.searchByText = opts.searchByText;
|
|
46
|
-
if (opts.sortByTvl) params.sortByTvl = opts.sortByTvl;
|
|
47
|
-
if (opts.sortByApy) params.sortByApy = opts.sortByApy;
|
|
48
|
-
if (opts.sortByTotalStakers) params.sortByTotalStakers = opts.sortByTotalStakers;
|
|
49
|
-
|
|
50
|
-
const { data } = await this.client.get('/avs', { params });
|
|
51
|
-
return data;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get AVS addresses only (lightweight).
|
|
56
|
-
*/
|
|
57
|
-
async getAVSAddresses() {
|
|
58
|
-
const { data } = await this.client.get('/avs/addresses');
|
|
59
|
-
return data;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Get detailed info for a single AVS.
|
|
64
|
-
* @param {string} address - AVS contract address
|
|
65
|
-
* @param {boolean} [withTvl=true]
|
|
66
|
-
*/
|
|
67
|
-
async getAVS(address, withTvl = true) {
|
|
68
|
-
const { data } = await this.client.get(`/avs/${address}`, {
|
|
69
|
-
params: { withTvl: withTvl ? 'true' : 'false' },
|
|
70
|
-
});
|
|
71
|
-
return data;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// ─── AVS ↔ Operators ─────────────────────────────────
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get operators registered to a specific AVS.
|
|
78
|
-
* @param {string} avsAddress
|
|
79
|
-
* @param {object} opts
|
|
80
|
-
*/
|
|
81
|
-
async getAVSOperators(avsAddress, opts = {}) {
|
|
82
|
-
const { data } = await this.client.get(`/avs/${avsAddress}/operators`, {
|
|
83
|
-
params: { skip: opts.skip || 0, take: opts.take || 12 },
|
|
84
|
-
});
|
|
85
|
-
return data;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// ─── AVS ↔ Stakers ───────────────────────────────────
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get stakers delegated to a specific AVS.
|
|
92
|
-
* @param {string} avsAddress
|
|
93
|
-
* @param {object} opts
|
|
94
|
-
*/
|
|
95
|
-
async getAVSStakers(avsAddress, opts = {}) {
|
|
96
|
-
const { data } = await this.client.get(`/avs/${avsAddress}/stakers`, {
|
|
97
|
-
params: { skip: opts.skip || 0, take: opts.take || 12 },
|
|
98
|
-
});
|
|
99
|
-
return data;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ─── AVS Registration Events ──────────────────────────
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Get registration/deregistration events for a specific AVS.
|
|
106
|
-
* @param {string} avsAddress
|
|
107
|
-
* @param {object} opts
|
|
108
|
-
*/
|
|
109
|
-
async getAVSRegistrationEvents(avsAddress, opts = {}) {
|
|
110
|
-
const { data } = await this.client.get(`/avs/${avsAddress}/events/registration-status`, {
|
|
111
|
-
params: { skip: opts.skip || 0, take: opts.take || 12 },
|
|
112
|
-
});
|
|
113
|
-
return data;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
module.exports = AVSAPI;
|