toolhome 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/README.zh.md +281 -0
  4. package/dist/server/app.d.ts +16 -0
  5. package/dist/server/app.d.ts.map +1 -0
  6. package/dist/server/app.js +166 -0
  7. package/dist/server/app.js.map +1 -0
  8. package/dist/server/cli/main.d.ts +3 -0
  9. package/dist/server/cli/main.d.ts.map +1 -0
  10. package/dist/server/cli/main.js +587 -0
  11. package/dist/server/cli/main.js.map +1 -0
  12. package/dist/server/cli-plane/allow-list.d.ts +18 -0
  13. package/dist/server/cli-plane/allow-list.d.ts.map +1 -0
  14. package/dist/server/cli-plane/allow-list.js +28 -0
  15. package/dist/server/cli-plane/allow-list.js.map +1 -0
  16. package/dist/server/cli-plane/cli-service.d.ts +41 -0
  17. package/dist/server/cli-plane/cli-service.d.ts.map +1 -0
  18. package/dist/server/cli-plane/cli-service.js +282 -0
  19. package/dist/server/cli-plane/cli-service.js.map +1 -0
  20. package/dist/server/cli-plane/frames.d.ts +26 -0
  21. package/dist/server/cli-plane/frames.d.ts.map +1 -0
  22. package/dist/server/cli-plane/frames.js +12 -0
  23. package/dist/server/cli-plane/frames.js.map +1 -0
  24. package/dist/server/cli-plane/models.d.ts +174 -0
  25. package/dist/server/cli-plane/models.d.ts.map +1 -0
  26. package/dist/server/cli-plane/models.js +169 -0
  27. package/dist/server/cli-plane/models.js.map +1 -0
  28. package/dist/server/cli-plane/routes.d.ts +32 -0
  29. package/dist/server/cli-plane/routes.d.ts.map +1 -0
  30. package/dist/server/cli-plane/routes.js +94 -0
  31. package/dist/server/cli-plane/routes.js.map +1 -0
  32. package/dist/server/cli-plane/runner.d.ts +41 -0
  33. package/dist/server/cli-plane/runner.d.ts.map +1 -0
  34. package/dist/server/cli-plane/runner.js +163 -0
  35. package/dist/server/cli-plane/runner.js.map +1 -0
  36. package/dist/server/cli-plane/status.d.ts +12 -0
  37. package/dist/server/cli-plane/status.d.ts.map +1 -0
  38. package/dist/server/cli-plane/status.js +24 -0
  39. package/dist/server/cli-plane/status.js.map +1 -0
  40. package/dist/server/config/harness-import.d.ts +44 -0
  41. package/dist/server/config/harness-import.d.ts.map +1 -0
  42. package/dist/server/config/harness-import.js +166 -0
  43. package/dist/server/config/harness-import.js.map +1 -0
  44. package/dist/server/config.d.ts +20 -0
  45. package/dist/server/config.d.ts.map +1 -0
  46. package/dist/server/config.js +80 -0
  47. package/dist/server/config.js.map +1 -0
  48. package/dist/server/control/client.d.ts +24 -0
  49. package/dist/server/control/client.d.ts.map +1 -0
  50. package/dist/server/control/client.js +115 -0
  51. package/dist/server/control/client.js.map +1 -0
  52. package/dist/server/control/control-api.d.ts +39 -0
  53. package/dist/server/control/control-api.d.ts.map +1 -0
  54. package/dist/server/control/control-api.js +291 -0
  55. package/dist/server/control/control-api.js.map +1 -0
  56. package/dist/server/control/control-service.d.ts +713 -0
  57. package/dist/server/control/control-service.d.ts.map +1 -0
  58. package/dist/server/control/control-service.js +693 -0
  59. package/dist/server/control/control-service.js.map +1 -0
  60. package/dist/server/control/openapi.d.ts +2 -0
  61. package/dist/server/control/openapi.d.ts.map +1 -0
  62. package/dist/server/control/openapi.js +370 -0
  63. package/dist/server/control/openapi.js.map +1 -0
  64. package/dist/server/data-plane/data-plane.d.ts +20 -0
  65. package/dist/server/data-plane/data-plane.d.ts.map +1 -0
  66. package/dist/server/data-plane/data-plane.js +335 -0
  67. package/dist/server/data-plane/data-plane.js.map +1 -0
  68. package/dist/server/data-plane/gateway-server.d.ts +13 -0
  69. package/dist/server/data-plane/gateway-server.d.ts.map +1 -0
  70. package/dist/server/data-plane/gateway-server.js +796 -0
  71. package/dist/server/data-plane/gateway-server.js.map +1 -0
  72. package/dist/server/data-plane/legacy-session.d.ts +18 -0
  73. package/dist/server/data-plane/legacy-session.d.ts.map +1 -0
  74. package/dist/server/data-plane/legacy-session.js +137 -0
  75. package/dist/server/data-plane/legacy-session.js.map +1 -0
  76. package/dist/server/data-plane/projection.d.ts +18 -0
  77. package/dist/server/data-plane/projection.d.ts.map +1 -0
  78. package/dist/server/data-plane/projection.js +44 -0
  79. package/dist/server/data-plane/projection.js.map +1 -0
  80. package/dist/server/data-plane/registry.d.ts +31 -0
  81. package/dist/server/data-plane/registry.d.ts.map +1 -0
  82. package/dist/server/data-plane/registry.js +129 -0
  83. package/dist/server/data-plane/registry.js.map +1 -0
  84. package/dist/server/data-plane/task-extension.d.ts +7 -0
  85. package/dist/server/data-plane/task-extension.d.ts.map +1 -0
  86. package/dist/server/data-plane/task-extension.js +33 -0
  87. package/dist/server/data-plane/task-extension.js.map +1 -0
  88. package/dist/server/data-plane/virtualization.d.ts +35 -0
  89. package/dist/server/data-plane/virtualization.d.ts.map +1 -0
  90. package/dist/server/data-plane/virtualization.js +228 -0
  91. package/dist/server/data-plane/virtualization.js.map +1 -0
  92. package/dist/server/domain/errors.d.ts +9 -0
  93. package/dist/server/domain/errors.d.ts.map +1 -0
  94. package/dist/server/domain/errors.js +19 -0
  95. package/dist/server/domain/errors.js.map +1 -0
  96. package/dist/server/domain/models.d.ts +720 -0
  97. package/dist/server/domain/models.d.ts.map +1 -0
  98. package/dist/server/domain/models.js +327 -0
  99. package/dist/server/domain/models.js.map +1 -0
  100. package/dist/server/main.d.ts +2 -0
  101. package/dist/server/main.d.ts.map +1 -0
  102. package/dist/server/main.js +37 -0
  103. package/dist/server/main.js.map +1 -0
  104. package/dist/server/manage/management-mcp.d.ts +27 -0
  105. package/dist/server/manage/management-mcp.d.ts.map +1 -0
  106. package/dist/server/manage/management-mcp.js +431 -0
  107. package/dist/server/manage/management-mcp.js.map +1 -0
  108. package/dist/server/market/catalog.d.ts +111 -0
  109. package/dist/server/market/catalog.d.ts.map +1 -0
  110. package/dist/server/market/catalog.js +784 -0
  111. package/dist/server/market/catalog.js.map +1 -0
  112. package/dist/server/market/installers.d.ts +64 -0
  113. package/dist/server/market/installers.d.ts.map +1 -0
  114. package/dist/server/market/installers.js +181 -0
  115. package/dist/server/market/installers.js.map +1 -0
  116. package/dist/server/market/market-service.d.ts +146 -0
  117. package/dist/server/market/market-service.d.ts.map +1 -0
  118. package/dist/server/market/market-service.js +930 -0
  119. package/dist/server/market/market-service.js.map +1 -0
  120. package/dist/server/observability/call-recorder.d.ts +22 -0
  121. package/dist/server/observability/call-recorder.d.ts.map +1 -0
  122. package/dist/server/observability/call-recorder.js +99 -0
  123. package/dist/server/observability/call-recorder.js.map +1 -0
  124. package/dist/server/observability/logger.d.ts +16 -0
  125. package/dist/server/observability/logger.d.ts.map +1 -0
  126. package/dist/server/observability/logger.js +25 -0
  127. package/dist/server/observability/logger.js.map +1 -0
  128. package/dist/server/security/api-keys.d.ts +15 -0
  129. package/dist/server/security/api-keys.d.ts.map +1 -0
  130. package/dist/server/security/api-keys.js +35 -0
  131. package/dist/server/security/api-keys.js.map +1 -0
  132. package/dist/server/security/auth-service.d.ts +26 -0
  133. package/dist/server/security/auth-service.d.ts.map +1 -0
  134. package/dist/server/security/auth-service.js +76 -0
  135. package/dist/server/security/auth-service.js.map +1 -0
  136. package/dist/server/security/control-session.d.ts +9 -0
  137. package/dist/server/security/control-session.d.ts.map +1 -0
  138. package/dist/server/security/control-session.js +51 -0
  139. package/dist/server/security/control-session.js.map +1 -0
  140. package/dist/server/security/credential-materializer.d.ts +20 -0
  141. package/dist/server/security/credential-materializer.d.ts.map +1 -0
  142. package/dist/server/security/credential-materializer.js +82 -0
  143. package/dist/server/security/credential-materializer.js.map +1 -0
  144. package/dist/server/security/cursor-codec.d.ts +13 -0
  145. package/dist/server/security/cursor-codec.d.ts.map +1 -0
  146. package/dist/server/security/cursor-codec.js +43 -0
  147. package/dist/server/security/cursor-codec.js.map +1 -0
  148. package/dist/server/security/oauth-routes.d.ts +21 -0
  149. package/dist/server/security/oauth-routes.d.ts.map +1 -0
  150. package/dist/server/security/oauth-routes.js +100 -0
  151. package/dist/server/security/oauth-routes.js.map +1 -0
  152. package/dist/server/security/oauth-server.d.ts +16 -0
  153. package/dist/server/security/oauth-server.d.ts.map +1 -0
  154. package/dist/server/security/oauth-server.js +544 -0
  155. package/dist/server/security/oauth-server.js.map +1 -0
  156. package/dist/server/security/secret-box.d.ts +7 -0
  157. package/dist/server/security/secret-box.d.ts.map +1 -0
  158. package/dist/server/security/secret-box.js +27 -0
  159. package/dist/server/security/secret-box.js.map +1 -0
  160. package/dist/server/security/secure-action.d.ts +21 -0
  161. package/dist/server/security/secure-action.d.ts.map +1 -0
  162. package/dist/server/security/secure-action.js +69 -0
  163. package/dist/server/security/secure-action.js.map +1 -0
  164. package/dist/server/storage/sqlite-store.d.ts +70 -0
  165. package/dist/server/storage/sqlite-store.d.ts.map +1 -0
  166. package/dist/server/storage/sqlite-store.js +1522 -0
  167. package/dist/server/storage/sqlite-store.js.map +1 -0
  168. package/dist/server/storage/store.d.ts +82 -0
  169. package/dist/server/storage/store.d.ts.map +1 -0
  170. package/dist/server/storage/store.js +2 -0
  171. package/dist/server/storage/store.js.map +1 -0
  172. package/dist/server/upstream/adapter.d.ts +52 -0
  173. package/dist/server/upstream/adapter.d.ts.map +1 -0
  174. package/dist/server/upstream/adapter.js +807 -0
  175. package/dist/server/upstream/adapter.js.map +1 -0
  176. package/dist/server/upstream/credential-resolver.d.ts +14 -0
  177. package/dist/server/upstream/credential-resolver.d.ts.map +1 -0
  178. package/dist/server/upstream/credential-resolver.js +56 -0
  179. package/dist/server/upstream/credential-resolver.js.map +1 -0
  180. package/dist/server/upstream/extension-transport.d.ts +17 -0
  181. package/dist/server/upstream/extension-transport.d.ts.map +1 -0
  182. package/dist/server/upstream/extension-transport.js +207 -0
  183. package/dist/server/upstream/extension-transport.js.map +1 -0
  184. package/dist/server/upstream/manager.d.ts +23 -0
  185. package/dist/server/upstream/manager.d.ts.map +1 -0
  186. package/dist/server/upstream/manager.js +324 -0
  187. package/dist/server/upstream/manager.js.map +1 -0
  188. package/dist/server/upstream/oauth-provider.d.ts +38 -0
  189. package/dist/server/upstream/oauth-provider.d.ts.map +1 -0
  190. package/dist/server/upstream/oauth-provider.js +225 -0
  191. package/dist/server/upstream/oauth-provider.js.map +1 -0
  192. package/dist/server/upstream/oauth-refresh.d.ts +65 -0
  193. package/dist/server/upstream/oauth-refresh.d.ts.map +1 -0
  194. package/dist/server/upstream/oauth-refresh.js +240 -0
  195. package/dist/server/upstream/oauth-refresh.js.map +1 -0
  196. package/dist/server/upstream/oauth-routes.d.ts +17 -0
  197. package/dist/server/upstream/oauth-routes.d.ts.map +1 -0
  198. package/dist/server/upstream/oauth-routes.js +87 -0
  199. package/dist/server/upstream/oauth-routes.js.map +1 -0
  200. package/dist/server/upstream/oauth-service.d.ts +143 -0
  201. package/dist/server/upstream/oauth-service.d.ts.map +1 -0
  202. package/dist/server/upstream/oauth-service.js +217 -0
  203. package/dist/server/upstream/oauth-service.js.map +1 -0
  204. package/dist/server/upstream/stable-json.d.ts +3 -0
  205. package/dist/server/upstream/stable-json.d.ts.map +1 -0
  206. package/dist/server/upstream/stable-json.js +17 -0
  207. package/dist/server/upstream/stable-json.js.map +1 -0
  208. package/package.json +69 -0
  209. package/skills/toolhome/SKILL.md +238 -0
  210. package/skills/toolhome/references/cli-reference.md +242 -0
  211. package/skills/toolhome/references/deployment.md +113 -0
  212. package/skills/toolhome/references/market-guide.md +128 -0
  213. package/skills/toolhome/references/oauth-guide.md +96 -0
  214. package/skills/toolhome/references/troubleshooting.md +133 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ToolHome contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,295 @@
