artifacty 0.8.0 → 0.10.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 CHANGED
@@ -82,6 +82,31 @@ artifacty install all
82
82
  artifacty check
83
83
  ```
84
84
 
85
+ For a central internal server, enable the HTTP MCP endpoint on the server and
86
+ let users issue personal MCP/API tokens from the account page:
87
+
88
+ ```bash
89
+ ARTIFACTY_BOOTSTRAP_TOKEN="$(artifacty token --raw)"
90
+ artifacty serve --host 10.0.0.50 --share-mode team --api-token "$ARTIFACTY_BOOTSTRAP_TOKEN" --mcp-http --foreground
91
+ # Open http://10.0.0.50:8787/login, create the first admin, then create a personal token at /account.
92
+ artifacty install all --mcp-url http://10.0.0.50:8787/mcp --api-token "$ARTIFACTY_PERSONAL_TOKEN"
93
+ ```
94
+
95
+ Administrators can create users individually at `/admin/users` or import them
96
+ from CSV. Use `email,name,role,password,password_reset_required` headers. If
97
+ `password` is empty, Artifacty generates a temporary password, shows it once in
98
+ the import result, and requires the user to change it on first sign-in.
99
+
100
+ ```csv
101
+ email,name,role
102
+ user@example.com,User,user
103
+ admin2@example.com,Admin Two,admin
104
+ ```
105
+
106
+ ```bash
107
+ artifacty users import --file users.csv
108
+ ```
109
+
85
110
  Run diagnostics for the local runtime, store, server, service definitions, and MCP discovery:
86
111
 
87
112
  ```bash
@@ -185,6 +210,7 @@ Run the MCP server:
185
210
 
186
211
  ```bash
187
212
  artifacty-mcp
213
+ ARTIFACTY_MCP_MODE=bridge ARTIFACTY_MCP_URL=http://10.0.0.50:8787/mcp ARTIFACTY_API_TOKEN=... artifacty-mcp
188
214
  ```
189
215
 
190
216
  MCP clients can create artifacts with `artifacty_create`. `artifacty_publish` remains as a backwards-compatible alias.
@@ -296,12 +322,14 @@ Schema and storage:
296
322
  - Copilot/Cursor examples cover PR reviews, screenshots, demo recordings, and visual evidence bundles.
297
323
  - See [docs/artifact-schema-v1.md](docs/artifact-schema-v1.md).
298
324
  - See [docs/mcp-public-api.md](docs/mcp-public-api.md) for MCP tools, resources, prompts, and compatibility notes.
325
+ - See [docs/central-team-deployment-design.md](docs/central-team-deployment-design.md) for central team deployment.
299
326
  - See [docs/sarif-csv-artifact-plan.md](docs/sarif-csv-artifact-plan.md) for the SARIF/CSV output artifact roadmap.
300
327
 
301
328
  ## Security Model
302
329
 
303
330
  - The HTTP server binds to `127.0.0.1` by default.
304
331
  - If `ARTIFACTY_API_TOKEN` is set, HTTP API routes require `Authorization: Bearer <token>` or `x-artifacty-token`; scripts should prefer headers over `?token=...` URLs.
332
+ - When users exist, personal API tokens issued from `/account` also authenticate HTTP API and MCP requests, and audit logs record the token owner's email as `actor`.
305
333
  - API token checks use timing-safe digest comparison.
306
334
  - Binding outside localhost requires both `ARTIFACTY_SHARE_MODE=lan` or `team` and `ARTIFACTY_API_TOKEN`.
307
335
  - Non-local sharing is intended for trusted LAN or VPN sessions. Prefer a specific interface IP over `0.0.0.0`, keep React rendering disabled, and see [docs/network-sharing.md](docs/network-sharing.md).
