@atomicmail/mcp 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +45 -145
  2. package/esm/lib/src/agent-auth-http.d.ts +26 -0
  3. package/esm/lib/src/agent-auth-http.d.ts.map +1 -0
  4. package/esm/lib/src/agent-auth-http.js +76 -0
  5. package/esm/{mcp/src/credentials.d.ts → lib/src/agent-credentials-store.d.ts} +3 -2
  6. package/esm/lib/src/agent-credentials-store.d.ts.map +1 -0
  7. package/esm/{mcp/src/credentials.js → lib/src/agent-credentials-store.js} +19 -16
  8. package/esm/lib/src/agent-help-content.d.ts +4 -0
  9. package/esm/lib/src/agent-help-content.d.ts.map +1 -0
  10. package/esm/lib/src/agent-help-content.js +236 -0
  11. package/esm/lib/src/agent-jmap.d.ts +49 -0
  12. package/esm/lib/src/agent-jmap.d.ts.map +1 -0
  13. package/esm/lib/src/agent-jmap.js +130 -0
  14. package/esm/lib/src/agent-jwt.d.ts +14 -0
  15. package/esm/lib/src/agent-jwt.d.ts.map +1 -0
  16. package/esm/lib/src/agent-jwt.js +29 -0
  17. package/esm/lib/src/agent-pow.d.ts +5 -0
  18. package/esm/lib/src/agent-pow.d.ts.map +1 -0
  19. package/esm/lib/src/agent-pow.js +49 -0
  20. package/esm/lib/src/agent-resolve-config.d.ts +24 -0
  21. package/esm/lib/src/agent-resolve-config.d.ts.map +1 -0
  22. package/esm/lib/src/agent-resolve-config.js +70 -0
  23. package/esm/lib/src/agent-session.d.ts +62 -0
  24. package/esm/lib/src/agent-session.d.ts.map +1 -0
  25. package/esm/lib/src/agent-session.js +206 -0
  26. package/esm/lib/src/agent-vars.d.ts +23 -0
  27. package/esm/lib/src/agent-vars.d.ts.map +1 -0
  28. package/esm/lib/src/agent-vars.js +65 -0
  29. package/esm/mcp/src/main.js +31 -61
  30. package/esm/mcp/src/tools/help.d.ts +3 -0
  31. package/esm/mcp/src/tools/help.d.ts.map +1 -0
  32. package/esm/mcp/src/tools/help.js +22 -0
  33. package/esm/mcp/src/tools/jmap.d.ts +2 -2
  34. package/esm/mcp/src/tools/jmap.d.ts.map +1 -1
  35. package/esm/mcp/src/tools/jmap.js +53 -140
  36. package/esm/mcp/src/tools/register.d.ts +2 -2
  37. package/esm/mcp/src/tools/register.d.ts.map +1 -1
  38. package/esm/mcp/src/tools/register.js +9 -45
  39. package/package.json +1 -1
  40. package/esm/mcp/src/auth-session.d.ts +0 -88
  41. package/esm/mcp/src/auth-session.d.ts.map +0 -1
  42. package/esm/mcp/src/auth-session.js +0 -378
  43. package/esm/mcp/src/credentials.d.ts.map +0 -1
  44. package/esm/mcp/src/docs-content.d.ts +0 -4
  45. package/esm/mcp/src/docs-content.d.ts.map +0 -1
  46. package/esm/mcp/src/docs-content.js +0 -405
  47. package/esm/mcp/src/tools/docs.d.ts +0 -3
  48. package/esm/mcp/src/tools/docs.d.ts.map +0 -1
  49. package/esm/mcp/src/tools/docs.js +0 -22
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @atomicmail/mcp
2
2
 
3
- AtomicMail MCP server — a local stdio Model Context Protocol server that gives
3
+ Atomic Mail MCP server — a local stdio Model Context Protocol server that gives
4
4
  an AI agent a programmable email inbox over JMAP, with automatic Proof-of-Work
5
5
  auth and capability-token rotation.
6
6
 
