neozip-mcp 0.1.0-beta

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 (113) hide show
  1. package/.cursor/mcp.json.global.example +10 -0
  2. package/CHANGELOG.md +16 -0
  3. package/DOCUMENTATION.md +40 -0
  4. package/LICENSE +16 -0
  5. package/README.md +223 -0
  6. package/SECURITY.md +37 -0
  7. package/dist/account/account-state.js +86 -0
  8. package/dist/account/format-account-status.js +37 -0
  9. package/dist/account/identity-provision.js +75 -0
  10. package/dist/account/identity-wrap.js +69 -0
  11. package/dist/account/profile-crypto.js +47 -0
  12. package/dist/account/profile-store.js +108 -0
  13. package/dist/account/require-account.js +29 -0
  14. package/dist/account/token-service-identity.js +395 -0
  15. package/dist/account/types.js +2 -0
  16. package/dist/account/wallet-evm.js +39 -0
  17. package/dist/archive/blockchain-status.js +303 -0
  18. package/dist/archive/crypto-self.js +114 -0
  19. package/dist/archive/detect-text.js +56 -0
  20. package/dist/archive/embed-metadata.js +283 -0
  21. package/dist/archive/encryption.js +166 -0
  22. package/dist/archive/extract-entry-buffer.js +18 -0
  23. package/dist/archive/find-entry.js +21 -0
  24. package/dist/archive/grep-content.js +141 -0
  25. package/dist/archive/identity-key.js +176 -0
  26. package/dist/archive/manifest.js +55 -0
  27. package/dist/archive/merkle.js +31 -0
  28. package/dist/archive/metadata-paths.js +14 -0
  29. package/dist/archive/mint-archive.js +61 -0
  30. package/dist/archive/open-archive.js +23 -0
  31. package/dist/archive/read-entry-buffer.js +11 -0
  32. package/dist/archive/read-entry-content.js +51 -0
  33. package/dist/archive/recipient-access.js +26 -0
  34. package/dist/archive/recipient-decrypt.js +21 -0
  35. package/dist/archive/recipient-lookup.js +55 -0
  36. package/dist/archive/timestamp-network.js +54 -0
  37. package/dist/config/capabilities.js +37 -0
  38. package/dist/config/index.js +74 -0
  39. package/dist/connect-cli.js +312 -0
  40. package/dist/connection/coordinator.js +74 -0
  41. package/dist/connection/credentials.js +29 -0
  42. package/dist/connection/crypto.js +56 -0
  43. package/dist/connection/dump.js +79 -0
  44. package/dist/connection/incomplete-setup.js +81 -0
  45. package/dist/connection/interactive.js +814 -0
  46. package/dist/connection/legacy-profile-reader.js +47 -0
  47. package/dist/connection/magic-link.js +138 -0
  48. package/dist/connection/migrate.js +76 -0
  49. package/dist/connection/onboarding.js +524 -0
  50. package/dist/connection/origin.js +63 -0
  51. package/dist/connection/phase.js +93 -0
  52. package/dist/connection/phone.js +20 -0
  53. package/dist/connection/promote-active.js +53 -0
  54. package/dist/connection/reset.js +20 -0
  55. package/dist/connection/setup-guidance.js +154 -0
  56. package/dist/connection/status-report.js +40 -0
  57. package/dist/connection/store.js +352 -0
  58. package/dist/connection/token-auth.js +42 -0
  59. package/dist/connection/types.js +2 -0
  60. package/dist/connection/wallet-setup.js +70 -0
  61. package/dist/constants/wallet-identity.js +11 -0
  62. package/dist/index.js +47 -0
  63. package/dist/load-env.js +16 -0
  64. package/dist/neozipkit-node.js +11 -0
  65. package/dist/register/resources.js +14 -0
  66. package/dist/register/tools.js +77 -0
  67. package/dist/resources/zip-resource.js +40 -0
  68. package/dist/resources/zip-uri.js +23 -0
  69. package/dist/security/auth.js +28 -0
  70. package/dist/security/capabilities.js +85 -0
  71. package/dist/security/rate-limiter.js +43 -0
  72. package/dist/security/resource-limiter.js +44 -0
  73. package/dist/security/sandbox.js +61 -0
  74. package/dist/server.js +32 -0
  75. package/dist/startup-account-gate.js +101 -0
  76. package/dist/startup-summary.js +40 -0
  77. package/dist/token-service/require-configured.js +23 -0
  78. package/dist/tools/account.js +504 -0
  79. package/dist/tools/compress.js +237 -0
  80. package/dist/tools/connect-status.js +143 -0
  81. package/dist/tools/extract.js +62 -0
  82. package/dist/tools/grep-entries.js +42 -0
  83. package/dist/tools/identity-status.js +157 -0
  84. package/dist/tools/info.js +147 -0
  85. package/dist/tools/list.js +118 -0
  86. package/dist/tools/lookup-recipient.js +37 -0
  87. package/dist/tools/mint.js +41 -0
  88. package/dist/tools/read-entry.js +35 -0
  89. package/dist/tools/search-entries.js +71 -0
  90. package/dist/tools/stamp.js +60 -0
  91. package/dist/tools/test.js +90 -0
  92. package/dist/tools/token-service-account.js +143 -0
  93. package/dist/tools/upgrade.js +60 -0
  94. package/dist/tools/verify.js +75 -0
  95. package/dist/tools/wallet-config-status.js +119 -0
  96. package/dist/tools/wallet-info.js +64 -0
  97. package/dist/translators/index.js +106 -0
  98. package/dist/types/index.js +7 -0
  99. package/dist/util/mask.js +30 -0
  100. package/dist/util/token-service-fetch.js +23 -0
  101. package/dist/vendor/neozipkit-pro.js +3 -0
  102. package/docs/NEOZIP_CONNECTION_STORE.md +238 -0
  103. package/docs/NEOZIP_CONNECT_CLI.md +185 -0
  104. package/docs/OPERATIONS.md +992 -0
  105. package/docs/examples/CLAUDE.md.example +22 -0
  106. package/docs/examples/claude/skills/neozip-mcp/SKILL.md +54 -0
  107. package/docs/examples/claude/skills/neozip-notarization/SKILL.md +75 -0
  108. package/docs/examples/mcp.json.claude.example +11 -0
  109. package/docs/examples/neozip-mcp-cursor-rule.mdc +31 -0
  110. package/docs/installation-guides/INSTALL_CLAUDE_CODE.md +286 -0
  111. package/docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md +301 -0
  112. package/docs/installation-guides/README.md +76 -0
  113. package/package.json +99 -0