@@ -0,0 +1,212 @@
1
+ # Central Team Deployment Design
2
+
3
+ This document defines the design for running Artifacty as a shared internal
4
+ service, where many users connect Claude Code, Codex, Gemini, GitHub Copilot,
5
+ Cursor, or another MCP client to one central Artifacty server.
6
+
7
+ ## Problem
8
+
9
+ Artifacty is local-first by default. The HTTP server can listen on a LAN
10
+ address, and the MCP server can either read and write the local `ARTIFACTY_HOME`
11
+ store directly or run as a stdio bridge to a central `/mcp` endpoint. The
12
+ installer `--url` option only controls the browser URL returned in MCP
13
+ responses; central MCP mode is selected with `--mcp-url`.
14
+
15
+ For a central deployment, every MCP client must write through the central
16
+ service instead of touching local SQLite or shared network files. The preferred
17
+ central surface is the native HTTP `/mcp` endpoint. A local stdio bridge remains
18
+ the default installer path for broad client compatibility.
19
+
20
+ ## Goals
21
+
22
+ - One central Artifacty store per internal deployment.
23
+ - Native central MCP over Streamable HTTP for clients that support remote MCP.
24
+ - Per-user local stdio bridge compatibility for clients that only support local
25
+ stdio MCP configuration.
26
+ - Stable install commands that can target a central server.
27
+ - Token-authenticated HTTP writes with no token leakage through query strings.
28
+ - Clear audit attribution for user, agent, host, and client surface.
29
+ - Safe defaults for LAN/team operation without weakening local-first behavior.
30
+
31
+ ## Non-Goals
32
+
33
+ - Public internet hosting without a reverse proxy, TLS, and stronger auth.
34
+ - SQLite access over NFS or SMB as the recommended sharing model.
35
+ - Relaxing browser-origin checks to make remote browser writes easier.
36
+ - Removing the local stdio MCP path for single-user or legacy clients.
37
+
38
+ ## Target Architecture
39
+
40
+ ```text
41
+ MCP client with remote transport support
42
+ -> https://artifacty.internal/mcp
43
+ -> central Artifacty MCP handler
44
+ -> central SQLite store and immutable version files
45
+ -> browser dashboard at the same central URL
46
+
47
+ MCP client with stdio-only support
48
+ -> local Artifacty stdio bridge
49
+ -> https://artifacty.internal/mcp
50
+ -> same central MCP handler
51
+ ```
52
+
53
+ The central MCP handler is the canonical team integration surface. HTTP JSON API
54
+ routes remain useful for scripts, browser workflows, and compatibility, but MCP
55
+ tool semantics should not be reimplemented separately in a REST-only bridge.
56
+ Both stdio and Streamable HTTP should share the same tool/resource/prompt
57
+ dispatcher.
58
+
59
+ ## Runtime Modes
60
+
61
+ Artifacty supports these explicit MCP operation modes:
62
+
63
+ - `local`: default mode; MCP reads and writes the local store directly.
64
+ - `streamable-http`: a central `/mcp` endpoint serves MCP over HTTP when
65
+ `--mcp-http` or `ARTIFACTY_MCP_HTTP=true` is enabled.
66
+ - `bridge`: local stdio process forwards MCP JSON-RPC to a remote `/mcp`
67
+ endpoint for clients that cannot connect to remote MCP directly.
68
+
69
+ Mode selection should be explicit. `ARTIFACTY_URL` must remain the public
70
+ browser URL override for backwards compatibility. New variables should define
71
+ remote MCP behavior:
72
+
73
+ ```bash
74
+ ARTIFACTY_MCP_MODE=bridge
75
+ ARTIFACTY_MCP_URL=https://artifacty.internal/mcp
76
+ ARTIFACTY_API_TOKEN=...
77
+ ```
78
+
79
+ `ARTIFACTY_URL` may default to the central browser URL when not set, but browser
80
+ links and MCP transport URLs should stay separate in the code and documentation.
81
+
82
+ ## Installer UX
83
+
84
+ The installer exposes central-server options for every supported client:
85
+
86
+ ```bash
87
+ artifacty install codex \
88
+ --mcp-url https://artifacty.internal/mcp \
89
+ --api-token "$ARTIFACTY_API_TOKEN"
90
+ ```
91
+
92
+ Equivalent commands work for `claude`, `gemini`, `copilot`, `cursor`, and `all`.
93
+
94
+ The current installer generates a local bridge entry for every supported client:
95
+
96
+ ```json
97
+ {
98
+ "ARTIFACTY_MCP_MODE": "bridge",
99
+ "ARTIFACTY_MCP_URL": "https://artifacty.internal/mcp",
100
+ "ARTIFACTY_API_TOKEN": "..."
101
+ }
102
+ ```
103
+
104
+ The installer should continue to support `--url` for link-only overrides.
105
+ `--mcp-url` should imply central MCP behavior; `--url` should not.
106
+
107
+ ## Central Server Operation
108
+
109
+ A minimal LAN deployment should bind to a specific internal interface and require
110
+ token auth:
111
+
112
+ ```bash
113
+ ARTIFACTY_API_TOKEN="$(artifacty token --raw)"
114
+ ARTIFACTY_SHARE_MODE=team \
115
+ artifacty serve \
116
+ --host 10.0.0.50 \
117
+ --port 8787 \
118
+ --api-token "$ARTIFACTY_API_TOKEN" \
119
+ --mcp-http
120
+ ```
121
+
122
+ Open `/login` after the server starts. If no users exist, the first successful
123
+ login form creates an administrator. Administrators can create users from
124
+ `/admin/users`, paste-import users from CSV, and every user can create or
125
+ revoke personal API tokens from `/account`. CSV imports support
126
+ `email,name,role,password,password_reset_required`; blank passwords are
127
+ generated once and require a password change on first sign-in. Use personal
128
+ tokens for `artifacty install ... --api-token` so MCP and API audit logs record
129
+ the user's email as `actor`.
130
+
131
+ Production-like internal deployments should run Artifacty behind a TLS reverse
132
+ proxy, keep `ARTIFACTY_ENABLE_REACT_RENDERER` disabled unless the team trusts
133
+ all artifact authors, and store `ARTIFACTY_HOME` on local server disk with
134
+ regular backups.
135
+
136
+ The central server exposes `/mcp` only when explicitly enabled. This keeps the
137
+ local browser/API server behavior unchanged while making team MCP exposure an
138
+ intentional operating mode.
139
+
140
+ ## MCP Requirements
141
+
142
+ Remote MCP mode needs complete parity with local MCP tools:
143
+
144
+ - create/import/list/get/update/archive/restore/audit/info
145
+ - resources: recent artifact list, artifact by ID, schema
146
+ - prompts: handoff, review, test report, visual QA, release notes
147
+
148
+ The stdio server and `/mcp` HTTP endpoint call the same dispatcher so tool
149
+ schemas, resources, prompts, validation, and audit behavior cannot drift.
150
+
151
+ All remote MCP requests must send `Authorization: Bearer` or an equivalent
152
+ header accepted by the central endpoint. Remote MCP should never place tokens in
153
+ URLs.
154
+
155
+ ## Audit and Identity
156
+
157
+ Remote MCP requests should include headers such as:
158
+
159
+ ```text
160
+ x-artifacty-client: codex
161
+ x-artifacty-actor: user@example.com
162
+ x-artifacty-host: IRAE-MACBOOK
163
+ ```
164
+
165
+ The server records the authenticated user's email as the audit `actor` when a
166
+ personal token is used. The `x-artifacty-actor` header remains a compatibility
167
+ fallback for the bootstrap/global token path.
168
+
169
+ ## Security Model
170
+
171
+ Central mode increases the trust boundary from one machine to a team network.
172
+ Required safeguards:
173
+
174
+ - non-loopback binding still requires `ARTIFACTY_SHARE_MODE=lan|team`
175
+ - central API always requires `ARTIFACTY_API_TOKEN`
176
+ - remote MCP uses header auth only
177
+ - shared instances should prefer TLS through a reverse proxy
178
+ - browser-origin protections remain in place
179
+ - artifact renderers continue treating stored content as untrusted
180
+
181
+ For larger organizations, the next step after personal tokens is scoped tokens,
182
+ token rotation policy, and SSO/OIDC.
183
+
184
+ ## Current Implementation
185
+
186
+ - `artifacty serve --mcp-http` exposes `POST /mcp`.
187
+ - `ARTIFACTY_MCP_MODE=bridge` forwards stdio JSON-RPC to `ARTIFACTY_MCP_URL`.
188
+ - `artifacty install <agent> --mcp-url ... --api-token ...` writes bridge env
189
+ config for Claude, Codex, Gemini, GitHub Copilot, and Cursor.
190
+ - `/login`, `/account`, and `/admin/users` provide server-side user management,
191
+ administrator/user roles, CSV user import, required password reset, password
192
+ change, and personal token issue/revoke flows.
193
+ - Remote MCP requests use header auth and never put tokens in URLs.
194
+ - Tests cover direct HTTP MCP calls and stdio bridge calls to a token-protected
195
+ central server.
196
+
197
+ ## Remaining Work
198
+
199
+ - Client-specific direct remote MCP config generation where the client supports
200
+ it.
201
+ - Scoped tokens, token rotation policy, and stronger audit identity.
202
+ - Optional reverse proxy examples for TLS termination.
203
+
204
+ ## Acceptance Criteria
205
+
206
+ - A user can install Artifacty MCP against a central `/mcp` endpoint without
207
+ sharing a filesystem.
208
+ - Artifacts created from any supported MCP client appear in the central
209
+ dashboard and are visible to other clients.
210
+ - Local MCP behavior remains unchanged when remote mode is not configured.
211
+ - Tokens are sent only in headers.
212
+ - CI covers remote MCP parity against the HTTP API.
@@ -68,6 +68,8 @@ Useful environment variables:
68
68
 