@@ -8,121 +8,64 @@ The server is authored in TypeScript on Deno and built with
8
8
  [`dnt`](https://jsr.io/@deno/dnt) into a Node-compatible npm package, so the
9
9
  **same source** runs unchanged on Deno, Node, and Bun.
10
10
 
11
- It is the MCP companion to [`@atomic-mail/agent-skill`](../../skill/) — a
12
- CLI-first skill with identical credential semantics. The MCP and the skill share
13
- the same on-disk credential layout (`credentials.json` + `session.jwt` +
14
- `capability.jwt`), so you can mix and match the two freely.
11
+ It is the MCP companion to
12
+ [`@atomicmail/agent-skill`](https://www.npmjs.com/package/@atomicmail/agent-skill)
13
+ a CLI with identical credential semantics. The MCP and the skill share the
14
+ same on-disk layout (`credentials.json` + `session.jwt` + `capability.jwt`).
15
15
 
16
16
  ## Tools exposed
17
17
 
18
- | Tool | Description |
19
- | -------------- | ----------------------------------------------------------------- |
20
- | `register` | PoW signup. Persists credentials to disk; returns the API key. |
21
- | `jmap_session` | `GET /.well-known/jmap` discover accountId + mailbox URLs. |
22
- | `jmap_request` | Send any JMAP method-call batch. Inline or via saved preset file. |
23
- | `get_docs` | Built-in docs. Topics include `installation`, `presets`, `auth`. |
18
+ | Tool | Description |
19
+ | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
20
+ | `register` | PoW signup; persists credentials. Idempotent when username matches inbox. |
21
+ | `jmap_request` | JMAP batch via `ops` or `ops_file`. Uppercase `$VAR_NAME` tokens are substituted (`$ACCOUNT_ID` / `$INBOX` from session; others via optional `vars` map). |
22
+ | `help` | Built-in docs (`topic` optional). |
24
23
 
25
24
  ## Install
26
25
 
27
- The package is published to npm. Any of these work:
28
-
29
26
  ```bash
30
27
  npx -y @atomicmail/mcp
31
28
  bunx @atomicmail/mcp
32
29
  deno run -A npm:@atomicmail/mcp/atomicmail-mcp
33
30
  ```
34
31
 
35
- You don't typically run it directly your MCP host (Cursor, Claude Desktop,
36
- ...) will spawn it for you. See the configuration section below.
37
-
38
- ## Configure (priority order)
39
-
40
- The server resolves configuration from two sources, with environment variables
41
- overriding individual fields from the file:
42
-
43
- 1. **`credentials.json` in the credential directory.** The same file produced by
44
- `atomic-mail-signup`. Default location: `~/.atomicmail/credentials.json`.
45
- Override the directory with `ATOMIC_MAIL_CREDENTIALS_DIR`.
46
- 2. **Environment variables.** Useful for hermetic MCP host configs:
47
-
48
- | Variable | Required | Description |
49
- | ----------------------------- | -------- | --------------------------------- |
50
- | `ATOMIC_MAIL_AUTH_URL` | Yes\* | Auth service base URL |
51
- | `ATOMIC_MAIL_API_URL` | Yes\* | API service / JMAP base URL |
52
- | `ATOMIC_MAIL_SCRYPT_SALT` | No | Optional PoW salt override |
53
- | `ATOMIC_MAIL_API_KEY` | No | Existing API key (skips signup) |
54
- | `ATOMIC_MAIL_CREDENTIALS_DIR` | No | Override default credential dir |
32
+ Your MCP host spawns this process; see configuration below.
55
33
 
56
- \* "Yes" means at least one source must provide `authUrl` and `apiUrl`. If
57
- `credentials.json` is present and complete, no env vars are required. PoW
58
- salt defaults to the built-in value that matches `auth-service`.
34
+ ## Defaults
59
35
 
60
- If neither source resolves `authUrl` and `apiUrl`, the server fails fast on
61
- startup with the missing fields listed.
36
+ - auth endpoint: `https://auth.atomicmail.ai`
37
+ - api endpoint: `https://api.atomicmail.ai`
38
+ - credentials directory: `~/.atomicmail`
62
39
 
63
40
  ## Credential files
64
41
 
65
- All three live in the credential directory and are written with mode `0600`:
42
+ Mode `0600`:
66
43
 
67
- - `credentials.json` — `{ apiKey, inboxId, authUrl, apiUrl, scryptSalt }`.
68
- Long-lived. Treat as a secret copying it to a new machine is enough to log
69
- in.
70
- - `session.jwt` — 4-hour TTL, rotated automatically via PoW when near expiry.
71
- - `capability.jwt` — 2-minute TTL, rotated automatically before each JMAP
72
- request when near expiry.
44
+ - `credentials.json` — `{ apiKey, inboxId, authUrl, apiUrl, scryptSalt }`
45
+ - `session.jwt`4h TTL, rotated via PoW
46
+ - `capability.jwt` — 2m TTL, rotated before JMAP calls
73
47
 
74
- Because the on-disk layout is identical to the
75
- [`@atomic-mail/agent-skill`](../../skill/) skill, you can:
76
-
77
- - Bootstrap once with `atomic-mail-signup`, then point the MCP at the same
78
- directory.
79
- - Run `atomic-mail-jmap` from a shell while the MCP is also running — both will
80
- see fresh JWTs as the other rotates them.
48
+ Use **`npx atomicmail register`** (from `@atomicmail/agent-skill`) against the
49
+ same directory, or the MCP `register` tool.
81
50
 
82
51
  ## MCP host configuration examples
83
52
 
84
53
  ### Cursor
85
54
 
86
- `~/.cursor/mcp.json` (or per-project `.cursor/mcp.json`):
87
-
88
- ```json
89
- {
90
- "mcpServers": {
91
- "atomicmail": {
92
- "command": "npx",
93
- "args": ["-y", "@atomicmail/mcp"],
94
- "env": {
95
- "ATOMIC_MAIL_AUTH_URL": "https://auth.atomicmail.io",
96
- "ATOMIC_MAIL_API_URL": "https://api.atomicmail.io"
97
- }
98
- }
99
- }
100
- }
101
- ```
102
-
103
- ### Claude Desktop
104
-
105
- `claude_desktop_config.json`:
55
+ `~/.cursor/mcp.json`:
106
56
 
107
57
  ```json
108
58
  {
109
59
  "mcpServers": {
110
60
  "atomicmail": {
111
61
  "command": "npx",
112
- "args": ["-y", "@atomicmail/mcp"],
113
- "env": {
114
- "ATOMIC_MAIL_AUTH_URL": "https://auth.atomicmail.io",
115
- "ATOMIC_MAIL_API_URL": "https://api.atomicmail.io"
116
- }
62
+ "args": ["-y", "@atomicmail/mcp"]
117
63
  }
118
64
  }
119
65
  }
120
66
  ```
121
67
 
122
- ### Sharing credentials with the skill CLI
123
-
124
- If you've already run `atomic-mail-signup`, no auth-service URL needs to be
125
- repeated — the MCP reads URLs (and optional salt override) from `credentials.json`:
68
+ ## Overriding defaults
126
69
 
127
70
  ```json
128
71
  {
@@ -131,102 +74,59 @@ repeated — the MCP reads URLs (and optional salt override) from `credentials.j
131
74
  "command": "npx",
132
75
  "args": ["-y", "@atomicmail/mcp"],
133
76
  "env": {
134
- "ATOMIC_MAIL_CREDENTIALS_DIR": "/Users/me/.atomicmail"
77
+ "ATOMIC_MAIL_AUTH_URL": "https://custom-auth.example",
78
+ "ATOMIC_MAIL_API_URL": "https://custom-api.example",
79
+ "ATOMIC_MAIL_CREDENTIALS_DIR": "/Users/me/.atomicmail",
80
+ "ATOMIC_MAIL_SCRYPT_SALT": "hex-salt-override",
81
+ "ATOMIC_MAIL_API_KEY": "existing-api-key"
135
82
  }
136
83
  }