@@ -0,0 +1,10 @@
1
+ {
2
+ "mcpServers": {
3
+ "neozip-mcp": {
4
+ "command": "neozip-mcp",
5
+ "env": {
6
+ "NEOZIP_MCP_SANDBOX_PATHS": "${workspaceFolder},${userHome}"
7
+ }
8
+ }
9
+ }
10
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ Release notes for [neozip-mcp](https://www.npmjs.com/package/neozip-mcp).
4
+
5
+ ## 0.1.0-beta (2026-06-26)
6
+
7
+ First npm release (**beta**).
8
+
9
+ - MCP stdio server with ZIP tools (`compress`, `extract`, `list`, `info`, `test`, `read_entry`, `search_entries`, `grep_entries`) and `zip://` resources
10
+ - Blockchain notarization tools (`stamp`, `mint`, `verify`, `upgrade_timestamped`, `wallet_info`)
11
+ - NeoZip Token Service integration via **`neozip-connect`** CLI and account tools
12
+ - Recipient encryption (Token Service X25519) bundled at build time — no GitHub Packages install required at runtime
13
+ - Path sandboxing, capability scoping, rate limiting, and resource limits
14
+ - Shipped docs, Claude Code install guides, and example agent skills under `docs/examples/claude/skills/`
15
+
16
+ See [README.md](README.md) and [docs/OPERATIONS.md](docs/OPERATIONS.md) for setup and tool reference.
@@ -0,0 +1,40 @@
1
+ # NeoZip MCP documentation
2
+
3
+ Documentation shipped with the [neozip-mcp](https://www.npmjs.com/package/neozip-mcp) npm package (**beta** — install with `npm install -g neozip-mcp@beta`).
4
+
5
+ ## Getting started
6
+
7
+ | Document | Description |
8
+ |----------|-------------|
9
+ | [README.md](README.md) | Installation, MCP host setup, environment variables |
10
+ | [CHANGELOG.md](CHANGELOG.md) | Version history and release notes |
11
+ | [SECURITY.md](SECURITY.md) | Security considerations and vulnerability reporting |
12
+
13
+ ## Tool reference
14
+
15
+ | Document | Description |
16
+ |----------|-------------|
17
+ | [docs/OPERATIONS.md](docs/OPERATIONS.md) | Full MCP tool and parameter reference |
18
+ | [docs/NEOZIP_CONNECT_CLI.md](docs/NEOZIP_CONNECT_CLI.md) | `neozip-connect` account setup CLI |
19
+ | [docs/NEOZIP_CONNECTION_STORE.md](docs/NEOZIP_CONNECTION_STORE.md) | Connection store layout (`~/.neozip/connection/`) |
20
+
21
+ ## MCP host installation
22
+
23
+ | Document | Description |
24
+ |----------|-------------|
25
+ | [docs/installation-guides/README.md](docs/installation-guides/README.md) | Index of host guides |
26
+ | [docs/installation-guides/INSTALL_CLAUDE_CODE.md](docs/installation-guides/INSTALL_CLAUDE_CODE.md) | Claude Code (user scope) |
27
+ | [docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md](docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md) | Claude Code workspace (`.mcp.json`) |
28
+
29
+ ## Examples (in package)
30
+
31
+ | Path | Description |
32
+ |------|-------------|
33
+ | [docs/examples/mcp.json.claude.example](docs/examples/mcp.json.claude.example) | Claude Code `.mcp.json` template |
34
+ | [docs/examples/claude/skills/](docs/examples/claude/skills/) | Agent skills for archives and notarization |
35
+ | [.cursor/mcp.json.global.example](.cursor/mcp.json.global.example) | Cursor global MCP config template |
36
+
37
+ ## Support
38
+
39
+ - **GitHub Issues:** [NeoWareInc/neozip-support](https://github.com/NeoWareInc/neozip-support/issues)
40
+ - **Email:** [support@neozip.io](mailto:support@neozip.io)
package/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright (c) 2026 NeoWare, Inc. All rights reserved.
2
+
3
+ This software and associated documentation files (the "Software") are
4
+ proprietary to NeoWare, Inc. The Software is provided only to authorized
5
+ recipients for internal use.
6
+
7
+ No license is granted to copy, modify, merge, publish, distribute,
8
+ sublicense, or sell copies of the Software except as expressly authorized
9
+ in writing by NeoWare, Inc.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
14
+ NEOWARE, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
15
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # neozip-mcp
2
+
3
+ > MCP server for ZIP archives, blockchain notarization, and AI agent integration — powered by [neozipkit](https://www.npmjs.com/package/neozipkit) and [neozip-blockchain](https://www.npmjs.com/package/neozip-blockchain)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/neozip-mcp?label=beta&color=blue)](https://www.npmjs.com/package/neozip-mcp)
6
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org/)
7
+
8
+ > **Beta version warning:** NeoZip MCP is currently in **beta** status. This means:
9
+ > - The MCP tool surface and CLI may change in future releases
10
+ > - Some features may be incomplete or experimental
11
+ > - Breaking changes may occur before the stable release
12
+ > - Use in production with caution and thorough testing
13
+ >
14
+ > Install the beta channel: `npm install -g neozip-mcp@beta`. Report issues on [GitHub](https://github.com/NeoWareInc/neozip-support/issues) or email [support@neozip.io](mailto:support@neozip.io).
15
+
16
+ ## Release notice
17
+
18
+ **Current version: v0.1.0-beta.** See [CHANGELOG.md](CHANGELOG.md) for details.
19
+
20
+ - **API stability:** MCP tool names and parameters may change before a stable release
21
+ - **Testing:** Test thoroughly in your MCP host before production use
22
+ - **Feedback:** Report issues via [GitHub Issues](https://github.com/NeoWareInc/neozip-support/issues) or email [support@neozip.io](mailto:support@neozip.io)
23
+ - **License:** Proprietary — NeoWare, Inc. See [LICENSE](LICENSE)
24
+
25
+ ## Overview
26
+
27
+ NeoZip MCP is a local stdio MCP server for AI coding agents (Claude Code, Cursor, and other MCP hosts). It exposes ZIP operations, blockchain notarization, and NeoZip Token Service tools to the agent — no repository checkout required.
28
+
29
+ ## Features
30
+
31
+ ### ZIP Operations
32
+ - **compress** -- Create ZIP archives (default: Zstandard). Options: `recipientEmails` (Token Service public-key encryption via `META-INF/ACCESS.NZIP`), `password` + `encryptionMethod`, `timestamp`, `tokenize`. SHA-256 is auto-enabled for timestamped/tokenized archives.
33
+ - **extract** -- Extract ZIP files to directories (password-protected archives supported)
34
+ - **list** -- List ZIP archive contents (text or JSON manifest)
35
+ - **info** -- Get detailed ZIP metadata (sizes, ratios, merkle root)
36
+ - **test** -- Test ZIP integrity per entry
37
+ - **read_entry** -- Read a single file inside an archive with pagination (optional `options.password` for encrypted entries)
38
+ - **search_entries** -- Search archive entry names by keyword or regex
39
+ - **grep_entries** -- Search file contents inside an archive for text or regex matches (no extraction)
40
+
41
+ ### MCP Resources
42
+ - **zip://** -- Direct access to archive manifests and entry contents as MCP resources
43
+
44
+ See [docs/OPERATIONS.md](docs/OPERATIONS.md) for full parameter reference.
45
+
46
+ ### NeoZip Token Service
47
+ Account, identity, and recipient-key tools that talk to the NeoZip Token Service (configured via `neozip-connect`); they do not operate on ZIP archives directly.
48
+ - **connect_status** -- Fast neozip-connect readiness: phase, compress option readiness, next terminal command (no secrets, no network)
49
+ - **token_service_status** -- Check Token Service email verification status
50
+ - **token_service_register** -- Register email and send verification code (requires `blockchain`)
51
+ - **token_service_verify** -- Verify email with 6-digit code (requires `blockchain`)
52
+ - **lookup_recipient** -- Resolve a recipient's Token Service X25519 public key by email before encrypting
53
+ - **identity_status** -- Token Service `/crypto/self` identity provisioning (Bearer token in env)
54
+ - **wallet_config_status** -- Diagnose credential sources and readiness (no secrets)
55
+
56
+ ### Blockchain Operations
57
+ - **mint** -- Mint ZIP hash as NFT on Base network
58
+ - **verify** -- Verify token authenticity against blockchain
59
+ - **stamp** -- Submit ZIP merkle root to the NeoZip Token Service for timestamping
60
+ - **upgrade_timestamped** -- Upgrade pending timestamp to confirmed (`META-INF/TIMESTAMP.NZIP`)
61
+ - **wallet_info** -- View wallet and network status (address, balance)
62
+
63
+ ### Security
64
+ - **Path sandboxing** -- Allowlist-based directory restrictions with symlink and traversal prevention
65
+ - **Capability scoping** -- Enable/disable tool groups (zip, blockchain, readonly)
66
+ - **Rate limiting** -- Token-bucket rate limiting per tool
67
+ - **Resource limiting** -- Max file size, entry count, and operation timeouts
68
+ - **Authentication** -- Wallet key sourcing and optional API key
69
+
70
+ ## Installation
71
+
72
+ ### Prerequisites
73
+
74
+ - Node.js 20.0.0 or higher
75
+ - npm or pnpm
76
+
77
+ ### Install from npm (beta)
78
+
79
+ ```bash
80
+ npm install -g neozip-mcp@beta
81
+ ```
82
+
83
+ After installation:
84
+
85
+ | Command | Purpose |
86
+ |---------|---------|
87
+ | `neozip-mcp` | MCP server (your host spawns this) |
88
+ | `neozip-connect` | Interactive account setup |
89
+
90
+ ### Verify installation
91
+
92
+ ```bash
93
+ which neozip-mcp
94
+ which neozip-connect
95
+ neozip-connect status
96
+ ```
97
+
98
+ ### Install in MCP hosts
99
+
100
+ | Host | Guide |
101
+ |------|-------|
102
+ | **Claude Code** (user/local scope) | [docs/installation-guides/INSTALL_CLAUDE_CODE.md](docs/installation-guides/INSTALL_CLAUDE_CODE.md) |
103
+ | **Claude Code workspace** (project `.mcp.json`) | [docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md](docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md) |
104
+ | **Cursor** | Quick start below |
105
+
106
+ Full index: [docs/installation-guides/README.md](docs/installation-guides/README.md)
107
+
108
+ ## Claude Code setup
109
+
110
+ 1. Install from npm (see above).
111
+ 2. Register MCP — user scope (all projects):
112
+
113
+ ```bash
114
+ claude mcp add-json neozip-mcp \
115
+ '{"type":"stdio","command":"neozip-mcp","env":{"NEOZIP_MCP_SANDBOX_PATHS":"${CLAUDE_PROJECT_DIR:-.},${HOME}"}}' \
116
+ --scope user
117
+ ```
118
+
119
+ For team repos, copy [`docs/examples/mcp.json.claude.example`](docs/examples/mcp.json.claude.example) to `.mcp.json` — see [INSTALL_CLAUDE_WORKSPACE.md](docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md).
120
+
121
+ 3. **Agent skills (recommended)** — copy from the package:
122
+
123
+ ```bash
124
+ pkg="$(npm root -g)/neozip-mcp"
125
+ mkdir -p ~/.claude/skills/neozip-mcp ~/.claude/skills/neozip-notarization
126
+ cp "$pkg/docs/examples/claude/skills/neozip-mcp/SKILL.md" ~/.claude/skills/neozip-mcp/
127
+ cp "$pkg/docs/examples/claude/skills/neozip-notarization/SKILL.md" ~/.claude/skills/neozip-notarization/
128
+ ```
129
+
130
+ Workspace teams: `cp -R node_modules/neozip-mcp/docs/examples/claude/skills .claude/` and commit.
131
+
132
+ 4. Optional always-on memory: copy [`docs/examples/CLAUDE.md.example`](docs/examples/CLAUDE.md.example) to `CLAUDE.md`.
133
+
134
+ 5. For tokenize/timestamp/encryption: run **`neozip-connect`** once, then start a new Claude Code session.
135
+
136
+ Full guide: [docs/installation-guides/INSTALL_CLAUDE_CODE.md](docs/installation-guides/INSTALL_CLAUDE_CODE.md)
137
+
138
+ ## Cursor setup
139
+
140
+ 1. Install from npm (see above).
141
+ 2. Copy [`.cursor/mcp.json.global.example`](.cursor/mcp.json.global.example) to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project).
142
+ 3. Optional agent steering (pick one):
143
+ - **Skills:** copy [`docs/examples/claude/skills/neozip-mcp/`](docs/examples/claude/skills/neozip-mcp/) to `~/.cursor/skills/neozip-mcp/` (archives), and [`docs/examples/claude/skills/neozip-notarization/`](docs/examples/claude/skills/neozip-notarization/) to `~/.cursor/skills/neozip-notarization/` (tokenize/timestamp/verify + recipient encryption)
144
+ - **Cursor rule:** copy [docs/examples/neozip-mcp-cursor-rule.mdc](docs/examples/neozip-mcp-cursor-rule.mdc) to `~/.cursor/rules/neozip-mcp.mdc`
145
+ 4. For tokenize/timestamp/encryption: run **`neozip-connect`** once, then reload MCP in Cursor Settings.
146
+
147
+ ```json
148
+ {
149
+ "mcpServers": {
150
+ "neozip-mcp": {
151
+ "command": "neozip-mcp",
152
+ "env": {
153
+ "NEOZIP_MCP_SANDBOX_PATHS": "${workspaceFolder},${userHome}"
154
+ }
155
+ }
156
+ }
157
+ }
158
+ ```
159
+
160
+ Capabilities default to **`auto`**: `zip,blockchain,readonly` after `neozip-connect` reaches `phase: ready`, otherwise `zip,readonly`. Set `NEOZIP_MCP_CAPABILITIES` explicitly to override (e.g. `zip` for ZIP-only). See [docs/OPERATIONS.md](docs/OPERATIONS.md) for every tool and option.
161
+
162
+ Connection secrets use **machine-local encryption** in `~/.neozip/connection/`. Optionally set `NEOZIP_UNLOCK_PASSPHRASE` if you use a custom passphrase.
163
+
164
+ ## Configuration
165
+
166
+ ### Environment Variables
167
+
168
+ | Variable | Default | Description |
169
+ |----------|---------|-------------|
170
+ | `NEOZIP_MCP_CAPABILITIES` | `auto` | Tool groups: `zip`, `blockchain`, `readonly`, `account`, or `auto` (default). `auto` → `zip,blockchain,readonly` when connect is `phase: ready` with a valid token; otherwise `zip,readonly` |
171
+ | `NEOZIP_MCP_REQUIRE_ACCOUNT` | on when `account` or `blockchain` cap | Exit at startup if connection not `phase: ready` or token expired (`false` to disable) |
172
+ | `NEOZIP_UNLOCK_PASSPHRASE` | machine-local key | Optional custom passphrase for `~/.neozip/connection/` (default: hostname + username on this machine) |
173
+ | `NEOZIP_MCP_STARTUP_SUMMARY` | on | Log wallet/account summary to stderr on start |
174
+ | `NEOZIP_MCP_SANDBOX_PATHS` | cwd, home | Comma-separated allowed directories |
175
+ | `NEOZIP_MCP_RATE_LIMIT` | `60` | Requests per minute (ZIP tools) |
176
+ | `NEOZIP_MCP_BLOCKCHAIN_RATE_LIMIT` | `10` | Requests per minute (blockchain tools) |
177
+ | `NEOZIP_MCP_MAX_FILE_SIZE` | `524288000` | Max file size in bytes (500 MB) |
178
+ | `NEOZIP_MCP_MAX_ENTRIES` | `10000` | Max ZIP entries |
179
+ | `NEOZIP_MCP_TIMEOUT` | `300` | Operation timeout in seconds |
180
+ | `NEOZIP_MCP_DEFAULT_MAX_CHARS` | `10000` | Default read size for `read_entry` |
181
+ | `NEOZIP_MCP_MAX_READ_CHARS` | `100000` | Hard cap on `read_entry` output |
182
+ | `NEOZIP_MCP_GREP_MAX_MATCHES` | `100` | Default max matches for `grep_entries` |
183
+ | `NEOZIP_MCP_GREP_MAX_SNIPPET_CHARS` | `200` | Max snippet length per grep match |
184
+ | `NEOZIP_MCP_GREP_MAX_FILE_BYTES` | `1048576` | Skip grepping entries larger than this (bytes) |
185
+ | `NEOZIP_MCP_API_KEY` | -- | Optional API key for access control |
186
+ | `NEOZIP_NETWORK` | `base-sepolia` | Blockchain network for tokenize/mint |
187
+ | `NEOZIP_TOKEN_SERVICE_INFO_URL` | `{profile URL}/info` | Link shown when Token Service setup is required |
188
+ | `NEOZIP_IDENTITY_PRIVATE_KEY_HEX` | -- | Optional X25519 private key (hex) for opening recipient-encrypted archives (MCP env only) |
189
+
190
+ Token Service email, access token, wallet key, and service URL come from **`neozip-connect`** (`~/.neozip/connection/`), not MCP env or NeoZip Desktop `wallet.json`.
191
+
192
+ ## Documentation
193
+
194
+ The following documentation is included with this package:
195
+
196
+ - **[README.md](README.md)** — Installation, MCP host setup, configuration
197
+ - **[DOCUMENTATION.md](DOCUMENTATION.md)** — Documentation index
198
+ - **[CHANGELOG.md](CHANGELOG.md)** — Version history
199
+ - **[SECURITY.md](SECURITY.md)** — Security considerations
200
+ - **[docs/OPERATIONS.md](docs/OPERATIONS.md)** — Full MCP tool reference
201
+
202
+ ## Publishing (npm)
203
+
204
+ The published tarball includes **`dist/`**, **`docs/`**, **`README.md`**, **`LICENSE`**, **`CHANGELOG.md`**, **`DOCUMENTATION.md`**, and **`SECURITY.md`** only. Preview with **`pnpm pack:dry-run`**.
205
+
206
+ Maintainers: see the [PUBLISHING.md](https://github.com/NeoWareInc/neozip-mcp/blob/main/docs-dev/PUBLISHING.md) guide in the GitHub repository.
207
+
208
+ ## Contributing
209
+
210
+ We welcome feedback and bug reports:
211
+
212
+ 1. **Report issues:** [GitHub Issues](https://github.com/NeoWareInc/neozip-support/issues) or [support@neozip.io](mailto:support@neozip.io)
213
+ 2. **Test and provide feedback:** Help us improve by testing in your MCP host
214
+
215
+ ## License
216
+
217
+ Proprietary — NeoWare, Inc. All rights reserved. See [LICENSE](LICENSE).
218
+
219
+ ## Support
220
+
221
+ - **GitHub Issues:** [NeoWareInc/neozip-support](https://github.com/NeoWareInc/neozip-support/issues)
222
+ - **Email:** [support@neozip.io](mailto:support@neozip.io)
223
+ - **Documentation:** [DOCUMENTATION.md](DOCUMENTATION.md)
package/SECURITY.md ADDED
@@ -0,0 +1,37 @@
1
+ # Security
2
+
3
+ Security considerations for **neozip-mcp** and how to report vulnerabilities.
4
+
5
+ ## Scope of this package
6
+
7
+ **neozip-mcp** is a local MCP (stdio) server. It reads and writes ZIP archives within configured sandbox paths, optionally talks to the NeoZip Token Service and Base network, and stores account credentials in `~/.neozip/connection/` (machine-local encryption).
8
+
9
+ ZIP format handling uses [neozipkit](https://www.npmjs.com/package/neozipkit). On-chain operations use [neozip-blockchain](https://www.npmjs.com/package/neozip-blockchain). See those packages for library-level crypto and archive security.
10
+
11
+ ## MCP host configuration
12
+
13
+ - **Sandbox paths** — Set `NEOZIP_MCP_SANDBOX_PATHS` to the smallest directory set the agent needs. The server rejects paths outside the allowlist.
14
+ - **Capabilities** — Default `auto` enables blockchain tools only after `neozip-connect` reaches `phase: ready`. Use `NEOZIP_MCP_CAPABILITIES=zip,readonly` for ZIP-only hosts.
15
+ - **Secrets in env** — Do not put wallet keys, Token Service tokens, or archive passwords in MCP `env` blocks committed to git. Use `neozip-connect` for account secrets; pass archive passwords per tool call when needed.
16
+
17
+ ## Connection store
18
+
19
+ - Credentials live under `~/.neozip/connection/` and are encrypted with a machine-local key (hostname + username by default, or `NEOZIP_UNLOCK_PASSPHRASE`).
20
+ - Treat this directory like SSH keys: restrict filesystem permissions and do not copy it to shared machines without understanding the risk.
21
+
22
+ ## General practices
23
+
24
+ - **Dependencies** — Run `pnpm audit` (or `npm audit`) before release; address high/critical issues.
25
+ - **Published tarball** — Recipient encryption code is bundled into `dist/vendor/neozipkit-pro.js` at build time; the published package does not require `@neowareinc/neozipkit-pro` at install time.
26
+ - **Inputs** — The server validates paths via `PathSandbox`; still avoid pointing sandbox paths at sensitive system directories unless required.
27
+
28
+ ## Reporting a vulnerability
29
+
30
+ 1. **Do not** open a public GitHub issue for security bugs.
31
+ 2. Report privately via [GitHub Security Advisories](https://github.com/NeoWareInc/neozip-mcp/security/advisories) for this repository, or email [support@neozip.io](mailto:support@neozip.io).
32
+ 3. Allow time for a fix before public disclosure.
33
+
34
+ ## References
35
+
36
+ - [OWASP Top 10](https://owasp.org/www-project-top-ten/)
37
+ - [Model Context Protocol security best practices](https://modelcontextprotocol.io/)
@@ -0,0 +1,86 @@
1
+ import { getTokenServiceUrl } from "neozip-blockchain/token-service";
2
+ import { maskEmail } from "../util/mask.js";
3
+ import { getActiveProfile, getActiveProfileId, listProfiles, readActiveSecrets, } from "./profile-store.js";
4
+ import { fetchCoordinatorConfig } from "./token-service-identity.js";
5
+ function nextStepsForPhase(phase) {
6
+ switch (phase) {
7
+ case "no_profile":
8
+ return listProfiles().length > 0
9
+ ? ["account_select", "account_list", "account_create"]
10
+ : ["account_create", "account_list"];
11
+ case "email_unverified":
12
+ return ["account_register_email", "account_verify_email"];
13
+ case "no_wallet":
14
+ return ["account_create_wallet", "account_import_wallet"];
15
+ case "wallet_unlinked":
16
+ return ["account_link_wallet"];
17
+ case "identity_missing":
18
+ return ["account_provision_identity"];
19
+ case "ready":
20
+ return ["account_logout"];
21
+ case "degraded":
22
+ return ["account_status"];
23
+ default:
24
+ return ["account_status"];
25
+ }
26
+ }
27
+ export function computeAccountPhase() {
28
+ const profileId = getActiveProfileId();
29
+ if (!profileId) {
30
+ return "no_profile";
31
+ }
32
+ const profile = getActiveProfile();
33
+ const secrets = readActiveSecrets();
34
+ if (!profile || !secrets)
35
+ return "no_profile";
36
+ if (!secrets.accessToken || !profile.emailVerified) {
37
+ return "email_unverified";
38
+ }
39
+ if (!secrets.evmPrivateKey || !profile.evmAddress) {
40
+ return "no_wallet";
41
+ }
42
+ if (!profile.walletId || profile.linkId == null) {
43
+ return "wallet_unlinked";
44
+ }
45
+ if (!profile.identityKeyId) {
46
+ return "identity_missing";
47
+ }
48
+ return "ready";
49
+ }
50
+ export async function buildAccountStatusReport(options) {
51
+ const profile = getActiveProfile();
52
+ const phase = computeAccountPhase();
53
+ const tokenServiceUrl = getTokenServiceUrl({
54
+ serverUrl: profile?.tokenServiceUrl || process.env.TOKEN_SERVICE_URL || undefined,
55
+ });
56
+ let tokenServiceReachable = null;
57
+ if (options?.probeTokenService !== false) {
58
+ try {
59
+ tokenServiceReachable = await fetchCoordinatorConfig(tokenServiceUrl);
60
+ }
61
+ catch {
62
+ tokenServiceReachable = false;
63
+ }
64
+ }
65
+ const nextSteps = nextStepsForPhase(tokenServiceReachable === false && phase !== "ready" ? "degraded" : phase);
66
+ const reloadRequired = phase === "ready" &&
67
+ Boolean(profile &&
68
+ (!process.env.NEOZIP_TOKEN_SERVICE_ACCESS_TOKEN ||
69
+ !process.env.NEOZIP_WALLET_PASSKEY));
70
+ return {
71
+ success: true,
72
+ phase: tokenServiceReachable === false && phase !== "ready" ? "degraded" : phase,
73
+ activeProfileId: getActiveProfileId(),
74
+ profile: profile
75
+ ? {
76
+ ...profile,
77
+ email: profile.email ? maskEmail(profile.email) : null,
78
+ }
79
+ : null,
80
+ tokenServiceReachable,
81
+ tokenServiceUrl,
82
+ nextSteps,
83
+ reloadRequired,
84
+ };
85
+ }
86
+ //# sourceMappingURL=account-state.js.map
@@ -0,0 +1,37 @@
1
+ export function formatAccountStatusText(report) {
2
+ const lines = [];
3
+ lines.push("NeoZip account status");
4
+ lines.push(`Phase: ${report.phase}`);
5
+ lines.push(`Token Service: ${report.tokenServiceUrl}`);
6
+ if (report.tokenServiceReachable != null) {
7
+ lines.push(`Token Service reachable: ${report.tokenServiceReachable ? "yes" : "no"}`);
8
+ }
9
+ if (report.activeProfileId) {
10
+ lines.push(`Active profile: ${report.activeProfileId}`);
11
+ }
12
+ if (report.profile) {
13
+ lines.push(`Label: ${report.profile.label}`);
14
+ if (report.profile.email)
15
+ lines.push(`Email: ${report.profile.email}`);
16
+ if (report.profile.evmAddress) {
17
+ lines.push(`EVM address: ${report.profile.evmAddress}`);
18
+ }
19
+ if (report.profile.walletId != null) {
20
+ lines.push(`Wallet ID: ${report.profile.walletId}`);
21
+ }
22
+ if (report.profile.identityKeyId != null) {
23
+ lines.push(`Identity key ID: ${report.profile.identityKeyId}`);
24
+ }
25
+ if (report.profile.x25519Fingerprint) {
26
+ lines.push(`X25519 fingerprint: ${report.profile.x25519Fingerprint}`);
27
+ }
28
+ }
29
+ if (report.nextSteps.length) {
30
+ lines.push(`Next steps: ${report.nextSteps.join(", ")}`);
31
+ }
32
+ if (report.reloadRequired) {
33
+ lines.push("Reload MCP in Cursor so the active connection credentials are loaded into this session.");
34
+ }
35
+ return lines.join("\n");
36
+ }
37
+ //# sourceMappingURL=format-account-status.js.map
@@ -0,0 +1,75 @@
1
+ import { IdentityKeyTamperError } from "../archive/identity-key.js";
2
+ import { fetchCryptoSelf } from "../archive/crypto-self.js";
3
+ import { buildIdentityKeyInitMessage, wrapNewX25519Keypair, } from "./identity-wrap.js";
4
+ import { IdentityKeyConflictError, completeIdentityKeyInit, getIdentityKeyBundle, requestIdentityKeyInitChallenge, } from "./token-service-identity.js";
5
+ import { rawEoaBytes, signEvmMessage } from "./wallet-evm.js";
6
+ export async function provisionWalletIdentityKey(params) {
7
+ const existing = await getIdentityKeyBundle(params.baseUrl, params.accessToken, params.walletId);
8
+ if (existing.found) {
9
+ return {
10
+ identityKeyId: existing.identityKeyId,
11
+ x25519PublicKey: existing.x25519PublicKey,
12
+ provisioned: false,
13
+ };
14
+ }
15
+ const eoaPriv = rawEoaBytes(params.evmPrivateKey);
16
+ try {
17
+ const wrap = wrapNewX25519Keypair({
18
+ rawEoaPrivBytes: eoaPriv,
19
+ evmAddress: params.evmAddress,
20
+ });
21
+ const bundleBody = {
22
+ x25519PublicKeyB64: wrap.x25519PublicKeyB64,
23
+ ...wrap.bundle,
24
+ };
25
+ const challenge = await requestIdentityKeyInitChallenge(params.baseUrl, params.accessToken, params.walletId, bundleBody);
26
+ const expectedMessage = buildIdentityKeyInitMessage({
27
+ walletId: params.walletId,
28
+ challengeId: challenge.challengeId,
29
+ evmAddress: params.evmAddress,
30
+ formatVersion: wrap.bundle.wrapFormatVersion,
31
+ x25519PublicKeyB64: wrap.x25519PublicKeyB64,
32
+ wrappedSha256Hex: wrap.wrappedSha256Hex,
33
+ });
34
+ if (challenge.message !== expectedMessage) {
35
+ throw new IdentityKeyTamperError("Server init message does not match canonical form expected by this client.");
36
+ }
37
+ const evmSignature = await signEvmMessage(params.evmPrivateKey, challenge.message);
38
+ try {
39
+ const completed = await completeIdentityKeyInit(params.baseUrl, params.accessToken, params.walletId, bundleBody, challenge.challengeId, evmSignature);
40
+ return {
41
+ identityKeyId: completed.identityKeyId,
42
+ x25519PublicKey: completed.x25519PublicKey,
43
+ provisioned: true,
44
+ };
45
+ }
46
+ catch (err) {
47
+ if (err instanceof IdentityKeyConflictError) {
48
+ const reloaded = await getIdentityKeyBundle(params.baseUrl, params.accessToken, params.walletId);
49
+ if (reloaded.found) {
50
+ return {
51
+ identityKeyId: reloaded.identityKeyId,
52
+ x25519PublicKey: reloaded.x25519PublicKey,
53
+ provisioned: false,
54
+ };
55
+ }
56
+ }
57
+ throw err;
58
+ }
59
+ }
60
+ finally {
61
+ eoaPriv.fill(0);
62
+ }
63
+ }
64
+ /** Sync profile metadata with live /crypto/self when token is available. */
65
+ export async function refreshIdentityFromCryptoSelf(config) {
66
+ const self = await fetchCryptoSelf(config);
67
+ if (!self.ok) {
68
+ return { identityKeyId: null, walletId: null };
69
+ }
70
+ return {
71
+ identityKeyId: self.data.identityKeyId,
72
+ walletId: self.data.walletId,
73
+ };
74
+ }
75
+ //# sourceMappingURL=identity-provision.js.map
@@ -0,0 +1,69 @@
1
+ import * as crypto from "node:crypto";
2
+ import { WRAP_AEAD, WRAP_FORMAT_VERSION, WRAP_IV_LEN, WRAP_KDF_INFO, WRAP_KDF_SALT_LEN, } from "../constants/wallet-identity.js";
3
+ function buildCanonicalAad(params) {
4
+ const lowerAddr = params.evmAddress.toLowerCase();
5
+ const addrBytes = Buffer.from(lowerAddr, "ascii");
6
+ return Buffer.concat([
7
+ addrBytes,
8
+ Buffer.from([WRAP_FORMAT_VERSION]),
9
+ params.x25519SpkiDer,
10
+ ]);
11
+ }
12
+ function deriveKek(rawEoaPrivBytes, saltB64) {
13
+ const salt = Buffer.from(saltB64, "base64");
14
+ if (salt.length !== WRAP_KDF_SALT_LEN) {
15
+ throw new Error(`Wrap KDF salt must be ${WRAP_KDF_SALT_LEN} bytes`);
16
+ }
17
+ return Buffer.from(crypto.hkdfSync("sha256", rawEoaPrivBytes, salt, WRAP_KDF_INFO, 32));
18
+ }
19
+ function sha256Hex(buf) {
20
+ return crypto.createHash("sha256").update(buf).digest("hex");
21
+ }
22
+ export function buildIdentityKeyInitMessage(params) {
23
+ return [
24
+ "NeoZip Token Service identity key init",
25
+ `walletId:${params.walletId}`,
26
+ `challenge:${params.challengeId}`,
27
+ `address:${params.evmAddress.toLowerCase()}`,
28
+ `formatVersion:${params.formatVersion}`,
29
+ `x25519:${params.x25519PublicKeyB64}`,
30
+ `wrappedSha256:${params.wrappedSha256Hex}`,
31
+ ].join("\n");
32
+ }
33
+ export function wrapNewX25519Keypair(params) {
34
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("x25519");
35
+ const spkiDer = publicKey.export({ type: "spki", format: "der" });
36
+ const pkcs8Der = privateKey.export({ type: "pkcs8", format: "der" });
37
+ const rawPriv = pkcs8Der.subarray(pkcs8Der.length - 32);
38
+ const saltB64 = crypto.randomBytes(WRAP_KDF_SALT_LEN).toString("base64");
39
+ const ivB64 = crypto.randomBytes(WRAP_IV_LEN).toString("base64");
40
+ const aad = buildCanonicalAad({
41
+ evmAddress: params.evmAddress,
42
+ x25519SpkiDer: spkiDer,
43
+ });
44
+ const kek = deriveKek(params.rawEoaPrivBytes, saltB64);
45
+ const iv = Buffer.from(ivB64, "base64");
46
+ const cipher = crypto.createCipheriv("aes-256-gcm", kek, iv);
47
+ cipher.setAAD(aad);
48
+ const ct = Buffer.concat([cipher.update(rawPriv), cipher.final()]);
49
+ const tag = cipher.getAuthTag();
50
+ const wrapped = Buffer.concat([ct, tag]);
51
+ kek.fill(0);
52
+ rawPriv.fill(0);
53
+ pkcs8Der.fill(0);
54
+ const bundle = {
55
+ wrappedPrivateKeyB64: wrapped.toString("base64"),
56
+ wrapFormatVersion: WRAP_FORMAT_VERSION,
57
+ wrapKdfInfo: WRAP_KDF_INFO,
58
+ wrapKdfSaltB64: saltB64,
59
+ wrapAead: WRAP_AEAD,
60
+ wrapIvB64: ivB64,
61
+ wrapAadB64: aad.toString("base64"),
62
+ };
63
+ return {
64
+ bundle,
65
+ x25519PublicKeyB64: spkiDer.toString("base64"),
66
+ wrappedSha256Hex: sha256Hex(wrapped),
67
+ };
68
+ }
69
+ //# sourceMappingURL=identity-wrap.js.map
@@ -0,0 +1,47 @@
1
+ import * as crypto from "node:crypto";
2
+ import * as os from "node:os";
3
+ const PROFILE_KDF_INFO = "NeoZip/McpProfileSecrets/v1";
4
+ const PROFILE_KDF_SALT = Buffer.from("NeoZipMcpProfileStoreSalt-v1", "utf8");
5
+ export function deriveProfileKey() {
6
+ const passphrase = process.env.NEOZIP_UNLOCK_PASSPHRASE?.trim() ||
7
+ `${os.hostname()}:${os.userInfo().username}:neozip-mcp-profile`;
8
+ const okm = crypto.hkdfSync("sha256", Buffer.from(passphrase, "utf8"), PROFILE_KDF_SALT, PROFILE_KDF_INFO, 32);
9
+ return Buffer.from(okm);
10
+ }
11
+ export function encryptJson(payload) {
12
+ const key = deriveProfileKey();
13
+ const iv = crypto.randomBytes(12);
14
+ const plaintext = Buffer.from(JSON.stringify(payload), "utf8");
15
+ try {
16
+ const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
17
+ const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
18
+ const tag = cipher.getAuthTag();
19
+ return JSON.stringify({
20
+ v: 1,
21
+ iv: iv.toString("base64"),
22
+ tag: tag.toString("base64"),
23
+ data: ct.toString("base64"),
24
+ });
25
+ }
26
+ finally {
27
+ key.fill(0);
28
+ plaintext.fill(0);
29
+ }
30
+ }
31
+ export function decryptJson(encrypted) {
32
+ const key = deriveProfileKey();
33
+ const parsed = JSON.parse(encrypted);
34
+ const iv = Buffer.from(parsed.iv, "base64");
35
+ const tag = Buffer.from(parsed.tag, "base64");
36
+ const ct = Buffer.from(parsed.data, "base64");
37
+ try {
38
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
39
+ decipher.setAuthTag(tag);
40
+ const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
41
+ return JSON.parse(pt.toString("utf8"));
42
+ }
43
+ finally {
44
+ key.fill(0);
45
+ }
46
+ }
47
+ //# sourceMappingURL=profile-crypto.js.map