69
69
  - `ARTIFACTY_HOME`: store directory, shared by all agents.
70
70
  - `ARTIFACTY_URL`: optional browser URL override. Leave it unset to let MCP read the last running server URL from `server.json`.
71
+ - `ARTIFACTY_MCP_MODE`: `local` by default, or `bridge` to forward stdio MCP to a central HTTP MCP endpoint.
72
+ - `ARTIFACTY_MCP_URL`: central MCP endpoint used by bridge mode, for example `http://10.0.0.50:8787/mcp`.
71
73
  - `ARTIFACTY_API_TOKEN`: required token for HTTP API routes when configured. Generate one with `node src/cli.js token --raw`.
72
74
  - `ARTIFACTY_SHARE_MODE`: set to `lan` or `team` before binding outside localhost.
73
75
  - `ARTIFACTY_ALLOW_SECRETS`: set to `true` only when intentionally storing detected secrets.
@@ -86,12 +88,47 @@ node src/cli.js install all
86
88
  node src/cli.js check
87
89
  ```
88
90
 
91
+ Central team server setup:
92
+
93
+ ```bash
94
+ ARTIFACTY_BOOTSTRAP_TOKEN="$(node src/cli.js token --raw)"
95
+ node src/cli.js serve --foreground \
96
+ --host 10.0.0.50 \
97
+ --share-mode team \
98
+ --api-token "$ARTIFACTY_BOOTSTRAP_TOKEN" \
99
+ --mcp-http
100
+ # Open http://10.0.0.50:8787/login, create the first admin, then create a personal token at /account.
101
+ node src/cli.js install all \
102
+ --mcp-url http://10.0.0.50:8787/mcp \
103
+ --api-token "$ARTIFACTY_PERSONAL_TOKEN"
104
+ ```
105
+
106
+ Administrators can create users one at a time from `/admin/users` or import a
107
+ CSV from the same page. The CLI can import the same file when run on the server:
108
+
109
+ ```csv
110
+ email,name,role,password,password_reset_required
111
+ user@example.com,User,user,,
112
+ admin2@example.com,Admin Two,admin,temporary-password,true
113
+ ```
114
+
115
+ ```bash
116
+ artifacty users import --file users.csv
117
+ ```
118
+
119
+ Rows without a password receive a generated temporary password. Generated
120
+ passwords are shown only in the import result, and imported users must change
121
+ their password before they can continue to `/account` and issue MCP/API tokens.
122
+
89
123
  - Claude: writes project `.mcp.json`. Claude Code's startup timeout is controlled by the parent `MCP_TIMEOUT` environment variable and defaults to 30 seconds, so Artifacty does not add a per-server `.mcp.json` `timeout` field.
90
124
  - Codex: writes or replaces the `[mcp_servers.artifacty]` block in `~/.codex/config.toml` unless `--config` is provided. The generated block uses a 30 second startup timeout so slower Windows or cold-start environments can load the MCP server reliably.
91
125
  - Gemini: writes project `.gemini/settings.json` with a 30 second timeout.
92
126
  - GitHub Copilot in VS Code: writes workspace `.vscode/mcp.json` using the VS Code `servers` shape. Pass `--config` to target a user-profile `mcp.json` instead.
93
127
  - Cursor: writes project `.cursor/mcp.json` using the Cursor `mcpServers` shape. Pass `--config ~/.cursor/mcp.json` for global Cursor setup.
94
128
  - `--dry-run` returns the generated config without writing it.
129
+ - `--mcp-url <url>` installs stdio bridge mode for central Artifacty. If the URL has no path, `/mcp` is appended.
130
+ - `--api-token <token>` is written into the generated MCP environment for bridge mode. For central servers, prefer a personal token issued from `/account`.
131
+ - `--url <url>` remains a browser-link override and does not enable central MCP by itself.
95
132
  - `--timeout <ms>` adjusts Codex `startup_timeout_sec` and Gemini `timeout`. It does not change Claude Code startup behavior; set `MCP_TIMEOUT` before launching Claude Code if you need a larger value there.
96
133
  - `check` starts the local MCP server and verifies required tools, resources, and prompts through MCP discovery methods.
97
134
  - `doctor` combines MCP discovery with runtime, storage, server, and service diagnostics.
@@ -278,6 +315,7 @@ tests.
278
315
  - `GET /import`: browser artifact import form.
279
316
  - `POST /import`: convert and save pasted agent output.
280
317
  - `GET /health`: health check.
318
+ - `POST /mcp`: token-protected MCP Streamable HTTP JSON-RPC endpoint when `--mcp-http` or `ARTIFACTY_MCP_HTTP=true` is enabled.
281
319
  - `GET /api/artifacts`: list artifacts.
282
320
  - `POST /api/artifacts`: create artifact.
283
321
  - `POST /api/import`: convert and save an agent-produced artifact.
@@ -295,7 +333,7 @@ tests.
295
333
  - `GET /artifacts/:id/diff`: compare two versions.
296
334
  - `GET /artifacts/:id/raw?version=n`: raw content.
297
335
 
298
- When `ARTIFACTY_API_TOKEN` is configured, `/api/*` routes require either `Authorization: Bearer <token>` or `x-artifacty-token: <token>`. Browser forms can also carry `?token=<token>` in the URL, which is copied to hidden form fields for local team workflows.
336
+ When `ARTIFACTY_API_TOKEN` is configured, `/api/*` routes require either `Authorization: Bearer <token>` or `x-artifacty-token: <token>`. When users exist, personal tokens issued from `/account` also authenticate API and MCP requests and are mapped to the token owner's email in audit logs. Browser forms can also carry `?token=<token>` in the URL, which is copied to hidden form fields for local team workflows.
299
337
 
300
338
  Renderer notes:
301
339
 
@@ -1,7 +1,10 @@
1
1
  # MCP Public API
2
2
 
3
- Artifacty's MCP stdio server is the primary agent-to-agent integration surface.
4
- The server currently targets MCP protocol `2025-06-18`.
3
+ Artifacty's MCP server is the primary agent-to-agent integration surface. It
4
+ supports local stdio MCP by default, a token-protected HTTP `/mcp` endpoint when
5
+ enabled on the browser server, and stdio bridge mode for clients that need local
6
+ stdio config but should write to a central Artifacty server. The server
7
+ currently targets MCP protocol `2025-06-18`.
5
8
 
6
9
  ## Capabilities
7
10
 
@@ -23,7 +26,7 @@ Stable tool names:
23
26
  - `artifacty_update`: append an immutable version.
24
27
  - `artifacty_archive` / `artifacty_restore`: toggle archive state.
25
28
  - `artifacty_audit`: list audit events.
26
- - `artifacty_info`: return local store and browser URL information.
29
+ - `artifacty_info`: return store, browser URL, transport, and protocol information.
27
30
 
28
31
  Tool schemas use Artifacty schema v1 formats and artifact types. New optional
29
32
  properties may be added during 0.x releases; existing names should not be
@@ -60,7 +63,13 @@ Prompts accept optional context arguments such as `artifactId`, `goal`, `scope`,
60
63
 
61
64
  ## Compatibility Notes
62
65
 
63
- - The MCP server is local stdio only. Remote MCP auth/OAuth is out of scope.
66
+ - Local stdio remains the default. Enable the central HTTP endpoint with
67
+ `artifacty serve --mcp-http` and install bridge mode with
68
+ `artifacty install <agent> --mcp-url http://host:8787/mcp --api-token <token>`.
69
+ - On central servers, use a personal token from `/account` so audit logs record
70
+ the token owner's email as the artifact actor.
71
+ - Remote MCP currently uses bearer/header token auth. OAuth and per-user scoped
72
+ tokens are future hardening work.
64
73
  - Binary media resources return stored base64 text through MCP; browser `/raw`
65
74
  decodes first-class `image` and `video` artifacts into bytes.
66
75
  - Clients may display resources and prompts differently. Tools remain the most
@@ -16,6 +16,16 @@ If another device on a trusted LAN or private VPN needs read access, prefer bind
16
16
  artifacty serve --host 192.168.1.20 --share-mode lan --generate-token
17
17
  ```
18
18
 
19
+ For a central internal MCP server, enable `/mcp` explicitly and install clients
20
+ with `--mcp-url` and a personal token from `/account`:
21
+
22
+ ```bash
23
+ ARTIFACTY_BOOTSTRAP_TOKEN="$(artifacty token --raw)"
24
+ artifacty serve --host 10.0.0.50 --share-mode team --api-token "$ARTIFACTY_BOOTSTRAP_TOKEN" --mcp-http --foreground
25
+ # Open /login to create the first admin, then /account to issue a personal token.
26
+ artifacty install all --mcp-url http://10.0.0.50:8787/mcp --api-token "$ARTIFACTY_PERSONAL_TOKEN"
27
+ ```
28
+
19
29
  Use `0.0.0.0` only when you intentionally want Artifacty to listen on every network interface:
20
30
 
21
31
  ```bash
@@ -43,3 +53,6 @@ Do not relax the origin check just to make remote browser writes easier. A futur
43
53
  Artifact content is untrusted. HTML, SVG, Mermaid, and React artifacts are rendered with sandboxing and CSP controls, but shared viewing still means content reaches another user's browser. Keep `ARTIFACTY_ENABLE_REACT_RENDERER` disabled for LAN sessions unless every viewer trusts the artifact source.
44
54
 
45
55
  See [threat-model.md](threat-model.md) for the full trust-boundary summary.
56
+
57
+ For a durable internal deployment where many MCP clients share one central
58
+ Artifacty instance, see [central-team-deployment-design.md](central-team-deployment-design.md).
@@ -8,6 +8,7 @@ operator, one local store, and trusted local MCP clients by default.
8
8
  - Artifact content, including generated code, reports, screenshots, and media.
9
9
  - Artifact metadata, tags, audit records, and version history.
10
10
  - API tokens and generated startup tokens.
11
+ - User accounts, password hashes, browser sessions, and personal API tokens.
11
12
  - Local MCP client configuration files.
12
13
  - The Artifacty SQLite database and immutable version files.
13
14
 
@@ -16,7 +17,11 @@ operator, one local store, and trusted local MCP clients by default.
16
17
  - **HTTP browser server**: local by default, optionally reachable on LAN/team
17
18
  networks when explicitly configured.
18
19
  - **MCP stdio server**: local process launched by an MCP client. It inherits the
19
- local user account's filesystem permissions.
20
+ local user account's filesystem permissions. In bridge mode, it forwards
21
+ JSON-RPC to a configured central `/mcp` endpoint instead of touching local
22
+ storage.
23
+ - **HTTP MCP endpoint**: optional `POST /mcp` endpoint exposed only when
24
+ `--mcp-http` or `ARTIFACTY_MCP_HTTP=true` is configured.
20
25
  - **Artifact renderers**: untrusted content is rendered inside browser sandbox
21
26
  boundaries where practical.
22
27
  - **Storage**: Artifacty stores content under `ARTIFACTY_HOME`; anyone with
@@ -50,6 +55,8 @@ Controls:
50
55
  - Scripts should use `x-artifacty-token` or `Authorization: Bearer <token>`.
51
56
  - Browser form token URLs exist only for local convenience.
52
57
  - Token comparisons use timing-safe digest comparison.
58
+ - Personal API tokens are stored only as hashes.
59
+ - Browser sessions use `HttpOnly` and `SameSite=Lax` cookies.
53
60
 
54
61
  Guidance: rotate tokens after sharing sessions, prefer header-based tokens for
55
62
  scripts, and use generated startup tokens only for temporary interactive shares.
@@ -98,22 +105,29 @@ of sensitive data.
98
105
 
99
106
  ### MCP Tool Abuse
100
107
 
101
- Risk: an MCP client can create, update, import, archive, restore, and read local
102
- artifacts through stdio.
108
+ Risk: an MCP client can create, update, import, archive, restore, and read
109
+ artifacts through local stdio or the central HTTP MCP endpoint.
103
110
 
104
111
  Controls:
105
112
 
106
- - MCP is local stdio only.
113
+ - Local stdio remains the default.
114
+ - The HTTP MCP endpoint is disabled unless explicitly enabled.
115
+ - Remote MCP requests require the configured API token.
116
+ - Stdio bridge mode sends tokens in headers, not URLs.
117
+ - Personal tokens map requests to a server-side user record for audit actor
118
+ attribution.
107
119
  - MCP writes go through the same secret scan and audit paths as CLI/HTTP writes.
108
120
  - MCP resources are read-only.
109
121
 
110
- Guidance: install Artifacty MCP only in clients and workspaces you trust.
122
+ Guidance: install Artifacty MCP only in clients and workspaces you trust. For
123
+ central deployments, prefer TLS through a reverse proxy and rotate shared tokens
124
+ after team changes.
111
125
 
112
126
  ## Out of Scope
113
127
 
114
128
  - Public internet hosting without a separate TLS/auth proxy.
115
129
  - Multi-user browser write access.
116
- - OAuth or remote MCP authorization.
130
+ - OAuth, scoped tokens, or per-user remote MCP authorization.
117
131
  - Per-artifact ACLs.
118
132
  - Encrypted-at-rest storage.
119
133
  - Malware analysis of arbitrary artifact content.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "artifacty",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Local artifact exchange for heterogeneous LLM agents via HTTP and MCP.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -36,6 +36,7 @@
36
36
  "src",
37
37
  "docs/artifact-schema-v1.md",
38
38
  "docs/assets/artifacty.png",
39
+ "docs/central-team-deployment-design.md",
39
40
  "docs/integrations.md",
40
41
  "docs/mcp-public-api.md",
41
42
  "docs/network-sharing.md",
package/src/cli.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  createArtifact,
9
9
  createStore,
10
10
  getArtifact,
11
+ importUsersFromCsv,
11
12
  listAuditEvents,
12
13
  listArtifactsPage,
13
14
  rebuildSearchIndex,
@@ -68,7 +69,8 @@ async function main() {
68
69
  home: options.home,
69
70
  apiToken: generatedToken?.token || options.apiToken,
70
71
  shareMode: options.shareMode,
71
- allowSecrets: options.allowSecrets
72
+ allowSecrets: options.allowSecrets,
73
+ mcpHttp: options.mcpHttp
72
74
  });
73
75
  process.stderr.write(`Artifacty listening on ${server.url}\n`);
74
76
  process.stderr.write(`Store: ${server.store.home}\n`);
@@ -183,6 +185,9 @@ async function main() {
183
185
  configPath: options.config,
184
186
  serverPath: options.serverPath,
185
187
  url: options.url,
188
+ mcpUrl: options.mcpUrl,
189
+ apiToken: options.apiToken,
190
+ transport: options.transport,
186
191
  home: options.home,
187
192
  dryRun: options.dryRun,
188
193
  trust: options.trust,
@@ -296,6 +301,18 @@ async function main() {
296
301
  return;
297
302
  }
298
303
 
304
+ if (command === "users") {
305
+ const action = options._[0];
306
+ if (action === "import") {
307
+ const csv = await readContent(options);
308
+ printJson(await importUsersFromCsv(store, csv, {
309
+ passwordResetRequired: !options.noPasswordReset
310
+ }));
311
+ return;
312
+ }
313
+ throw new Error("users requires an action: import");
314
+ }
315
+
299
316
  if (command === "service") {
300
317
  const action = options._[0] || "plist";
301
318
  printJson(await serviceCommand(action, {
@@ -309,6 +326,7 @@ async function main() {
309
326
  apiToken: options.apiToken,
310
327
  shareMode: options.shareMode,
311
328
  allowSecrets: options.allowSecrets,
329
+ mcpHttp: options.mcpHttp,
312
330
  host: options.host,
313
331
  port: options.port,
314
332
  home: options.home,
@@ -346,7 +364,7 @@ function parseArgs(args) {
346
364
  }
347
365
 
348
366
  const key = arg.slice(2);
349
- if (key === "raw" || key === "dry-run" || key === "trust" || key === "include-archived" || key === "allow-secrets" || key === "generate-token" || key === "detach" || key === "foreground" || key === "force" || key === "skip-mcp") {
367
+ if (key === "raw" || key === "dry-run" || key === "trust" || key === "include-archived" || key === "allow-secrets" || key === "generate-token" || key === "detach" || key === "foreground" || key === "force" || key === "skip-mcp" || key === "mcp-http" || key === "no-password-reset") {
350
368
  options[toCamelCase(key)] = true;
351
369
  continue;
352
370
  }
@@ -429,15 +447,15 @@ function printHelp() {
429
447
 
430
448
  Usage:
431
449
  artifacty token [--bytes 32] [--raw]
432
- artifacty serve [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--bytes 32] [--foreground]
450
+ artifacty serve [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--bytes 32] [--mcp-http] [--foreground]
433
451
  artifacty serve --foreground [--generate-token]
434
- artifacty start [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--timeout 30000]
452
+ artifacty start [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--mcp-http] [--timeout 30000]
435
453
  artifacty status [--home ~/.artifacty]
436
454
  artifacty stop [--home ~/.artifacty] [--timeout 30000] [--force]
437
455
  artifacty doctor [--home ~/.artifacty] [--skip-mcp] [--timeout 5000]
438
456
  artifacty publish --title <title> (--file <path> | --content <text>) [--format html|markdown|text|json|code|svg|mermaid|react] [--source agent] [--tag tag]
439
457
  artifacty import --agent claude|codex|gemini|copilot|cursor|auto (--file <path> | --content <text>) [--title <title>] [--format html|markdown|text|json|code|svg|mermaid|react] [--tag tag]
440
- artifacty install claude|codex|gemini|copilot|cursor|all [--dry-run] [--config <path>] [--server-path <path>] [--url http://127.0.0.1:8787] [--timeout 30000]
458
+ artifacty install claude|codex|gemini|copilot|cursor|all [--dry-run] [--config <path>] [--server-path <path>] [--url http://127.0.0.1:8787] [--mcp-url http://127.0.0.1:8787/mcp] [--api-token token] [--transport local|bridge] [--timeout 30000]
441
459
  artifacty check [--server-path <path>] [--timeout 5000]
442
460
  artifacty update <id> (--file <path> | --content <text>) [--title <title>] [--format html|markdown|text|json|code|svg|mermaid|react]
443
461
  artifacty archive <id>
@@ -448,13 +466,16 @@ Usage:
448
466
  artifacty export --file <path>
449
467
  artifacty backup [--file <path>]
450
468
  artifacty import-store --file <path>
451
- artifacty service plist|unit|task|install|uninstall [--platform macos|linux|windows] [--dry-run] [--path <path>]
469
+ artifacty users import --file <path.csv> [--no-password-reset]
470
+ artifacty service plist|unit|task|install|uninstall [--platform macos|linux|windows] [--dry-run] [--path <path>] [--mcp-http]
452
471
  artifacty list [--query text] [--tag tag] [--source agent] [--limit 50] [--offset 0] [--include-archived]
453
472
  artifacty show <id> [--version n] [--raw]
454
473
 
455
474
  Environment:
456
475
  ARTIFACTY_HOME Storage directory. Defaults to ~/.artifacty
457
476
  ARTIFACTY_URL Public URL override. Otherwise CLI/MCP read the last running server URL
477
+ ARTIFACTY_MCP_URL Central MCP HTTP endpoint used by bridge mode
478
+ ARTIFACTY_MCP_MODE local or bridge. bridge forwards stdio MCP to ARTIFACTY_MCP_URL
458
479
  ARTIFACTY_API_TOKEN Required token for HTTP API and LAN mode
459
480
  ARTIFACTY_SHARE_MODE Use lan or team before binding outside localhost
460
481
  ARTIFACTY_ALLOW_SECRETS Set true only to intentionally store detected secrets
@@ -485,6 +506,7 @@ function serverOptions(options) {
485
506
  allowSecrets: options.allowSecrets,
486
507
  generateToken: options.generateToken,
487
508
  bytes: options.bytes,
509
+ mcpHttp: options.mcpHttp,
488
510
  timeout: options.timeout
489
511
  };
490
512
  }
@@ -235,6 +235,9 @@ export function buildServerArgs(options, store) {
235
235
  if (options.allowSecrets) {
236
236
  args.push("--allow-secrets");
237
237
  }
238
+ if (options.mcpHttp) {
239
+ args.push("--mcp-http");
240
+ }
238
241
  return args;
239
242
  }
240
243
 
@@ -48,6 +48,17 @@ export function createMcpServerConfig(options = {}) {
48
48
  env.ARTIFACTY_URL = options.url || process.env.ARTIFACTY_URL;
49
49
  }
50
50
 
51
+ if (options.mcpUrl || process.env.ARTIFACTY_MCP_URL) {
52
+ env.ARTIFACTY_MCP_MODE = normalizeMcpMode(options.transport || "bridge");
53
+ env.ARTIFACTY_MCP_URL = normalizeMcpEndpoint(options.mcpUrl || process.env.ARTIFACTY_MCP_URL);
54
+ } else if (options.transport || process.env.ARTIFACTY_MCP_MODE) {
55
+ env.ARTIFACTY_MCP_MODE = normalizeMcpMode(options.transport || process.env.ARTIFACTY_MCP_MODE);
56
+ }
57
+
58
+ if (options.apiToken || process.env.ARTIFACTY_API_TOKEN) {
59
+ env.ARTIFACTY_API_TOKEN = options.apiToken || process.env.ARTIFACTY_API_TOKEN;
60
+ }
61
+
51
62
  if (options.home || process.env.ARTIFACTY_HOME) {
52
63
  env.ARTIFACTY_HOME = path.resolve(options.home || process.env.ARTIFACTY_HOME);
53
64
  }
@@ -241,6 +252,26 @@ function normalizeTimeoutMs(value) {
241
252
  return Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_MCP_TIMEOUT_MS;
242
253
  }
243
254
 
255
+ function normalizeMcpMode(value) {
256
+ const mode = String(value || "bridge").trim().toLowerCase();
257
+ if (mode === "remote") {
258
+ return "bridge";
259
+ }
260
+ if (!["local", "bridge"].includes(mode)) {
261
+ throw new Error("MCP transport must be local or bridge");
262
+ }
263
+ return mode;
264
+ }
265
+
266
+ function normalizeMcpEndpoint(value) {
267
+ const parsed = new URL(value);
268
+ const pathname = parsed.pathname.replace(/\/+$/, "");
269
+ parsed.pathname = pathname || "/mcp";
270
+ parsed.search = "";
271
+ parsed.hash = "";
272
+ return parsed.toString();
273
+ }
274
+
244
275
  function quoteTomlString(value) {
245
276
  return JSON.stringify(String(value));
246
277
  }