@rickydata/agent0-mcp 0.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/.env.example +17 -0
- package/Dockerfile +25 -0
- package/README.md +85 -0
- package/dist/auth/sdk-client.d.ts +47 -0
- package/dist/auth/sdk-client.js +142 -0
- package/dist/auth/sdk-client.js.map +1 -0
- package/dist/auth/token.d.ts +5 -0
- package/dist/auth/token.js +6 -0
- package/dist/auth/token.js.map +1 -0
- package/dist/auth/wallet-derivation.d.ts +26 -0
- package/dist/auth/wallet-derivation.js +76 -0
- package/dist/auth/wallet-derivation.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +140 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/a2a.d.ts +3 -0
- package/dist/tools/a2a.js +170 -0
- package/dist/tools/a2a.js.map +1 -0
- package/dist/tools/discovery.d.ts +3 -0
- package/dist/tools/discovery.js +465 -0
- package/dist/tools/discovery.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +38 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/payments.d.ts +3 -0
- package/dist/tools/payments.js +124 -0
- package/dist/tools/payments.js.map +1 -0
- package/dist/tools/registration.d.ts +3 -0
- package/dist/tools/registration.js +324 -0
- package/dist/tools/registration.js.map +1 -0
- package/dist/tools/reputation.d.ts +3 -0
- package/dist/tools/reputation.js +147 -0
- package/dist/tools/reputation.js.map +1 -0
- package/dist/utils/chains.d.ts +10 -0
- package/dist/utils/chains.js +33 -0
- package/dist/utils/chains.js.map +1 -0
- package/dist/utils/trust-labels.d.ts +10 -0
- package/dist/utils/trust-labels.js +48 -0
- package/dist/utils/trust-labels.js.map +1 -0
- package/dist/utils/validation.d.ts +12 -0
- package/dist/utils/validation.js +19 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +32 -0
- package/src/auth/sdk-client.ts +171 -0
- package/src/auth/token.ts +19 -0
- package/src/auth/wallet-derivation.ts +91 -0
- package/src/index.ts +184 -0
- package/src/tools/a2a.ts +205 -0
- package/src/tools/discovery.ts +517 -0
- package/src/tools/index.ts +45 -0
- package/src/tools/payments.ts +146 -0
- package/src/tools/registration.ts +389 -0
- package/src/tools/reputation.ts +183 -0
- package/src/utils/chains.ts +42 -0
- package/src/utils/trust-labels.ts +53 -0
- package/src/utils/validation.ts +20 -0
- package/tests/a2a.test.ts +234 -0
- package/tests/chains.test.ts +57 -0
- package/tests/discovery.test.ts +455 -0
- package/tests/e2e.test.ts +234 -0
- package/tests/payments.test.ts +148 -0
- package/tests/registration.test.ts +313 -0
- package/tests/reputation.test.ts +231 -0
- package/tests/sdk-client.test.ts +143 -0
- package/tests/tool-router.test.ts +28 -0
- package/tests/trust-labels.test.ts +229 -0
- package/tests/validation.test.ts +132 -0
- package/tests/wallet-derivation.test.ts +109 -0
- package/tsconfig.json +8 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
|
|
3
|
+
// Mock agent0-sdk
|
|
4
|
+
const mockGetAgent = vi.fn();
|
|
5
|
+
const mockCreateA2AClient = vi.fn();
|
|
6
|
+
|
|
7
|
+
vi.mock("agent0-sdk", () => {
|
|
8
|
+
return {
|
|
9
|
+
SDK: vi.fn().mockImplementation(() => ({
|
|
10
|
+
getAgent: mockGetAgent,
|
|
11
|
+
createA2AClient: mockCreateA2AClient,
|
|
12
|
+
})),
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
import { a2aTools, handleA2ATool } from "../src/tools/a2a.js";
|
|
17
|
+
import { setDerivedKey, setChainId } from "../src/auth/sdk-client.js";
|
|
18
|
+
|
|
19
|
+
function makeA2AClient(overrides: Record<string, unknown> = {}) {
|
|
20
|
+
return {
|
|
21
|
+
messageA2A: vi.fn().mockResolvedValue({
|
|
22
|
+
taskId: "task-123",
|
|
23
|
+
status: "completed",
|
|
24
|
+
response: "Hello from agent",
|
|
25
|
+
}),
|
|
26
|
+
listTasks: vi.fn().mockResolvedValue([
|
|
27
|
+
{ taskId: "task-1", status: "completed" },
|
|
28
|
+
{ taskId: "task-2", status: "working" },
|
|
29
|
+
]),
|
|
30
|
+
loadTask: vi.fn().mockResolvedValue({
|
|
31
|
+
taskId: "task-123",
|
|
32
|
+
status: "completed",
|
|
33
|
+
messages: [{ role: "user", text: "hi" }],
|
|
34
|
+
}),
|
|
35
|
+
...overrides,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("a2a tools", () => {
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
vi.clearAllMocks();
|
|
42
|
+
setChainId(11155111);
|
|
43
|
+
setDerivedKey("0x" + "cc".repeat(32));
|
|
44
|
+
mockGetAgent.mockResolvedValue({
|
|
45
|
+
agentId: "11155111:42",
|
|
46
|
+
name: "Test Agent",
|
|
47
|
+
a2a: "https://a2a.test/agent.json",
|
|
48
|
+
});
|
|
49
|
+
mockCreateA2AClient.mockReturnValue(makeA2AClient());
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// ===========================================================================
|
|
53
|
+
// Tool registration
|
|
54
|
+
// ===========================================================================
|
|
55
|
+
describe("tool registration", () => {
|
|
56
|
+
it("registers 3 A2A tools", () => {
|
|
57
|
+
expect(a2aTools).toHaveLength(3);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const expected = ["a2a_send_message", "a2a_list_tasks", "a2a_get_task"];
|
|
61
|
+
for (const name of expected) {
|
|
62
|
+
it(`registers ${name}`, () => {
|
|
63
|
+
expect(a2aTools.find((t) => t.name === name)).toBeDefined();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// ===========================================================================
|
|
69
|
+
// a2a_send_message
|
|
70
|
+
// ===========================================================================
|
|
71
|
+
describe("a2a_send_message", () => {
|
|
72
|
+
it("sends message and returns task info", async () => {
|
|
73
|
+
const result = (await handleA2ATool("a2a_send_message", {
|
|
74
|
+
agentId: "11155111:42",
|
|
75
|
+
message: "Hello agent",
|
|
76
|
+
})) as { success: boolean; taskId: string; status: string };
|
|
77
|
+
|
|
78
|
+
expect(result.success).toBe(true);
|
|
79
|
+
expect(result.taskId).toBe("task-123");
|
|
80
|
+
expect(result.status).toBe("completed");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("returns error when agent not found", async () => {
|
|
84
|
+
mockGetAgent.mockResolvedValue(null);
|
|
85
|
+
|
|
86
|
+
const result = (await handleA2ATool("a2a_send_message", {
|
|
87
|
+
agentId: "11155111:99999",
|
|
88
|
+
message: "Hello",
|
|
89
|
+
})) as { error: string };
|
|
90
|
+
|
|
91
|
+
expect(result.error).toContain("not found");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("returns error when agent has no A2A endpoint", async () => {
|
|
95
|
+
mockGetAgent.mockResolvedValue({
|
|
96
|
+
agentId: "11155111:42",
|
|
97
|
+
name: "No A2A Agent",
|
|
98
|
+
a2a: null,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const result = (await handleA2ATool("a2a_send_message", {
|
|
102
|
+
agentId: "11155111:42",
|
|
103
|
+
message: "Hello",
|
|
104
|
+
})) as { error: string };
|
|
105
|
+
|
|
106
|
+
expect(result.error).toContain("does not have an A2A endpoint");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("passes taskId for conversation continuation", async () => {
|
|
110
|
+
const client = makeA2AClient();
|
|
111
|
+
mockCreateA2AClient.mockReturnValue(client);
|
|
112
|
+
|
|
113
|
+
await handleA2ATool("a2a_send_message", {
|
|
114
|
+
agentId: "11155111:42",
|
|
115
|
+
message: "Follow up",
|
|
116
|
+
taskId: "existing-task",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(client.messageA2A).toHaveBeenCalledWith("Follow up", {
|
|
120
|
+
taskId: "existing-task",
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("includes chain name in result", async () => {
|
|
125
|
+
const result = (await handleA2ATool("a2a_send_message", {
|
|
126
|
+
agentId: "8453:42",
|
|
127
|
+
message: "Hello",
|
|
128
|
+
})) as { chain: string };
|
|
129
|
+
|
|
130
|
+
expect(result.chain).toBe("Base");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// ===========================================================================
|
|
135
|
+
// a2a_list_tasks
|
|
136
|
+
// ===========================================================================
|
|
137
|
+
describe("a2a_list_tasks", () => {
|
|
138
|
+
it("returns task list with count", async () => {
|
|
139
|
+
const result = (await handleA2ATool("a2a_list_tasks", {
|
|
140
|
+
agentId: "11155111:42",
|
|
141
|
+
})) as { agentId: string; count: number; tasks: unknown[] };
|
|
142
|
+
|
|
143
|
+
expect(result.agentId).toBe("11155111:42");
|
|
144
|
+
expect(result.count).toBe(2);
|
|
145
|
+
expect(result.tasks).toHaveLength(2);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("returns error when agent not found", async () => {
|
|
149
|
+
mockGetAgent.mockResolvedValue(null);
|
|
150
|
+
|
|
151
|
+
const result = (await handleA2ATool("a2a_list_tasks", {
|
|
152
|
+
agentId: "11155111:99999",
|
|
153
|
+
})) as { error: string };
|
|
154
|
+
|
|
155
|
+
expect(result.error).toContain("not found");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("returns error when agent has no A2A endpoint", async () => {
|
|
159
|
+
mockGetAgent.mockResolvedValue({
|
|
160
|
+
agentId: "11155111:42",
|
|
161
|
+
a2a: null,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const result = (await handleA2ATool("a2a_list_tasks", {
|
|
165
|
+
agentId: "11155111:42",
|
|
166
|
+
})) as { error: string };
|
|
167
|
+
|
|
168
|
+
expect(result.error).toContain("does not have an A2A endpoint");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("handles empty task list", async () => {
|
|
172
|
+
const client = makeA2AClient({ listTasks: vi.fn().mockResolvedValue([]) });
|
|
173
|
+
mockCreateA2AClient.mockReturnValue(client);
|
|
174
|
+
|
|
175
|
+
const result = (await handleA2ATool("a2a_list_tasks", {
|
|
176
|
+
agentId: "11155111:42",
|
|
177
|
+
})) as { count: number; tasks: unknown[] };
|
|
178
|
+
|
|
179
|
+
expect(result.count).toBe(0);
|
|
180
|
+
expect(result.tasks).toEqual([]);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ===========================================================================
|
|
185
|
+
// a2a_get_task
|
|
186
|
+
// ===========================================================================
|
|
187
|
+
describe("a2a_get_task", () => {
|
|
188
|
+
it("returns task details", async () => {
|
|
189
|
+
const result = (await handleA2ATool("a2a_get_task", {
|
|
190
|
+
agentId: "11155111:42",
|
|
191
|
+
taskId: "task-123",
|
|
192
|
+
})) as { agentId: string; taskId: string; task: Record<string, unknown> };
|
|
193
|
+
|
|
194
|
+
expect(result.agentId).toBe("11155111:42");
|
|
195
|
+
expect(result.taskId).toBe("task-123");
|
|
196
|
+
expect(result.task.status).toBe("completed");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("returns error when agent not found", async () => {
|
|
200
|
+
mockGetAgent.mockResolvedValue(null);
|
|
201
|
+
|
|
202
|
+
const result = (await handleA2ATool("a2a_get_task", {
|
|
203
|
+
agentId: "11155111:99999",
|
|
204
|
+
taskId: "task-123",
|
|
205
|
+
})) as { error: string };
|
|
206
|
+
|
|
207
|
+
expect(result.error).toContain("not found");
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("returns task error when task not found", async () => {
|
|
211
|
+
const client = makeA2AClient({
|
|
212
|
+
loadTask: vi.fn().mockResolvedValue(null),
|
|
213
|
+
});
|
|
214
|
+
mockCreateA2AClient.mockReturnValue(client);
|
|
215
|
+
|
|
216
|
+
const result = (await handleA2ATool("a2a_get_task", {
|
|
217
|
+
agentId: "11155111:42",
|
|
218
|
+
taskId: "nonexistent",
|
|
219
|
+
})) as { task: { error: string } };
|
|
220
|
+
|
|
221
|
+
expect(result.task.error).toBe("Task not found");
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// ===========================================================================
|
|
226
|
+
// Unknown tool
|
|
227
|
+
// ===========================================================================
|
|
228
|
+
it("returns error for unknown tool", async () => {
|
|
229
|
+
const result = (await handleA2ATool("nonexistent", {})) as {
|
|
230
|
+
error: string;
|
|
231
|
+
};
|
|
232
|
+
expect(result.error).toContain("Unknown A2A tool");
|
|
233
|
+
});
|
|
234
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { CHAINS, getChain, getChainName } from "../src/utils/chains.js";
|
|
3
|
+
|
|
4
|
+
describe("CHAINS config", () => {
|
|
5
|
+
it("includes Ethereum Mainnet (1)", () => {
|
|
6
|
+
expect(CHAINS[1]).toBeDefined();
|
|
7
|
+
expect(CHAINS[1].name).toBe("Ethereum Mainnet");
|
|
8
|
+
expect(CHAINS[1].chainId).toBe(1);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("includes Base (8453)", () => {
|
|
12
|
+
expect(CHAINS[8453]).toBeDefined();
|
|
13
|
+
expect(CHAINS[8453].name).toBe("Base");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("includes Arbitrum One (42161)", () => {
|
|
17
|
+
expect(CHAINS[42161]).toBeDefined();
|
|
18
|
+
expect(CHAINS[42161].name).toBe("Arbitrum One");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("includes Optimism (10)", () => {
|
|
22
|
+
expect(CHAINS[10]).toBeDefined();
|
|
23
|
+
expect(CHAINS[10].name).toBe("Optimism");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("all chains have required fields", () => {
|
|
27
|
+
for (const chain of Object.values(CHAINS)) {
|
|
28
|
+
expect(chain.chainId).toBeTypeOf("number");
|
|
29
|
+
expect(chain.name).toBeTypeOf("string");
|
|
30
|
+
expect(chain.rpcUrl).toMatch(/^https?:\/\//);
|
|
31
|
+
expect(chain.explorerUrl).toMatch(/^https?:\/\//);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("getChain", () => {
|
|
37
|
+
it("returns config for known chain", () => {
|
|
38
|
+
const chain = getChain(8453);
|
|
39
|
+
expect(chain).toBeDefined();
|
|
40
|
+
expect(chain!.name).toBe("Base");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("returns undefined for unknown chain", () => {
|
|
44
|
+
expect(getChain(99999)).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("getChainName", () => {
|
|
49
|
+
it("returns name for known chain", () => {
|
|
50
|
+
expect(getChainName(1)).toBe("Ethereum Mainnet");
|
|
51
|
+
expect(getChainName(8453)).toBe("Base");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("returns fallback string for unknown chain", () => {
|
|
55
|
+
expect(getChainName(12345)).toBe("Chain 12345");
|
|
56
|
+
});
|
|
57
|
+
});
|