137
84
  }
138
85
  }
139
86
  ```
140
87
 
141
- When you skip the env entirely (`{}`), the MCP defaults to `~/.atomicmail/`.
142
-
143
88
  ## Typical agent workflow
144
89
 
145
- Once the MCP is wired in, an agent will:
146
-
147
- 1. Call `register` (only on the first run, with no existing API key).
148
- 2. Call `jmap_session` to discover the `accountId` and the INBOX id.
149
- 3. Call `jmap_request` with whatever method calls it needs (inline) or reference
150
- saved presets via `opsFile`.
151
- 4. Call `get_docs` with topic `presets` or `jmap_cheatsheet` for ready-to-use
152
- JMAP recipes.
90
+ 1. `register` with a username (or rely on existing `credentials.json`).
91
+ 2. `jmap_request` with `ops` or `ops_file` (optional `vars` for `$TO`,
92
+ `$SUBJECT`, etc.).
93
+ 3. `help` when stuck.
153
94
 
154
- ## JMAP presets (the `opsFile` parameter)
95
+ ## JMAP presets (`ops_file`)
155
96
 
156
- `jmap_request` accepts either an inline `methodCalls` array or an `opsFile`
157
- path. Relative paths resolve against the credential directory, so common batches
158
- can be saved once and reused. This mirrors the skill's
159
- `atomic-mail-jmap --ops-file` behavior — both consume the same files.
97
+ Relative paths resolve against the credential directory. Example file
98
+ `fetch_last_100.json` then call `jmap_request` with
99
+ `{ "ops_file": "fetch_last_100.json" }`.
160
100
 
161
- Example: drop `~/.atomicmail/fetch_last_100.json` containing
162
-
163
- ```json
164
- [
165
- [
166
- "Email/query",
167
- {
168
- "accountId": "ACC",
169
- "filter": { "inMailbox": "INBOX" },
170
- "sort": [{ "property": "receivedAt", "isAscending": false }],
171
- "limit": 100
172
- },
173
- "q0"
174
- ]
175
- ]
176
- ```
177
-
178
- …then `jmap_request` with `{ "opsFile": "fetch_last_100.json" }`.
179
-
180
- See `get_docs presets` for the full preset format.
101
+ See `help` with topic `presets`.
181
102
 
182
103
  ## Develop
183
104
 
184
- The project is a Deno-first codebase. You'll need [Deno](https://deno.com/)
185
- installed.
186
-
187
105
  ```bash
