registro-br-mcp 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 +124 -0
- package/package.json +40 -0
- package/src/index.js +375 -0
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Registro.br MCP Server
|
|
2
|
+
|
|
3
|
+
Um servidor [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) para consultar o RDAP do Registro.br.
|
|
4
|
+
|
|
5
|
+
## Ferramentas Disponíveis
|
|
6
|
+
|
|
7
|
+
| Ferramenta | Descrição |
|
|
8
|
+
|------------|-----------|
|
|
9
|
+
| `rdap_domain` | Consulta informações de domínios .br (ex: `nic.br`, `registro.br`) |
|
|
10
|
+
| `rdap_entity` | Consulta entidades por CNPJ, CPF ou handle (ex: `05506560000136`, `FAN`) |
|
|
11
|
+
| `rdap_nameserver` | Consulta informações de nameservers (ex: `a.dns.br`) |
|
|
12
|
+
| `rdap_ip` | Consulta informações de IP ou rede (ex: `200.160.0.0`, `200.160.0.0/20`) |
|
|
13
|
+
| `rdap_asn` | Consulta Autonomous System Numbers (ex: `22548`, `AS22548`) |
|
|
14
|
+
|
|
15
|
+
## Instalação
|
|
16
|
+
|
|
17
|
+
### Via npx (recomendado)
|
|
18
|
+
|
|
19
|
+
Não é necessário instalar. Configure diretamente no seu cliente MCP.
|
|
20
|
+
|
|
21
|
+
### Via npm (global)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -g registro-br-mcp
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configuração
|
|
28
|
+
|
|
29
|
+
### Claude Desktop
|
|
30
|
+
|
|
31
|
+
Adicione ao arquivo de configuração (`~/Library/Application Support/Claude/claude_desktop_config.json` no macOS):
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"registro-br": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["registro-br-mcp"]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Claude Code
|
|
45
|
+
|
|
46
|
+
Adicione ao arquivo `~/.claude/settings.json`:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"mcpServers": {
|
|
51
|
+
"registro-br": {
|
|
52
|
+
"command": "npx",
|
|
53
|
+
"args": ["registro-br-mcp"]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Exemplos de Uso
|
|
60
|
+
|
|
61
|
+
Após configurar, você pode fazer perguntas como:
|
|
62
|
+
|
|
63
|
+
- "Consulte o domínio nic.br"
|
|
64
|
+
- "Quem é o registrante do domínio registro.br?"
|
|
65
|
+
- "Busque informações do ASN 22548"
|
|
66
|
+
- "Qual o IP do nameserver a.dns.br?"
|
|
67
|
+
- "Consulte a entidade com CNPJ 05506560000136"
|
|
68
|
+
|
|
69
|
+
## Exemplo de Resposta
|
|
70
|
+
|
|
71
|
+
Consulta do domínio `nic.br`:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Domain: nic.br
|
|
75
|
+
Handle: nic.br
|
|
76
|
+
Status: active
|
|
77
|
+
|
|
78
|
+
Events:
|
|
79
|
+
- registration: 1997-07-11T12:00:00Z
|
|
80
|
+
- last changed: 2018-03-27T20:09:08Z
|
|
81
|
+
|
|
82
|
+
Nameservers:
|
|
83
|
+
- a.dns.br
|
|
84
|
+
- b.dns.br
|
|
85
|
+
- c.dns.br
|
|
86
|
+
- d.dns.br
|
|
87
|
+
- e.dns.br
|
|
88
|
+
|
|
89
|
+
DNSSEC: Signed
|
|
90
|
+
- KeyTag: 47828, Algorithm: 13, DigestType: 2
|
|
91
|
+
|
|
92
|
+
Entities:
|
|
93
|
+
- Núcleo de Inf. e Coord. do Ponto BR - NIC.BR (registrant)
|
|
94
|
+
- Frederico Augusto de Carvalho Neves (technical)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API RDAP
|
|
98
|
+
|
|
99
|
+
Este servidor utiliza a API RDAP pública do Registro.br:
|
|
100
|
+
|
|
101
|
+
- Base URL: `https://rdap.registro.br`
|
|
102
|
+
- Documentação: https://registro.br/rdap/
|
|
103
|
+
|
|
104
|
+
## Desenvolvimento
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Clonar o repositório
|
|
108
|
+
git clone https://github.com/yvesmariano/registro-br-mcp.git
|
|
109
|
+
cd registro-br-mcp
|
|
110
|
+
|
|
111
|
+
# Instalar dependências
|
|
112
|
+
npm install
|
|
113
|
+
|
|
114
|
+
# Executar localmente
|
|
115
|
+
npm start
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Requisitos
|
|
119
|
+
|
|
120
|
+
- Node.js >= 18.0.0
|
|
121
|
+
|
|
122
|
+
## Licença
|
|
123
|
+
|
|
124
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "registro-br-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP Server para consultar o RDAP do Registro.br",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"registro-br-mcp": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"start": "node src/index.js"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
18
|
+
"zod": "^3.23.0"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"model-context-protocol",
|
|
23
|
+
"rdap",
|
|
24
|
+
"registro.br",
|
|
25
|
+
"whois",
|
|
26
|
+
"domain",
|
|
27
|
+
"brasil",
|
|
28
|
+
"brazil"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18.0.0"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/yvesmariano/registro-br-mcp.git"
|
|
37
|
+
},
|
|
38
|
+
"author": "Yves Mariano",
|
|
39
|
+
"homepage": "https://github.com/yvesmariano/registro-br-mcp#readme"
|
|
40
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
const RDAP_BASE_URL = "https://rdap.registro.br";
|
|
8
|
+
|
|
9
|
+
async function fetchRdap(path) {
|
|
10
|
+
const url = `${RDAP_BASE_URL}${path}`;
|
|
11
|
+
const response = await fetch(url, {
|
|
12
|
+
headers: {
|
|
13
|
+
Accept: "application/rdap+json",
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
if (response.status === 404) {
|
|
19
|
+
throw new Error(`Not found: ${path}`);
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`RDAP request failed: ${response.status} ${response.statusText}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function formatDomainInfo(data) {
|
|
28
|
+
const lines = [];
|
|
29
|
+
|
|
30
|
+
lines.push(`Domain: ${data.ldhName}`);
|
|
31
|
+
lines.push(`Handle: ${data.handle}`);
|
|
32
|
+
lines.push(`Status: ${data.status?.join(", ") || "N/A"}`);
|
|
33
|
+
|
|
34
|
+
if (data.events) {
|
|
35
|
+
lines.push("\nEvents:");
|
|
36
|
+
for (const event of data.events) {
|
|
37
|
+
lines.push(` - ${event.eventAction}: ${event.eventDate}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (data.nameservers) {
|
|
42
|
+
lines.push("\nNameservers:");
|
|
43
|
+
for (const ns of data.nameservers) {
|
|
44
|
+
lines.push(` - ${ns.ldhName}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (data.secureDNS) {
|
|
49
|
+
lines.push(`\nDNSSEC: ${data.secureDNS.delegationSigned ? "Signed" : "Not signed"}`);
|
|
50
|
+
if (data.secureDNS.dsData) {
|
|
51
|
+
for (const ds of data.secureDNS.dsData) {
|
|
52
|
+
lines.push(` - KeyTag: ${ds.keyTag}, Algorithm: ${ds.algorithm}, DigestType: ${ds.digestType}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (data.entities) {
|
|
58
|
+
lines.push("\nEntities:");
|
|
59
|
+
for (const entity of data.entities) {
|
|
60
|
+
const name = entity.vcardArray?.[1]?.find(v => v[0] === "fn")?.[3] || entity.handle;
|
|
61
|
+
lines.push(` - ${name} (${entity.roles?.join(", ") || "N/A"})`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return lines.join("\n");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function formatEntityInfo(data) {
|
|
69
|
+
const lines = [];
|
|
70
|
+
|
|
71
|
+
lines.push(`Handle: ${data.handle}`);
|
|
72
|
+
|
|
73
|
+
if (data.vcardArray) {
|
|
74
|
+
const vcard = data.vcardArray[1];
|
|
75
|
+
const fn = vcard.find(v => v[0] === "fn")?.[3];
|
|
76
|
+
const email = vcard.find(v => v[0] === "email")?.[3];
|
|
77
|
+
const kind = vcard.find(v => v[0] === "kind")?.[3];
|
|
78
|
+
|
|
79
|
+
if (fn) lines.push(`Name: ${fn}`);
|
|
80
|
+
if (kind) lines.push(`Type: ${kind}`);
|
|
81
|
+
if (email) lines.push(`Email: ${email}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (data.roles) {
|
|
85
|
+
lines.push(`Roles: ${data.roles.join(", ")}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (data.publicIds) {
|
|
89
|
+
lines.push("\nPublic IDs:");
|
|
90
|
+
for (const pid of data.publicIds) {
|
|
91
|
+
lines.push(` - ${pid.type}: ${pid.identifier}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (data.events) {
|
|
96
|
+
lines.push("\nEvents:");
|
|
97
|
+
for (const event of data.events) {
|
|
98
|
+
lines.push(` - ${event.eventAction}: ${event.eventDate}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (data.legalRepresentative) {
|
|
103
|
+
lines.push(`\nLegal Representative: ${data.legalRepresentative}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return lines.join("\n");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function formatNameserverInfo(data) {
|
|
110
|
+
const lines = [];
|
|
111
|
+
|
|
112
|
+
lines.push(`Nameserver: ${data.ldhName}`);
|
|
113
|
+
lines.push(`Handle: ${data.handle || "N/A"}`);
|
|
114
|
+
|
|
115
|
+
if (data.ipAddresses) {
|
|
116
|
+
if (data.ipAddresses.v4) {
|
|
117
|
+
lines.push(`IPv4: ${data.ipAddresses.v4.join(", ")}`);
|
|
118
|
+
}
|
|
119
|
+
if (data.ipAddresses.v6) {
|
|
120
|
+
lines.push(`IPv6: ${data.ipAddresses.v6.join(", ")}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (data.events) {
|
|
125
|
+
lines.push("\nEvents:");
|
|
126
|
+
for (const event of data.events) {
|
|
127
|
+
lines.push(` - ${event.eventAction}: ${event.eventDate}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return lines.join("\n");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function formatIpInfo(data) {
|
|
135
|
+
const lines = [];
|
|
136
|
+
|
|
137
|
+
lines.push(`Handle: ${data.handle}`);
|
|
138
|
+
lines.push(`Start Address: ${data.startAddress}`);
|
|
139
|
+
lines.push(`End Address: ${data.endAddress}`);
|
|
140
|
+
lines.push(`IP Version: ${data.ipVersion}`);
|
|
141
|
+
lines.push(`Name: ${data.name || "N/A"}`);
|
|
142
|
+
lines.push(`Type: ${data.type || "N/A"}`);
|
|
143
|
+
lines.push(`Country: ${data.country || "N/A"}`);
|
|
144
|
+
|
|
145
|
+
if (data.status) {
|
|
146
|
+
lines.push(`Status: ${data.status.join(", ")}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (data.events) {
|
|
150
|
+
lines.push("\nEvents:");
|
|
151
|
+
for (const event of data.events) {
|
|
152
|
+
lines.push(` - ${event.eventAction}: ${event.eventDate}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return lines.join("\n");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function formatAsnInfo(data) {
|
|
160
|
+
const lines = [];
|
|
161
|
+
|
|
162
|
+
lines.push(`Handle: ${data.handle}`);
|
|
163
|
+
lines.push(`Start ASN: ${data.startAutnum}`);
|
|
164
|
+
lines.push(`End ASN: ${data.endAutnum}`);
|
|
165
|
+
lines.push(`Name: ${data.name || "N/A"}`);
|
|
166
|
+
lines.push(`Type: ${data.type || "N/A"}`);
|
|
167
|
+
lines.push(`Country: ${data.country || "N/A"}`);
|
|
168
|
+
|
|
169
|
+
if (data.status) {
|
|
170
|
+
lines.push(`Status: ${data.status.join(", ")}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (data.events) {
|
|
174
|
+
lines.push("\nEvents:");
|
|
175
|
+
for (const event of data.events) {
|
|
176
|
+
lines.push(` - ${event.eventAction}: ${event.eventDate}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return lines.join("\n");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const server = new McpServer({
|
|
184
|
+
name: "registro-br-rdap",
|
|
185
|
+
version: "1.0.0",
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Tool: Query domain information
|
|
189
|
+
server.tool(
|
|
190
|
+
"rdap_domain",
|
|
191
|
+
"Query RDAP information for a .br domain",
|
|
192
|
+
{
|
|
193
|
+
domain: z.string().describe("The domain name to query (e.g., nic.br, registro.br)"),
|
|
194
|
+
},
|
|
195
|
+
async ({ domain }) => {
|
|
196
|
+
try {
|
|
197
|
+
const data = await fetchRdap(`/domain/${domain}`);
|
|
198
|
+
return {
|
|
199
|
+
content: [
|
|
200
|
+
{
|
|
201
|
+
type: "text",
|
|
202
|
+
text: formatDomainInfo(data),
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: "text",
|
|
206
|
+
text: "\n\n--- Raw JSON ---\n" + JSON.stringify(data, null, 2),
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
} catch (error) {
|
|
211
|
+
return {
|
|
212
|
+
content: [
|
|
213
|
+
{
|
|
214
|
+
type: "text",
|
|
215
|
+
text: `Error querying domain: ${error.message}`,
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
isError: true,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// Tool: Query entity information
|
|
225
|
+
server.tool(
|
|
226
|
+
"rdap_entity",
|
|
227
|
+
"Query RDAP information for an entity (by CNPJ, CPF, or handle)",
|
|
228
|
+
{
|
|
229
|
+
entity: z.string().describe("The entity identifier (CNPJ without punctuation, CPF, or handle like 'FAN')"),
|
|
230
|
+
},
|
|
231
|
+
async ({ entity }) => {
|
|
232
|
+
try {
|
|
233
|
+
const data = await fetchRdap(`/entity/${entity}`);
|
|
234
|
+
return {
|
|
235
|
+
content: [
|
|
236
|
+
{
|
|
237
|
+
type: "text",
|
|
238
|
+
text: formatEntityInfo(data),
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
type: "text",
|
|
242
|
+
text: "\n\n--- Raw JSON ---\n" + JSON.stringify(data, null, 2),
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
};
|
|
246
|
+
} catch (error) {
|
|
247
|
+
return {
|
|
248
|
+
content: [
|
|
249
|
+
{
|
|
250
|
+
type: "text",
|
|
251
|
+
text: `Error querying entity: ${error.message}`,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
isError: true,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
// Tool: Query nameserver information
|
|
261
|
+
server.tool(
|
|
262
|
+
"rdap_nameserver",
|
|
263
|
+
"Query RDAP information for a nameserver",
|
|
264
|
+
{
|
|
265
|
+
nameserver: z.string().describe("The nameserver hostname (e.g., a.dns.br)"),
|
|
266
|
+
},
|
|
267
|
+
async ({ nameserver }) => {
|
|
268
|
+
try {
|
|
269
|
+
const data = await fetchRdap(`/nameserver/${nameserver}`);
|
|
270
|
+
return {
|
|
271
|
+
content: [
|
|
272
|
+
{
|
|
273
|
+
type: "text",
|
|
274
|
+
text: formatNameserverInfo(data),
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
type: "text",
|
|
278
|
+
text: "\n\n--- Raw JSON ---\n" + JSON.stringify(data, null, 2),
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
};
|
|
282
|
+
} catch (error) {
|
|
283
|
+
return {
|
|
284
|
+
content: [
|
|
285
|
+
{
|
|
286
|
+
type: "text",
|
|
287
|
+
text: `Error querying nameserver: ${error.message}`,
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
isError: true,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
// Tool: Query IP network information
|
|
297
|
+
server.tool(
|
|
298
|
+
"rdap_ip",
|
|
299
|
+
"Query RDAP information for an IP address or network",
|
|
300
|
+
{
|
|
301
|
+
ip: z.string().describe("The IP address or CIDR notation (e.g., 200.160.0.0, 200.160.0.0/20)"),
|
|
302
|
+
},
|
|
303
|
+
async ({ ip }) => {
|
|
304
|
+
try {
|
|
305
|
+
const data = await fetchRdap(`/ip/${ip}`);
|
|
306
|
+
return {
|
|
307
|
+
content: [
|
|
308
|
+
{
|
|
309
|
+
type: "text",
|
|
310
|
+
text: formatIpInfo(data),
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
type: "text",
|
|
314
|
+
text: "\n\n--- Raw JSON ---\n" + JSON.stringify(data, null, 2),
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
};
|
|
318
|
+
} catch (error) {
|
|
319
|
+
return {
|
|
320
|
+
content: [
|
|
321
|
+
{
|
|
322
|
+
type: "text",
|
|
323
|
+
text: `Error querying IP: ${error.message}`,
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
isError: true,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
// Tool: Query ASN information
|
|
333
|
+
server.tool(
|
|
334
|
+
"rdap_asn",
|
|
335
|
+
"Query RDAP information for an Autonomous System Number",
|
|
336
|
+
{
|
|
337
|
+
asn: z.string().describe("The AS number (e.g., 22548 or AS22548)"),
|
|
338
|
+
},
|
|
339
|
+
async ({ asn }) => {
|
|
340
|
+
try {
|
|
341
|
+
const asnNumber = asn.replace(/^AS/i, "");
|
|
342
|
+
const data = await fetchRdap(`/autnum/${asnNumber}`);
|
|
343
|
+
return {
|
|
344
|
+
content: [
|
|
345
|
+
{
|
|
346
|
+
type: "text",
|
|
347
|
+
text: formatAsnInfo(data),
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
type: "text",
|
|
351
|
+
text: "\n\n--- Raw JSON ---\n" + JSON.stringify(data, null, 2),
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
};
|
|
355
|
+
} catch (error) {
|
|
356
|
+
return {
|
|
357
|
+
content: [
|
|
358
|
+
{
|
|
359
|
+
type: "text",
|
|
360
|
+
text: `Error querying ASN: ${error.message}`,
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
isError: true,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
async function main() {
|
|
370
|
+
const transport = new StdioServerTransport();
|
|
371
|
+
await server.connect(transport);
|
|
372
|
+
console.error("Registro.br RDAP MCP Server running on stdio");
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
main().catch(console.error);
|