@formstr/mcp 0.1.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 ADDED
@@ -0,0 +1,120 @@
1
+ # @formstr/mcp
2
+
3
+ A standalone [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that
4
+ exposes the **Formstr** super-app (forms, calendar, pages, drive, polls) to any MCP host —
5
+ Claude Code/Desktop, Cursor, and others. It builds on `@formstr/core` and the super-app's
6
+ service layer and talks to Nostr relays directly. Transport: **stdio**.
7
+
8
+ v2 adds a **secure login flow** (your key lives in the OS keychain or a remote NIP-46
9
+ signer — never in your host config or the chat) and the **complete forms tool surface**.
10
+
11
+ ## Quick start
12
+
13
+ ```bash
14
+ # 1. Sign in once (opens a browser; key is stored in your OS keychain)
15
+ npx -y @formstr/mcp login
16
+
17
+ # 2. Point your MCP host at the server (see "Host configuration")
18
+ # No key in the config — it's read from the keychain at startup.
19
+ ```
20
+
21
+ Subcommands: `formstr-mcp login` · `formstr-mcp whoami` · `formstr-mcp logout` ·
22
+ `formstr-mcp` (run the stdio server, the default).
23
+
24
+ ## Sign-in
25
+
26
+ `formstr-mcp login` starts a one-shot localhost page (it also prints the URL for
27
+ headless/SSH use) offering the same choices as the super-app:
28
+
29
+ | Method | What happens |
30
+ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
31
+ | **Paste nsec** | Validated locally; the key is stored in your OS keychain. |
32
+ | **Create guest** | A fresh Nostr key is generated and stored in your keychain. |
33
+ | **Connect signer (NIP-46)** | Scan/paste a `nostrconnect://` URI in Amber / nsec.app / nsecbunker. Your key stays there; the MCP keeps only a session token. |
34
+
35
+ **Where the key lives:** the OS keychain (macOS Keychain / Windows Credential Manager /
36
+ Linux Secret Service via `@napi-rs/keyring`). On hosts without a keychain (e.g. headless
37
+ Linux), set `FORMSTR_MCP_PASSPHRASE` to use an AES-256-GCM encrypted file at
38
+ `~/.config/formstr-mcp/credentials.enc` (mode `0600`). Multiple identities are supported;
39
+ select one with `--account <pubkey>`.
40
+
41
+ **The agent never sees your key.** No tool returns key material, and login happens
42
+ out-of-band, so secrets never enter the chat transcript.
43
+
44
+ ## Host configuration
45
+
46
+ After `login`, no key belongs in the config:
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "formstr": {
52
+ "command": "npx",
53
+ "args": ["-y", "@formstr/mcp"]
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ Add `"--allow-writes"` to `args` to enable the gated (destructive/outward) tools, and
60
+ `"--relays", "wss://a,wss://b"` to override relays.
61
+
62
+ ## Headless / CI
63
+
64
+ For unattended use where no keychain or browser is available, provide a plaintext key.
65
+ The server **prints a prominent security warning** when you do this — prefer `login`.
66
+
67
+ | Variable | Meaning |
68
+ | --------------------------- | --------------------------------------------------- |
69
+ | `FORMSTR_NSEC` | signing key (plaintext) |
70
+ | `FORMSTR_RELAYS` | comma-separated relay override (optional) |
71
+ | `FORMSTR_ALLOW_WRITES=true` | enable gated tools (optional) |
72
+ | `FORMSTR_MCP_PASSPHRASE` | passphrase for the encrypted-file keystore fallback |
73
+
74
+ CLI flags: `--nsec <nsec>`, `--relays <wss://a,wss://b>`, `--allow-writes`, `--account <pubkey>`.
75
+ Precedence: plaintext flag/env/`config.json` → keychain → "run `formstr-mcp login`".
76
+
77
+ ## Forms tools
78
+
79
+ The forms module is fully implemented — the MCP can create **every** field type the
80
+ service supports (more than the super-app builder UI currently exposes).
81
+
82
+ **Read (always on)**
83
+
84
+ - `list_forms` — your forms with ids, encryption status, and naddr coordinates.
85
+ - `get_form` — a form's fields, settings, and encryption status (pass `viewKey` for encrypted forms).
86
+ - `fetch_form_responses` — submissions with responder npub and per-field answers.
87
+
88
+ **Create / import (always on)**
89
+
90
+ - `create_form` — name, description, fields (short/paragraph/choice/dropdown/number/date/
91
+ time/grid/file/signature/section), per-field `validation`, title/cover images, thank-you
92
+ text, `publicForm`, `encrypted`, `allowedResponders`, `collaborators`, `notifyNpubs`.
93
+ - `import_form_from_naddr` — add a form by `naddr1…` / `pubkey:formId` to your forms list.
94
+
95
+ **Gated (require `--allow-writes` + `confirm: true`)**
96
+
97
+ - `update_form` — republish a form's name/fields/description.
98
+ - `share_form` — gift-wrap (NIP-59) an encrypted form's view key to collaborators.
99
+ - `delete_form` — publish a NIP-09 deletion.
100
+ - `submit_form_response` — submit a response on your identity.
101
+
102
+ Other modules (calendar, pages, polls, drive) expose the v1 read/create tools and gated
103
+ actions; see the source under `src/tools/`.
104
+
105
+ ## Safety model
106
+
107
+ Destructive / outward tools are **not registered** unless `--allow-writes` (or
108
+ `FORMSTR_ALLOW_WRITES=true`) is set, AND each such call additionally requires
109
+ `"confirm": true`. Without `confirm`, the tool returns a structured "confirmation
110
+ required" message naming the irreversible effect instead of executing. `share_form`
111
+ distributes only the view key (read access) — never the signing key. Logging goes to
112
+ stderr (stdout is the MCP transport).
113
+
114
+ ## Tests
115
+
116
+ ```bash
117
+ pnpm --filter @formstr/mcp test # unit + stdio smoke test
118
+ pnpm --filter @formstr/mcp typecheck
119
+ pnpm --filter @formstr/mcp build # single-file CJS bundle (keychain dep stays external)
120
+ ```