domeneshop-mcp 1.0.2 → 1.0.4

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +151 -194
  3. package/dist/domeneshop/assert.d.ts +0 -7
  4. package/dist/domeneshop/assert.d.ts.map +1 -1
  5. package/dist/domeneshop/assert.js +0 -7
  6. package/dist/domeneshop/assert.js.map +1 -1
  7. package/dist/domeneshop/client.d.ts +1 -6
  8. package/dist/domeneshop/client.d.ts.map +1 -1
  9. package/dist/domeneshop/client.js +1 -5
  10. package/dist/domeneshop/client.js.map +1 -1
  11. package/dist/domeneshop/http.d.ts +2 -23
  12. package/dist/domeneshop/http.d.ts.map +1 -1
  13. package/dist/domeneshop/http.js +0 -11
  14. package/dist/domeneshop/http.js.map +1 -1
  15. package/dist/domeneshop/resources/dns.d.ts +0 -12
  16. package/dist/domeneshop/resources/dns.d.ts.map +1 -1
  17. package/dist/domeneshop/resources/dns.js +0 -4
  18. package/dist/domeneshop/resources/dns.js.map +1 -1
  19. package/dist/domeneshop/resources/domains.d.ts +0 -2
  20. package/dist/domeneshop/resources/domains.d.ts.map +1 -1
  21. package/dist/domeneshop/resources/domains.js +0 -2
  22. package/dist/domeneshop/resources/domains.js.map +1 -1
  23. package/dist/domeneshop/resources/dyndns.d.ts +1 -5
  24. package/dist/domeneshop/resources/dyndns.d.ts.map +1 -1
  25. package/dist/domeneshop/resources/dyndns.js +1 -5
  26. package/dist/domeneshop/resources/dyndns.js.map +1 -1
  27. package/dist/domeneshop/resources/forwards.d.ts +1 -12
  28. package/dist/domeneshop/resources/forwards.d.ts.map +1 -1
  29. package/dist/domeneshop/resources/forwards.js +1 -13
  30. package/dist/domeneshop/resources/forwards.js.map +1 -1
  31. package/dist/domeneshop/resources/invoices.d.ts +3 -7
  32. package/dist/domeneshop/resources/invoices.d.ts.map +1 -1
  33. package/dist/domeneshop/resources/invoices.js +3 -7
  34. package/dist/domeneshop/resources/invoices.js.map +1 -1
  35. package/dist/mcp/annotations.d.ts +4 -6
  36. package/dist/mcp/annotations.d.ts.map +1 -1
  37. package/dist/mcp/annotations.js +4 -6
  38. package/dist/mcp/annotations.js.map +1 -1
  39. package/dist/mcp/result.d.ts +1 -3
  40. package/dist/mcp/result.d.ts.map +1 -1
  41. package/dist/mcp/result.js +1 -3
  42. package/dist/mcp/result.js.map +1 -1
  43. package/dist/mcp/schema.d.ts +0 -1
  44. package/dist/mcp/schema.d.ts.map +1 -1
  45. package/dist/mcp/server.d.ts +0 -1
  46. package/dist/mcp/server.d.ts.map +1 -1
  47. package/dist/mcp/server.js +0 -1
  48. package/dist/mcp/server.js.map +1 -1
  49. package/dist/mcp/tool.d.ts +1 -4
  50. package/dist/mcp/tool.d.ts.map +1 -1
  51. package/dist/mcp/tool.js +1 -4
  52. package/dist/mcp/tool.js.map +1 -1
  53. package/dist/mcp/tools/dns.d.ts.map +1 -1
  54. package/dist/mcp/tools/dns.js +0 -2
  55. package/dist/mcp/tools/dns.js.map +1 -1
  56. package/dist/version.d.ts +0 -1
  57. package/dist/version.d.ts.map +1 -1
  58. package/dist/version.js +0 -1
  59. package/dist/version.js.map +1 -1
  60. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # domeneshop-mcp
2
2
 