188
- # Run directly with Deno (live source, no build step)
189
106
  deno task start
190
-
191
- # Type-check
192
107
  deno task check
193
-
194
- # Format
195
108
  deno task fmt
196
-
197
- # Build the npm package via dnt
198
109
  deno task build:npm
199
-
200
- # Run the built artifact under Node
201
- node npm/esm/main.js
110
+ node npm/esm/mcp/src/main.js
202
111
  ```
203
112
 
204
- The dnt build emits to `./npm/`. The package's `bin` is `atomicmail-mcp`, mapped
205
- to `npm/esm/main.js`. After a build you can also `npm install` it locally and
206
- use the binary directly.
207
-
208
113
  ### Project layout
209
114
 
210
115
  ```
211
- services/mcp-server-local/
212
- ├── deno.json # Deno config + import map
213
- ├── build_npm.ts # dnt build script
116
+ mcp/
117
+ ├── deno.json
118
+ ├── build_npm.ts
214
119
  ├── README.md
215
120
  ├── src/
216
- │ ├── main.ts # MCP server entry (stdio transport)
217
- │ ├── auth-session.ts# PoW + JWT rotation, with disk persistence
218
- │ ├── credentials.ts # File I/O: credentials.json, *.jwt
219
- │ ├── docs-content.ts# Static text served by the get_docs tool
121
+ │ ├── main.ts
220
122
  │ └── tools/
221
123
  │ ├── register.ts
222
124
  │ ├── jmap.ts
223
- │ └── docs.ts
125
+ │ └── help.ts
224
126
  └── npm/ # dnt output (gitignored)
