@agentdomain/mcp-server 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/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @agentdomain/mcp-server
2
+
3
+ [Model Context Protocol](https://modelcontextprotocol.io) server for AgentDomain.
4
+
5
+ Lets any MCP-compatible LLM client (Claude Desktop, ChatGPT desktop apps, custom agents) register and manage agent identities through natural language.
6
+
7
+ ## Tools exposed
8
+
9
+ - `check_domain_availability` - is a domain available?
10
+ - `quote_registration` - price a registration
11
+ - `register_agent_identity` - register a complete identity (requires wallet)
12
+ - `lookup_agent` - find an agent by wallet
13
+ - `search_agents` - search the public registry
14
+ - `send_agent_email` - send an email from an agent's address
15
+ - `list_agent_email` - read agent inbox/outbox messages
16
+ - `list_dns_records` - list DNS records for an agent domain
17
+ - `create_dns_record` - create a user-managed DNS record
18
+ - `update_dns_record` - update a user-managed DNS record
19
+ - `delete_dns_record` - delete a user-managed DNS record
20
+ - `reconfigure_ssl` - rebuild Cloudflare SaaS SSL and DNS validation records
21
+ - `fund_renewal_vault` - top up an agent's renewal vault
22
+ - `withdraw_renewal_vault` - build an owner-signed vault withdrawal transaction
23
+ - `get_renewal_status` - check renewal date, amount, vault balance, and auto-renew state
24
+ - `enable_auto_renew` - enable on-chain auto-renew with the AgentID NFT owner wallet
25
+ - `get_service_plan` - inspect per-agent Included/Pro/Enterprise limits
26
+ - `purchase_service_plan` - upgrade to Pro or Enterprise with x402 USDC
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ npm install -g @agentdomain/mcp-server
32
+ ```
33
+
34
+ ## Configure (Claude Desktop example)
35
+
36
+ `~/Library/Application Support/Claude/claude_desktop_config.json`:
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "agentdomain": {
42
+ "command": "npx",
43
+ "args": ["-y", "@agentdomain/mcp-server"],
44
+ "env": {
45
+ "AGENTDOMAIN_API_URL": "https://agentdomain.app/api/v1",
46
+ "AGENT_PRIVATE_KEY": "0x...",
47
+ "AGENTDOMAIN_NETWORK": "base",
48
+ "RENEWAL_VAULT_ADDRESS": "0x..."
49
+ }
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ For `enable_auto_renew`, `AGENT_PRIVATE_KEY` must be the AgentID NFT owner wallet. Funding can come
56
+ from any wallet, but the RenewalVault contract only accepts auto-renew changes from the owner.
57
+
58
+ ## Pricing flags
59
+
60
+ Domain, DNS, service fee, and SSL certification are mandatory. SSL certification
61
+ costs `$1.20` per year and is included in registration and exact renewal status
62
+ quotes.
63
+
64
+ Optional services charge only when enabled:
65
+
66
+ - `registerBasename: false` skips Basename and Basename cost.
67
+ - `registerEns: false` skips ENS and ENS cost.
68
+ - `emailEnabled: false` skips email and email cost.
69
+
70
+ Use `quote_registration` first so the agent sees `sslCertificationFeeUsdc`,
71
+ optional component costs, and `totalUsdc` before it signs the x402 payment.
72
+
73
+ For renewals, `get_renewal_status` returns the exact next renewal amount and the
74
+ shortfall to fund before the keeper can reserve and complete the renewal.
75
+
76
+ For service plans, `purchase_service_plan` accepts `prepayPeriods`. Extra
77
+ periods become prepaid service-plan credit; service-plan auto-renew consumes
78
+ that credit instead of pretending a reusable x402 signature exists.
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentDomain MCP Server
4
+ *
5
+ * Exposes AgentDomain identity tools to any MCP-compatible LLM client
6
+ * (Claude Desktop, ChatGPT desktop, custom agents, etc.).
7
+ *
8
+ * Stdio transport. Run via:
9
+ * agentdomain-mcp
10
+ * or in a client config:
11
+ * {
12
+ * "mcpServers": {
13
+ * "agentdomain": {
14
+ * "command": "npx",
15
+ * "args": ["-y", "@agentdomain/mcp-server"],
16
+ * "env": {
17
+ * "AGENTDOMAIN_API_URL": "https://agentdomain.app/api/v1",
18
+ * "AGENT_PRIVATE_KEY": "0x..."
19
+ * }
20
+ * }
21
+ * }
22
+ * }
23
+ */
24
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,611 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentDomain MCP Server
4
+ *
5
+ * Exposes AgentDomain identity tools to any MCP-compatible LLM client
6
+ * (Claude Desktop, ChatGPT desktop, custom agents, etc.).
7
+ *
8
+ * Stdio transport. Run via:
9
+ * agentdomain-mcp
10
+ * or in a client config:
11
+ * {
12
+ * "mcpServers": {
13
+ * "agentdomain": {
14
+ * "command": "npx",
15
+ * "args": ["-y", "@agentdomain/mcp-server"],
16
+ * "env": {
17
+ * "AGENTDOMAIN_API_URL": "https://agentdomain.app/api/v1",
18
+ * "AGENT_PRIVATE_KEY": "0x..."
19
+ * }
20
+ * }
21
+ * }
22
+ * }
23
+ */
24
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
25
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
26
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
27
+ import { z } from 'zod';
28
+ import { AgentDomain } from '@agentdomain/sdk';
29
+ import { AGENTDOMAIN_API_BASE_URL, SUPPORTED_FRAMEWORKS, SUPPORTED_TLDS, } from '@agentdomain/shared/constants';
30
+ import { createPublicClient, createWalletClient, http } from 'viem';
31
+ import { privateKeyToAccount } from 'viem/accounts';
32
+ import { base, baseSepolia } from 'viem/chains';
33
+ const API_URL = process.env.AGENTDOMAIN_API_URL ?? AGENTDOMAIN_API_BASE_URL;
34
+ const NETWORK = (process.env.AGENTDOMAIN_NETWORK ?? 'base');
35
+ const AGENT_PRIVATE_KEY = process.env.AGENT_PRIVATE_KEY;
36
+ const AGENTDOMAIN_API_KEY = process.env.AGENTDOMAIN_API_KEY;
37
+ const RENEWAL_VAULT_ADDRESS = process.env.RENEWAL_VAULT_ADDRESS;
38
+ function getClient() {
39
+ const config = {
40
+ apiUrl: API_URL,
41
+ apiKey: AGENTDOMAIN_API_KEY,
42
+ network: NETWORK,
43
+ renewalVaultAddress: RENEWAL_VAULT_ADDRESS,
44
+ };
45
+ if (AGENT_PRIVATE_KEY) {
46
+ const account = privateKeyToAccount(AGENT_PRIVATE_KEY);
47
+ const chain = NETWORK === 'base' ? base : baseSepolia;
48
+ const rpc = NETWORK === 'base' ? 'https://mainnet.base.org' : 'https://sepolia.base.org';
49
+ // Cast: viem's deeply-generic types do not always match cleanly across
50
+ // duplicated installs in monorepos. Behaviour is identical at runtime.
51
+ config.walletClient = createWalletClient({ account, chain, transport: http(rpc) });
52
+ config.publicClient = createPublicClient({ chain, transport: http(rpc) });
53
+ }
54
+ return new AgentDomain(config);
55
+ }
56
+ const server = new Server({ name: 'agentdomain-mcp', version: '0.1.0' }, { capabilities: { tools: {} } });
57
+ // ----------------------------------------------------------------------
58
+ // TOOL DEFINITIONS
59
+ // ----------------------------------------------------------------------
60
+ const TOOLS = [
61
+ {
62
+ name: 'check_domain_availability',
63
+ description: 'Check whether an agent domain (name + tld) is available for registration. Returns availability status and pricing.',
64
+ inputSchema: {
65
+ type: 'object',
66
+ properties: {
67
+ name: { type: 'string', description: 'The desired label, e.g. "myagent"' },
68
+ tld: {
69
+ type: 'string',
70
+ enum: SUPPORTED_TLDS,
71
+ description: 'TLD',
72
+ },
73
+ },
74
+ required: ['name'],
75
+ },
76
+ },
77
+ {
78
+ name: 'quote_registration',
79
+ description: 'Get a price quote for registering an agent identity bundle. Domain, DNS, SSL certification, and service fee are mandatory. Basename, ENS, and email are optional.',
80
+ inputSchema: {
81
+ type: 'object',
82
+ properties: {
83
+ preferredName: { type: 'string' },
84
+ tld: { type: 'string', enum: SUPPORTED_TLDS },
85
+ registerBasename: {
86
+ type: 'boolean',
87
+ description: 'Set false to skip Basename registration and cost.',
88
+ default: true,
89
+ },
90
+ registerEns: {
91
+ type: 'boolean',
92
+ description: 'Set true to add ENS; false skips ENS cost.',
93
+ default: false,
94
+ },
95
+ emailEnabled: {
96
+ type: 'boolean',
97
+ description: 'Set true to add an email inbox; false skips email cost.',
98
+ default: false,
99
+ },
100
+ years: { type: 'integer', default: 1, minimum: 1, maximum: 10 },
101
+ discountCode: { type: 'string', description: 'Optional service-fee discount code' },
102
+ },
103
+ required: ['preferredName'],
104
+ },
105
+ },
106
+ {
107
+ name: 'register_agent_identity',
108
+ description: 'Register a complete agent identity bundle. Domain, DNS, SSL certification, and service fee are mandatory. Set optional booleans false to skip Basename, ENS, or email. Pays in USDC on Base. Requires AGENT_PRIVATE_KEY env var.',
109
+ inputSchema: {
110
+ type: 'object',
111
+ properties: {
112
+ preferredName: { type: 'string' },
113
+ tld: { type: 'string', enum: SUPPORTED_TLDS },
114
+ registerBasename: {
115
+ type: 'boolean',
116
+ description: 'Set false to skip Basename registration and cost.',
117
+ default: true,
118
+ },
119
+ basenameLabel: { type: 'string', description: 'Optional alternate Basename label' },
120
+ registerEns: {
121
+ type: 'boolean',
122
+ description: 'Set true to add ENS; false skips ENS cost.',
123
+ default: false,
124
+ },
125
+ ensLabel: { type: 'string', description: 'Optional alternate ENS label' },
126
+ ownerAddress: {
127
+ type: 'string',
128
+ description: 'Optional EVM address to receive NFT ownership',
129
+ },
130
+ emailEnabled: {
131
+ type: 'boolean',
132
+ description: 'Set true to add an email inbox; false skips email cost.',
133
+ default: false,
134
+ },
135
+ discountCode: { type: 'string', description: 'Optional service-fee discount code' },
136
+ years: { type: 'integer', default: 1, minimum: 1, maximum: 10 },
137
+ autoRenew: { type: 'boolean', default: false },
138
+ dnsTarget: { type: 'string', description: 'URL or IP to point the domain at' },
139
+ metadata: {
140
+ type: 'object',
141
+ properties: {
142
+ name: { type: 'string' },
143
+ description: { type: 'string' },
144
+ capabilities: { type: 'array', items: { type: 'string' } },
145
+ framework: { type: 'string', enum: SUPPORTED_FRAMEWORKS },
146
+ x402Endpoint: { type: 'string' },
147
+ },
148
+ },
149
+ },
150
+ required: ['preferredName'],
151
+ },
152
+ },
153
+ {
154
+ name: 'lookup_agent',
155
+ description: 'Look up agent identities by wallet address.',
156
+ inputSchema: {
157
+ type: 'object',
158
+ properties: {
159
+ wallet: { type: 'string', description: '0x wallet address' },
160
+ },
161
+ required: ['wallet'],
162
+ },
163
+ },
164
+ {
165
+ name: 'search_agents',
166
+ description: 'Search the public agent registry by name, capability, or framework.',
167
+ inputSchema: {
168
+ type: 'object',
169
+ properties: {
170
+ q: { type: 'string', description: 'Free-text query' },
171
+ capability: { type: 'string' },
172
+ framework: {
173
+ type: 'string',
174
+ enum: SUPPORTED_FRAMEWORKS,
175
+ },
176
+ limit: { type: 'number', default: 20 },
177
+ },
178
+ },
179
+ },
180
+ {
181
+ name: 'send_agent_email',
182
+ description: "Send an email from an agent's address (requires email-enabled identity).",
183
+ inputSchema: {
184
+ type: 'object',
185
+ properties: {
186
+ agentId: { type: 'string', description: 'AgentDomain agent ID (UUID)' },
187
+ to: { type: 'string' },
188
+ subject: { type: 'string' },
189
+ text: { type: 'string' },
190
+ },
191
+ required: ['agentId', 'to', 'subject'],
192
+ },
193
+ },
194
+ {
195
+ name: 'list_agent_email',
196
+ description: 'List received/sent text-only email messages for an email-enabled agent, including extracted verification codes.',
197
+ inputSchema: {
198
+ type: 'object',
199
+ properties: {
200
+ agentId: { type: 'string', description: 'AgentDomain agent ID (UUID)' },
201
+ limit: { type: 'number', default: 20 },
202
+ },
203
+ required: ['agentId'],
204
+ },
205
+ },
206
+ {
207
+ name: 'list_dns_records',
208
+ description: 'List Spaceship-backed DNS records for an agent domain.',
209
+ inputSchema: {
210
+ type: 'object',
211
+ properties: {
212
+ agentId: { type: 'string', description: 'AgentDomain agent ID (UUID)' },
213
+ },
214
+ required: ['agentId'],
215
+ },
216
+ },
217
+ {
218
+ name: 'create_dns_record',
219
+ description: 'Create a user-managed DNS record and sync the full DNS state to Spaceship.',
220
+ inputSchema: {
221
+ type: 'object',
222
+ properties: {
223
+ agentId: { type: 'string' },
224
+ type: { type: 'string', enum: ['A', 'AAAA', 'ALIAS', 'CNAME', 'MX', 'TXT', 'NS', 'SRV'] },
225
+ name: { type: 'string' },
226
+ value: { type: 'string' },
227
+ ttl: { type: 'number', default: 3600 },
228
+ priority: { type: 'number' },
229
+ },
230
+ required: ['agentId', 'type', 'name', 'value'],
231
+ },
232
+ },
233
+ {
234
+ name: 'update_dns_record',
235
+ description: 'Update a user-managed DNS record and sync the DNS state to Spaceship.',
236
+ inputSchema: {
237
+ type: 'object',
238
+ properties: {
239
+ agentId: { type: 'string' },
240
+ recordId: { type: 'string' },
241
+ type: { type: 'string', enum: ['A', 'AAAA', 'ALIAS', 'CNAME', 'MX', 'TXT', 'NS', 'SRV'] },
242
+ name: { type: 'string' },
243
+ value: { type: 'string' },
244
+ ttl: { type: 'number' },
245
+ priority: { type: 'number' },
246
+ },
247
+ required: ['agentId', 'recordId'],
248
+ },
249
+ },
250
+ {
251
+ name: 'delete_dns_record',
252
+ description: 'Delete a user-managed DNS record and sync the DNS state to Spaceship.',
253
+ inputSchema: {
254
+ type: 'object',
255
+ properties: {
256
+ agentId: { type: 'string' },
257
+ recordId: { type: 'string' },
258
+ },
259
+ required: ['agentId', 'recordId'],
260
+ },
261
+ },
262
+ {
263
+ name: 'reconfigure_ssl',
264
+ description: 'Rebuild the Cloudflare SaaS SSL hostname and sync required DNS validation records.',
265
+ inputSchema: {
266
+ type: 'object',
267
+ properties: {
268
+ agentId: { type: 'string' },
269
+ },
270
+ required: ['agentId'],
271
+ },
272
+ },
273
+ {
274
+ name: 'fund_renewal_vault',
275
+ description: "Deposit USDC into an agent's renewal vault to keep its domain alive.",
276
+ inputSchema: {
277
+ type: 'object',
278
+ properties: {
279
+ agentId: { type: 'string' },
280
+ amountUsdc: { type: 'string', description: 'USDC amount, e.g. "10.00"' },
281
+ },
282
+ required: ['agentId', 'amountUsdc'],
283
+ },
284
+ },
285
+ {
286
+ name: 'withdraw_renewal_vault',
287
+ description: 'Build the owner-signed withdrawal transaction for unused funds in an AgentID renewal vault.',
288
+ inputSchema: {
289
+ type: 'object',
290
+ properties: {
291
+ agentId: { type: 'string' },
292
+ amountUsdc: { type: 'string', description: 'USDC amount, e.g. "5.00"' },
293
+ },
294
+ required: ['agentId', 'amountUsdc'],
295
+ },
296
+ },
297
+ {
298
+ name: 'get_renewal_status',
299
+ description: 'Get renewal vault status for an agent, including exact renewal amount, vault balance, missing deposit, expiry, and auto-renew readiness.',
300
+ inputSchema: {
301
+ type: 'object',
302
+ properties: {
303
+ agentId: { type: 'string', description: 'AgentDomain agent ID (UUID)' },
304
+ },
305
+ required: ['agentId'],
306
+ },
307
+ },
308
+ {
309
+ name: 'get_service_plan',
310
+ description: 'Get the current AgentDomain service plan, entitlement limits, billing interval, and recent purchases for one agent.',
311
+ inputSchema: {
312
+ type: 'object',
313
+ properties: {
314
+ agentId: { type: 'string', description: 'AgentDomain agent ID (UUID)' },
315
+ },
316
+ required: ['agentId'],
317
+ },
318
+ },
319
+ {
320
+ name: 'purchase_service_plan',
321
+ description: 'Upgrade one agent to Pro or Enterprise with x402 USDC. Requires AGENT_PRIVATE_KEY for the owner wallet.',
322
+ inputSchema: {
323
+ type: 'object',
324
+ properties: {
325
+ agentId: { type: 'string' },
326
+ plan: { type: 'string', enum: ['pro', 'enterprise'] },
327
+ interval: { type: 'string', enum: ['monthly', 'yearly'] },
328
+ autoRenew: { type: 'boolean', default: false },
329
+ prepayPeriods: {
330
+ type: 'number',
331
+ minimum: 1,
332
+ maximum: 12,
333
+ default: 1,
334
+ description: 'Number of periods to prepay. Extra periods become auto-renew credit.',
335
+ },
336
+ },
337
+ required: ['agentId', 'plan', 'interval'],
338
+ },
339
+ },
340
+ {
341
+ name: 'enable_auto_renew',
342
+ description: 'Enable on-chain auto-renew for an agent. Requires the owner wallet private key and the RenewalVault contract address.',
343
+ inputSchema: {
344
+ type: 'object',
345
+ properties: {
346
+ agentId: { type: 'string', description: 'AgentDomain agent ID (UUID)' },
347
+ },
348
+ required: ['agentId'],
349
+ },
350
+ },
351
+ ];
352
+ // ----------------------------------------------------------------------
353
+ // HANDLERS
354
+ // ----------------------------------------------------------------------
355
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
356
+ tools: TOOLS,
357
+ }));
358
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
359
+ const { name, arguments: args } = request.params;
360
+ const client = getClient();
361
+ try {
362
+ switch (name) {
363
+ case 'check_domain_availability': {
364
+ const a = z
365
+ .object({ name: z.string(), tld: z.enum(SUPPORTED_TLDS).default('xyz') })
366
+ .parse(args);
367
+ const result = await client.checkAvailability(a.name, { tld: a.tld });
368
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
369
+ }
370
+ case 'quote_registration': {
371
+ const a = z
372
+ .object({
373
+ preferredName: z.string(),
374
+ tld: z.enum(SUPPORTED_TLDS).default('xyz'),
375
+ registerBasename: z.boolean().default(true),
376
+ registerEns: z.boolean().default(false),
377
+ emailEnabled: z.boolean().default(false),
378
+ years: z.number().int().min(1).max(10).default(1),
379
+ discountCode: z.string().max(50).optional(),
380
+ })
381
+ .parse(args);
382
+ const result = await client.quote(a);
383
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
384
+ }
385
+ case 'register_agent_identity': {
386
+ if (!AGENT_PRIVATE_KEY) {
387
+ return {
388
+ isError: true,
389
+ content: [
390
+ {
391
+ type: 'text',
392
+ text: "AGENT_PRIVATE_KEY env var is required for registration. Set it to your agent's wallet private key.",
393
+ },
394
+ ],
395
+ };
396
+ }
397
+ const a = z
398
+ .object({
399
+ preferredName: z.string(),
400
+ tld: z.enum(SUPPORTED_TLDS).default('xyz'),
401
+ registerBasename: z.boolean().default(true),
402
+ basenameLabel: z.string().optional(),
403
+ registerEns: z.boolean().default(false),
404
+ ensLabel: z.string().optional(),
405
+ ownerAddress: z
406
+ .string()
407
+ .regex(/^0x[a-fA-F0-9]{40}$/)
408
+ .optional(),
409
+ emailEnabled: z.boolean().default(false),
410
+ years: z.number().int().min(1).max(10).default(1),
411
+ autoRenew: z.boolean().default(false),
412
+ discountCode: z.string().max(50).optional(),
413
+ dnsTarget: z.string().optional(),
414
+ metadata: z.record(z.any()).optional(),
415
+ })
416
+ .parse(args);
417
+ const account = privateKeyToAccount(AGENT_PRIVATE_KEY);
418
+ const result = await client.register({
419
+ ...a,
420
+ wallet: account.address,
421
+ ownerAddress: a.ownerAddress,
422
+ metadata: a.metadata,
423
+ });
424
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
425
+ }
426
+ case 'lookup_agent': {
427
+ const a = z.object({ wallet: z.string() }).parse(args);
428
+ const result = await client.getAgentsByWallet(a.wallet);
429
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
430
+ }
431
+ case 'search_agents': {
432
+ const a = z
433
+ .object({
434
+ q: z.string().optional(),
435
+ capability: z.string().optional(),
436
+ framework: z.enum(SUPPORTED_FRAMEWORKS).optional(),
437
+ limit: z.number().default(20),
438
+ })
439
+ .parse(args);
440
+ const result = await client.search(a);
441
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
442
+ }
443
+ case 'send_agent_email': {
444
+ const a = z
445
+ .object({
446
+ agentId: z.string(),
447
+ to: z.string(),
448
+ subject: z.string(),
449
+ text: z.string(),
450
+ })
451
+ .parse(args);
452
+ const result = await client.sendEmail(a.agentId, {
453
+ to: a.to,
454
+ subject: a.subject,
455
+ text: a.text,
456
+ });
457
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
458
+ }
459
+ case 'list_agent_email': {
460
+ const a = z.object({ agentId: z.string(), limit: z.number().default(20) }).parse(args);
461
+ const result = await client.listEmail(a.agentId, { limit: a.limit });
462
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
463
+ }
464
+ case 'list_dns_records': {
465
+ const a = z.object({ agentId: z.string() }).parse(args);
466
+ const result = await client.listDnsRecords(a.agentId);
467
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
468
+ }
469
+ case 'create_dns_record': {
470
+ const a = z
471
+ .object({
472
+ agentId: z.string(),
473
+ type: z.enum(['A', 'AAAA', 'ALIAS', 'CNAME', 'MX', 'TXT', 'NS', 'SRV']),
474
+ name: z.string(),
475
+ value: z.string(),
476
+ ttl: z.number().default(3600),
477
+ priority: z.number().optional(),
478
+ })
479
+ .parse(args);
480
+ const result = await client.createDnsRecord(a.agentId, {
481
+ type: a.type,
482
+ name: a.name,
483
+ value: a.value,
484
+ ttl: a.ttl,
485
+ priority: a.priority,
486
+ });
487
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
488
+ }
489
+ case 'update_dns_record': {
490
+ const a = z
491
+ .object({
492
+ agentId: z.string(),
493
+ recordId: z.string(),
494
+ type: z.enum(['A', 'AAAA', 'ALIAS', 'CNAME', 'MX', 'TXT', 'NS', 'SRV']).optional(),
495
+ name: z.string().optional(),
496
+ value: z.string().optional(),
497
+ ttl: z.number().optional(),
498
+ priority: z.number().optional(),
499
+ })
500
+ .parse(args);
501
+ const { agentId, recordId, ...record } = a;
502
+ const result = await client.updateDnsRecord(agentId, recordId, record);
503
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
504
+ }
505
+ case 'delete_dns_record': {
506
+ const a = z.object({ agentId: z.string(), recordId: z.string() }).parse(args);
507
+ const result = await client.deleteDnsRecord(a.agentId, a.recordId);
508
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
509
+ }
510
+ case 'reconfigure_ssl': {
511
+ const a = z.object({ agentId: z.string() }).parse(args);
512
+ const result = await client.reconfigureSsl(a.agentId);
513
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
514
+ }
515
+ case 'fund_renewal_vault': {
516
+ const a = z.object({ agentId: z.string(), amountUsdc: z.string() }).parse(args);
517
+ const result = await client.fundRenewalVault(a.agentId, a.amountUsdc);
518
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
519
+ }
520
+ case 'withdraw_renewal_vault': {
521
+ const a = z.object({ agentId: z.string(), amountUsdc: z.string() }).parse(args);
522
+ const result = await client.withdrawFromVault(a.agentId, a.amountUsdc);
523
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
524
+ }
525
+ case 'get_renewal_status': {
526
+ const a = z.object({ agentId: z.string() }).parse(args);
527
+ const result = await client.getRenewalStatus(a.agentId);
528
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
529
+ }
530
+ case 'get_service_plan': {
531
+ const a = z.object({ agentId: z.string() }).parse(args);
532
+ const result = await client.getServicePlan(a.agentId);
533
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
534
+ }
535
+ case 'purchase_service_plan': {
536
+ if (!AGENT_PRIVATE_KEY) {
537
+ return {
538
+ isError: true,
539
+ content: [
540
+ {
541
+ type: 'text',
542
+ text: 'AGENT_PRIVATE_KEY env var is required to purchase a service plan.',
543
+ },
544
+ ],
545
+ };
546
+ }
547
+ const a = z
548
+ .object({
549
+ agentId: z.string(),
550
+ plan: z.enum(['pro', 'enterprise']),
551
+ interval: z.enum(['monthly', 'yearly']),
552
+ autoRenew: z.boolean().default(false),
553
+ prepayPeriods: z.number().int().min(1).max(12).default(1),
554
+ })
555
+ .parse(args);
556
+ const result = await client.purchaseServicePlan(a);
557
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
558
+ }
559
+ case 'enable_auto_renew': {
560
+ if (!AGENT_PRIVATE_KEY) {
561
+ return {
562
+ isError: true,
563
+ content: [
564
+ {
565
+ type: 'text',
566
+ text: 'AGENT_PRIVATE_KEY env var is required to enable auto-renew. Use the owner wallet private key.',
567
+ },
568
+ ],
569
+ };
570
+ }
571
+ if (!RENEWAL_VAULT_ADDRESS) {
572
+ return {
573
+ isError: true,
574
+ content: [
575
+ {
576
+ type: 'text',
577
+ text: 'RENEWAL_VAULT_ADDRESS env var is required to enable auto-renew on-chain.',
578
+ },
579
+ ],
580
+ };
581
+ }
582
+ const a = z.object({ agentId: z.string() }).parse(args);
583
+ const result = await client.setAutoRenew(a.agentId, true);
584
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
585
+ }
586
+ default:
587
+ return {
588
+ isError: true,
589
+ content: [{ type: 'text', text: `Unknown tool: ${name}` }],
590
+ };
591
+ }
592
+ }
593
+ catch (e) {
594
+ return {
595
+ isError: true,
596
+ content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }],
597
+ };
598
+ }
599
+ });
600
+ // ----------------------------------------------------------------------
601
+ // MAIN
602
+ // ----------------------------------------------------------------------
603
+ async function main() {
604
+ const transport = new StdioServerTransport();
605
+ await server.connect(transport);
606
+ console.error('AgentDomain MCP server running on stdio');
607
+ }
608
+ main().catch((e) => {
609
+ console.error('Fatal:', e);
610
+ process.exit(1);
611
+ });
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@agentdomain/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server exposing AgentDomain registration and management tools to any LLM",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "agentdomain-mcp": "./dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md",
15
+ "package.json"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "prepublishOnly": "pnpm run build",
23
+ "dev": "tsx watch src/index.ts",
24
+ "start": "node dist/index.js",
25
+ "typecheck": "tsc --noEmit",
26
+ "lint": "echo \"no lint\""
27
+ },
28
+ "dependencies": {
29
+ "@agentdomain/sdk": "workspace:^",
30
+ "@agentdomain/shared": "workspace:^",
31
+ "@modelcontextprotocol/sdk": "^1.0.4",
32
+ "viem": "^2.21.55",
33
+ "zod": "^3.24.1"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^22.10.5",
37
+ "tsx": "^4.19.2",
38
+ "typescript": "^5.7.2"
39
+ }
40
+ }