@cyanheads/whois-mcp-server 0.1.4 → 0.1.6
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/AGENTS.md +61 -28
- package/CLAUDE.md +61 -28
- package/Dockerfile +44 -33
- package/README.md +41 -65
- package/changelog/0.1.x/0.1.5.md +35 -0
- package/changelog/0.1.x/0.1.6.md +41 -0
- package/changelog/template.md +9 -26
- package/dist/app.d.ts +216 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +47 -0
- package/dist/app.js.map +1 -0
- package/dist/index.js +2 -33
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-check-availability.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-check-availability.tool.js +1 -3
- package/dist/mcp-server/tools/definitions/whois-check-availability.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-get-dns.tool.d.ts +17 -0
- package/dist/mcp-server/tools/definitions/whois-get-dns.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-get-dns.tool.js +21 -14
- package/dist/mcp-server/tools/definitions/whois-get-dns.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-get-dossier.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-get-dossier.tool.js +39 -31
- package/dist/mcp-server/tools/definitions/whois-get-dossier.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-lookup-asn.tool.d.ts +4 -2
- package/dist/mcp-server/tools/definitions/whois-lookup-asn.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-lookup-asn.tool.js +8 -5
- package/dist/mcp-server/tools/definitions/whois-lookup-asn.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-lookup-domain.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-lookup-domain.tool.js +2 -5
- package/dist/mcp-server/tools/definitions/whois-lookup-domain.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-lookup-ip.tool.d.ts +4 -2
- package/dist/mcp-server/tools/definitions/whois-lookup-ip.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-lookup-ip.tool.js +13 -12
- package/dist/mcp-server/tools/definitions/whois-lookup-ip.tool.js.map +1 -1
- package/dist/services/doh/doh-service.d.ts.map +1 -1
- package/dist/services/doh/doh-service.js +10 -12
- package/dist/services/doh/doh-service.js.map +1 -1
- package/dist/services/doh/types.d.ts +4 -0
- package/dist/services/doh/types.d.ts.map +1 -1
- package/dist/services/rdap/rdap-service.d.ts +10 -3
- package/dist/services/rdap/rdap-service.d.ts.map +1 -1
- package/dist/services/rdap/rdap-service.js +67 -109
- package/dist/services/rdap/rdap-service.js.map +1 -1
- package/package.json +13 -11
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/whois-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/whois-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -21,9 +21,11 @@
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Overview
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Domain and network intelligence via RDAP and DNS-over-HTTPS. Look up domain registrations, check availability, fetch DNS records, and resolve IPs and ASNs to their registries — all via public, keyless data sources. Runs as a stdio process or a local Streamable HTTP server.
|
|
27
|
+
|
|
28
|
+
### Tools
|
|
27
29
|
|
|
28
30
|
| Tool | Description |
|
|
29
31
|
|:-----|:------------|
|
|
@@ -34,97 +36,70 @@ Six tools covering domain intelligence, DNS, and IP/ASN resolution:
|
|
|
34
36
|
| `whois_lookup_asn` | Resolve an ASN to its org name, country, and RIR source |
|
|
35
37
|
| `whois_get_dossier` | One-call domain triage — registration + DNS in parallel, normalized into a single record with factual signals |
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
---
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
## Capability reference
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
- Returns registrar, creation/expiry dates, nameservers, EPP status codes, DNSSEC delegation flag
|
|
43
|
-
- Surfaces `registrant_redacted: true` explicitly when privacy redaction is in effect (standard post-GDPR for gTLDs)
|
|
44
|
-
- Returns `rdap_coverage: false` for TLDs without RDAP coverage rather than silently failing
|
|
45
|
-
- Includes `last_update_of_rdap_db` event timestamp for data freshness transparency
|
|
43
|
+
### `whois_lookup_domain` <sub>tool</sub>
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
- Accepts a fully qualified domain name and selects the registry RDAP server through IANA bootstrap.
|
|
46
|
+
- Returns registrar, registration dates, nameservers, EPP status, DNSSEC, and `registrant_redacted`; throws `rdap_no_coverage` or `domain_not_found` when no record can be returned.
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
---
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
### `whois_check_availability` <sub>tool</sub>
|
|
52
51
|
|
|
53
|
-
-
|
|
54
|
-
- Returns `available: false` with
|
|
55
|
-
- Returns `available: null` with `rdap_coverage: false` for TLDs without RDAP — cannot determine availability
|
|
56
|
-
- Optimized for bulk name sweeps — thin response, no unnecessary fields
|
|
52
|
+
- Accepts a fully qualified domain name for a registration check.
|
|
53
|
+
- Returns `available: true` for RDAP 404, `false` with registrar and expiry for a registered domain, or `null` with `rdap_coverage: false` when coverage is absent.
|
|
57
54
|
|
|
58
55
|
---
|
|
59
56
|
|
|
60
|
-
### `whois_get_dns`
|
|
61
|
-
|
|
62
|
-
Fetch DNS records via DNS-over-HTTPS.
|
|
57
|
+
### `whois_get_dns` <sub>tool</sub>
|
|
63
58
|
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
- Returns records with TTLs and the resolving source (`cloudflare` or `nextdns`)
|
|
67
|
-
- `nxdomain: true` in result (not an error) when the domain doesn't exist in DNS
|
|
59
|
+
- Accepts a hostname and optional nonempty `types`: A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, PTR; omission defaults to A, AAAA, MX, TXT, NS. Duplicate types are queried once.
|
|
60
|
+
- Returns records with TTLs and ordered `query_sources: [{type, source}]`, including empty answers and NXDOMAIN. Legacy `source` is `cloudflare` if any query consumed a successful Cloudflare response, otherwise `nextdns`; a nonexistent domain returns `nxdomain: true` as data.
|
|
68
61
|
|
|
69
62
|
---
|
|
70
63
|
|
|
71
|
-
### `whois_lookup_ip`
|
|
64
|
+
### `whois_lookup_ip` <sub>tool</sub>
|
|
72
65
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
- Returns netblock CIDR, org name, country, abuse contact email
|
|
77
|
-
- Fetches PTR (reverse DNS) via DoH as a best-effort step — `ptr: null` on failure, not an error
|
|
78
|
-
- Validates and rejects private/reserved ranges (RFC 1918, loopback, link-local) with a clear error
|
|
66
|
+
- Accepts a complete IPv4/IPv6 address with at most one decimal CIDR prefix (0–32 / 0–128); no whitespace, zone IDs, or brackets. Queries the base address and echoes the original `ip`. IPv4-mapped IPv6 uses the embedded IPv4 for policy, RDAP, and PTR; other IPv6 uses 32 reversed PTR nibbles.
|
|
67
|
+
- Returns netblock CIDR, organization, country, abuse contact, and best-effort PTR (`null` on failure); throws `invalid_ip` for malformed input or `ip_not_found` on an RIR RDAP 404.
|
|
68
|
+
- `private_range` enforces an explicit policy: IPv4 `0.0.0.0/8`, `10.0.0.0/8`, `100.64.0.0/10`, `127.0.0.0/8`, `169.254.0.0/16`, `172.16.0.0/12`, `192.168.0.0/16`, `255.0.0.0/8`; IPv6 `::1/128`, `fc00::/7`, `fe80::/10`. Other special-use addresses remain eligible for registry records or normal no-coverage/not-found outcomes.
|
|
79
69
|
|
|
80
70
|
---
|
|
81
71
|
|
|
82
|
-
### `whois_lookup_asn`
|
|
83
|
-
|
|
84
|
-
Resolve an ASN to its org name, country, and RIR.
|
|
72
|
+
### `whois_lookup_asn` <sub>tool</sub>
|
|
85
73
|
|
|
86
|
-
- Accepts `
|
|
87
|
-
-
|
|
88
|
-
- Returns `name`, `org`, `country`, `rir`, `start_autnum`, `end_autnum`
|
|
74
|
+
- Accepts a decimal ASN from 1 to 4294967295 with an optional case-insensitive `AS` prefix and leading `+` (e.g., `AS15169`, `AS 15169`, `+15169`). Outer whitespace and whitespace after `AS` are allowed; whitespace inside digits or after `+`, suffixes, decimals, and out-of-range values return `invalid_asn`.
|
|
75
|
+
- Returns `name`, `org_name`, `country`, `rir`, `start_autnum`, and `end_autnum`; throws `asn_not_found` when no ASN record exists.
|
|
89
76
|
|
|
90
77
|
---
|
|
91
78
|
|
|
92
|
-
### `whois_get_dossier`
|
|
79
|
+
### `whois_get_dossier` <sub>tool</sub>
|
|
93
80
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
- Runs RDAP domain lookup and DoH (A, MX, NS, TXT) in parallel via `Promise.allSettled`
|
|
97
|
-
- Inferred signals: `age_days`, `privacy_redacted`, `registrar`, `ns_provider` (from NS records), `mx_provider` (from MX records)
|
|
98
|
-
- No synthesized risk scores — factual signals only; the agent decides the verdict
|
|
99
|
-
- Partial results surfaced when one leg fails (`source_error` on the failed leg)
|
|
100
|
-
- Both-legs-fail throws `ServiceUnavailable`; individual leg failures are data, not errors
|
|
81
|
+
- Accepts a fully qualified domain name for parallel registration and A/MX/NS/TXT lookups.
|
|
82
|
+
- Returns registration, DNS, domain age, privacy status, and inferred NS/MX providers. Individual failures remain partial data in `rdap_source_error` or `dns_source_error`; `both_legs_failed` means neither source succeeded.
|
|
101
83
|
|
|
102
84
|
---
|
|
103
85
|
|
|
104
86
|
## Features
|
|
105
87
|
|
|
106
|
-
Built on [`@cyanheads/mcp-ts-core`](https://
|
|
107
|
-
|
|
108
|
-
- Declarative tool definitions — single file per tool, framework handles registration and validation
|
|
109
|
-
- Unified error handling — handlers throw, framework catches, classifies, and formats
|
|
110
|
-
- Pluggable auth: `none`, `jwt`, `oauth`
|
|
111
|
-
- Swappable storage backends: `in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`
|
|
112
|
-
- Structured logging with optional OpenTelemetry tracing
|
|
113
|
-
- STDIO and Streamable HTTP transports
|
|
88
|
+
Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): stdio and Streamable HTTP transports, pluggable auth (`none` / `jwt` / `oauth`), swappable storage (`in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`), structured logging with optional OpenTelemetry tracing.
|
|
114
89
|
|
|
115
|
-
|
|
90
|
+
RDAP / DNS-specific:
|
|
116
91
|
|
|
117
|
-
- RDAP over HTTPS — no port-43 TCP dependency
|
|
118
|
-
- IANA bootstrap auto-selection — correct registry RDAP server picked per TLD, RIR, or ASN range; bootstrap JSON cached
|
|
119
|
-
- DNS-over-HTTPS via Cloudflare and NextDNS —
|
|
92
|
+
- RDAP over HTTPS — no port-43 TCP dependency
|
|
93
|
+
- IANA bootstrap auto-selection — correct registry RDAP server picked per TLD, RIR, or ASN range; bootstrap JSON cached in-memory for 24h
|
|
94
|
+
- DNS-over-HTTPS via Cloudflare and NextDNS — dual-provider with per-type routing (NextDNS for CAA; Cloudflare for all others) and automatic fallback
|
|
120
95
|
- No API keys required — all sources (IANA, registry RDAP endpoints, RIR RDAP, Cloudflare DoH, NextDNS DoH) are public and keyless
|
|
121
96
|
|
|
122
97
|
Agent-friendly output:
|
|
123
98
|
|
|
124
|
-
-
|
|
99
|
+
- Coverage signaled two ways — `rdap_coverage: false` returned as data by `whois_check_availability` and `whois_get_dossier`, while `whois_lookup_domain` throws `rdap_no_coverage` for the same case
|
|
125
100
|
- Privacy redaction surfaced as a field — `registrant_redacted: true` rather than silently absent contact data
|
|
126
|
-
- Partial failure model — `whois_get_dossier` marks individual legs with `source_error` and continues; only both-legs-fail escalates to an error
|
|
127
|
-
- Factual signals, not scores — `age_days`, `privacy_redacted`, `ns_provider`, `mx_provider` are real data
|
|
101
|
+
- Partial failure model — `whois_get_dossier` marks individual legs with a `source_error` field and continues; only both-legs-fail escalates to an error
|
|
102
|
+
- Factual signals, not scores — `age_days`, `privacy_redacted`, `ns_provider`, `mx_provider` are real data, not synthesized risk scores
|
|
128
103
|
|
|
129
104
|
---
|
|
130
105
|
|
|
@@ -193,7 +168,7 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
|
|
|
193
168
|
|
|
194
169
|
### Prerequisites
|
|
195
170
|
|
|
196
|
-
- [Bun v1.
|
|
171
|
+
- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
197
172
|
- No API keys required — all data sources are public.
|
|
198
173
|
|
|
199
174
|
### Installation
|
|
@@ -279,7 +254,8 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
279
254
|
|
|
280
255
|
| Path | Purpose |
|
|
281
256
|
|:-----|:--------|
|
|
282
|
-
| `src/index.ts` |
|
|
257
|
+
| `src/index.ts` | Entry point — starts the app. |
|
|
258
|
+
| `src/app.ts` | `createApp()` options — registers tools, inits services, declares the session mode. |
|
|
283
259
|
| `src/config/` | Server-specific environment variable parsing and validation (Zod). |
|
|
284
260
|
| `src/services/rdap/` | RDAP client — IANA bootstrap cache, domain/IP/ASN lookup, retry. |
|
|
285
261
|
| `src/services/doh/` | DNS-over-HTTPS client — Cloudflare primary, NextDNS fallback. |
|
|
@@ -294,15 +270,15 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
294
270
|
See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:
|
|
295
271
|
|
|
296
272
|
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
297
|
-
- Use `ctx.log` for request-scoped logging
|
|
298
|
-
- Register new tools via `src/
|
|
273
|
+
- Use `ctx.log` for request-scoped logging
|
|
274
|
+
- Register new tools via `src/app.ts`'s `tools` array
|
|
299
275
|
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
|
|
300
276
|
|
|
301
277
|
---
|
|
302
278
|
|
|
303
279
|
## Contributing
|
|
304
280
|
|
|
305
|
-
Issues
|
|
281
|
+
Issues are welcome. Run checks and tests before submitting:
|
|
306
282
|
|
|
307
283
|
```sh
|
|
308
284
|
bun run devcheck
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Adopt mcp-ts-core 0.13.6 — the server resolves to a stateless session posture however it is launched, and an out-of-schema argument fails as InvalidParams (-32602) with a Recovery line instead of ValidationError (-32007). The Bun floor rises to 1.4.0."
|
|
3
|
+
breaking: true
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.5 — 2026-09-20
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`.github/FUNDING.yml`** — GitHub Sponsors and Buy Me a Coffee.
|
|
12
|
+
- **`bun run audit:fix`** — `bun audit fix`, the first response to a transitive advisory, ahead of `audit:refresh`.
|
|
13
|
+
- **`devcheck.config.json` `lint` block** — where `lint.truncationAllowlist` now lives, in place of a per-script `MCP_LINT_TRUNCATION_ALLOWLIST` env var.
|
|
14
|
+
- **`tests/app.test.ts`** — asserts the resolved session posture and the registered tool surface against a live `createApp()`.
|
|
15
|
+
|
|
16
|
+
## Changed
|
|
17
|
+
|
|
18
|
+
- **The session mode is `stateless` however the server is launched** ([#11](https://github.com/cyanheads/whois-mcp-server/issues/11)). `src/app.ts` declares `createApp({ sessionMode: 'stateless' })` and `.env.example` sets the variable actively, so the `Dockerfile` line restates the posture rather than overriding it; previously only the container was stateless and a `bunx`, `npm start`, or from-source run resolved to `stateful`. No tool holds per-session state or calls `ctx.requestInput`.
|
|
19
|
+
- **An out-of-schema argument now fails as `InvalidParams` (`-32602`), not `ValidationError` (`-32007`).** The rejection carries `data.reason: "invalid_arguments"` and its text ends with a `Recovery: …` line naming the field to fix. A client branching on the old code needs updating.
|
|
20
|
+
- **Tool error text closes with `(reason <reason> · not retryable)`** whenever the error carries a `reason` or a boolean `retryable`. `structuredContent` is unchanged.
|
|
21
|
+
- **A caller that disconnects mid-call classifies as `RequestCancelled` (`-32011`)** rather than `InternalError`, and logs at `info`. An upstream 500 on a DNS-over-HTTPS query now retries instead of failing on the first attempt.
|
|
22
|
+
- **Bun engines floor `>=1.3.0` → `>=1.4.0`**, required by the framework.
|
|
23
|
+
- **`whois_lookup_ip` and `whois_lookup_asn` mark their service-thrown contract entries `thrownBy: 'service'`** — `private_range`, `ip_not_found`, `invalid_asn`, `asn_not_found` (lint-only metadata; the advertised error surface is unchanged).
|
|
24
|
+
- **The framework skill tree moved from `skills/` to `framework-skills/`** — Claude Code and Codex auto-load a plugin's root `skills/`, so this server's plugin manifests no longer hand its development skills to every agent that installs it.
|
|
25
|
+
- **`createApp()` options live in `src/app.ts` as `appOptions`**; `src/index.ts` is the entry point that starts them.
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
- `@cyanheads/mcp-ts-core` `^0.12.3` → `^0.13.6`
|
|
30
|
+
- `zod` `^4.4.3` → `^4.6.5`
|
|
31
|
+
- `vitest` (dev) `^4.1.11` → `^5.0.1`
|
|
32
|
+
- `@biomejs/biome` (dev) `^2.5.9` → `^2.5.14`
|
|
33
|
+
- `@types/node` (dev) `^26` → `^26.6.1`
|
|
34
|
+
- `ignore` (dev) `^7.0.6` → `^7.0.9`
|
|
35
|
+
- `tsc-alias` (dev) `^1.9.2` → `^1.9.5`
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Lookup inputs are validated whole before any request, DNS results attribute each query to its resolver, and the dossier renders every TXT record and labels providers by domain."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.6 — 2026-09-30
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`whois_get_dns` `query_sources`** ([#10](https://github.com/cyanheads/whois-mcp-server/issues/10)) — one `{type, source}` entry per requested type, in request order, naming the resolver whose response was consumed, empty answers and NXDOMAIN included. Duplicate types are queried once; `source` stays the aggregate (`cloudflare` when any query used Cloudflare, otherwise `nextdns`).
|
|
12
|
+
- **Contract tests over the real services** — `tests/helpers/upstream.ts` replaces only outbound HTTP, and `tests/fixtures/` holds captured IANA, ARIN, and APNIC responses that the IP suite replays.
|
|
13
|
+
|
|
14
|
+
## Changed
|
|
15
|
+
|
|
16
|
+
- **Framework `@cyanheads/mcp-ts-core` `^0.13.6` → `^0.13.10`** — tool errors carry `data.requestId` and their text closes with `request <id>`, an integer sent for a string argument is repaired to its digits, and framework-built errors keep stack traces and request context out of `data`.
|
|
17
|
+
- **Recovery hints reach the wire through the framework's contract fill** — throws whose `errors[]` entry supplies the hint no longer forward `ctx.recoveryFor`.
|
|
18
|
+
- **Docker image** — production dependencies and the OpenTelemetry peers install in a `deps` stage on the build platform through `scripts/install-otel.ts`, at the framework's declared peer ranges, so no target-platform stage runs Bun while building. The unread `MCP_FORCE_CONSOLE_LOGGING` is gone.
|
|
19
|
+
- **Packaging** — `package.json` `files` carries `!dist/*.mcpb`, keeping a built bundle out of the npm tarball, and `.mcpbignore` excludes `docs/idea.md` and `logs/` from the bundle.
|
|
20
|
+
- **Tooling synced from the framework** — `lint:packaging` checks the bundle exclusion, `manifest.json` version parity, and the Dockerfile build platform; `lint:mcp` fails on a definition it cannot import; `release:github -- --check` validates the tag annotation.
|
|
21
|
+
- **Docs** — README tool sections state each tool's input and output contract, `docs/design.md` records the IP exclusion policy, and `CLAUDE.md` / `AGENTS.md` plus 31 framework skills follow the 0.13.10 templates.
|
|
22
|
+
|
|
23
|
+
## Fixed
|
|
24
|
+
|
|
25
|
+
- **`whois_lookup_asn` validates the whole token** ([#5](https://github.com/cyanheads/whois-mcp-server/issues/5)) — a decimal ASN from 1 to 4294967295 with an optional `AS` prefix and leading `+`. `AS15169abc`, `1.5`, and out-of-range values fail as `invalid_asn` before any request instead of resolving a truncated number.
|
|
26
|
+
- **`whois_lookup_ip` parses IP and CIDR input completely** ([#6](https://github.com/cyanheads/whois-mcp-server/issues/6)) — extra slashes, trailing text, whitespace, zone IDs, brackets, and malformed IPv6 fail as `invalid_ip` before any request. A CIDR prefix is one decimal within 0–32 or 0–128.
|
|
27
|
+
- **`private_range` follows the numeric address** — equivalent IPv6 spellings classify alike (`0:0:0:0:0:0:0:1`, `fe90::1`), `::10` is no longer excluded, and the tool description lists the excluded ranges.
|
|
28
|
+
- **IPv6 with a dotted IPv4 tail is accepted** — `2001:db8::192.0.2.1` resolves with a 32-nibble PTR name, and IPv4-mapped addresses (`::ffff:8.8.8.8`) are classified, routed, and PTR-resolved as their embedded IPv4.
|
|
29
|
+
- **`whois_get_dossier` renders every TXT value** ([#8](https://github.com/cyanheads/whois-mcp-server/issues/8)) — `content[]` dropped values past the third. Each value now sits in its own fence, longer than any backtick run inside it.
|
|
30
|
+
- **`whois_get_dns` rejects `types: []`** ([#9](https://github.com/cyanheads/whois-mcp-server/issues/9)) — it fails as `InvalidParams` (`-32602`) before any query instead of reporting a NextDNS lookup that never ran. Omitting `types` still fetches A, AAAA, MX, TXT, NS.
|
|
31
|
+
- **Provider and registry labels match whole domains** ([#12](https://github.com/cyanheads/whois-mcp-server/issues/12)) — `ns_provider` and `mx_provider` compare hostnames at label boundaries with the MX priority removed, and `rdap_source` / `rir` read only the self link's hostname. `ns1.hostname.com` no longer reads as Name.com; Fastmail's `messagingengine.com` is recognized.
|
|
32
|
+
- **`whois_lookup_domain` description** — a TLD without RDAP coverage throws `rdap_no_coverage`; the description previously promised `rdap_coverage: false`.
|
|
33
|
+
|
|
34
|
+
## Dependencies
|
|
35
|
+
|
|
36
|
+
- `@cyanheads/mcp-ts-core` `^0.13.6` → `^0.13.10`
|
|
37
|
+
- `@socketsecurity/bun-security-scanner` (dev) `^1.1.2` → `^1.1.3`
|
|
38
|
+
- `@types/node` (dev) `^26.6.1` → `^26.6.3`
|
|
39
|
+
- `ignore` (dev) `^7.0.9` → `^7.0.10`
|
|
40
|
+
- `vitest` (dev) `^5.0.1` → `^5.0.2`
|
|
41
|
+
- Bun `1.4.0` → `1.4.2` (`packageManager`, Docker base images)
|
package/changelog/template.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
# Required. One-line GitHub Release-style headline. 350 character cap — a
|
|
8
8
|
# ceiling, not a target. Default short and scannable. Don't pad, don't stitch
|
|
9
|
-
# unrelated changes with commas/semicolons into an inventory — pick the
|
|
10
|
-
# headline
|
|
9
|
+
# unrelated changes with commas/semicolons into an inventory — pick the one
|
|
10
|
+
# headline the release is about. Quotes required: unquoted YAML treats
|
|
11
11
|
# `: ` inside the value as a key separator and fails GitHub's strict parser.
|
|
12
12
|
summary: ""
|
|
13
13
|
|
|
@@ -117,30 +117,13 @@ security: false
|
|
|
117
117
|
in that unrelated item's metadata.
|
|
118
118
|
|
|
119
119
|
TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
|
|
120
|
-
via `gh release create --notes-from-tag`.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Dependency bumps: ← section header
|
|
128
|
-
← blank line
|
|
129
|
-
- `@cyanheads/mcp-ts-core` ^0.9.1 → ^0.9.6 ← bullet
|
|
130
|
-
← blank line
|
|
131
|
-
Changed: ← only sections with entries
|
|
132
|
-
← blank line
|
|
133
|
-
- `format()` output includes `query` in text mode
|
|
134
|
-
← blank line
|
|
135
|
-
Added:
|
|
136
|
-
← blank line
|
|
137
|
-
- `manifest.json` scaffolded for MCPB bundle support
|
|
138
|
-
- Install badges (Claude Desktop, Cursor, VS Code)
|
|
139
|
-
← blank line
|
|
140
|
-
<N> tests pass; `bun run devcheck` clean. ← footer
|
|
141
|
-
|
|
142
|
-
Never a flat comma-separated string. Always structured markdown with
|
|
143
|
-
sections. The tag must scan well as a rendered GitHub Release page.
|
|
120
|
+
via `gh release create --notes-from-tag`. It is a condensed digest of this
|
|
121
|
+
entry, never a copy, and its format is owned by the `release-and-publish`
|
|
122
|
+
skill (step 4, "Create the annotated tag"): a short subject line without the
|
|
123
|
+
version, flat headline bullets — no Keep-a-Changelog section headers, no
|
|
124
|
+
gates line — at most one deps line, issue backlinks, and the changelog link
|
|
125
|
+
last. In release-PR mode the `git-wrapup` skill authors those bullets as the
|
|
126
|
+
PR body's `## Changes` and the tag copies them.
|
|
144
127
|
-->
|
|
145
128
|
|
|
146
129
|
## Added
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview whois-mcp-server application wiring — the `createApp()` options
|
|
3
|
+
* the entry point starts and tests assert against.
|
|
4
|
+
* @module app
|
|
5
|
+
*/
|
|
6
|
+
export declare const appOptions: {
|
|
7
|
+
name: string;
|
|
8
|
+
title: string;
|
|
9
|
+
/**
|
|
10
|
+
* No per-session state, and no handler calls `ctx.requestInput` — the session
|
|
11
|
+
* store and the per-session `McpServer` allocation are pure overhead, and the
|
|
12
|
+
* process scales horizontally without them. Declared here so the posture holds
|
|
13
|
+
* however the server is launched; a deployment's `MCP_SESSION_MODE` still wins
|
|
14
|
+
* when it carries a meaningful value.
|
|
15
|
+
*/
|
|
16
|
+
sessionMode: "stateless";
|
|
17
|
+
tools: (import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
18
|
+
domain: import("zod").ZodString;
|
|
19
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
20
|
+
domain: import("zod").ZodString;
|
|
21
|
+
available: import("zod").ZodNullable<import("zod").ZodBoolean>;
|
|
22
|
+
rdap_coverage: import("zod").ZodBoolean;
|
|
23
|
+
registrar: import("zod").ZodOptional<import("zod").ZodString>;
|
|
24
|
+
expiry_date: import("zod").ZodOptional<import("zod").ZodString>;
|
|
25
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
26
|
+
readonly reason: "invalid_domain";
|
|
27
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
28
|
+
readonly when: "Input is not a valid FQDN.";
|
|
29
|
+
readonly recovery: "Provide a valid fully-qualified domain name like \"example.com\" or \"sub.example.org\".";
|
|
30
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
31
|
+
domain: import("zod").ZodString;
|
|
32
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
33
|
+
domain: import("zod").ZodString;
|
|
34
|
+
rdap_coverage: import("zod").ZodNullable<import("zod").ZodBoolean>;
|
|
35
|
+
registered: import("zod").ZodNullable<import("zod").ZodBoolean>;
|
|
36
|
+
registrar: import("zod").ZodOptional<import("zod").ZodString>;
|
|
37
|
+
created_date: import("zod").ZodOptional<import("zod").ZodString>;
|
|
38
|
+
expiry_date: import("zod").ZodOptional<import("zod").ZodString>;
|
|
39
|
+
age_days: import("zod").ZodNullable<import("zod").ZodNumber>;
|
|
40
|
+
dnssec_signed: import("zod").ZodNullable<import("zod").ZodBoolean>;
|
|
41
|
+
privacy_redacted: import("zod").ZodNullable<import("zod").ZodBoolean>;
|
|
42
|
+
status: import("zod").ZodArray<import("zod").ZodString>;
|
|
43
|
+
nameservers: import("zod").ZodArray<import("zod").ZodString>;
|
|
44
|
+
a_records: import("zod").ZodArray<import("zod").ZodString>;
|
|
45
|
+
mx_records: import("zod").ZodArray<import("zod").ZodString>;
|
|
46
|
+
ns_records: import("zod").ZodArray<import("zod").ZodString>;
|
|
47
|
+
txt_records: import("zod").ZodArray<import("zod").ZodString>;
|
|
48
|
+
dns_nxdomain: import("zod").ZodNullable<import("zod").ZodBoolean>;
|
|
49
|
+
ns_provider: import("zod").ZodNullable<import("zod").ZodString>;
|
|
50
|
+
mx_provider: import("zod").ZodNullable<import("zod").ZodString>;
|
|
51
|
+
rdap_source_error: import("zod").ZodOptional<import("zod").ZodString>;
|
|
52
|
+
dns_source_error: import("zod").ZodOptional<import("zod").ZodString>;
|
|
53
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
54
|
+
readonly reason: "invalid_domain";
|
|
55
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
56
|
+
readonly when: "Input is not a valid FQDN.";
|
|
57
|
+
readonly recovery: "Provide a valid fully-qualified domain name like \"example.com\" or \"sub.example.org\".";
|
|
58
|
+
}, {
|
|
59
|
+
readonly reason: "both_legs_failed";
|
|
60
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
61
|
+
readonly when: "Both RDAP and DoH legs failed — no data could be retrieved.";
|
|
62
|
+
readonly recovery: "Both RDAP and DNS services are unavailable. Retry in a few minutes or check network connectivity.";
|
|
63
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
64
|
+
domain: import("zod").ZodString;
|
|
65
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
66
|
+
domain: import("zod").ZodString;
|
|
67
|
+
rdap_coverage: import("zod").ZodBoolean;
|
|
68
|
+
handle: import("zod").ZodOptional<import("zod").ZodString>;
|
|
69
|
+
registrar: import("zod").ZodOptional<import("zod").ZodString>;
|
|
70
|
+
registrar_iana_id: import("zod").ZodOptional<import("zod").ZodString>;
|
|
71
|
+
created_date: import("zod").ZodOptional<import("zod").ZodString>;
|
|
72
|
+
updated_date: import("zod").ZodOptional<import("zod").ZodString>;
|
|
73
|
+
expiry_date: import("zod").ZodOptional<import("zod").ZodString>;
|
|
74
|
+
rdap_last_updated: import("zod").ZodOptional<import("zod").ZodString>;
|
|
75
|
+
status: import("zod").ZodArray<import("zod").ZodString>;
|
|
76
|
+
nameservers: import("zod").ZodArray<import("zod").ZodString>;
|
|
77
|
+
dnssec_signed: import("zod").ZodBoolean;
|
|
78
|
+
registrant_org: import("zod").ZodOptional<import("zod").ZodString>;
|
|
79
|
+
registrant_redacted: import("zod").ZodBoolean;
|
|
80
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
81
|
+
readonly reason: "invalid_domain";
|
|
82
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
83
|
+
readonly when: "Input is not a valid FQDN.";
|
|
84
|
+
readonly recovery: "Provide a valid fully-qualified domain name like \"example.com\" or \"sub.example.org\".";
|
|
85
|
+
}, {
|
|
86
|
+
readonly reason: "rdap_no_coverage";
|
|
87
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
88
|
+
readonly when: "TLD has no RDAP server in the IANA bootstrap — cannot perform lookup.";
|
|
89
|
+
readonly recovery: "This TLD has no RDAP coverage. Use whois_check_availability to test registration status when possible.";
|
|
90
|
+
}, {
|
|
91
|
+
readonly reason: "domain_not_found";
|
|
92
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
93
|
+
readonly when: "RDAP server returned 404 — domain is not registered.";
|
|
94
|
+
readonly recovery: "The domain is not registered. Use whois_check_availability to confirm availability for registration.";
|
|
95
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
96
|
+
domain: import("zod").ZodString;
|
|
97
|
+
types: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodEnum<{
|
|
98
|
+
A: "A";
|
|
99
|
+
AAAA: "AAAA";
|
|
100
|
+
CAA: "CAA";
|
|
101
|
+
CNAME: "CNAME";
|
|
102
|
+
MX: "MX";
|
|
103
|
+
NS: "NS";
|
|
104
|
+
PTR: "PTR";
|
|
105
|
+
SOA: "SOA";
|
|
106
|
+
TXT: "TXT";
|
|
107
|
+
}>>>;
|
|
108
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
109
|
+
domain: import("zod").ZodString;
|
|
110
|
+
nxdomain: import("zod").ZodBoolean;
|
|
111
|
+
records: import("zod").ZodArray<import("zod").ZodObject<{
|
|
112
|
+
type: import("zod").ZodEnum<{
|
|
113
|
+
A: "A";
|
|
114
|
+
AAAA: "AAAA";
|
|
115
|
+
CAA: "CAA";
|
|
116
|
+
CNAME: "CNAME";
|
|
117
|
+
MX: "MX";
|
|
118
|
+
NS: "NS";
|
|
119
|
+
PTR: "PTR";
|
|
120
|
+
SOA: "SOA";
|
|
121
|
+
TXT: "TXT";
|
|
122
|
+
}>;
|
|
123
|
+
name: import("zod").ZodString;
|
|
124
|
+
ttl: import("zod").ZodNumber;
|
|
125
|
+
data: import("zod").ZodString;
|
|
126
|
+
}, import("zod/v4/core").$strip>>;
|
|
127
|
+
source: import("zod").ZodEnum<{
|
|
128
|
+
cloudflare: "cloudflare";
|
|
129
|
+
nextdns: "nextdns";
|
|
130
|
+
}>;
|
|
131
|
+
query_sources: import("zod").ZodArray<import("zod").ZodObject<{
|
|
132
|
+
type: import("zod").ZodEnum<{
|
|
133
|
+
A: "A";
|
|
134
|
+
AAAA: "AAAA";
|
|
135
|
+
CAA: "CAA";
|
|
136
|
+
CNAME: "CNAME";
|
|
137
|
+
MX: "MX";
|
|
138
|
+
NS: "NS";
|
|
139
|
+
PTR: "PTR";
|
|
140
|
+
SOA: "SOA";
|
|
141
|
+
TXT: "TXT";
|
|
142
|
+
}>;
|
|
143
|
+
source: import("zod").ZodEnum<{
|
|
144
|
+
cloudflare: "cloudflare";
|
|
145
|
+
nextdns: "nextdns";
|
|
146
|
+
}>;
|
|
147
|
+
}, import("zod/v4/core").$strip>>;
|
|
148
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
149
|
+
readonly reason: "invalid_domain";
|
|
150
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
151
|
+
readonly when: "Input is not a valid FQDN.";
|
|
152
|
+
readonly recovery: "Provide a valid fully-qualified domain name like \"example.com\" or \"sub.example.org\".";
|
|
153
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
154
|
+
ip: import("zod").ZodString;
|
|
155
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
156
|
+
ip: import("zod").ZodString;
|
|
157
|
+
handle: import("zod").ZodOptional<import("zod").ZodString>;
|
|
158
|
+
start_address: import("zod").ZodOptional<import("zod").ZodString>;
|
|
159
|
+
end_address: import("zod").ZodOptional<import("zod").ZodString>;
|
|
160
|
+
cidr: import("zod").ZodOptional<import("zod").ZodString>;
|
|
161
|
+
ip_version: import("zod").ZodOptional<import("zod").ZodString>;
|
|
162
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
163
|
+
type: import("zod").ZodOptional<import("zod").ZodString>;
|
|
164
|
+
country: import("zod").ZodOptional<import("zod").ZodString>;
|
|
165
|
+
org_name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
166
|
+
abuse_email: import("zod").ZodOptional<import("zod").ZodString>;
|
|
167
|
+
ptr: import("zod").ZodNullable<import("zod").ZodString>;
|
|
168
|
+
rdap_source: import("zod").ZodOptional<import("zod").ZodString>;
|
|
169
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
170
|
+
readonly reason: "invalid_ip";
|
|
171
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
172
|
+
readonly when: "Input is not a valid IPv4, IPv6, or CIDR address.";
|
|
173
|
+
readonly recovery: "Provide a valid IPv4 (e.g., \"8.8.8.8\"), IPv6 (e.g., \"2001:db8::1\"), or CIDR (e.g., \"192.0.2.0/24\").";
|
|
174
|
+
}, {
|
|
175
|
+
readonly reason: "private_range";
|
|
176
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
177
|
+
readonly when: "The numeric address falls within the server’s explicit excluded ranges.";
|
|
178
|
+
readonly recovery: "Choose an address outside the excluded ranges listed in this tool’s description.";
|
|
179
|
+
readonly thrownBy: "service";
|
|
180
|
+
}, {
|
|
181
|
+
readonly reason: "ip_not_found";
|
|
182
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
183
|
+
readonly when: "RIR RDAP returned 404 — no netblock record for this address.";
|
|
184
|
+
readonly recovery: "The IP address is not found in any RIR RDAP database. Try a different IP or verify it is globally routable.";
|
|
185
|
+
readonly thrownBy: "service";
|
|
186
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
187
|
+
asn: import("zod").ZodString;
|
|
188
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
189
|
+
asn: import("zod").ZodString;
|
|
190
|
+
handle: import("zod").ZodOptional<import("zod").ZodString>;
|
|
191
|
+
start_autnum: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
192
|
+
end_autnum: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
193
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
194
|
+
type: import("zod").ZodOptional<import("zod").ZodString>;
|
|
195
|
+
country: import("zod").ZodOptional<import("zod").ZodString>;
|
|
196
|
+
org_name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
197
|
+
rir: import("zod").ZodOptional<import("zod").ZodString>;
|
|
198
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
199
|
+
readonly reason: "invalid_asn";
|
|
200
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
201
|
+
readonly when: "The complete token is not a decimal ASN from 1 to 4294967295.";
|
|
202
|
+
readonly recovery: "Provide a decimal integer from 1 to 4294967295, optionally prefixed with AS and +, such as \"AS15169\" or \"+15169\".";
|
|
203
|
+
readonly thrownBy: "service";
|
|
204
|
+
}, {
|
|
205
|
+
readonly reason: "asn_not_found";
|
|
206
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
207
|
+
readonly when: "RDAP returned 404 — ASN not found in any RIR.";
|
|
208
|
+
readonly recovery: "The ASN is not found in any RIR RDAP database. Verify the ASN number is correct and assigned.";
|
|
209
|
+
readonly thrownBy: "service";
|
|
210
|
+
}], undefined>)[];
|
|
211
|
+
resources: never[];
|
|
212
|
+
prompts: never[];
|
|
213
|
+
instructions: string;
|
|
214
|
+
setup(core: import("@cyanheads/mcp-ts-core").CoreServices<object>): void;
|
|
215
|
+
};
|
|
216
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,eAAO,MAAM,UAAU;;;IAGrB;;;;;;OAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBuB,CAAC"}
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview whois-mcp-server application wiring — the `createApp()` options
|
|
3
|
+
* the entry point starts and tests assert against.
|
|
4
|
+
* @module app
|
|
5
|
+
*/
|
|
6
|
+
import { whoisCheckAvailability } from './mcp-server/tools/definitions/whois-check-availability.tool.js';
|
|
7
|
+
import { whoisGetDns } from './mcp-server/tools/definitions/whois-get-dns.tool.js';
|
|
8
|
+
import { whoisGetDossier } from './mcp-server/tools/definitions/whois-get-dossier.tool.js';
|
|
9
|
+
import { whoisLookupAsn } from './mcp-server/tools/definitions/whois-lookup-asn.tool.js';
|
|
10
|
+
import { whoisLookupDomain } from './mcp-server/tools/definitions/whois-lookup-domain.tool.js';
|
|
11
|
+
import { whoisLookupIp } from './mcp-server/tools/definitions/whois-lookup-ip.tool.js';
|
|
12
|
+
import { initDohService } from './services/doh/doh-service.js';
|
|
13
|
+
import { initRdapService } from './services/rdap/rdap-service.js';
|
|
14
|
+
export const appOptions = {
|
|
15
|
+
name: 'whois-mcp-server',
|
|
16
|
+
title: 'whois-mcp-server',
|
|
17
|
+
/**
|
|
18
|
+
* No per-session state, and no handler calls `ctx.requestInput` — the session
|
|
19
|
+
* store and the per-session `McpServer` allocation are pure overhead, and the
|
|
20
|
+
* process scales horizontally without them. Declared here so the posture holds
|
|
21
|
+
* however the server is launched; a deployment's `MCP_SESSION_MODE` still wins
|
|
22
|
+
* when it carries a meaningful value.
|
|
23
|
+
*/
|
|
24
|
+
sessionMode: 'stateless',
|
|
25
|
+
tools: [
|
|
26
|
+
whoisLookupDomain,
|
|
27
|
+
whoisCheckAvailability,
|
|
28
|
+
whoisGetDns,
|
|
29
|
+
whoisLookupIp,
|
|
30
|
+
whoisLookupAsn,
|
|
31
|
+
whoisGetDossier,
|
|
32
|
+
],
|
|
33
|
+
resources: [],
|
|
34
|
+
prompts: [],
|
|
35
|
+
instructions: 'whois-mcp-server: domain and IP intelligence via RDAP and DNS-over-HTTPS. No API keys required.\n' +
|
|
36
|
+
'- whois_lookup_domain: full registration record (registrar, dates, status, nameservers)\n' +
|
|
37
|
+
'- whois_check_availability: is a domain available to register? (RDAP 404 = available)\n' +
|
|
38
|
+
'- whois_get_dns: DNS records for any hostname (A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, PTR)\n' +
|
|
39
|
+
'- whois_lookup_ip: IP/CIDR netblock, org, abuse contact, and PTR via RIR RDAP\n' +
|
|
40
|
+
'- whois_lookup_asn: ASN to org/RIR resolution\n' +
|
|
41
|
+
'- whois_get_dossier: one-call domain triage — registration + DNS in parallel with inferred signals',
|
|
42
|
+
setup(core) {
|
|
43
|
+
initRdapService(core.config, core.storage);
|
|
44
|
+
initDohService(core.config, core.storage);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,iEAAiE,CAAC;AACzG,OAAO,EAAE,WAAW,EAAE,MAAM,sDAAsD,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAC;AAC3F,OAAO,EAAE,cAAc,EAAE,MAAM,yDAAyD,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4DAA4D,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,wDAAwD,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,kBAAkB;IACzB;;;;;;OAMG;IACH,WAAW,EAAE,WAAW;IACxB,KAAK,EAAE;QACL,iBAAiB;QACjB,sBAAsB;QACtB,WAAW;QACX,aAAa;QACb,cAAc;QACd,eAAe;KAChB;IACD,SAAS,EAAE,EAAE;IACb,OAAO,EAAE,EAAE;IACX,YAAY,EACV,mGAAmG;QACnG,2FAA2F;QAC3F,yFAAyF;QACzF,8FAA8F;QAC9F,iFAAiF;QACjF,iDAAiD;QACjD,oGAAoG;IACtG,KAAK,CAAC,IAAI;QACR,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;CACyB,CAAC"}
|