@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.
- package/README.md +45 -145
- package/esm/lib/src/agent-auth-http.d.ts +26 -0
- package/esm/lib/src/agent-auth-http.d.ts.map +1 -0
- package/esm/lib/src/agent-auth-http.js +76 -0
- package/esm/{mcp/src/credentials.d.ts → lib/src/agent-credentials-store.d.ts} +3 -2
- package/esm/lib/src/agent-credentials-store.d.ts.map +1 -0
- package/esm/{mcp/src/credentials.js → lib/src/agent-credentials-store.js} +19 -16
- package/esm/lib/src/agent-help-content.d.ts +4 -0
- package/esm/lib/src/agent-help-content.d.ts.map +1 -0
- package/esm/lib/src/agent-help-content.js +236 -0
- package/esm/lib/src/agent-jmap.d.ts +49 -0
- package/esm/lib/src/agent-jmap.d.ts.map +1 -0
- package/esm/lib/src/agent-jmap.js +130 -0
- package/esm/lib/src/agent-jwt.d.ts +14 -0
- package/esm/lib/src/agent-jwt.d.ts.map +1 -0
- package/esm/lib/src/agent-jwt.js +29 -0
- package/esm/lib/src/agent-pow.d.ts +5 -0
- package/esm/lib/src/agent-pow.d.ts.map +1 -0
- package/esm/lib/src/agent-pow.js +49 -0
- package/esm/lib/src/agent-resolve-config.d.ts +24 -0
- package/esm/lib/src/agent-resolve-config.d.ts.map +1 -0
- package/esm/lib/src/agent-resolve-config.js +70 -0
- package/esm/lib/src/agent-session.d.ts +62 -0
- package/esm/lib/src/agent-session.d.ts.map +1 -0
- package/esm/lib/src/agent-session.js +206 -0
- package/esm/lib/src/agent-vars.d.ts +23 -0
- package/esm/lib/src/agent-vars.d.ts.map +1 -0
- package/esm/lib/src/agent-vars.js +65 -0
- package/esm/mcp/src/main.js +31 -61
- package/esm/mcp/src/tools/help.d.ts +3 -0
- package/esm/mcp/src/tools/help.d.ts.map +1 -0
- package/esm/mcp/src/tools/help.js +22 -0
- package/esm/mcp/src/tools/jmap.d.ts +2 -2
- package/esm/mcp/src/tools/jmap.d.ts.map +1 -1
- package/esm/mcp/src/tools/jmap.js +53 -140
- package/esm/mcp/src/tools/register.d.ts +2 -2
- package/esm/mcp/src/tools/register.d.ts.map +1 -1
- package/esm/mcp/src/tools/register.js +9 -45
- package/package.json +1 -1
- package/esm/mcp/src/auth-session.d.ts +0 -88
- package/esm/mcp/src/auth-session.d.ts.map +0 -1
- package/esm/mcp/src/auth-session.js +0 -378
- package/esm/mcp/src/credentials.d.ts.map +0 -1
- package/esm/mcp/src/docs-content.d.ts +0 -4
- package/esm/mcp/src/docs-content.d.ts.map +0 -1
- package/esm/mcp/src/docs-content.js +0 -405
- package/esm/mcp/src/tools/docs.d.ts +0 -3
- package/esm/mcp/src/tools/docs.d.ts.map +0 -1
- package/esm/mcp/src/tools/docs.js +0 -22
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @atomicmail/mcp
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`
|
|
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
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
61
|
-
|
|
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
|
-
|
|
42
|
+
Mode `0600`:
|
|
66
43
|
|
|
67
|
-
- `credentials.json` — `{ apiKey, inboxId, authUrl, apiUrl, scryptSalt }
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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 (
|
|
95
|
+
## JMAP presets (`ops_file`)
|
|
155
96
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
212
|
-
├── deno.json
|
|
213
|
-
├── build_npm.ts
|
|
116
|
+
mcp/
|
|
117
|
+
├── deno.json
|
|
118
|
+
├── build_npm.ts
|
|
214
119
|
├── README.md
|
|
215
120
|
├── src/
|
|
216
|
-
│ ├── main.ts
|
|
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
|
-
│ └──
|
|
125
|
+
│ └── help.ts
|
|
224
126
|
└── npm/ # dnt output (gitignored)
|
|
225
127
|
```
|
|
226
128
|
|
|
227
|
-
|
|
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
|
-
|
|
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
|
|
2
|
-
//
|
|
3
|
-
|
|
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
|
|
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 @@
|
|
|
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"}
|