3
+ ## 1.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Update dependencies, including `@modelcontextprotocol/sdk` 1.31.0 and zod 4.6, and resolve npm audit advisories in transitive dependencies.
8
+
9
+ ## 1.0.3
10
+
11
+ ### Patch Changes
12
+
13
+ - [#11](https://github.com/martinzachariassen/domeneshop-mcp/pull/11) [`fe54cb3`](https://github.com/martinzachariassen/domeneshop-mcp/commit/fe54cb30944801983814540dc4489372308d9a90) Thanks [@martinzachariassen](https://github.com/martinzachariassen)! - Refresh README structure and trim non-essential comments across the codebase.
14
+
3
15
  ## 1.0.2
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -1,92 +1,38 @@
1
- # domeneshop-mcp
1
+ <h1 align="center">domeneshop-mcp</h1>
2
2
 
3
- [![CI](https://github.com/martinzachariassen/domeneshop-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/martinzachariassen/domeneshop-mcp/actions/workflows/ci.yml)
4
- [![npm version](https://img.shields.io/npm/v/domeneshop-mcp)](https://www.npmjs.com/package/domeneshop-mcp)
3
+ <p align="center">
4
+ Manage your Domeneshop domains, DNS records, HTTP forwards and invoices from any AI assistant.
5
+ </p>
5
6
 
6
- An [MCP](https://modelcontextprotocol.io) server that exposes the
7
- [Domeneshop API](https://api.domeneshop.no/docs/) as tools, so an AI assistant can
8
- manage your domains, DNS records, HTTP forwards and invoices.
7
+ <p align="center">
8
+ <a href="https://github.com/martinzachariassen/domeneshop-mcp/actions/workflows/ci.yml"><img src="https://github.com/martinzachariassen/domeneshop-mcp/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
9
+ <a href="https://www.npmjs.com/package/domeneshop-mcp"><img src="https://img.shields.io/npm/v/domeneshop-mcp" alt="npm version"></a>
10
+ </p>
9
11
 
10
- Every operation the Domeneshop API offers is available as a tool — 15 of them,
11
- covering domains, DNS, HTTP forwarding, dynamic DNS and invoices.
12
+ <p align="center">
13
+ <a href="https://www.npmjs.com/package/domeneshop-mcp"><b>npm package</b></a>
14
+ &nbsp;·&nbsp;
15
+ <a href="https://api.domeneshop.no/docs/"><b>Domeneshop API</b></a>
16
+ &nbsp;·&nbsp;
17
+ <a href="https://www.domeneshop.no/admin?view=api"><b>Get API credentials</b></a>
18
+ </p>
12
19
 
13
- This is a standard MCP server communicating over stdio, so it works with
14
- **any MCP-compatible client**. That includes Claude Code,
15
- Claude Desktop, Cursor, VS Code (with GitHub Copilot), Codex, Windsurf, Cline,
16
- and anything else that speaks MCP. See [Configuration](#configuration) for
17
- setup in each of those, and [Tools](#tools) for everything the server can do.
20
+ An [MCP](https://modelcontextprotocol.io) server that turns the
21
+ [Domeneshop API](https://api.domeneshop.no/docs/) into tools an assistant can call.
22
+ Every operation the API offers is covered — 15 tools across domains, DNS, HTTP
23
+ forwarding, dynamic DNS and invoices.
18
24
 
19
- ## Quick start
20
-
21
- 1. Get an API token and secret from
22
- [domeneshop.no/admin?view=api](https://www.domeneshop.no/admin?view=api).
23
- 2. Register the server with your MCP client. For Claude Code:
24
-
25
- ```sh
26
- claude mcp add domeneshop \
27
- --env DOMENESHOP_API_TOKEN=your-token \
28
- --env DOMENESHOP_API_SECRET=your-secret \
29
- -- npx -y domeneshop-mcp
30
- ```
31
-
32
- That's it — ask your assistant to list your domains and it will pick up the
33
- new tools. This registers the server for the current project only; add
34
- `--scope user` to make it available everywhere. If you're using a different
35
- client, jump to [Configuration](#configuration) for the equivalent setup.
36
-
37
- ## Contents
38
-
39
- - [Quick start](#quick-start)
40
- - [Requirements](#requirements)
41
- - [Installation](#installation)
42
- - [Configuration](#configuration)
43
- - [Tools](#tools)
44
- - [Notes on the Domeneshop API](#notes-on-the-domeneshop-api)
45
- - [Development](#development)
46
- - [Contributing](#contributing)
47
- - [Security](#security)
48
- - [License](#license)
49
-
50
- ## Requirements
51
-
52
- - A Domeneshop account with API credentials, created at
53
- [domeneshop.no/admin?view=api](https://www.domeneshop.no/admin?view=api).
54
- - Node.js 20 or newer.
55
-
56
- ## Installation
57
-
58
- ```sh
59
- npm install -g domeneshop-mcp
60
- ```
61
-
62
- Or run it directly without installing, via `npx`:
63
-
64
- ```sh
65
- npx domeneshop-mcp
66
- ```
25
+ It talks MCP over stdio, so it works with **any MCP-compatible client**: Claude
26
+ Code, Claude Desktop, Cursor, VS Code, Codex, Windsurf, Cline and others.
67
27
 
68
- ## Configuration
69
-
70
- The server reads its credentials from two environment variables and refuses to
71
- start without them:
72
-
73
- | Variable | Description |
74
- | --- | --- |
75
- | `DOMENESHOP_API_TOKEN` | API token from the Domeneshop control panel |
76
- | `DOMENESHOP_API_SECRET` | The matching API secret |
28
+ ## Quick start
77
29
 
78
- It speaks MCP over stdio, so it is launched by your MCP client rather than run
79
- directly — `npx -y domeneshop-mcp` is the command every client below runs to
80
- start it. Swap in your real token and secret wherever you see the placeholders.
30
+ You need Node.js 20 or newer and a Domeneshop account.
81
31
 
82
- Most clients also let you scope a server to just the current project (private,
83
- or shared with your team via a file checked into version control) or make it
84
- available everywhere on your machine — usually by picking which config file
85
- you write to. Each client below notes this where it applies; Claude Desktop
86
- and Codex only have a single, machine-wide config file.
32
+ **1. Create an API token and secret** at
33
+ [domeneshop.no/admin?view=api](https://www.domeneshop.no/admin?view=api).
87
34
 
88
- <details>
89
- <summary><strong>Claude Code</strong></summary>
35
+ **2. Register the server.** In Claude Code:
90
36
 
91
37
  ```sh
92
38
  claude mcp add domeneshop \
@@ -95,29 +41,22 @@ claude mcp add domeneshop \
95
41
  -- npx -y domeneshop-mcp
96
42
  ```
97
43
 
98
- This defaults to `--scope local` (private to you, only in this project). Use
99
- `--scope project` to write it to `<your-project>/.mcp.json` instead (shared via
100
- version control — see the block below), or `--scope user` for every project on
101
- your account.
44
+ **3. Ask for something.** "List my domains" is enough to confirm the tools loaded.
102
45
 
103
- If you'd rather not resolve the package via `npx` on every launch, install it
104
- once and point Claude Code at the binary directly:
46
+ Using a different client? See [Client setup](#client-setup) below.
105
47
 
106
- ```sh
107
- npm install -g domeneshop-mcp
108
- claude mcp add domeneshop \
109
- --env DOMENESHOP_API_TOKEN=your-token \
110
- --env DOMENESHOP_API_SECRET=your-secret \
111
- -- domeneshop-mcp
112
- ```
48
+ ## Client setup
113
49
 
114
- You can also add it from raw JSON:
50
+ The server is launched by your client rather than run by hand, and reads its
51
+ credentials from two environment variables:
115
52
 
116
- ```sh
117
- claude mcp add-json domeneshop '{"command":"npx","args":["-y","domeneshop-mcp"],"env":{"DOMENESHOP_API_TOKEN":"your-token","DOMENESHOP_API_SECRET":"your-secret"}}'
118
- ```
53
+ | Variable | Description |
54
+ | --- | --- |
55
+ | `DOMENESHOP_API_TOKEN` | API token from the Domeneshop control panel |
56
+ | `DOMENESHOP_API_SECRET` | The matching API secret |
119
57
 
120
- Or, for `--scope project`, edit `<your-project>/.mcp.json` directly:
58
+ Most clients take the same **standard config**. Swap in your real token and
59
+ secret wherever you see the placeholders.
121
60
 
122
61
  ```json
123
62
  {
@@ -134,12 +73,33 @@ Or, for `--scope project`, edit `<your-project>/.mcp.json` directly:
134
73
  }
135
74
  ```
136
75
 
76
+ Most clients can also scope a server to the current project or make it
77
+ available everywhere, usually by choosing which config file you write to. The
78
+ blocks below note this where it applies.
79
+
80
+ <details>
81
+ <summary><strong>Claude Code</strong></summary>
82
+
83
+ Use the CLI command from [Quick start](#quick-start). It defaults to
84
+ `--scope local`, private to you and this project. Use `--scope project` to
85
+ write `<your-project>/.mcp.json` instead, shared via version control, or
86
+ `--scope user` for every project on your account.
87
+
88
+ You can also pass the standard config as raw JSON:
89
+
90
+ ```sh
91
+ claude mcp add-json domeneshop '{"command":"npx","args":["-y","domeneshop-mcp"],"env":{"DOMENESHOP_API_TOKEN":"your-token","DOMENESHOP_API_SECRET":"your-secret"}}'
92
+ ```
93
+
94
+ Or write the standard config straight into `<your-project>/.mcp.json`.
95
+
137
96
  </details>
138
97
 
139
98
  <details>
140
99
  <summary><strong>Claude Desktop</strong></summary>
141
100
 
142
- Edit `claude_desktop_config.json` (Settings → Developer → Edit Config), found at:
101
+ Add the standard config to `claude_desktop_config.json`, reachable from
102
+ Settings → Developer → Edit Config:
143
103
 
144
104
  | Platform | Full path |
145
105
  | --- | --- |
@@ -147,27 +107,12 @@ Edit `claude_desktop_config.json` (Settings → Developer → Edit Config), foun
147
107
  | Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
148
108
  | Linux (unofficial builds) | `~/.config/Claude/claude_desktop_config.json` |
149
109
 
150
- ```json
151
- {
152
- "mcpServers": {
153
- "domeneshop": {
154
- "command": "npx",
155
- "args": ["-y", "domeneshop-mcp"],
156
- "env": {
157
- "DOMENESHOP_API_TOKEN": "your-token",
158
- "DOMENESHOP_API_SECRET": "your-secret"
159
- }
160
- }
161
- }
162
- }
163
- ```
164
-
165
110
  </details>
166
111
 
167
112
  <details>
168
113
  <summary><strong>Cursor</strong></summary>
169
114
 
170
- Add the same `mcpServers` block to a `mcp.json` file, found at:
115
+ Add the standard config to an `mcp.json` file:
171
116
 
172
117
  | Scope | Full path |
173
118
  | --- | --- |
@@ -175,28 +120,13 @@ Add the same `mcpServers` block to a `mcp.json` file, found at:
175
120
  | Every project (macOS/Linux) | `~/.cursor/mcp.json` |
176
121
  | Every project (Windows) | `%USERPROFILE%\.cursor\mcp.json` |
177
122
 
178
- ```json
179
- {
180
- "mcpServers": {
181
- "domeneshop": {
182
- "command": "npx",
183
- "args": ["-y", "domeneshop-mcp"],
184
- "env": {
185
- "DOMENESHOP_API_TOKEN": "your-token",
186
- "DOMENESHOP_API_SECRET": "your-secret"
187
- }
188
- }
189
- }
190
- }
191
- ```
192
-
193
123
  </details>
194
124
 
195
125
  <details>
196
126
  <summary><strong>VS Code (GitHub Copilot)</strong></summary>
197
127
 
198
- VS Code uses a `servers` key instead of `mcpServers`. For this project only,
199
- add it to `<your-project>/.vscode/mcp.json`:
128
+ VS Code uses a `servers` key instead of `mcpServers`, and wants an explicit
129
+ `type`. For this project only, add it to `<your-project>/.vscode/mcp.json`:
200
130
 
201
131
  ```json
202
132
  {
@@ -215,8 +145,7 @@ add it to `<your-project>/.vscode/mcp.json`:
215
145
  ```
216
146
 
217
147
  For every project, run the command palette action **MCP: Open User
218
- Configuration** and add the same block there — or register it in one line
219
- from a terminal:
148
+ Configuration** and add the same block there, or register it in one line:
220
149
 
221
150
  ```sh
222
151
  code --add-mcp '{"name":"domeneshop","command":"npx","args":["-y","domeneshop-mcp"],"env":{"DOMENESHOP_API_TOKEN":"your-token","DOMENESHOP_API_SECRET":"your-secret"}}'
@@ -227,7 +156,7 @@ code --add-mcp '{"name":"domeneshop","command":"npx","args":["-y","domeneshop-mc
227
156
  <details>
228
157
  <summary><strong>Codex</strong></summary>
229
158
 
230
- Codex CLI reads MCP servers from `mcp_servers` in its config file, found at:
159
+ Codex CLI reads MCP servers from `mcp_servers` in its config file:
231
160
 
232
161
  | Platform | Full path |
233
162
  | --- | --- |
@@ -241,58 +170,105 @@ args = ["-y", "domeneshop-mcp"]
241
170
  env = { DOMENESHOP_API_TOKEN = "your-token", DOMENESHOP_API_SECRET = "your-secret" }
242
171
  ```
243
172
 
244
- Or register it from the command line:
245
-
246
- ```sh
247
- codex mcp add domeneshop -- npx -y domeneshop-mcp
248
- ```
249
-
250
- Then set the two env vars in the `[mcp_servers.domeneshop]` block it creates,
251
- since `codex mcp add` doesn't take them as flags.
173
+ `codex mcp add domeneshop -- npx -y domeneshop-mcp` registers it from the
174
+ command line, but takes no env flags, so set the two variables in the
175
+ `[mcp_servers.domeneshop]` block it creates.
252
176
 
253
177
  </details>
254
178
 
255
179
  <details>
256
180
  <summary><strong>Any other MCP client</strong></summary>
257
181
 
258
- Any client that supports MCP servers over stdio can run this server — Windsurf,
259
- Cline, Continue, LM Studio, or a client you've built yourself with the MCP SDK.
260
- Most follow the same `mcpServers`-with-`command`/`args`/`env` shape used above
261
- for Claude Desktop and Cursor; check your client's documentation for the exact
262
- config file and key name, then point it at:
182
+ Windsurf, Cline, Continue, LM Studio and anything else that runs MCP servers
183
+ over stdio will work. Most use the same shape as the standard config above;
184
+ check your client's documentation for the config file and key name, then point
185
+ it at:
263
186
 
264
187
  - **command**: `npx`
265
188
  - **args**: `["-y", "domeneshop-mcp"]`
266
189
  - **env**: `DOMENESHOP_API_TOKEN` and `DOMENESHOP_API_SECRET`
267
190
 
268
- If your client can't run `npx` directly, install the package globally with
269
- `npm install -g domeneshop-mcp` and use `domeneshop-mcp` as the command with no
270
- args instead.
191
+ </details>
192
+
193
+ <details>
194
+ <summary><strong>Skipping npx</strong></summary>
195
+
196
+ To avoid resolving the package on every launch, install it once and use
197
+ `domeneshop-mcp` as the command with no args:
198
+
199
+ ```sh
200
+ npm install -g domeneshop-mcp
201
+ ```
271
202
 
272
203
  </details>
273
204
 
205
+ ## What you can ask for
206
+
207
+ | Area | Example prompt |
208
+ | --- | --- |
209
+ | Domains | "Which domains are on my account, and when do they renew?" |
210
+ | DNS | "Show every DNS record for example.no" |
211
+ | DNS | "Point blog.example.no at 203.0.113.10" |
212
+ | DNS | "Add the TXT record Google gave me for domain verification" |
213
+ | DNS | "Set up Fastmail's MX records on example.no" |
214
+ | Forwarding | "Forward old.example.no to https://example.no" |
215
+ | Dynamic DNS | "Update home.example.no to my current IP" |
216
+ | Invoices | "List my unpaid Domeneshop invoices" |
217
+
274
218
  ## Tools
275
219
 
276
- Read-only tools are annotated as such, and the tools that overwrite or delete
277
- state are marked destructive, so clients can decide what to run without asking
278
- you first.
220
+ Every tool declares MCP annotations, so clients know which ones are safe to run
221
+ without asking you first. The Access column below mirrors those annotations.
279
222
 
280
223
  ### Domains
281
224
 
282
- | Tool | Description |
283
- | --- | --- |
284
- | `list_domains` | List all domains on the account, optionally filtered by name |
285
- | `get_domain` | Get a single domain by its Domeneshop domain ID |
225
+ | Tool | Access | Description |
226
+ | --- | --- | --- |
227
+ | `list_domains` | Read-only | List all domains on the account, optionally filtered by name |
228
+ | `get_domain` | Read-only | Get a single domain by its Domeneshop domain ID |
286
229
 
287
230
  ### DNS
288
231
 
289
- | Tool | Description |
290
- | --- | --- |
291
- | `list_dns_records` | List a domain's records, optionally filtered by host and type |
292
- | `get_dns_record` | Get a single record by ID |
293
- | `create_dns_record` | Create a record |
294
- | `update_dns_record` | Replace a record (destructive — see the note below) |
295
- | `delete_dns_record` | Delete a record |
232
+ | Tool | Access | Description |
233
+ | --- | --- | --- |
234
+ | `list_dns_records` | Read-only | List a domain's records, optionally filtered by host and type |
235
+ | `get_dns_record` | Read-only | Get a single record by ID |
236
+ | `create_dns_record` | Adds | Create a record |
237
+ | `update_dns_record` | Overwrites | Replace a record — see the warning below |
238
+ | `delete_dns_record` | Deletes | Delete a record |
239
+
240
+ > **Heads up:** `update_dns_record` replaces the whole record rather than
241
+ > patching it. Any field left out is dropped, and omitting `ttl` resets it to
242
+ > the default 3600 seconds. Read the record first if you are only changing part
243
+ > of it.
244
+
245
+ ### HTTP forwarding
246
+
247
+ | Tool | Access | Description |
248
+ | --- | --- | --- |
249
+ | `list_forwards` | Read-only | List a domain's HTTP forwards |
250
+ | `get_forward` | Read-only | Get the forward for one host |
251
+ | `create_forward` | Adds | Create a forward |
252
+ | `update_forward` | Overwrites | Update a forward |
253
+ | `delete_forward` | Deletes | Delete a forward |
254
+
255
+ ### Dynamic DNS
256
+
257
+ | Tool | Access | Description |
258
+ | --- | --- | --- |
259
+ | `update_dyndns` | Overwrites | Point a hostname at a given IP, or at the caller's apparent IP |
260
+
261
+ ### Invoices
262
+
263
+ | Tool | Access | Description |
264
+ | --- | --- | --- |
265
+ | `list_invoices` | Read-only | List invoices from the past three years, optionally filtered by status |
266
+ | `get_invoice` | Read-only | Get a single invoice |
267
+
268
+ ## Reference
269
+
270
+ <details>
271
+ <summary><strong>Supported DNS record types</strong></summary>
296
272
 
297
273
  All eleven record types Domeneshop accepts are supported, with their
298
274
  type-specific fields:
@@ -306,34 +282,13 @@ type-specific fields:
306
282
  | `DS` | `tag`, `alg`, `digest` |
307
283
  | `CAA` | `flags`, `tag` |
308
284
 
309
- `update_dns_record` replaces the whole record rather than patching it: any field
310
- left out is dropped, and omitting `ttl` resets it to the default 3600 seconds.
311
- Read the record first if you are only changing part of it.
312
-
313
- ### HTTP forwarding
314
-
315
- | Tool | Description |
316
- | --- | --- |
317
- | `list_forwards` | List a domain's HTTP forwards |
318
- | `get_forward` | Get the forward for one host |
319
- | `create_forward` | Create a forward |
320
- | `update_forward` | Update a forward |
321
- | `delete_forward` | Delete a forward |
322
-
323
- ### Dynamic DNS
324
-
325
- | Tool | Description |
326
- | --- | --- |
327
- | `update_dyndns` | Point a hostname at a given IP, or at the caller's apparent IP |
328
-
329
- ### Invoices
285
+ The `tag` field is deliberately untyped: it is a numeric key tag for `DS` and a
286
+ property tag such as `issue` for `CAA`, and Domeneshop documents neither.
330
287
 
331
- | Tool | Description |
332
- | --- | --- |
333
- | `list_invoices` | List invoices from the past three years, optionally filtered by status |
334
- | `get_invoice` | Get a single invoice |
288
+ </details>
335
289
 
336
- ## Notes on the Domeneshop API
290
+ <details>
291
+ <summary><strong>Undocumented Domeneshop API behaviour</strong></summary>
337
292
 
338
293
  A few things this server relies on are not in Domeneshop's published OpenAPI
339
294
  spec, but are supported and used by their own client libraries:
@@ -347,8 +302,7 @@ spec, but are supported and used by their own client libraries:
347
302
  only in the `Location` header.
348
303
  - `GET /dyndns/update` answers with a plain-text status line, not JSON.
349
304
 
350
- The `tag` field is deliberately untyped: it is a numeric key tag for `DS` and a
351
- property tag such as `issue` for `CAA`, and Domeneshop documents neither.
305
+ </details>
352
306
 
353
307
  ## Development
354
308
 
@@ -366,7 +320,8 @@ The tests stub the Domeneshop API with a local `node:http` server and drive the
366
320
  MCP server over an in-memory transport, so they need no credentials and make no
367
321
  network calls.
368
322
 
369
- ### Project layout
323
+ <details>
324
+ <summary><strong>Project layout</strong></summary>
370
325
 
371
326
  ```
372
327
  src/
@@ -378,6 +333,8 @@ test/
378
333
  mcp/ End-to-end tool tests, against an in-memory MCP transport
379
334
  ```
380
335
 
336
+ </details>
337
+
381
338
  ## Contributing
382
339
 
383
340
  Issues and pull requests are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md)
@@ -1,9 +1,2 @@
1
- /**
2
- * Asserts that a value is defined, narrowing it and throwing otherwise.
3
- *
4
- * Used after requests that the Domeneshop API guarantees a body for on
5
- * success (single-resource GETs, creates and updates), so callers get a
6
- * concrete type instead of threading `| undefined` through the client.
7
- */
8
1
  export declare function assertDefined<T>(value: T | undefined, message: string): T;
9
2
  //# sourceMappingURL=assert.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../src/domeneshop/assert.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAKzE"}
1
+ {"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../src/domeneshop/assert.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAKzE"}
@@ -1,10 +1,3 @@
1
- /**
2
- * Asserts that a value is defined, narrowing it and throwing otherwise.
3
- *
4
- * Used after requests that the Domeneshop API guarantees a body for on
5
- * success (single-resource GETs, creates and updates), so callers get a
6
- * concrete type instead of threading `| undefined` through the client.
7
- */
8
1
  export function assertDefined(value, message) {
9
2
  if (value === undefined) {
10
3
  throw new Error(message);
@@ -1 +1 @@
1
- {"version":3,"file":"assert.js","sourceRoot":"","sources":["../../src/domeneshop/assert.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAI,KAAoB,EAAE,OAAe;IACpE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"assert.js","sourceRoot":"","sources":["../../src/domeneshop/assert.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAI,KAAoB,EAAE,OAAe;IACpE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -4,14 +4,9 @@ import { DynDnsResource } from "./resources/dyndns.js";
4
4
  import { ForwardsResource } from "./resources/forwards.js";
5
5
  import { InvoicesResource } from "./resources/invoices.js";
6
6
  export interface DomeneshopClientOptions {
7
- /** Overrides the API base URL. Intended for tests. */
8
7
  baseUrl?: string;
9
8
  }
10
- /**
11
- * A Domeneshop API client (https://api.domeneshop.no/docs/), authenticated
12
- * via HTTP Basic Auth using an API token and secret from
13
- * https://www.domeneshop.no/admin?view=api.
14
- */
9
+ /** Authenticate with a token/secret pair from https://www.domeneshop.no/admin?view=api. */
15
10
  export declare class DomeneshopClient {
16
11
  readonly domains: DomainsResource;
17
12
  readonly dns: DnsResource;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/domeneshop/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;gBAExB,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B;CAQjF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/domeneshop/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,2FAA2F;AAC3F,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;gBAExB,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B;CAQjF"}
@@ -4,11 +4,7 @@ import { DomainsResource } from "./resources/domains.js";
4
4
  import { DynDnsResource } from "./resources/dyndns.js";
5
5
  import { ForwardsResource } from "./resources/forwards.js";
6
6
  import { InvoicesResource } from "./resources/invoices.js";
7
- /**
8
- * A Domeneshop API client (https://api.domeneshop.no/docs/), authenticated
9
- * via HTTP Basic Auth using an API token and secret from
10
- * https://www.domeneshop.no/admin?view=api.
11
- */
7
+ /** Authenticate with a token/secret pair from https://www.domeneshop.no/admin?view=api. */
12
8
  export class DomeneshopClient {
13
9
  domains;
14
10
  dns;
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/domeneshop/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAO3D;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IAClB,OAAO,CAAkB;IACzB,GAAG,CAAc;IACjB,QAAQ,CAAmB;IAC3B,MAAM,CAAiB;IACvB,QAAQ,CAAmB;IAEpC,YAAY,KAAa,EAAE,MAAc,EAAE,UAAmC,EAAE;QAC9E,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACpE,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC;CACF"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/domeneshop/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAM3D,2FAA2F;AAC3F,MAAM,OAAO,gBAAgB;IAClB,OAAO,CAAkB;IACzB,GAAG,CAAc;IACjB,QAAQ,CAAmB;IAC3B,MAAM,CAAiB;IACvB,QAAQ,CAAmB;IAEpC,YAAY,KAAa,EAAE,MAAc,EAAE,UAAmC,EAAE;QAC9E,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACpE,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC;CACF"}
@@ -1,40 +1,19 @@
1
- /**
2
- * Minimal HTTP transport for the Domeneshop API
3
- * (https://api.domeneshop.no/docs/), authenticated via HTTP Basic Auth using
4
- * an API token and secret from https://www.domeneshop.no/admin?view=api.
5
- */
6
- /** Thrown for non-2xx responses from the Domeneshop API. */
7
1
  export declare class DomeneshopApiError extends Error {
8
2
  readonly statusCode: number;
9
3
  readonly body: string;
10
4
  constructor(statusCode: number, body: string);
11
5
  }
12
6
  export interface RequestOptions {
13
- /** Query parameters. Undefined and empty-string values are omitted. */
14
7
  query?: Record<string, string | undefined>;
15
- /** Request body, marshalled as JSON. */
16
8
  body?: unknown;
17
- /**
18
- * Whether to parse the response body as JSON. Defaults to true; set to
19
- * false for endpoints that return a non-JSON (or irrelevant) body, such
20
- * as the dynamic DNS update protocol's plain-text response.
21
- */
9
+ /** Set false for endpoints with a non-JSON body, e.g. the dynamic DNS update protocol. */
22
10
  decodeJson?: boolean;
23
11
  }
24
12
  export interface ApiResponse<T> {
25
- /** The parsed JSON response body, or undefined if the response was empty. */
26
13
  data: T | undefined;
27
- /**
28
- * The raw response headers. Some endpoints report their result there
29
- * rather than in the body — see ForwardsResource.create.
30
- */
14
+ /** Some endpoints report their result here rather than in the body — see ForwardsResource.create. */
31
15
  headers: Headers;
32
16
  }
33
- /**
34
- * HttpTransport performs authenticated HTTP requests against the Domeneshop
35
- * API and decodes JSON responses. It has no knowledge of individual
36
- * endpoints; that lives in the resource classes built on top of it.
37
- */
38
17
  export declare class HttpTransport {
39
18
  private readonly baseUrl;
40
19
  private readonly authorization;
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/domeneshop/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,4DAA4D;AAC5D,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAU7C;AAED,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3C,wCAAwC;IACxC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IACpB;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,MAAyB;IAKvE,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CA8B3B"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/domeneshop/http.ts"],"names":[],"mappings":"AAEA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAU7C;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0FAA0F;IAC1F,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IACpB,qGAAqG;IACrG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,MAAyB;IAKvE,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CA8B3B"}
@@ -1,10 +1,4 @@
1
- /**
2
- * Minimal HTTP transport for the Domeneshop API
3
- * (https://api.domeneshop.no/docs/), authenticated via HTTP Basic Auth using
4
- * an API token and secret from https://www.domeneshop.no/admin?view=api.
5
- */
6
1
  const DEFAULT_BASE_URL = "https://api.domeneshop.no/v0";
7
- /** Thrown for non-2xx responses from the Domeneshop API. */
8
2
  export class DomeneshopApiError extends Error {
9
3
  statusCode;
10
4
  body;
@@ -17,11 +11,6 @@ export class DomeneshopApiError extends Error {
17
11
  this.body = body;
18
12
  }
19
13
  }
20
- /**
21
- * HttpTransport performs authenticated HTTP requests against the Domeneshop
22
- * API and decodes JSON responses. It has no knowledge of individual
23
- * endpoints; that lives in the resource classes built on top of it.
24
- */
25
14
  export class HttpTransport {
26
15
  baseUrl;
27
16
  authorization;