225
127
  ```
226
128
 
227
- The auth-session and credentials files are kept in-step with their counterparts
228
- in [`skill/scripts/lib/`](../../skill/scripts/lib/) so both projects produce and
229
- consume identical credential files.
129
+ Shared auth/JMAP logic lives in [`../lib/`](../lib/) (`AgentSession`, etc.).
230
130
 
231
131
  ## License
232
132
 
@@ -0,0 +1,26 @@
1
+ export declare function fetchChallenge(authUrl: string): Promise<{
2
+ challengeJWT: string;
3
+ challenge: string;
4
+ difficulty: number;
5
+ }>;
6
+ export interface SessionResponse {
7
+ sessionJWT: string;
8
+ apiKey?: string;
9
+ }
10
+ export declare function exchangeSession(authUrl: string, body: {
11
+ challengeJWT: string;
12
+ powHex: string;
13
+ nonce: string;
14
+ apiKey?: string;
15
+ username?: string;
16
+ }): Promise<SessionResponse>;
17
+ export declare function fetchCapability(authUrl: string, sessionJWT: string): Promise<string>;
18
+ export interface PerformPoWInput {
19
+ authUrl: string;
20
+ scryptSalt: string;
21
+ apiKey?: string;
22
+ username?: string;
23
+ onPowProgress?: (nonce: bigint) => void;
24
+ }
25
+ export declare function performPoWAndSession(input: PerformPoWInput): Promise<SessionResponse>;
26
+ //# sourceMappingURL=agent-auth-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-auth-http.d.ts","sourceRoot":"","sources":["../../../src/lib/src/agent-auth-http.ts"],"names":[],"mappings":"AAoCA,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,CAqBD;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IACJ,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,eAAe,CAAC,CAS1B;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,eAAe,CAAC,CAgB1B"}
@@ -0,0 +1,76 @@
1
+ // auth-service HTTP: challenge → session → capability.
2
+ import { decodeJwtPayload } from "./agent-jwt.js";
3
+ import { solvePow } from "./agent-pow.js";
4
+ async function postJson(url, body, headers = {}) {
5
+ const res = await fetch(url, {
6
+ method: "POST",
7
+ headers: {
8
+ ...(body ? { "Content-Type": "application/json" } : {}),
9
+ ...headers,
10
+ },
11
+ body: body ? JSON.stringify(body) : undefined,
12
+ });
13
+ const text = await res.text();
14
+ const path = (() => {
15
+ try {
16
+ return new URL(url).pathname;
17
+ }
18
+ catch {
19
+ return url;
20
+ }
21
+ })();
22
+ if (!res.ok) {
23
+ throw new Error(`auth-service ${path} returned ${res.status}: ${text}`);
24
+ }
25
+ try {
26
+ return JSON.parse(text);
27
+ }
28
+ catch {
29
+ throw new Error(`auth-service ${path} returned non-JSON body: ${text}`);
30
+ }
31
+ }
32
+ export async function fetchChallenge(authUrl) {
33
+ const data = await postJson(`${authUrl}/api/v1/challenge`, undefined);
34
+ if (typeof data.challengeJWT !== "string") {
35
+ throw new Error("Challenge response missing challengeJWT.");
36
+ }
37
+ const payload = decodeJwtPayload(data.challengeJWT);
38
+ if (typeof payload.jti !== "string" ||
39
+ typeof payload.difficulty !== "number") {
40
+ throw new Error("Challenge JWT payload malformed (missing jti or difficulty).");
41
+ }
42
+ return {
43
+ challengeJWT: data.challengeJWT,
44
+ challenge: payload.jti,
45
+ difficulty: payload.difficulty,
46
+ };
47
+ }
48
+ export async function exchangeSession(authUrl, body) {
49
+ const data = await postJson(`${authUrl}/api/v1/session`, { ...body });
50
+ if (typeof data.sessionJWT !== "string") {
51
+ throw new Error("Session response missing sessionJWT.");
52
+ }
53
+ return {
54
+ sessionJWT: data.sessionJWT,
55
+ apiKey: typeof data.apiKey === "string" ? data.apiKey : undefined,
56
+ };
57
+ }
58
+ export async function fetchCapability(authUrl, sessionJWT) {
59
+ const data = await postJson(`${authUrl}/api/v1/capability`, undefined, { Authorization: `Bearer ${sessionJWT}` });
60
+ if (typeof data.capabilityJWT !== "string") {
61
+ throw new Error("Capability response missing capabilityJWT.");
62
+ }
63
+ return data.capabilityJWT;
64
+ }
65
+ export async function performPoWAndSession(input) {
66
+ const { authUrl, scryptSalt } = input;
67
+ const { challengeJWT, challenge, difficulty } = await fetchChallenge(authUrl);
68
+ const { powHex, nonce } = await solvePow(challenge, difficulty, scryptSalt, input.onPowProgress);
69
+ return exchangeSession(authUrl, {
70
+ challengeJWT,
71
+ powHex,
72
+ nonce,
73
+ apiKey: input.apiKey,
74
+ username: input.username,
75
+ });
76
+ }
@@ -13,8 +13,9 @@ export interface SkillFiles {
13
13
  export declare function defaultFilesFromOutDir(outDir: string): SkillFiles;
14
14
  export declare function writeCredentials(path: string, creds: Credentials): Promise<void>;
15
15
  export declare function readCredentials(path: string): Promise<Credentials>;
16
- /** Like readCredentials, but returns undefined when the file does not exist. */
17
16
  export declare function tryReadCredentials(path: string): Promise<Credentials | undefined>;
18
17
  export declare function writeJwtFile(path: string, jwt: string): Promise<void>;
19
18
  export declare function tryReadJwtFile(path: string): Promise<string | undefined>;
20
- //# sourceMappingURL=credentials.d.ts.map
19
+ /** Best-effort removal of credential artifacts (ignore missing files). */
20
+ export declare function unlinkCredentialArtifacts(files: SkillFiles): Promise<void>;
21
+ //# sourceMappingURL=agent-credentials-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-credentials-store.d.ts","sourceRoot":"","sources":["../../../src/lib/src/agent-credentials-store.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAOjE;AAMD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAiCxE;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAOlC;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3E;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO7B;AAED,0EAA0E;AAC1E,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -1,17 +1,6 @@
1
- // Credential file I/O. Three files form a complete credential set:
2
- // credentials.json — long-lived: apiKey, inboxId, server URLs, PoW salt.
3
- // session.jwt — short-lived (~4h): rotates via /session + PoW.
4
- // capability.jwt — short-lived (~2min): rotates via /capability.
5
- //
6
- // Files are written with mode 0600 so other local users cannot read them.
7
- //
8
- // This file mirrors skill/scripts/lib/credentials.ts so that the MCP server
9
- // reads and writes the same on-disk layout as the atomic-mail-signup /
10
- // atomic-mail-jmap CLIs from the @atomic-mail/agent-skill skill. The two
11
- // are interchangeable: you can run the skill CLI to bootstrap credentials
12
- // and the MCP server will pick them up automatically (see resolveConfig
13
- // in auth-session.ts).
14
- import { mkdir, readFile, writeFile } from "node:fs/promises";
1
+ // Credential file I/O shared by MCP and AgentSkill.
2
+ // Three files: credentials.json, session.jwt, capability.jwt (mode 0600).
3
+ import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
15
4
  import { dirname, join, resolve } from "node:path";
16
5
  export function defaultFilesFromOutDir(outDir) {
17
6
  const base = resolve(outDir);
@@ -35,7 +24,7 @@ export async function readCredentials(path) {
35
24
  }
36
25
  catch (err) {
37
26
  throw new Error(`Could not read credentials file '${path}': ${err.message}. ` +
38
- "Did you run signup first?");
27
+ "Did you run register first?");
39
28
  }
40
29
  let obj;
41
30
  try {
@@ -58,7 +47,6 @@ export async function readCredentials(path) {
58
47
  }
59
48
  return obj;
60
49
  }
61
- /** Like readCredentials, but returns undefined when the file does not exist. */
62
50
  export async function tryReadCredentials(path) {
63
51
  try {
64
52
  await readFile(path, "utf-8");
@@ -81,3 +69,18 @@ export async function tryReadJwtFile(path) {
81
69
  return undefined;
82
70
  }
83
71
  }
72
+ /** Best-effort removal of credential artifacts (ignore missing files). */
73
+ export async function unlinkCredentialArtifacts(files) {
74
+ for (const p of [
75
+ files.credentialsFile,
76
+ files.sessionFile,
77
+ files.capabilityFile,
78
+ ]) {
79
+ try {
80
+ await unlink(p);
81
+ }
82
+ catch {
83
+ // ignore
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,4 @@
1
+ export declare const HELP_TOPICS: Record<string, string>;
2
+ export declare const HELP_TOPIC_LIST: string[];
3
+ export declare function getHelp(topic?: string): string;
4
+ //# sourceMappingURL=agent-help-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-help-content.d.ts","sourceRoot":"","sources":["../../../src/lib/src/agent-help-content.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuO9C,CAAC;AAEF,eAAO,MAAM,eAAe,UAA2B,CAAC;AAExD,wBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAW9C"}