1
+ # ToolHome
2
+
3
+ > **🌐 Language: English · [中文](README.zh.md)**
4
+
5
+ ToolHome is a single-user, self-hosted control plane for MCP servers and Hosted CLIs. Manage upstream MCP capabilities, platform CLIs such as Azure `az`, GitHub `gh`, and Tailscale, and their encrypted credentials in one place.
6
+
7
+ It exposes two data planes:
8
+
9
+ - **MCP**: `POST /mcp` aggregates enabled servers; `POST /mcp/{server_slug}` preserves one server's original names and extensions.
10
+ - **Hosted CLI**: `POST /cli/{slug}/exec` runs an allow-listed argv array on the ToolHome host or in a pinned sibling container and streams NDJSON stdout/stderr/exit frames. `GET /cli/{slug}/status` runs the declared status probe.
11
+
12
+ ToolHome does not write harness-specific adapters for Claude Code, Codex, Cursor, or anything else. MCP clients use standard Streamable HTTP with Bearer auth; management and Hosted CLI operations use Control Keys.
13
+
14
+ ## For AI Agents
15
+
16
+ Install the ToolHome skill to teach your agent how to deploy and manage ToolHome:
17
+
18
+ ```bash
19
+ npx skills add crayonlu/toolhome -g -y
20
+ ```
21
+
22
+ This gives the agent knowledge of all CLI commands, OAuth flows, Market installation, troubleshooting, and deployment patterns. The agent will know when and how to use ToolHome without manual instructions.
23
+
24
+ ## Web Console
25
+
26
+ The web console mirrors the full CLI surface: server and credential management, OAuth authorization, one-click Market installs, tool call observability, diagnostics, events, config export/import — with Chinese/English UI and mobile support.
27
+
28
+ <div style="display: flex; flex-wrap: wrap; gap: 8px;">
29
+ <img src="docs/screenshots/en/dashboard.png" width="49%" alt="Dashboard">
30
+ <img src="docs/screenshots/en/servers.png" width="49%" alt="Servers">
31
+ <img src="docs/screenshots/en/calls.png" width="49%" alt="Calls">
32
+ <img src="docs/screenshots/en/credentials.png" width="49%" alt="Credentials">
33
+ <img src="docs/screenshots/en/market.png" width="49%" alt="Market">
34
+ <img src="docs/screenshots/en/settings.png" width="49%" alt="Settings">
35
+ </div>
36
+
37
+ Mobile:
38
+
39
+ <div style="display: flex; gap: 8px;">
40
+ <img src="docs/screenshots/en/market-mobile.png" width="49%" alt="Market mobile">
41
+ <img src="docs/screenshots/en/dashboard-mobile.png" width="49%" alt="Dashboard mobile">
42
+ </div>
43
+
44
+ ## Project Scope
45
+
46
+ ToolHome has two first-class planes:
47
+
48
+ - **MCP**: Remote-native servers use Streamable HTTP; Home-hosted servers use stdio on the ToolHome host.
49
+ - **Hosted CLI**: platform CLIs represent an external service or control plane, for example Azure `az`, GitHub `gh`, and Tailscale. They are invoked with complete argv, stdin, timeout and output limits, allow/deny rules, and NDJSON output frames. Package managers and developer tools such as `npm`, `go`, `cargo`, `uv`, `pipx`, `docker`, and `cursor` are installer/runtime details, not Hosted CLI products.
50
+
51
+ MCPs or CLIs that must run on the harness machine and depend on its browser or desktop state remain local to that harness. The first release explicitly excludes multi-tenancy, profiles, workspaces, and project management.
52
+
53
+ ## Protocol Capabilities
54
+
55
+ The per-server entry proxies losslessly; the aggregate virtualizes conflicting names while keeping everything routable:
56
+
57
+ - Tools, Prompts, Resources, Resource Templates, Completion
58
+ - Resource subscriptions and list-changed notifications
59
+ - Sampling, Roots, Elicitation, and 2026 MRTR `input_required`
60
+ - Final Tasks extension: `tasks/get`, `tasks/update`, `tasks/cancel`, task-ID virtualization, and `Mcp-Name` binding
61
+ - MCP Apps: `ui://` URIs are preserved on the aggregate; original App semantics on per-server entries
62
+ - Logging, Progress, cancellation, and custom extension methods
63
+ - Automatic 2026-07-28 / 2025-era negotiation, with remote SSE available as an explicit fallback
64
+
65
+ Downstream 2026 requests stay stateless; 2025-era clients use a persistent session bound to the authenticated principal, preserving initialize capability declarations and bidirectional request semantics. Parts of the Final Tasks extension not yet registered by SDK 2.0 are filled in by an isolated compatibility layer that still speaks the official `tasks/*` wire contract.
66
+
67
+ Aggregated tool names are `{server_slug}.{upstream_name}`. Unknown extension methods use `toolhome/{server_slug}/{upstream_method}` on the aggregate and pass through untouched on per-server entries. MCP Apps that use original tool names are routed by App resource context or globally unique names; use a per-server entry when names collide.
68
+
69
+ When a modern harness calls a legacy upstream, ToolHome suspends push-style Elicitation, Sampling, and Roots in Tool, Prompt, and Resource Read calls, converts them to modern `input_required` multi-turn interactions, then resumes the same upstream request. Legacy extensions that issue private server-to-client requests inside a custom method have no standard representation in the closed MRTR type set; use a legacy harness or upgrade the upstream protocol for those.
70
+
71
+ See [architecture](docs/architecture.md) and [protocol compatibility](docs/protocol-compatibility.md) for details.
72
+
73
+ ## Quick Start
74
+
75
+ Requires Node.js 24 or newer.
76
+
77
+ ```bash
78
+ npm install
79
+ cp .env.example .env
80
+ ```
81
+
82
+ Generate two independent random values for `TOOLHOME_MASTER_KEY` and the first-boot `TOOLHOME_BOOTSTRAP_CONTROL_KEY`. Both must be at least 32 characters and must differ.
83
+
84
+ ```bash
85
+ npm run build
86
+ set -a
87
+ source .env
88
+ set +a
89
+ npm start
90
+ ```
91
+
92
+ Open `TOOLHOME_PUBLIC_URL` and sign in to the web console with the bootstrap Control API Key. Once you create a new Control Key, you can revoke the bootstrap key.
93
+
94
+ For development, run the server and web separately:
95
+
96
+ ```bash
97
+ npm run dev
98
+ npm run dev:web
99
+ ```
100
+
101
+ Vite proxies `/api` requests to `http://127.0.0.1:3344`.
102
+
103
+ ## Docker
104
+
105
+ ```bash
106
+ export TOOLHOME_MASTER_KEY="$(openssl rand -base64 48)"
107
+ export TOOLHOME_BOOTSTRAP_CONTROL_KEY="tch_ctl_$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"
108
+ export TOOLHOME_PUBLIC_URL="https://tool.cyncyn.xyz"
109
+ export TOOLHOME_ALLOWED_HOSTS="tool.cyncyn.xyz"
110
+ docker compose up -d --build
111
+ ```
112
+
113
+ Put an HTTPS reverse proxy in front of ToolHome in production. OAuth callbacks, URL-based Client IDs, and remote harness connections should all use a stable HTTPS `TOOLHOME_PUBLIC_URL`. The value must be a canonical origin — no path, query, fragment, username, or password. Data lives in `/data/toolhome.sqlite` (SQLite, WAL mode).
114
+
115
+ Market installers are hidden behind curated capability entries. The catalog can use npm, Go, GitHub Release archives, uvx, or Docker recipes; the product surface remains MCP servers and Hosted platform CLIs. Uvx entries execute the installed binary from the persistent ToolHome tool directory instead of resolving the package again on every refresh. Docker-backed entries require the Docker socket mount shown in `docker-compose.yml`. Hosted CLI state directories are explicit named volumes, never implicit mounts of a user's local credential directory.
116
+
117
+ ## CI/CD
118
+
119
+ GitHub Actions (`.github/workflows/ci.yml`) runs on every push to main or tag:
120
+
121
+ 1. **test**: server check + test, web typecheck + test
122
+ 2. **docker**: build dists -> `docker build` -> push `ghcr.io/crayonlu/toolhome:latest` (tags also get `:v*`)
123
+ 3. **deploy**: SSH to server `docker compose pull && up -d`
124
+
125
+ Deployment requires three GitHub Secrets: `DEPLOY_HOST`, `DEPLOY_USER`, `DEPLOY_KEY` (SSH private key). The GHCR package must be set to Public (after first push, in Package Settings).
126
+
127
+ ## Market
128
+
129
+ The Market ships curated MCP servers and Hosted platform CLIs. Installing an entry creates the encrypted Credential and the corresponding Server or CLI record:
130
+
131
+ ```bash
132
+ npm run cli -- market list
133
+ npm run cli -- market install resend --set RESEND_API_KEY=re_xxx
134
+ npm run cli -- market install gh-cli --set GH_TOKEN=ghp_xxx
135
+ npm run cli -- market uninstall gh-cli
136
+ ```
137
+
138
+ - MCP entries may be remote, npm-backed, uvx-backed, or Docker-backed.
139
+ - Hosted CLI entries include Azure `az`, GitHub `gh`, and Tailscale. They pin the platform artifact, define allowed argv, and declare how stored credential material reaches the CLI.
140
+ - A CLI can use a bearer token (`GH_TOKEN`), selected Env Credential variables (Azure service principal), or an OAuth access token after the shared MCP authorization flow completes.
141
+ - The web console's Market page offers the same flow graphically. MCP/CLI is a plane switch: only entries and records from the selected plane are shown.
142
+
143
+ ## Connecting a Harness
144
+
145
+ First create an MCP Access API Key from the console or CLI. The generic aggregate configuration is:
146
+
147
+ ```json
148
+ {
149
+ "url": "https://tool.cyncyn.xyz/mcp",
150
+ "headers": {
151
+ "Authorization": "Bearer tch_mcp_..."
152
+ }
153
+ }
154
+ ```
155
+
156
+ For a single GitHub server only:
157
+
158
+ ```json
159
+ {
160
+ "url": "https://tool.cyncyn.xyz/mcp/github",
161
+ "headers": {
162
+ "Authorization": "Bearer tch_mcp_..."
163
+ }
164
+ }
165
+ ```
166
+
167
+ Access Keys only call the MCP data plane; they cannot read server or credential configuration. Control Keys only call the control plane and cannot be used as an MCP identity.
168
+
169
+ The data plane also implements OAuth 2.1: a harness can discover the authorization server via RFC 9728 metadata and use Authorization Code + PKCE to obtain an access token bound to a specific MCP endpoint.
170
+
171
+ Downstream Dynamic Client Registration returns a stateless Client ID signed with the master key — no in-process registry, valid across restarts with the same key. HTTPS URL-based Client Metadata is also supported, with limits on response size, redirects, and non-public targets.
172
+
173
+ ## Upstream Authentication
174
+
175
+ Remote-native servers support:
176
+
177
+ - Bearer token
178
+ - API key header
179
+ - Multiple custom headers
180
+ - OAuth 2.1 / OIDC
181
+
182
+ OAuth/OIDC uses the official MCP TypeScript SDK auth orchestrator, covering RFC 9728 discovery, Authorization Server/OIDC metadata, PKCE, RFC 9207 issuer validation, CIMD, DCR, refresh, and RFC 8707 resource indicators. An OAuth Credential is bound 1:1 to a Remote Server, preventing token reuse across resources or issuers.
183
+
184
+ > If an upstream authorization server advertises URL-based Client Metadata support but cannot fetch it from a proxied origin (for example Cloudflare-hosted MCP), set `TOOLHOME_OAUTH_URL_CLIENT_ID=false` to force Dynamic Client Registration.
185
+
186
+ Home-hosted servers use an Environment Credential or the transport's own `env`.
187
+
188
+ Put secrets in Credentials, not in Remote URL query strings or stdio arguments — the latter are structural configuration and cannot be reliably redacted.
189
+
190
+ ## CLI
191
+
192
+ After building, run `toolhome`; from source, use `npm run cli --`.
193
+
194
+ ```bash
195
+ export TOOLHOME_URL="https://tool.cyncyn.xyz"
196
+ export TOOLHOME_CONTROL_KEY="tch_ctl_<your-control-key>"
197
+ # Optional: override the default ~/.config/toolhome/config.json path
198
+ export TOOLHOME_CONFIG="$HOME/.config/toolhome/config.json"
199
+ npm run cli -- auth login
200
+
201
+ npm run cli -- server list
202
+ npm run cli -- server add ./server.json
203
+ npm run cli -- cli list
204
+ npm run cli -- cli status az
205
+ npm run cli -- cli exec az -- account show
206
+ npm run cli -- cli exec gh --stdin-file ./input.txt -- issue list
207
+ npm run cli -- credential authorize cloudflare
208
+ npm run cli -- access-key create laptop
209
+ npm run cli -- endpoint aggregate
210
+ npm run cli -- doctor
211
+ ```
212
+
213
+ `cli exec` sends an argv array to the hosted CLI and streams stdout/stderr without invoking a shell. Put `--` before CLI arguments that start with `-`; `--stdin` and `--stdin-file` feed remote stdin, and `--output json` emits one JSON object per frame plus the final exit outcome:
214
+
215
+ ```bash
216
+ npm run cli -- cli exec az --timeout 30000 -- account show --subscription "$SUBSCRIPTION_ID"
217
+ npm run cli -- cli exec gh --stdin-file ./issue.md -- issue create --title "Bug" --body-file -
218
+ npm run cli --output json -- cli exec host-shell -- -c 'printf hello'
219
+ ```
220
+
221
+ The CLI command family also supports `cli get`, `cli add`, `cli update`, `cli delete`, `cli enable`, and `cli disable`. `cli exec` returns exit status 0 only when the hosted process reports `result: "ok"`; SIGINT/SIGTERM abort the HTTP stream and the remote process.
222
+
223
+ `credential authorize <name>` resolves by credential name (or id), opens the browser, and waits until authorization succeeds, fails, or times out:
224
+
225
+ ```bash
226
+ npm run cli -- credential authorize notion --server notion # explicit server (auto-resolved if omitted)
227
+ npm run cli -- credential authorize notion --force # clear the old client and re-authorize
228
+ npm run cli -- credential authorize notion --no-open # don't open the browser
229
+ npm run cli -- credential authorize notion --no-wait # print the URL and exit
230
+ npm run cli -- credential authorize notion --timeout 300 # wait time in seconds (default 600)
231
+ ```
232
+
233
+ The CLI exposes a command for every Control API capability plus a general escape hatch:
234
+
235
+ ```bash
236
+ npm run cli -- api GET /api/v1/openapi.json
237
+ ```
238
+
239
+ Config export is redacted and reviewable by default, and cannot be used to restore. Credential payloads, static HTTP header values, and stdio transport env values are hidden. When secrets are explicitly included, the CLI writes the file with `0600` permissions; import rebuilds credentials, remaps related IDs, and rolls back atomically in a single SQLite transaction if any step fails.
240
+
241
+ ```bash
242
+ npm run cli -- config export backup.json --include-secrets
243
+ npm run cli -- config import backup.json
244
+ ```
245
+
246
+ Backups contain plaintext secrets and deserve the same protection as the master key. `--include-secrets` requires an explicit output file to avoid leaking secrets into terminal logs, and the CLI forces `0600` after writing. Omit it for routine review.
247
+
248
+ ## Configuration
249
+
250
+ | Environment variable | Description | Default |
251
+ | -------------------------------- | ----------------------------------------------------------------------------- | ----------------------- |
252
+ | `TOOLHOME_HOST` | Listen address | `127.0.0.1` |
253
+ | `TOOLHOME_PORT` | Listen port | `3344` |
254
+ | `TOOLHOME_PUBLIC_URL` | Externally reachable canonical origin (production: `https://tool.cyncyn.xyz`) | `http://127.0.0.1:3344` |
255
+ | `TOOLHOME_DATA_DIR` | SQLite and runtime data directory | `./data` |
256
+ | `TOOLHOME_MASTER_KEY` | Root key for secret encryption/signing/digests | required |
257
+ | `TOOLHOME_BOOTSTRAP_CONTROL_KEY` | Control Key written on first database boot | required on first boot |
258
+ | `TOOLHOME_ALLOWED_HOSTS` | Allowed Hosts, comma-separated | Public URL hostname |
259
+ | `TOOLHOME_LOG_LEVEL` | `debug`, `info`, `warn`, `error` | `info` |
260
+ | `TOOLHOME_WEB_DIR` | Web console static files directory | disabled |
261
+ | `TOOLHOME_MARKET_DIR` | Market npm install directory | `<dataDir>/market` |
262
+ | `TOOLHOME_OAUTH_URL_CLIENT_ID` | Enable URL-based Client Metadata | `true` |
263
+
264
+ ## Security Model
265
+
266
+ - Upstream secrets are AES-256-GCM encrypted before being written to SQLite.
267
+ - The database stores an encrypted master-key check; booting with the wrong master key fails immediately instead of silently locking existing API keys.
268
+ - API Keys are stored only as HMAC digests; the full secret is returned once at creation.
269
+ - Control and MCP Access Keys use distinct prefixes and validation domains.
270
+ - The web console exchanges the Control Key for a short-lived, HttpOnly, SameSite=Strict session cookie.
271
+ - Downstream OAuth tokens have exact endpoint audiences; an aggregate token cannot call per-server endpoints and vice versa.
272
+ - OAuth callbacks validate state, PKCE, issuer, and discovery state.
273
+ - URL-based client metadata rejects private-network and insecure targets and pins validated public-resolved addresses for HTTPS fetches, reducing SSRF and DNS-rebinding risk.
274
+ - Downstream DCR Client IDs are signed with the master key, verifiable across restarts, and never stored in the database.
275
+ - Diagnostic events keep the last ~10,000 entries; Home-hosted stderr is redacted against transport env and Environment Credential values before entering the event stream.
276
+
277
+ Back up the database and `TOOLHOME_MASTER_KEY`, or keep a tightly protected `--include-secrets` config export. Losing the master key makes encrypted credentials in the original database unrecoverable.
278
+
279
+ ## Engineering Commands
280
+
281
+ ```bash
282
+ npm run check
283
+ npm run format:check
284
+ npm run build
285
+ npm run test
286
+ npm run test:real
287
+ ```
288
+
289
+ `npm run test:real` prefers to launch the built ToolHome process and connects Home-hosted stdio and Remote-native HTTP fixtures. It uses the official MCP Client to verify aggregate/per-server entries, modern/legacy harnesses, Progress, cancellation, list-changed, MRTR, Tasks, and auth boundaries; it falls back to source entry points when no build artifact exists, which is handy for local debugging.
290
+
291
+ `/healthz` reports process liveness only; `/readyz` returns `503` while runtime state is unavailable.
292
+
293
+ ## License
294
+
295
+ [MIT](LICENSE)
package/README.zh.md ADDED
@@ -0,0 +1,281 @@
1
+ # ToolHome
2
+
3
+ > **🌐 中文 · [English](README.md)**
4
+
5
+ ToolHome 是一个单用户、可自托管的 MCP 与 Hosted CLI 控制面。你可以在一个地方管理上游 MCP 能力、Azure `az`、GitHub `gh`、Tailscale 等平台 CLI,以及加密保存的凭据。
6
+
7
+ 它同时暴露两种数据面:
8
+
9
+ - **MCP**:`POST /mcp` 聚合启用的 Server;`POST /mcp/{server_slug}` 保留单个 Server 的原始名称和扩展语义。
10
+ - **Hosted CLI**:`POST /cli/{slug}/exec` 在 ToolHome 宿主机或固定版本的 sibling 容器中执行受 allow-list 限制的 argv,并以 NDJSON 流返回 stdout/stderr/exit;`GET /cli/{slug}/status` 执行声明的状态探针。
11
+
12
+ ToolHome 不为 Claude Code、Codex、Cursor 或其他 Harness 编写专属适配层。MCP 客户端使用标准 Streamable HTTP 与 Bearer 鉴权;管理面和 Hosted CLI 使用 Control Key。
13
+
14
+ ## AI Agent 快速开始
15
+
16
+ 安装 ToolHome skill,让 AI agent 自动掌握 ToolHome 的部署和操作:
17
+
18
+ ```bash
19
+ npx skills add crayonlu/toolhome -g -y
20
+ ```
21
+
22
+ 安装后 agent 会获得全部 CLI 命令、OAuth 授权流程、Market 安装、排错和部署模式的知识,无需手动编写指令。
23
+
24
+ ## Web 控制台
25
+
26
+ 控制台提供与 CLI 完全对齐的功能:服务器与凭据管理、OAuth 授权、Market 一键安装、调用观测、诊断、事件、配置导入导出,以及中英双语和移动端适配。
27
+
28
+ <div style="display: flex; flex-wrap: wrap; gap: 8px;">
29
+ <img src="docs/screenshots/zh/dashboard.png" width="49%" alt="Dashboard">
30
+ <img src="docs/screenshots/zh/servers.png" width="49%" alt="Servers">
31
+ <img src="docs/screenshots/zh/calls.png" width="49%" alt="Calls">
32
+ <img src="docs/screenshots/zh/credentials.png" width="49%" alt="Credentials">
33
+ <img src="docs/screenshots/zh/market.png" width="49%" alt="Market">
34
+ <img src="docs/screenshots/zh/settings.png" width="49%" alt="Settings">
35
+ </div>
36
+
37
+ 移动端:
38
+
39
+ <div style="display: flex; gap: 8px;">
40
+ <img src="docs/screenshots/zh/market-mobile.png" width="49%" alt="Market mobile">
41
+ <img src="docs/screenshots/zh/dashboard-mobile.png" width="49%" alt="Dashboard mobile">
42
+ </div>
43
+
44
+ ## 项目边界
45
+
46
+ ToolHome 有两个一等平面:
47
+
48
+ - **MCP**:Remote-native 使用 Streamable HTTP;Home-hosted 使用 ToolHome 宿主机上的 stdio。
49
+ - **Hosted CLI**:CLI 必须代表外部平台或 SaaS 控制面,例如 Azure `az`、GitHub `gh`、Tailscale。它支持完整 argv、stdin、timeout、输出限制、allow/deny 规则和 NDJSON 输出。`npm`、`go`、`cargo`、`uv`、`pipx`、`docker`、`cursor` 等安装器或开发工具只是实现细节,不是 Hosted CLI 产品。
50
+
51
+ 必须运行在 Harness 所在本机、依赖该机器浏览器或桌面状态的 MCP/CLI 仍属于 Harness 本地配置。首版明确不包含多租户、Profile、Workspace 或 Project 管理。
52
+
53
+ ## 协议能力
54
+
55
+ 独立入口以无损代理为目标,聚合入口在保持可路由性的前提下虚拟化冲突名称:
56
+
57
+ - Tools、Prompts、Resources、Resource Templates、Completion
58
+ - Resource subscriptions 与 list-changed 通知
59
+ - Sampling、Roots、Elicitation 与 2026 MRTR `input_required`
60
+ - 最终 Tasks 扩展:`tasks/get`、`tasks/update`、`tasks/cancel`、任务 ID 虚拟化和 `Mcp-Name` 绑定
61
+ - MCP Apps,聚合入口保留 `ui://` URI;独立入口保持原始 App 语义
62
+ - Logging、Progress、取消与自定义扩展方法
63
+ - 2026-07-28 与 2025-era 自动协商,远程 SSE 可显式作为回退
64
+
65
+ 下游 2026 请求保持无状态;2025-era 使用与认证 principal 绑定的持久 Session,保留 initialize 能力声明和双向请求语义。最终 Tasks extension 在 SDK 2.0 尚未注册的部分由隔离兼容层补齐,对外仍是官方 `tasks/*` wire contract。
66
+
67
+ 聚合工具名为 `{server_slug}.{upstream_name}`。未知扩展方法在聚合入口使用 `toolhome/{server_slug}/{upstream_method}`;独立入口原样透传。MCP App 若使用原始工具名,ToolHome 会根据 App 资源上下文或全局唯一名称路由;存在同名歧义时应使用独立入口。
68
+
69
+ 当现代 Harness 调用旧式上游时,ToolHome 会把 Tool、Prompt 和 Resource Read 中的 push-style Elicitation、Sampling、Roots 暂停并转换成现代 `input_required` 多轮交互,再恢复同一个上游请求。旧式自定义扩展若在自定义 method 内主动发起私有 server-to-client request,则没有可映射到现代 MRTR 封闭类型集的标准表示;这类扩展应使用 legacy Harness 或升级上游协议。
70
+
71
+ 更多细节见 [架构说明](docs/architecture.md) 和 [协议兼容说明](docs/protocol-compatibility.md)。
72
+
73
+ ## 快速开始
74
+
75
+ 需要 Node.js 24 或更新版本。
76
+
77
+ ```bash
78
+ npm install
79
+ cp .env.example .env
80
+ ```
81
+
82
+ 生成两个独立随机值,分别填写 `TOOLHOME_MASTER_KEY` 和首次启动所需的 `TOOLHOME_BOOTSTRAP_CONTROL_KEY`。二者都至少 32 个字符,且不能相同。
83
+
84
+ ```bash
85
+ npm run build
86
+ set -a
87
+ source .env
88
+ set +a
89
+ npm start
90
+ ```
91
+
92
+ 打开 `TOOLHOME_PUBLIC_URL`,使用 bootstrap Control API Key 登录 Web 控制台。创建新的 Control Key 后,可以撤销 bootstrap key。
93
+
94
+ 开发模式分别运行:
95
+
96
+ ```bash
97
+ npm run dev
98
+ npm run dev:web
99
+ ```
100
+
101
+ Vite 会把 `/api` 请求代理到 `http://127.0.0.1:3344`。
102
+
103
+ ## Docker
104
+
105
+ ```bash
106
+ export TOOLHOME_MASTER_KEY="$(openssl rand -base64 48)"
107
+ export TOOLHOME_BOOTSTRAP_CONTROL_KEY="tch_ctl_$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"
108
+ export TOOLHOME_PUBLIC_URL="https://tool.cyncyn.xyz"
109
+ export TOOLHOME_ALLOWED_HOSTS="tool.cyncyn.xyz"
110
+ docker compose up -d --build
111
+ ```
112
+
113
+ 生产环境应在 ToolHome 前放置 HTTPS 反向代理。OAuth 回调、URL-based Client ID 和远程 Harness 接入都应使用稳定的 HTTPS `TOOLHOME_PUBLIC_URL`。该值必须是规范 origin,不能包含路径、查询、fragment 或用户名密码。数据保存在 `/data/toolhome.sqlite`,SQLite 使用 WAL 模式。
114
+
115
+ Market 安装器隐藏在 curated 能力条目之后,可以使用 npm、Go、GitHub Release archive、uvx 或 Docker recipe;产品表面仍然只有 MCP Server 和 Hosted 平台 CLI。Uvx 条目直接执行持久化 ToolHome 工具目录中的已安装二进制,不会在每次刷新时重新解析包。Docker 条目需要 `docker-compose.yml` 中的 Docker socket 挂载。Hosted CLI 的状态目录由条目显式声明为 Docker named volume,ToolHome 不会默认挂载用户本机的认证目录。
116
+
117
+ ## CI/CD
118
+
119
+ GitHub Actions(`.github/workflows/ci.yml`)在 push 到 main 或打 tag 时自动执行:
120
+
121
+ 1. **test**:服务端 check + test,前端 typecheck + test
122
+ 2. **docker**:构建 dist -> `docker build` -> 推送 `ghcr.io/crayonlu/toolhome:latest`(tag 额外打 `:v*` 版本标签)
123
+ 3. **deploy**:SSH 到服务器 `docker compose pull && up -d`
124
+
125
+ 部署需要三个 GitHub Secret:`DEPLOY_HOST`、`DEPLOY_USER`、`DEPLOY_KEY`(SSH 私钥)。GHCR 镜像包需设为 Public(首次推送后在 Package Settings 里改)。
126
+
127
+ ## Market
128
+
129
+ Market 提供 curated 的 MCP Server 和 Hosted 平台 CLI。一键安装会创建加密 Credential,以及对应的 Server 或 CLI record:
130
+
131
+ ```bash
132
+ npm run cli -- market list
133
+ npm run cli -- market install resend --set RESEND_API_KEY=re_xxx
134
+ npm run cli -- market install gh-cli --set GH_TOKEN=ghp_xxx
135
+ npm run cli -- market uninstall gh-cli
136
+ ```
137
+
138
+ - MCP 条目可以是 remote、npm、uvx 或 Docker 实现。
139
+ - Hosted CLI 条目包含 Azure `az`、GitHub `gh`、Tailscale;它们固定平台 artifact 版本,声明 argv allow-list,并声明如何把已保存凭据映射给 CLI。
140
+ - CLI 可以使用 bearer token(`GH_TOKEN`)、Env Credential 中选定的变量(Azure service principal),或共享 MCP OAuth 授权流程完成后的 access token。
141
+ - Web 控制台的 Market 页提供相同流程;MCP/CLI 是平面 switch,切换后只显示当前平面的条目和记录。
142
+
143
+ ## Harness 接入
144
+
145
+ 先在控制台或 CLI 创建 MCP Access API Key。聚合入口的通用配置等价于:
146
+
147
+ ```json
148
+ {
149
+ "url": "https://tool.cyncyn.xyz/mcp",
150
+ "headers": {
151
+ "Authorization": "Bearer tch_mcp_..."
152
+ }
153
+ }
154
+ ```
155
+
156
+ 只接入 GitHub Server 时使用:
157
+
158
+ ```json
159
+ {
160
+ "url": "https://tool.cyncyn.xyz/mcp/github",
161
+ "headers": {
162
+ "Authorization": "Bearer tch_mcp_..."
163
+ }
164
+ }
165
+ ```
166
+
167
+ Access Key 只能调用 MCP 数据面,不能读取 Server 或 Credential 配置。Control Key 只能调用控制面,不能作为 MCP 身份使用。
168
+
169
+ ToolHome 的数据面也实现 OAuth 2.1:Harness 可通过 RFC 9728 元数据发现授权服务器,使用 Authorization Code + PKCE 获取只绑定到具体 MCP endpoint 的 access token。
170
+
171
+ 下游 Dynamic Client Registration 返回由主密钥签名的无状态 Client ID,不依赖进程内注册表;使用同一主密钥重启后仍然有效。同时支持 HTTPS URL-based Client Metadata,并限制响应大小、重定向和非公网目标。
172
+
173
+ ## 上游鉴权
174
+
175
+ Remote-native Server 支持:
176
+
177
+ - Bearer token
178
+ - API key header
179
+ - 多个自定义 headers
180
+ - OAuth 2.1 / OIDC
181
+
182
+ OAuth/OIDC 使用 MCP TypeScript SDK 的官方认证编排器,覆盖 RFC 9728 发现、Authorization Server/OIDC metadata、PKCE、RFC 9207 issuer 校验、CIMD、DCR、刷新和 RFC 8707 resource indicator。OAuth Credential 与一个 Remote Server 一对一绑定,避免 token 跨 resource 或 issuer 复用。
183
+
184
+ > 若上游授权服务器声明支持 URL-based Client Metadata 但无法从代理域名抓取(例如 Cloudflare 托管的 MCP),可设置 `TOOLHOME_OAUTH_URL_CLIENT_ID=false` 强制使用 Dynamic Client Registration。
185
+
186
+ Home-hosted Server 使用 Environment Credential 或 transport 自身的 `env`。
187
+
188
+ Secret 应放入 Credential,而不是 Remote URL query 或 stdio arguments;后两者属于结构配置,无法可靠判断哪些片段需要脱敏。
189
+
190
+ ## CLI
191
+
192
+ 构建后可以运行 `toolhome`;源码开发时使用 `npm run cli --`。
193
+
194
+ ```bash
195
+ export TOOLHOME_URL="https://tool.cyncyn.xyz"
196
+ export TOOLHOME_CONTROL_KEY="tch_ctl_<your-control-key>"
197
+ # 可选:覆盖默认的 ~/.config/toolhome/config.json 路径
198
+ export TOOLHOME_CONFIG="$HOME/.config/toolhome/config.json"
199
+ npm run cli -- auth login
200
+
201
+ npm run cli -- server list
202
+ npm run cli -- server add ./server.json
203
+ npm run cli -- credential authorize cloudflare
204
+ npm run cli -- access-key create laptop
205
+ npm run cli -- endpoint aggregate
206
+ npm run cli -- doctor
207
+ ```
208
+
209
+ `credential authorize <name>` 按凭据名(或 id)解析,自动在浏览器打开授权链接并保持等待,直到授权成功、失败或超时:
210
+
211
+ ```bash
212
+ npm run cli -- credential authorize notion --server notion # 指定 server(可省略,自动解析)
213
+ npm run cli -- credential authorize notion --force # 清掉旧 client 重新授权
214
+ npm run cli -- credential authorize notion --no-open # 不自动打开浏览器
215
+ npm run cli -- credential authorize notion --no-wait # 只打印链接,不等待
216
+ npm run cli -- credential authorize notion --timeout 300 # 等待时长(秒,默认 600)
217
+ ```
218
+
219
+ CLI 为每项 Control API 能力提供命令,并保留通用入口:
220
+
221
+ ```bash
222
+ npm run cli -- api GET /api/v1/openapi.json
223
+ ```
224
+
225
+ 默认导出只包含可审阅的脱敏配置,不能用于恢复;Credential payload、静态 HTTP Header 值和 stdio transport env 值都会被隐藏。显式包含 Secret 时,CLI 以 `0600` 权限写文件;导入会在一个 SQLite 事务中重建 Credential、重新映射关联 ID,并在任一步失败时整体回滚。
226
+
227
+ ```bash
228
+ npm run cli -- config export backup.json --include-secrets
229
+ npm run cli -- config import backup.json
230
+ ```
231
+
232
+ 备份文件包含明文 Secret,应使用与主密钥同等级别的保护。为避免 Secret 意外进入终端日志,`--include-secrets` 必须同时提供目标文件;CLI 会在写入后强制设置 `0600`。日常审阅可省略 `--include-secrets`。
233
+
234
+ ## 配置
235
+
236
+ | 环境变量 | 说明 | 默认值 |
237
+ | -------------------------------- | ------------------------------------------------- | ----------------------- |
238
+ | `TOOLHOME_HOST` | 监听地址 | `127.0.0.1` |
239
+ | `TOOLHOME_PORT` | 监听端口 | `3344` |
240
+ | `TOOLHOME_PUBLIC_URL` | 外部可访问的规范 origin,不含 path/query/fragment | `http://127.0.0.1:3344` |
241
+ | `TOOLHOME_DATA_DIR` | SQLite 与运行数据目录 | `./data` |
242
+ | `TOOLHOME_MASTER_KEY` | Secret 加密、签名与摘要根密钥,至少 32 字符 | 必填 |
243
+ | `TOOLHOME_BOOTSTRAP_CONTROL_KEY` | 数据库首次启动时写入的 Control Key | 首次必填 |
244
+ | `TOOLHOME_ALLOWED_HOSTS` | 允许的 Host,逗号分隔 | Public URL hostname |
245
+ | `TOOLHOME_LOG_LEVEL` | `debug`、`info`、`warn`、`error` | `info` |
246
+ | `TOOLHOME_WEB_DIR` | Web 控制台静态文件目录 | 未启用 |
247
+ | `TOOLHOME_MARKET_DIR` | Market npm 安装目录 | `<dataDir>/market` |
248
+ | `TOOLHOME_OAUTH_URL_CLIENT_ID` | 是否启用 URL-based Client Metadata | `true` |
249
+
250
+ ## 安全模型
251
+
252
+ - 上游 Secret 使用 AES-256-GCM 加密后写入 SQLite。
253
+ - 数据库保存加密的主密钥校验标记;误用不同主密钥时启动会立即失败,避免静默锁死现有 API Key。
254
+ - API Key 只保存 HMAC 摘要,完整 Secret 仅创建时返回。
255
+ - Control 与 MCP Access Key 使用不同前缀和验证域。
256
+ - Web 控制台把 Control Key 换成短期、HttpOnly、SameSite=Strict session cookie。
257
+ - 下游 OAuth token 具有精确 endpoint audience;聚合 token 不能调用独立 endpoint,反之亦然。
258
+ - OAuth callback 校验 state、PKCE、issuer 与发现状态。
259
+ - URL-based client metadata 会拒绝私网和非安全目标,并固定使用已校验的公网解析地址发起 HTTPS 请求,降低 SSRF 与 DNS rebinding 风险。
260
+ - 下游 DCR Client ID 使用主密钥签名,可跨进程重启验证且不在数据库保存 Client Secret。
261
+ - 诊断事件保留最近约 10,000 条;Home-hosted stderr 进入事件流前会按 transport env 与 Environment Credential 值脱敏。
262
+
263
+ 请备份数据库与 `TOOLHOME_MASTER_KEY`,或保存一份受严格保护的 `--include-secrets` 配置导出。丢失主密钥后,原数据库中的加密 Credential 无法恢复。
264
+
265
+ ## 工程命令
266
+
267
+ ```bash
268
+ npm run check
269
+ npm run format:check
270
+ npm run build
271
+ npm run test
272
+ npm run test:real
273
+ ```
274
+
275
+ `npm run test:real` 优先启动构建后的真实 ToolHome 进程,并连接 Home-hosted stdio 与 Remote-native HTTP fixture。它使用官方 MCP Client 验证聚合/独立入口、modern/legacy Harness、Progress、取消、list-changed、MRTR、Tasks 和鉴权边界;没有构建产物时回退到源码入口,便于本地诊断。
276
+
277
+ `/healthz` 只表示进程存活;`/readyz` 在运行状态不可用时返回 `503`。
278
+
279
+ ## License
280
+
281
+ [MIT](LICENSE)
@@ -0,0 +1,16 @@
1
+ import { type RuntimeConfig } from './config.js';
2
+ import { DataPlane } from './data-plane/data-plane.js';
3
+ import { type Logger } from './observability/logger.js';
4
+ import type { Store } from './storage/store.js';
5
+ import { UpstreamManager } from './upstream/manager.js';
6
+ export interface ApplicationRuntime {
7
+ app: ReturnType<DataPlane['createApp']>;
8
+ config: RuntimeConfig;
9
+ logger: Logger;
10
+ store: Store;
11
+ upstreams: UpstreamManager;
12
+ dataPlane: DataPlane;
13
+ close(): Promise<void>;
14
+ }
15
+ export declare function createApplication(config?: RuntimeConfig): ApplicationRuntime;
16
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAS7D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAKvD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAYtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAKxD,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IACxC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,eAAe,CAAC;IAC3B,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAkBD,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,aAA4B,GAAG,kBAAkB,CAwJ1F"}