@cyanheads/whois-mcp-server 0.1.4 → 0.1.5
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 +57 -25
- package/CLAUDE.md +57 -25
- package/README.md +46 -56
- package/changelog/0.1.x/0.1.5.md +35 -0
- package/changelog/template.md +9 -26
- package/dist/app.d.ts +199 -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-lookup-asn.tool.d.ts +2 -0
- 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 +2 -0
- package/dist/mcp-server/tools/definitions/whois-lookup-asn.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/whois-lookup-ip.tool.d.ts +2 -0
- 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 +2 -0
- package/dist/mcp-server/tools/definitions/whois-lookup-ip.tool.js.map +1 -1
- package/package.json +10 -9
- 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,84 @@ 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
|
+
---
|
|
40
|
+
|
|
41
|
+
## Capability reference
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
### `whois_lookup_domain` <sub>tool</sub>
|
|
40
44
|
|
|
41
45
|
- RDAP-first via IANA auto-bootstrap — automatically selects the correct registry RDAP server per TLD
|
|
42
|
-
- Returns registrar, creation/expiry dates, nameservers, EPP status codes, DNSSEC delegation flag
|
|
43
|
-
- Surfaces `registrant_redacted: true`
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
+
- Returns registrar, creation/expiry dates, nameservers, EPP status codes, and DNSSEC delegation flag
|
|
47
|
+
- Surfaces `registrant_redacted: true` when privacy redaction is in effect (standard post-GDPR for gTLDs)
|
|
48
|
+
- Throws `rdap_no_coverage` when the TLD has no RDAP server in the IANA bootstrap — use `whois_check_availability` instead
|
|
49
|
+
- Throws `domain_not_found` on an RDAP 404 (domain not registered) — use `whois_check_availability` to confirm
|
|
46
50
|
|
|
47
51
|
---
|
|
48
52
|
|
|
49
|
-
### `whois_check_availability`
|
|
53
|
+
### `whois_check_availability` <sub>tool</sub>
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
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
|
|
55
|
+
- RDAP 404 response maps to `available: true`
|
|
56
|
+
- Registered domains return `available: false` with `registrar` and `expiry_date`
|
|
57
|
+
- `available: null` with `rdap_coverage: false` when the TLD has no RDAP coverage — availability cannot be determined
|
|
58
|
+
- Thin response optimized for bulk name sweeps — no extra fields
|
|
57
59
|
|
|
58
60
|
---
|
|
59
61
|
|
|
60
|
-
### `whois_get_dns`
|
|
61
|
-
|
|
62
|
-
Fetch DNS records via DNS-over-HTTPS.
|
|
62
|
+
### `whois_get_dns` <sub>tool</sub>
|
|
63
63
|
|
|
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
|
|
64
|
+
- Supports A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, PTR; multiple types fetched in parallel; defaults to A, AAAA, MX, TXT, NS when `types` is omitted
|
|
65
|
+
- Cloudflare primary, NextDNS fallback per type (CAA always uses NextDNS — Cloudflare returns raw hex wire format for it)
|
|
66
|
+
- Returns records with TTLs and the resolving `source` (`cloudflare` or `nextdns`)
|
|
67
|
+
- `nxdomain: true` in the result (not an error) when the domain doesn't exist in DNS
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
71
|
-
### `whois_lookup_ip`
|
|
71
|
+
### `whois_lookup_ip` <sub>tool</sub>
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- Auto-routes to the correct RIR (ARIN, RIPE, APNIC, LACNIC, AFRINIC) via IANA IP bootstrap
|
|
73
|
+
- Accepts an IPv4/IPv6 address or CIDR block; auto-routes to the correct RIR (ARIN, RIPE, APNIC, LACNIC, AFRINIC) via IANA IP bootstrap
|
|
76
74
|
- Returns netblock CIDR, org name, country, abuse contact email
|
|
77
75
|
- Fetches PTR (reverse DNS) via DoH as a best-effort step — `ptr: null` on failure, not an error
|
|
78
|
-
-
|
|
76
|
+
- Throws `private_range` for RFC 1918, loopback, and link-local addresses — no RIR RDAP record exists for them
|
|
77
|
+
- Throws `ip_not_found` on an RIR RDAP 404
|
|
79
78
|
|
|
80
79
|
---
|
|
81
80
|
|
|
82
|
-
### `whois_lookup_asn`
|
|
83
|
-
|
|
84
|
-
Resolve an ASN to its org name, country, and RIR.
|
|
81
|
+
### `whois_lookup_asn` <sub>tool</sub>
|
|
85
82
|
|
|
86
83
|
- Accepts `AS15169` or bare integer `15169` format
|
|
87
84
|
- Routes to the correct RIR RDAP endpoint via IANA ASN bootstrap
|
|
88
|
-
- Returns `name`, `
|
|
85
|
+
- Returns `name`, `org_name`, `country`, `rir`, `start_autnum`, `end_autnum`
|
|
86
|
+
- Throws `asn_not_found` on an RIR RDAP 404
|
|
89
87
|
|
|
90
88
|
---
|
|
91
89
|
|
|
92
|
-
### `whois_get_dossier`
|
|
93
|
-
|
|
94
|
-
One-call domain triage aggregating registration and DNS data in parallel.
|
|
90
|
+
### `whois_get_dossier` <sub>tool</sub>
|
|
95
91
|
|
|
96
92
|
- Runs RDAP domain lookup and DoH (A, MX, NS, TXT) in parallel via `Promise.allSettled`
|
|
97
93
|
- Inferred signals: `age_days`, `privacy_redacted`, `registrar`, `ns_provider` (from NS records), `mx_provider` (from MX records)
|
|
98
94
|
- No synthesized risk scores — factual signals only; the agent decides the verdict
|
|
99
|
-
- Partial results surfaced when one leg fails (`
|
|
100
|
-
-
|
|
95
|
+
- Partial results surfaced when one leg fails (`rdap_source_error` / `dns_source_error` on the failed leg)
|
|
96
|
+
- Throws `both_legs_failed` only when both RDAP and DNS fail; individual leg failures are data, not errors
|
|
101
97
|
|
|
102
98
|
---
|
|
103
99
|
|
|
104
100
|
## Features
|
|
105
101
|
|
|
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
|
|
102
|
+
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
103
|
|
|
115
|
-
|
|
104
|
+
RDAP / DNS-specific:
|
|
116
105
|
|
|
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 —
|
|
106
|
+
- RDAP over HTTPS — no port-43 TCP dependency
|
|
107
|
+
- IANA bootstrap auto-selection — correct registry RDAP server picked per TLD, RIR, or ASN range; bootstrap JSON cached in-memory for 24h
|
|
108
|
+
- DNS-over-HTTPS via Cloudflare and NextDNS — dual-provider with per-type routing (NextDNS for CAA; Cloudflare for all others) and automatic fallback
|
|
120
109
|
- No API keys required — all sources (IANA, registry RDAP endpoints, RIR RDAP, Cloudflare DoH, NextDNS DoH) are public and keyless
|
|
121
110
|
|
|
122
111
|
Agent-friendly output:
|
|
123
112
|
|
|
124
|
-
-
|
|
113
|
+
- 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
114
|
- 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
|
|
115
|
+
- Partial failure model — `whois_get_dossier` marks individual legs with a `source_error` field and continues; only both-legs-fail escalates to an error
|
|
116
|
+
- Factual signals, not scores — `age_days`, `privacy_redacted`, `ns_provider`, `mx_provider` are real data, not synthesized risk scores
|
|
128
117
|
|
|
129
118
|
---
|
|
130
119
|
|
|
@@ -279,7 +268,8 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
279
268
|
|
|
280
269
|
| Path | Purpose |
|
|
281
270
|
|:-----|:--------|
|
|
282
|
-
| `src/index.ts` |
|
|
271
|
+
| `src/index.ts` | Entry point — starts the app. |
|
|
272
|
+
| `src/app.ts` | `createApp()` options — registers tools, inits services, declares the session mode. |
|
|
283
273
|
| `src/config/` | Server-specific environment variable parsing and validation (Zod). |
|
|
284
274
|
| `src/services/rdap/` | RDAP client — IANA bootstrap cache, domain/IP/ASN lookup, retry. |
|
|
285
275
|
| `src/services/doh/` | DNS-over-HTTPS client — Cloudflare primary, NextDNS fallback. |
|
|
@@ -294,15 +284,15 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
294
284
|
See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:
|
|
295
285
|
|
|
296
286
|
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
297
|
-
- Use `ctx.log` for request-scoped logging
|
|
298
|
-
- Register new tools via `src/
|
|
287
|
+
- Use `ctx.log` for request-scoped logging
|
|
288
|
+
- Register new tools via `src/app.ts`'s `tools` array
|
|
299
289
|
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
|
|
300
290
|
|
|
301
291
|
---
|
|
302
292
|
|
|
303
293
|
## Contributing
|
|
304
294
|
|
|
305
|
-
Issues
|
|
295
|
+
Issues are welcome. Run checks and tests before submitting:
|
|
306
296
|
|
|
307
297
|
```sh
|
|
308
298
|
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`
|
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,199 @@
|
|
|
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
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
132
|
+
readonly reason: "invalid_domain";
|
|
133
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
134
|
+
readonly when: "Input is not a valid FQDN.";
|
|
135
|
+
readonly recovery: "Provide a valid fully-qualified domain name like \"example.com\" or \"sub.example.org\".";
|
|
136
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
137
|
+
ip: import("zod").ZodString;
|
|
138
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
139
|
+
ip: import("zod").ZodString;
|
|
140
|
+
handle: import("zod").ZodOptional<import("zod").ZodString>;
|
|
141
|
+
start_address: import("zod").ZodOptional<import("zod").ZodString>;
|
|
142
|
+
end_address: import("zod").ZodOptional<import("zod").ZodString>;
|
|
143
|
+
cidr: import("zod").ZodOptional<import("zod").ZodString>;
|
|
144
|
+
ip_version: import("zod").ZodOptional<import("zod").ZodString>;
|
|
145
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
146
|
+
type: import("zod").ZodOptional<import("zod").ZodString>;
|
|
147
|
+
country: import("zod").ZodOptional<import("zod").ZodString>;
|
|
148
|
+
org_name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
149
|
+
abuse_email: import("zod").ZodOptional<import("zod").ZodString>;
|
|
150
|
+
ptr: import("zod").ZodNullable<import("zod").ZodString>;
|
|
151
|
+
rdap_source: import("zod").ZodOptional<import("zod").ZodString>;
|
|
152
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
153
|
+
readonly reason: "invalid_ip";
|
|
154
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
155
|
+
readonly when: "Input is not a valid IPv4, IPv6, or CIDR address.";
|
|
156
|
+
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\").";
|
|
157
|
+
}, {
|
|
158
|
+
readonly reason: "private_range";
|
|
159
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
160
|
+
readonly when: "Input is a private or reserved range — no RIR RDAP record exists for it.";
|
|
161
|
+
readonly recovery: "Use a public, globally-routable IP address. RFC 1918, loopback, and link-local addresses have no RIR records.";
|
|
162
|
+
readonly thrownBy: "service";
|
|
163
|
+
}, {
|
|
164
|
+
readonly reason: "ip_not_found";
|
|
165
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
166
|
+
readonly when: "RIR RDAP returned 404 — no netblock record for this address.";
|
|
167
|
+
readonly recovery: "The IP address is not found in any RIR RDAP database. Try a different IP or verify it is globally routable.";
|
|
168
|
+
readonly thrownBy: "service";
|
|
169
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
170
|
+
asn: import("zod").ZodString;
|
|
171
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
172
|
+
asn: import("zod").ZodString;
|
|
173
|
+
handle: import("zod").ZodOptional<import("zod").ZodString>;
|
|
174
|
+
start_autnum: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
175
|
+
end_autnum: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
176
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
177
|
+
type: import("zod").ZodOptional<import("zod").ZodString>;
|
|
178
|
+
country: import("zod").ZodOptional<import("zod").ZodString>;
|
|
179
|
+
org_name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
180
|
+
rir: import("zod").ZodOptional<import("zod").ZodString>;
|
|
181
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
182
|
+
readonly reason: "invalid_asn";
|
|
183
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
184
|
+
readonly when: "Input does not match AS<number> or bare integer format.";
|
|
185
|
+
readonly recovery: "Provide a valid ASN like \"AS15169\" or \"15169\". Numbers must be positive integers.";
|
|
186
|
+
readonly thrownBy: "service";
|
|
187
|
+
}, {
|
|
188
|
+
readonly reason: "asn_not_found";
|
|
189
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
190
|
+
readonly when: "RDAP returned 404 — ASN not found in any RIR.";
|
|
191
|
+
readonly recovery: "The ASN is not found in any RIR RDAP database. Verify the ASN number is correct and assigned.";
|
|
192
|
+
readonly thrownBy: "service";
|
|
193
|
+
}], undefined>)[];
|
|
194
|
+
resources: never[];
|
|
195
|
+
prompts: never[];
|
|
196
|
+
instructions: string;
|
|
197
|
+
setup(core: import("@cyanheads/mcp-ts-core").CoreServices<object>): void;
|
|
198
|
+
};
|
|
199
|
+
//# 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"}
|
package/dist/index.js
CHANGED
|
@@ -4,37 +4,6 @@
|
|
|
4
4
|
* @module index
|
|
5
5
|
*/
|
|
6
6
|
import { createApp } from '@cyanheads/mcp-ts-core';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import { whoisGetDossier } from './mcp-server/tools/definitions/whois-get-dossier.tool.js';
|
|
10
|
-
import { whoisLookupAsn } from './mcp-server/tools/definitions/whois-lookup-asn.tool.js';
|
|
11
|
-
import { whoisLookupDomain } from './mcp-server/tools/definitions/whois-lookup-domain.tool.js';
|
|
12
|
-
import { whoisLookupIp } from './mcp-server/tools/definitions/whois-lookup-ip.tool.js';
|
|
13
|
-
import { initDohService } from './services/doh/doh-service.js';
|
|
14
|
-
import { initRdapService } from './services/rdap/rdap-service.js';
|
|
15
|
-
await createApp({
|
|
16
|
-
name: 'whois-mcp-server',
|
|
17
|
-
title: 'whois-mcp-server',
|
|
18
|
-
tools: [
|
|
19
|
-
whoisLookupDomain,
|
|
20
|
-
whoisCheckAvailability,
|
|
21
|
-
whoisGetDns,
|
|
22
|
-
whoisLookupIp,
|
|
23
|
-
whoisLookupAsn,
|
|
24
|
-
whoisGetDossier,
|
|
25
|
-
],
|
|
26
|
-
resources: [],
|
|
27
|
-
prompts: [],
|
|
28
|
-
instructions: 'whois-mcp-server: domain and IP intelligence via RDAP and DNS-over-HTTPS. No API keys required.\n' +
|
|
29
|
-
'- whois_lookup_domain: full registration record (registrar, dates, status, nameservers)\n' +
|
|
30
|
-
'- whois_check_availability: is a domain available to register? (RDAP 404 = available)\n' +
|
|
31
|
-
'- whois_get_dns: DNS records for any hostname (A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, PTR)\n' +
|
|
32
|
-
'- whois_lookup_ip: IP/CIDR netblock, org, abuse contact, and PTR via RIR RDAP\n' +
|
|
33
|
-
'- whois_lookup_asn: ASN to org/RIR resolution\n' +
|
|
34
|
-
'- whois_get_dossier: one-call domain triage — registration + DNS in parallel with inferred signals',
|
|
35
|
-
setup(core) {
|
|
36
|
-
initRdapService(core.config, core.storage);
|
|
37
|
-
initDohService(core.config, core.storage);
|
|
38
|
-
},
|
|
39
|
-
});
|
|
7
|
+
import { appOptions } from './app.js';
|
|
8
|
+
await createApp(appOptions);
|
|
40
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC"}
|
|
@@ -21,10 +21,12 @@ export declare const whoisLookupAsn: import("@cyanheads/mcp-ts-core").ToolDefini
|
|
|
21
21
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
22
22
|
readonly when: "Input does not match AS<number> or bare integer format.";
|
|
23
23
|
readonly recovery: "Provide a valid ASN like \"AS15169\" or \"15169\". Numbers must be positive integers.";
|
|
24
|
+
readonly thrownBy: "service";
|
|
24
25
|
}, {
|
|
25
26
|
readonly reason: "asn_not_found";
|
|
26
27
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
27
28
|
readonly when: "RDAP returned 404 — ASN not found in any RIR.";
|
|
28
29
|
readonly recovery: "The ASN is not found in any RIR RDAP database. Verify the ASN number is correct and assigned.";
|
|
30
|
+
readonly thrownBy: "service";
|
|
29
31
|
}], undefined>;
|
|
30
32
|
//# sourceMappingURL=whois-lookup-asn.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whois-lookup-asn.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/whois-lookup-asn.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"whois-lookup-asn.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/whois-lookup-asn.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;cAkFzB,CAAC"}
|
|
@@ -40,12 +40,14 @@ export const whoisLookupAsn = tool('whois_lookup_asn', {
|
|
|
40
40
|
code: JsonRpcErrorCode.ValidationError,
|
|
41
41
|
when: 'Input does not match AS<number> or bare integer format.',
|
|
42
42
|
recovery: 'Provide a valid ASN like "AS15169" or "15169". Numbers must be positive integers.',
|
|
43
|
+
thrownBy: 'service',
|
|
43
44
|
},
|
|
44
45
|
{
|
|
45
46
|
reason: 'asn_not_found',
|
|
46
47
|
code: JsonRpcErrorCode.NotFound,
|
|
47
48
|
when: 'RDAP returned 404 — ASN not found in any RIR.',
|
|
48
49
|
recovery: 'The ASN is not found in any RIR RDAP database. Verify the ASN number is correct and assigned.',
|
|
50
|
+
thrownBy: 'service',
|
|
49
51
|
},
|
|
50
52
|
],
|
|
51
53
|
async handler(input, ctx) {
|