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.
- package/LICENSE +21 -0
- package/README.md +295 -0
- package/README.zh.md +281 -0
- package/dist/server/app.d.ts +16 -0
- package/dist/server/app.d.ts.map +1 -0
- package/dist/server/app.js +166 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/cli/main.d.ts +3 -0
- package/dist/server/cli/main.d.ts.map +1 -0
- package/dist/server/cli/main.js +587 -0
- package/dist/server/cli/main.js.map +1 -0
- package/dist/server/cli-plane/allow-list.d.ts +18 -0
- package/dist/server/cli-plane/allow-list.d.ts.map +1 -0
- package/dist/server/cli-plane/allow-list.js +28 -0
- package/dist/server/cli-plane/allow-list.js.map +1 -0
- package/dist/server/cli-plane/cli-service.d.ts +41 -0
- package/dist/server/cli-plane/cli-service.d.ts.map +1 -0
- package/dist/server/cli-plane/cli-service.js +282 -0
- package/dist/server/cli-plane/cli-service.js.map +1 -0
- package/dist/server/cli-plane/frames.d.ts +26 -0
- package/dist/server/cli-plane/frames.d.ts.map +1 -0
- package/dist/server/cli-plane/frames.js +12 -0
- package/dist/server/cli-plane/frames.js.map +1 -0
- package/dist/server/cli-plane/models.d.ts +174 -0
- package/dist/server/cli-plane/models.d.ts.map +1 -0
- package/dist/server/cli-plane/models.js +169 -0
- package/dist/server/cli-plane/models.js.map +1 -0
- package/dist/server/cli-plane/routes.d.ts +32 -0
- package/dist/server/cli-plane/routes.d.ts.map +1 -0
- package/dist/server/cli-plane/routes.js +94 -0
- package/dist/server/cli-plane/routes.js.map +1 -0
- package/dist/server/cli-plane/runner.d.ts +41 -0
- package/dist/server/cli-plane/runner.d.ts.map +1 -0
- package/dist/server/cli-plane/runner.js +163 -0
- package/dist/server/cli-plane/runner.js.map +1 -0
- package/dist/server/cli-plane/status.d.ts +12 -0
- package/dist/server/cli-plane/status.d.ts.map +1 -0
- package/dist/server/cli-plane/status.js +24 -0
- package/dist/server/cli-plane/status.js.map +1 -0
- package/dist/server/config/harness-import.d.ts +44 -0
- package/dist/server/config/harness-import.d.ts.map +1 -0
- package/dist/server/config/harness-import.js +166 -0
- package/dist/server/config/harness-import.js.map +1 -0
- package/dist/server/config.d.ts +20 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +80 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/control/client.d.ts +24 -0
- package/dist/server/control/client.d.ts.map +1 -0
- package/dist/server/control/client.js +115 -0
- package/dist/server/control/client.js.map +1 -0
- package/dist/server/control/control-api.d.ts +39 -0
- package/dist/server/control/control-api.d.ts.map +1 -0
- package/dist/server/control/control-api.js +291 -0
- package/dist/server/control/control-api.js.map +1 -0
- package/dist/server/control/control-service.d.ts +713 -0
- package/dist/server/control/control-service.d.ts.map +1 -0
- package/dist/server/control/control-service.js +693 -0
- package/dist/server/control/control-service.js.map +1 -0
- package/dist/server/control/openapi.d.ts +2 -0
- package/dist/server/control/openapi.d.ts.map +1 -0
- package/dist/server/control/openapi.js +370 -0
- package/dist/server/control/openapi.js.map +1 -0
- package/dist/server/data-plane/data-plane.d.ts +20 -0
- package/dist/server/data-plane/data-plane.d.ts.map +1 -0
- package/dist/server/data-plane/data-plane.js +335 -0
- package/dist/server/data-plane/data-plane.js.map +1 -0
- package/dist/server/data-plane/gateway-server.d.ts +13 -0
- package/dist/server/data-plane/gateway-server.d.ts.map +1 -0
- package/dist/server/data-plane/gateway-server.js +796 -0
- package/dist/server/data-plane/gateway-server.js.map +1 -0
- package/dist/server/data-plane/legacy-session.d.ts +18 -0
- package/dist/server/data-plane/legacy-session.d.ts.map +1 -0
- package/dist/server/data-plane/legacy-session.js +137 -0
- package/dist/server/data-plane/legacy-session.js.map +1 -0
- package/dist/server/data-plane/projection.d.ts +18 -0
- package/dist/server/data-plane/projection.d.ts.map +1 -0
- package/dist/server/data-plane/projection.js +44 -0
- package/dist/server/data-plane/projection.js.map +1 -0
- package/dist/server/data-plane/registry.d.ts +31 -0
- package/dist/server/data-plane/registry.d.ts.map +1 -0
- package/dist/server/data-plane/registry.js +129 -0
- package/dist/server/data-plane/registry.js.map +1 -0
- package/dist/server/data-plane/task-extension.d.ts +7 -0
- package/dist/server/data-plane/task-extension.d.ts.map +1 -0
- package/dist/server/data-plane/task-extension.js +33 -0
- package/dist/server/data-plane/task-extension.js.map +1 -0
- package/dist/server/data-plane/virtualization.d.ts +35 -0
- package/dist/server/data-plane/virtualization.d.ts.map +1 -0
- package/dist/server/data-plane/virtualization.js +228 -0
- package/dist/server/data-plane/virtualization.js.map +1 -0
- package/dist/server/domain/errors.d.ts +9 -0
- package/dist/server/domain/errors.d.ts.map +1 -0
- package/dist/server/domain/errors.js +19 -0
- package/dist/server/domain/errors.js.map +1 -0
- package/dist/server/domain/models.d.ts +720 -0
- package/dist/server/domain/models.d.ts.map +1 -0
- package/dist/server/domain/models.js +327 -0
- package/dist/server/domain/models.js.map +1 -0
- package/dist/server/main.d.ts +2 -0
- package/dist/server/main.d.ts.map +1 -0
- package/dist/server/main.js +37 -0
- package/dist/server/main.js.map +1 -0
- package/dist/server/manage/management-mcp.d.ts +27 -0
- package/dist/server/manage/management-mcp.d.ts.map +1 -0
- package/dist/server/manage/management-mcp.js +431 -0
- package/dist/server/manage/management-mcp.js.map +1 -0
- package/dist/server/market/catalog.d.ts +111 -0
- package/dist/server/market/catalog.d.ts.map +1 -0
- package/dist/server/market/catalog.js +784 -0
- package/dist/server/market/catalog.js.map +1 -0
- package/dist/server/market/installers.d.ts +64 -0
- package/dist/server/market/installers.d.ts.map +1 -0
- package/dist/server/market/installers.js +181 -0
- package/dist/server/market/installers.js.map +1 -0
- package/dist/server/market/market-service.d.ts +146 -0
- package/dist/server/market/market-service.d.ts.map +1 -0
- package/dist/server/market/market-service.js +930 -0
- package/dist/server/market/market-service.js.map +1 -0
- package/dist/server/observability/call-recorder.d.ts +22 -0
- package/dist/server/observability/call-recorder.d.ts.map +1 -0
- package/dist/server/observability/call-recorder.js +99 -0
- package/dist/server/observability/call-recorder.js.map +1 -0
- package/dist/server/observability/logger.d.ts +16 -0
- package/dist/server/observability/logger.d.ts.map +1 -0
- package/dist/server/observability/logger.js +25 -0
- package/dist/server/observability/logger.js.map +1 -0
- package/dist/server/security/api-keys.d.ts +15 -0
- package/dist/server/security/api-keys.d.ts.map +1 -0
- package/dist/server/security/api-keys.js +35 -0
- package/dist/server/security/api-keys.js.map +1 -0
- package/dist/server/security/auth-service.d.ts +26 -0
- package/dist/server/security/auth-service.d.ts.map +1 -0
- package/dist/server/security/auth-service.js +76 -0
- package/dist/server/security/auth-service.js.map +1 -0
- package/dist/server/security/control-session.d.ts +9 -0
- package/dist/server/security/control-session.d.ts.map +1 -0
- package/dist/server/security/control-session.js +51 -0
- package/dist/server/security/control-session.js.map +1 -0
- package/dist/server/security/credential-materializer.d.ts +20 -0
- package/dist/server/security/credential-materializer.d.ts.map +1 -0
- package/dist/server/security/credential-materializer.js +82 -0
- package/dist/server/security/credential-materializer.js.map +1 -0
- package/dist/server/security/cursor-codec.d.ts +13 -0
- package/dist/server/security/cursor-codec.d.ts.map +1 -0
- package/dist/server/security/cursor-codec.js +43 -0
- package/dist/server/security/cursor-codec.js.map +1 -0
- package/dist/server/security/oauth-routes.d.ts +21 -0
- package/dist/server/security/oauth-routes.d.ts.map +1 -0
- package/dist/server/security/oauth-routes.js +100 -0
- package/dist/server/security/oauth-routes.js.map +1 -0
- package/dist/server/security/oauth-server.d.ts +16 -0
- package/dist/server/security/oauth-server.d.ts.map +1 -0
- package/dist/server/security/oauth-server.js +544 -0
- package/dist/server/security/oauth-server.js.map +1 -0
- package/dist/server/security/secret-box.d.ts +7 -0
- package/dist/server/security/secret-box.d.ts.map +1 -0
- package/dist/server/security/secret-box.js +27 -0
- package/dist/server/security/secret-box.js.map +1 -0
- package/dist/server/security/secure-action.d.ts +21 -0
- package/dist/server/security/secure-action.d.ts.map +1 -0
- package/dist/server/security/secure-action.js +69 -0
- package/dist/server/security/secure-action.js.map +1 -0
- package/dist/server/storage/sqlite-store.d.ts +70 -0
- package/dist/server/storage/sqlite-store.d.ts.map +1 -0
- package/dist/server/storage/sqlite-store.js +1522 -0
- package/dist/server/storage/sqlite-store.js.map +1 -0
- package/dist/server/storage/store.d.ts +82 -0
- package/dist/server/storage/store.d.ts.map +1 -0
- package/dist/server/storage/store.js +2 -0
- package/dist/server/storage/store.js.map +1 -0
- package/dist/server/upstream/adapter.d.ts +52 -0
- package/dist/server/upstream/adapter.d.ts.map +1 -0
- package/dist/server/upstream/adapter.js +807 -0
- package/dist/server/upstream/adapter.js.map +1 -0
- package/dist/server/upstream/credential-resolver.d.ts +14 -0
- package/dist/server/upstream/credential-resolver.d.ts.map +1 -0
- package/dist/server/upstream/credential-resolver.js +56 -0
- package/dist/server/upstream/credential-resolver.js.map +1 -0
- package/dist/server/upstream/extension-transport.d.ts +17 -0
- package/dist/server/upstream/extension-transport.d.ts.map +1 -0
- package/dist/server/upstream/extension-transport.js +207 -0
- package/dist/server/upstream/extension-transport.js.map +1 -0
- package/dist/server/upstream/manager.d.ts +23 -0
- package/dist/server/upstream/manager.d.ts.map +1 -0
- package/dist/server/upstream/manager.js +324 -0
- package/dist/server/upstream/manager.js.map +1 -0
- package/dist/server/upstream/oauth-provider.d.ts +38 -0
- package/dist/server/upstream/oauth-provider.d.ts.map +1 -0
- package/dist/server/upstream/oauth-provider.js +225 -0
- package/dist/server/upstream/oauth-provider.js.map +1 -0
- package/dist/server/upstream/oauth-refresh.d.ts +65 -0
- package/dist/server/upstream/oauth-refresh.d.ts.map +1 -0
- package/dist/server/upstream/oauth-refresh.js +240 -0
- package/dist/server/upstream/oauth-refresh.js.map +1 -0
- package/dist/server/upstream/oauth-routes.d.ts +17 -0
- package/dist/server/upstream/oauth-routes.d.ts.map +1 -0
- package/dist/server/upstream/oauth-routes.js +87 -0
- package/dist/server/upstream/oauth-routes.js.map +1 -0
- package/dist/server/upstream/oauth-service.d.ts +143 -0
- package/dist/server/upstream/oauth-service.d.ts.map +1 -0
- package/dist/server/upstream/oauth-service.js +217 -0
- package/dist/server/upstream/oauth-service.js.map +1 -0
- package/dist/server/upstream/stable-json.d.ts +3 -0
- package/dist/server/upstream/stable-json.d.ts.map +1 -0
- package/dist/server/upstream/stable-json.js +17 -0
- package/dist/server/upstream/stable-json.js.map +1 -0
- package/package.json +69 -0
- package/skills/toolhome/SKILL.md +238 -0
- package/skills/toolhome/references/cli-reference.md +242 -0
- package/skills/toolhome/references/deployment.md +113 -0
- package/skills/toolhome/references/market-guide.md +128 -0
- package/skills/toolhome/references/oauth-guide.md +96 -0
- package/skills/toolhome/references/troubleshooting.md +133 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
## auth
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
export TOOLHOME_URL="https://tool.cyncyn.xyz"
|
|
7
|
+
export TOOLHOME_CONTROL_KEY="tch_ctl_<your-control-key>"
|
|
8
|
+
toolhome auth login --url "$TOOLHOME_URL" --control-key "$TOOLHOME_CONTROL_KEY"
|
|
9
|
+
toolhome auth logout
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Credentials saved to `~/.config/toolhome/config.json` (0600). Supports env vars `TOOLHOME_URL`, `TOOLHOME_CONTROL_KEY`, and `TOOLHOME_CONFIG` (an alternate config-file path).
|
|
13
|
+
|
|
14
|
+
## server
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
toolhome server list # list all servers
|
|
18
|
+
toolhome server get <id> # get a server by id
|
|
19
|
+
toolhome server add <file|-> # add from JSON file or stdin
|
|
20
|
+
toolhome server update <id> <file|-> # update fields (partial)
|
|
21
|
+
toolhome server delete <id> # delete a server
|
|
22
|
+
toolhome server enable <id> # enable
|
|
23
|
+
toolhome server disable <id> # disable
|
|
24
|
+
toolhome server refresh <id> # force reconnect + snapshot
|
|
25
|
+
toolhome server restart <id> # restart home-hosted stdio
|
|
26
|
+
toolhome server test <id> # test connectivity
|
|
27
|
+
toolhome server capabilities <id> # show capability snapshot
|
|
28
|
+
toolhome server status <id> # runtime status + last error
|
|
29
|
+
toolhome server logs <id> # recent log entries
|
|
30
|
+
toolhome server endpoint <id> # per-server endpoint URL
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Server JSON (create):
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"slug": "firecrawl",
|
|
38
|
+
"name": "Firecrawl",
|
|
39
|
+
"kind": "remote",
|
|
40
|
+
"transport": { "type": "streamable-http", "url": "https://mcp.firecrawl.dev/v2/mcp" },
|
|
41
|
+
"credentialId": "<uuid>",
|
|
42
|
+
"enabled": true,
|
|
43
|
+
"settings": { "urlClientId": false }
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Home-hosted stdio:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"slug": "resend",
|
|
52
|
+
"name": "Resend",
|
|
53
|
+
"kind": "home",
|
|
54
|
+
"transport": {
|
|
55
|
+
"type": "stdio",
|
|
56
|
+
"command": "/data/market/node_modules/.bin/resend-mcp",
|
|
57
|
+
"args": []
|
|
58
|
+
},
|
|
59
|
+
"credentialId": "<uuid>",
|
|
60
|
+
"enabled": true
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## credential
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
toolhome credential list # list all credentials
|
|
68
|
+
toolhome credential get <id> # get a credential
|
|
69
|
+
toolhome credential add <file|-> # add from JSON
|
|
70
|
+
toolhome credential update <id> <file|-> # update
|
|
71
|
+
toolhome credential delete <id> # delete
|
|
72
|
+
toolhome credential test <id> # validate + refresh
|
|
73
|
+
toolhome credential revoke <id> # revoke OAuth tokens
|
|
74
|
+
toolhome credential authorize <name> # start OAuth flow (by name or id)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Authorize options:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
--server <slug> specify the server (auto-resolved if omitted)
|
|
81
|
+
--force clear old client + re-authorize
|
|
82
|
+
--no-open don't open browser
|
|
83
|
+
--no-wait print URL and exit
|
|
84
|
+
--timeout <sec> wait time (default 600)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Credential JSON (create):
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{ "name": "firecrawl", "payload": { "type": "bearer", "token": "fc-xxx" } }
|
|
91
|
+
{ "name": "apifox", "payload": { "type": "headers", "headers": { "Authorization": "Bearer xxx", "X-Apifox-Api-Version": "2025-09-01" } } }
|
|
92
|
+
{ "name": "cloudflare", "payload": { "type": "oauth" } }
|
|
93
|
+
{ "name": "resend", "payload": { "type": "env", "variables": { "RESEND_API_KEY": "re_xxx" } } }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## access-key
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
toolhome access-key create <name> # returns secret once
|
|
100
|
+
toolhome access-key list
|
|
101
|
+
toolhome access-key revoke <id>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## control-key
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
toolhome control-key create <name> # returns secret once
|
|
108
|
+
toolhome control-key list
|
|
109
|
+
toolhome control-key revoke <id>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## market
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
toolhome market list # browse catalog with install status
|
|
116
|
+
toolhome market install <id> # install MCP or CLI; browser URL for missing secrets
|
|
117
|
+
toolhome market install <id> --set KEY=value # non-secret config (repeatable --set)
|
|
118
|
+
toolhome market uninstall <id> # remove MCP server or CLI and credential
|
|
119
|
+
toolhome market updates # installed vs catalog pin (+ upstream latest)
|
|
120
|
+
toolhome market update <id> # update to the catalog pin (keeps credential, restarts)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## config
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
toolhome config export <file> # redacted export
|
|
127
|
+
toolhome config export <file> --include-secrets # full backup (0600)
|
|
128
|
+
toolhome config import <file> # restore (atomic transaction)
|
|
129
|
+
toolhome config import-harness <file> [--preview] [--upsert]
|
|
130
|
+
# import a Claude Desktop / Cursor mcpServers JSON;
|
|
131
|
+
# secrets become encrypted credentials (never echoed)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Harness import accepts `{ "mcpServers": { name: { command, args, env } | { url, headers } } }`.
|
|
135
|
+
Secret-looking env keys (password/token/secret/key/authorization) and `Authorization` headers
|
|
136
|
+
are stored as encrypted credentials; everything else lands in the server transport.
|
|
137
|
+
`--upsert` re-imports as an update: existing servers are diffed (unchanged → skip,
|
|
138
|
+
changed → update transport/env/credential) instead of reported as conflicts.
|
|
139
|
+
|
|
140
|
+
## endpoint
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
toolhome endpoint aggregate # aggregate /mcp URL
|
|
144
|
+
toolhome endpoint server <id> # per-server /mcp/{slug} URL
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## diagnostics
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
toolhome status # overview (servers, credentials, keys, endpoints)
|
|
151
|
+
toolhome doctor # health check per server
|
|
152
|
+
toolhome events # recent events
|
|
153
|
+
toolhome events --limit 100 # includes hosted cli.exec audit events
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## api (raw)
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
toolhome api GET /api/v1/openapi.json
|
|
160
|
+
toolhome api POST /api/v1/servers --body ./server.json
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## cli (hosted CLI plane)
|
|
164
|
+
|
|
165
|
+
Server-side CLI hosting (Form A): register a CLI once on the ToolHome host; client
|
|
166
|
+
machines never install or log in to it. Records live in the `clis` table and execs are
|
|
167
|
+
audited in the events stream. The web console has a parallel **CLIs** page
|
|
168
|
+
(register/edit/delete, enable toggle, and a Run sheet that streams exec output).
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
toolhome cli list
|
|
172
|
+
toolhome cli get <id>
|
|
173
|
+
toolhome cli add ./cli.json
|
|
174
|
+
toolhome cli update <id> ./cli-patch.json
|
|
175
|
+
toolhome cli enable <id>
|
|
176
|
+
toolhome cli disable <id>
|
|
177
|
+
toolhome cli delete <id>
|
|
178
|
+
toolhome cli status <slug>
|
|
179
|
+
toolhome cli exec <slug> -- --version
|
|
180
|
+
toolhome cli exec <slug> --timeout 60000 --max-output-bytes 65536 -- <args...>
|
|
181
|
+
toolhome cli exec <slug> --stdin-file ./input.txt -- <args...>
|
|
182
|
+
toolhome cli exec <slug> --stdin-file - -- <args...>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`--stdin <text>` and `--stdin-file <path|->` are mutually exclusive. Put platform arguments after `--`; timeout is in milliseconds and cannot exceed the record's limit. Human output streams stdout/stderr; `--output json` emits NDJSON frames and an outcome. A failed or timed-out remote execution exits locally with code 1. Ctrl-C cancels the stream.
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# registry (Control API, admin key)
|
|
189
|
+
toolhome api GET /api/v1/clis # list registered CLIs
|
|
190
|
+
toolhome api POST /api/v1/clis --body ./cli.json # register (201); prefer Market for Azure bootstrap
|
|
191
|
+
toolhome api GET /api/v1/clis/<id> # fetch
|
|
192
|
+
echo '{"enabled":false}' | toolhome api PATCH /api/v1/clis/<id> --body -
|
|
193
|
+
toolhome api DELETE /api/v1/clis/<id> # delete
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Exec and status live on the data plane (`POST /cli/{slug}/exec`, `GET /cli/{slug}/status`):
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# exec: argv array only — never a shell string; body must be JSON
|
|
200
|
+
toolhome cli exec azure-cli --timeout 30000 -- account show -o table
|
|
201
|
+
# → 200 NDJSON stream: {"type":"stdout","data":...} {"type":"stderr","data":...}
|
|
202
|
+
# {"type":"exit","code":0,"durationMs":4211,"result":"ok"}
|
|
203
|
+
# timeout → {"type":"exit","code":null,"durationMs":...,"result":"timeout"}
|
|
204
|
+
# truncated output → exit frame carries "truncated":true
|
|
205
|
+
|
|
206
|
+
toolhome api GET /cli/azure-cli/status
|
|
207
|
+
# → { "installed":true, "version":"azure-cli 2.x", "loggedIn":true, "lastCheckedAt":"..." }
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Semantics:
|
|
211
|
+
|
|
212
|
+
- **argv array only**: `spawn(command, argv)` with no shell; a shell string is rejected (400).
|
|
213
|
+
- **Allow-list**: `deny` rules are evaluated first; a non-empty `allow` list must match at
|
|
214
|
+
least one rule (`*` matches one argv token, rules match as argv prefixes). Denied argv is
|
|
215
|
+
rejected with 403 before any process is spawned.
|
|
216
|
+
- **Credential materialization**: MCP and hosted CLI entries share the encrypted credential
|
|
217
|
+
payload format. CLI bindings project `env:<name>`, `token`, `value`, `header:<name>`, or
|
|
218
|
+
`accessToken` into the process environment. OAuth uses its stored access token and returns
|
|
219
|
+
`credential_authorization_required` until authorization is complete.
|
|
220
|
+
- **Env injection**: every exec gets `CI=true`, `NO_COLOR=1`, `PAGER=cat`, `TERM=dumb`
|
|
221
|
+
(unless the record sets `interactive: true`), plus the bound credential variables.
|
|
222
|
+
- **Status probe**: the declared `probe.command` runs in the same context; its stdout is
|
|
223
|
+
parsed as `version=...` / `loggedIn=true|false` lines; `installed` = exit code 0.
|
|
224
|
+
- **Isolation**: `executionMode: 'host'` spawns on the ToolHome host (trusted entries);
|
|
225
|
+
`'docker'` spawns a one-shot sibling container (`docker run --rm -i <image> <argv…>`).
|
|
226
|
+
`containerVolumes` are explicit Docker named volumes forwarded with `--volume`; bind paths,
|
|
227
|
+
duplicate targets, and host credential directories are rejected.
|
|
228
|
+
credential directories are never mounted implicitly. `authStrategy: "azure-service-principal"`
|
|
229
|
+
performs a fixed `az login --service-principal` bootstrap from bound environment variables,
|
|
230
|
+
while `authStrategy: "tailscale-auth-key"` starts an in-container userspace `tailscaled` and performs a fixed `tailscale --socket=... up --auth-key` bootstrap.
|
|
231
|
+
Catalog entries may use npm, Go, GitHub Release, uv, or Docker installer backends, but those
|
|
232
|
+
backends are hidden implementation details rather than separate Market products.
|
|
233
|
+
- **Audit**: every exec appends a `cli.exec` event (slug, argv, exit code, duration) visible
|
|
234
|
+
via `toolhome events` / `GET /api/v1/events`.
|
|
235
|
+
|
|
236
|
+
## global options
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
--url <url> control API URL (or TOOLHOME_URL env)
|
|
240
|
+
--key <key> control key (or TOOLHOME_CONTROL_KEY env)
|
|
241
|
+
--output <human|json> output format (default human)
|
|
242
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Deployment Guide
|
|
2
|
+
|
|
3
|
+
## Docker (Recommended)
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
# docker-compose.yml
|
|
7
|
+
services:
|
|
8
|
+
toolhome:
|
|
9
|
+
image: ghcr.io/crayonlu/toolhome:latest
|
|
10
|
+
init: true
|
|
11
|
+
restart: unless-stopped
|
|
12
|
+
ports:
|
|
13
|
+
- '127.0.0.1:3344:3344'
|
|
14
|
+
volumes:
|
|
15
|
+
- ./data:/data
|
|
16
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
17
|
+
group_add:
|
|
18
|
+
- '${DOCKER_GROUP_ID:-999}'
|
|
19
|
+
env_file: .env
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# .env
|
|
24
|
+
TOOLHOME_MASTER_KEY=<32+ char random>
|
|
25
|
+
TOOLHOME_BOOTSTRAP_CONTROL_KEY=tch_ctl_<random suffix, different from master>
|
|
26
|
+
TOOLHOME_PUBLIC_URL=https://tool.cyncyn.xyz
|
|
27
|
+
TOOLHOME_ALLOWED_HOSTS=tool.cyncyn.xyz
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
docker compose up -d
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## CI/CD (GitHub Actions)
|
|
35
|
+
|
|
36
|
+
The repo includes `.github/workflows/ci.yml` with three jobs:
|
|
37
|
+
|
|
38
|
+
1. **test**: server check + test, web typecheck + test
|
|
39
|
+
2. **docker**: build dists -> docker build -> push `ghcr.io/crayonlu/toolhome:latest`
|
|
40
|
+
3. **deploy**: download the app image artifact, build the pinned GitHub CLI image, transfer both over SSH, load them with Docker, and run `docker compose up -d`
|
|
41
|
+
|
|
42
|
+
### Required GitHub Secrets
|
|
43
|
+
|
|
44
|
+
| Secret | Value |
|
|
45
|
+
| ------------- | ------------------------------- |
|
|
46
|
+
| `DEPLOY_HOST` | Server IP or hostname |
|
|
47
|
+
| `DEPLOY_USER` | SSH username |
|
|
48
|
+
| `DEPLOY_KEY` | SSH private key (no passphrase) |
|
|
49
|
+
|
|
50
|
+
### GHCR Package Visibility
|
|
51
|
+
|
|
52
|
+
After first CI push, set the package to Public:
|
|
53
|
+
`github.com/<user>?tab=packages -> toolhome -> Package settings -> Change visibility -> Public`
|
|
54
|
+
|
|
55
|
+
### Deployment Flow
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
git push main -> test -> docker build + push GHCR -> SSH deploy -> done
|
|
59
|
+
git tag v* -> test -> docker build + push :v* tag (no deploy)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The current image job also updates `:latest` on tag pushes. Tags alone do not publish npm packages or create GitHub Releases. For a release, verify both independently: `npm view toolhome version` and `gh release list`. Build/check/test both planes, include `skills/toolhome` in the npm archive, publish npm with the user's 2FA confirmation when requested, and create a GitHub Release for the matching version tag. Never overwrite an already published npm version.
|
|
63
|
+
|
|
64
|
+
## Reverse Proxy
|
|
65
|
+
|
|
66
|
+
Put an HTTPS reverse proxy (nginx/Caddy/openresty) in front. Key requirements:
|
|
67
|
+
|
|
68
|
+
- **WebSocket/SSE support**: MCP uses Streamable HTTP with SSE responses. The proxy must not buffer SSE.
|
|
69
|
+
- **No CDN proxy for the domain**: If behind Cloudflare (orange cloud), SSE POST responses get buffered for ~25s. Use DNS-only (grey cloud) for the ToolHome subdomain.
|
|
70
|
+
- **Valid TLS certificate**: OAuth callbacks and URL-based client metadata require HTTPS.
|
|
71
|
+
|
|
72
|
+
### nginx Example
|
|
73
|
+
|
|
74
|
+
```nginx
|
|
75
|
+
location / {
|
|
76
|
+
proxy_pass http://127.0.0.1:3344;
|
|
77
|
+
proxy_http_version 1.1;
|
|
78
|
+
proxy_set_header Host $host;
|
|
79
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
80
|
+
proxy_buffering off;
|
|
81
|
+
proxy_read_timeout 600s;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Data Persistence
|
|
86
|
+
|
|
87
|
+
| Path | Content | Persist? |
|
|
88
|
+
| --------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------ |
|
|
89
|
+
| `/data/toolhome.sqlite` | SQLite database (servers, credentials, keys, events) | Yes (volume) |
|
|
90
|
+
| `/data/market/` | Market-installed npm/Go/GitHub Release artifacts | Yes (volume) |
|
|
91
|
+
| `/data/.uv/` | uv tool and cache state | Yes (volume) |
|
|
92
|
+
| Docker named volumes declared by Hosted CLI entries | Platform CLI state, such as Azure `/root/.azure` or Tailscale `/var/lib/tailscale` | Yes (volume) |
|
|
93
|
+
| `/app/dist/` | Server code (baked in image) | No (image) |
|
|
94
|
+
| `/app/web-dist/` | Web console (baked in image) | No (image) |
|
|
95
|
+
|
|
96
|
+
## Local Development
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm install
|
|
100
|
+
npm run dev # server (tsx watch)
|
|
101
|
+
npm run dev:web # web console (Vite, proxies /api to :3344)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Building from Source
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npm run build # builds server dist + web dist
|
|
108
|
+
docker compose up -d --build # build image locally
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The Dockerfile copies prebuilt `dist/` and `web/dist/` from the build context (not built in-container, to avoid memory issues on low-RAM hosts).
|
|
112
|
+
|
|
113
|
+
For Docker-backed MCP or Hosted CLI entries, keep the Docker socket mount and `group_add` configuration. The curated Tailscale CLI uses userspace networking inside the sibling container and persists its identity in the declared named volume, so it does not require a host TUN device, extra capabilities, or a special network mode. A basic `docker run --rm -i` container is sufficient for the curated read-only platform CLI entries.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Market Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Market is a curated catalog of MCP servers and hosted platform CLIs. One command installs the target, creates the credential, and configures the runtime. A Market entry represents the capability itself; installer technologies such as npm, Go, GitHub Release, uv, and Docker remain implementation details.
|
|
6
|
+
|
|
7
|
+
## Catalog Entries (35)
|
|
8
|
+
|
|
9
|
+
### Remote (OAuth)
|
|
10
|
+
|
|
11
|
+
linear, slack, stripe, figma, sentry, supabase, notion, cloudflare
|
|
12
|
+
|
|
13
|
+
### Remote (API Key)
|
|
14
|
+
|
|
15
|
+
github (PAT), context7, exa, tavily, firecrawl, openrouter, apifox
|
|
16
|
+
|
|
17
|
+
### Remote (no auth)
|
|
18
|
+
|
|
19
|
+
deepwiki
|
|
20
|
+
|
|
21
|
+
### Home-stdio MCP servers
|
|
22
|
+
|
|
23
|
+
resend, tailscale, playwright, postgres, sqlite, memory, sequential-thinking, mosaic
|
|
24
|
+
|
|
25
|
+
### Uvx-backed MCP server
|
|
26
|
+
|
|
27
|
+
fetch
|
|
28
|
+
|
|
29
|
+
### Docker-backed MCP server
|
|
30
|
+
|
|
31
|
+
markitdown
|
|
32
|
+
|
|
33
|
+
### Hosted platform CLIs
|
|
34
|
+
|
|
35
|
+
azure-cli (`az`), gh-cli (`gh`), tailscale-cli, lark-cli, firecrawl-cli (`firecrawl`), wrangler-cli (`wrangler`), vercel-cli, aliyun-cli (`aliyun`)
|
|
36
|
+
|
|
37
|
+
### Existing host binary
|
|
38
|
+
|
|
39
|
+
host-shell (`/bin/sh`), explicit opt-in for trusted shell execution. This is the ninth CLI entry; there are 26 MCP entries.
|
|
40
|
+
|
|
41
|
+
### Deployment coverage
|
|
42
|
+
|
|
43
|
+
| Installer / source | CLI execution | Curated CLI examples |
|
|
44
|
+
| --------------------------------- | ------------- | ------------------------------------------- |
|
|
45
|
+
| npm | host | Lark, Firecrawl, Wrangler, Vercel |
|
|
46
|
+
| GitHub Release archive | host | Aliyun (linux-amd64 only) |
|
|
47
|
+
| Docker image or inline Dockerfile | docker | Azure, GitHub, Tailscale |
|
|
48
|
+
| Existing host binary | host | host-shell |
|
|
49
|
+
| Go module | host | Backend supported; no curated CLI entry yet |
|
|
50
|
+
| uv / Python | host | Backend supported; no curated CLI entry yet |
|
|
51
|
+
|
|
52
|
+
There is no Cargo, apt, Homebrew, arbitrary installer-script, or remote-SSH installer backend. To use other binaries, provision them on the ToolHome host and register them with `toolhome cli add`. The catalog is curated, not an exhaustive list of platform CLIs. All five artifact installers are shared by MCP and CLI; the two execution modes are `host` and `docker`. Docker deployment includes npm, Go, uv, curl, tar, unzip, and the Docker client. Sibling containers additionally require the host socket and its group permissions.
|
|
53
|
+
|
|
54
|
+
Hosted CLI entries are parallel to MCP entries. The catalog describes the platform command, pinned artifact, credential requirements, and allowed argv; it does not expose npm, Go, uv, or Docker as products.
|
|
55
|
+
|
|
56
|
+
npm-backed CLI entries (`lark-cli`, `firecrawl-cli`, `wrangler-cli`, `vercel-cli`) install into the persistent market volume and run in host mode. Credentials are injected as environment variables (`FIRECRAWL_API_KEY`, `CLOUDFLARE_API_TOKEN`, `VERCEL_TOKEN`); `lark-cli` ships no token env var — run `lark-cli auth login --no-wait --json` through exec, complete the device flow in a browser, then finish with `lark-cli auth login --device-code <code>`. Its npm package downloads the platform binary on first execution, so the first command needs a generous exec timeout. `aliyun-cli` installs a pinned GitHub Release tarball (linux-amd64) and authenticates through `ALIBABA_CLOUD_ACCESS_KEY_ID`, `ALIBABA_CLOUD_ACCESS_KEY_SECRET`, and `ALIBABA_CLOUD_REGION_ID`; bare probe commands (its `aliyun version` probe) resolve next to the installed binary.
|
|
57
|
+
|
|
58
|
+
`gh-cli` installs without any credential and authenticates afterwards through the GitHub device flow. CI preloads `toolhome/gh-cli:2.97.0` for the managed deployment. Fresh self-hosted instances build it from the pinned upstream release when the image is unavailable; this requires access to Alpine and GitHub and supports amd64/arm64. The managed CI image sets a deployment-specific `GH_HOST` relay; the catalog fallback uses GitHub directly. Match the login hostname to the installed image's configuration. Login state persists in the `toolhome-gh-cli-state` named volume:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
toolhome cli exec gh-cli --stdin $'\n' -- auth login --hostname github.com --git-protocol https --web
|
|
62
|
+
# copy the one-time code, open https://github.com/login/device, then wait for the exec to finish
|
|
63
|
+
toolhome cli exec gh-cli -- auth status
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`gh auth token` stays denied so stored tokens can never reach argv logs; a token alternative is still possible via `gh auth login --with-token` with the token fed through exec stdin.
|
|
67
|
+
|
|
68
|
+
> ⚠️ The npm package name `mcp-server-fetch` is **squatted** by a canary (npx-confusion) package that runs code on install. The official Fetch server is Python — the catalog installs it via `uvx`, never via npm.
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
toolhome market list # browse with install status
|
|
74
|
+
toolhome market install resend # enter missing secret at browser URL
|
|
75
|
+
toolhome market install context7 # enter missing secret at browser URL
|
|
76
|
+
toolhome market install deepwiki # no config needed
|
|
77
|
+
toolhome market install fetch # uvx (Python), no config
|
|
78
|
+
toolhome market uninstall resend
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### How It Works
|
|
82
|
+
|
|
83
|
+
**Remote entries**: Creates a credential (bearer/headers/oauth) + a remote server with the upstream URL. For OAuth entries, run `toolhome credential authorize <name>` after install.
|
|
84
|
+
|
|
85
|
+
**Home-stdio entries**: The installer backend runs the pinned npm recipe, creates an env credential, and creates a home server with the stdio command pointing to the installed binary. The install is async with progress logging.
|
|
86
|
+
|
|
87
|
+
**Uvx entries**: The installer backend runs `uv tool install <package>` (Python packages from PyPI), then creates a home server that executes the installed binary from the persistent `UV_TOOL_BIN_DIR`. It does not run `uvx <package>` again during every MCP refresh, so the pinned artifact is reused without a second dependency resolution. Some entries pin extra dependencies via `--with` (e.g. `mcp-server-fetch` pins `mcp<2` because upstream still imports the pre-2.0 `McpError` name).
|
|
88
|
+
|
|
89
|
+
**Hosted CLI entries**: A CLI entry provisions a first-class CLI record and installs its pinned artifact through the entry's hidden npm, Go, GitHub Release, uvx, or Docker recipe. Execution remains argv-only and uses the same encrypted credential payloads as MCP. A declarative binding maps credential material to the platform CLI environment, for example `GH_TOKEN <- bearer token` or `AZURE_CLIENT_ID <- env:CLIENT_ID`. OAuth-backed CLI records use the stored access token and return `credential_authorization_required` until the credential is authorized. ToolHome never mounts a user's local `~/.azure`, `~/.config/gh`, `~/.aws`, or similar directory by default.
|
|
90
|
+
|
|
91
|
+
Azure service-principal entries use `authStrategy: "azure-service-principal"`: the runner starts `/bin/sh` inside the pinned Azure image, executes a fixed non-interactive `az login --service-principal` from `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, and `AZURE_TENANT_ID`, then executes the allow-listed `az` argv. The named `/root/.azure` volume preserves CLI state across runs without importing a user's local Azure profile.
|
|
92
|
+
|
|
93
|
+
Tailscale entries use `authStrategy: "tailscale-auth-key"` and an explicit named `/var/lib/tailscale` volume. Each invocation starts `tailscaled` in userspace-networking mode inside the pinned container, waits for its socket, performs the fixed `tailscale --socket=/var/run/tailscale/tailscaled.sock up --auth-key="$TS_AUTHKEY" --reset` bootstrap, then executes the allow-listed `tailscale` argv through that socket. This avoids requiring host TUN devices or kernel capabilities; the state volume preserves the node identity. The entry remains limited to the catalog's read-only `version`, `status`, and `netcheck` commands.
|
|
94
|
+
|
|
95
|
+
### Hosted CLI Authentication
|
|
96
|
+
|
|
97
|
+
MCP and CLI credentials share the encrypted `CredentialPayload` storage format and a common materialization layer:
|
|
98
|
+
|
|
99
|
+
- `env` credentials pass variables through, or select them with `env:<name>` bindings.
|
|
100
|
+
- `bearer` credentials bind with `token`.
|
|
101
|
+
- `api-key` credentials bind with `value`.
|
|
102
|
+
- `headers` credentials bind with `header:<Header-Name>`.
|
|
103
|
+
- `oauth` credentials bind with `accessToken` after authorization.
|
|
104
|
+
|
|
105
|
+
The MCP side still owns OAuth provider discovery, refresh, and callback handling. The CLI side only consumes the stored access token; it does not implement a second OAuth transport.
|
|
106
|
+
|
|
107
|
+
### Install Location
|
|
108
|
+
|
|
109
|
+
Home-stdio packages, Go binaries, and GitHub Release binaries install to `TOOLHOME_MARKET_DIR` (default `<dataDir>/market`), which is a persistent Docker volume. Packages survive container restarts. Uvx tools and caches install to `<dataDir>/.uv`, also persistent.
|
|
110
|
+
|
|
111
|
+
### Installation Progress
|
|
112
|
+
|
|
113
|
+
- CLI: shows `installing: npm install <package>...` with live progress
|
|
114
|
+
- Web console: InstallSheet shows spinner + current step + live npm output log
|
|
115
|
+
- API: `POST /market/:id/install` returns a `jobId`; `GET /market/install/:jobId` polls status
|
|
116
|
+
|
|
117
|
+
## Adding Custom Servers (outside Market)
|
|
118
|
+
|
|
119
|
+
For servers not in the catalog, use the standard CLI:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
echo '{"name":"custom","payload":{"type":"bearer","token":"xxx"}}' | toolhome credential add -
|
|
123
|
+
echo '{"slug":"custom","name":"Custom","kind":"remote","transport":{"type":"streamable-http","url":"https://example.com/mcp"},"credentialId":"<id>","enabled":true}' | toolhome server add -
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Market Catalog Source
|
|
127
|
+
|
|
128
|
+
The catalog is defined in `src/market/catalog.ts` (bundled). To add entries, edit this file and redeploy. A remote catalog URL (`TOOLHOME_MARKET_URL`) is planned for future updates without redeployment.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# OAuth Guide
|
|
2
|
+
|
|
3
|
+
## Two Registration Methods
|
|
4
|
+
|
|
5
|
+
ToolHome supports two OAuth client registration methods for upstream MCP servers:
|
|
6
|
+
|
|
7
|
+
1. **URL-based Client Metadata** (RFC 9728, default): ToolHome publishes a client metadata document at `https://<public-url>/oauth/upstream/client/<credential-id>`. The upstream authorization server fetches this document to register the client.
|
|
8
|
+
|
|
9
|
+
2. **Dynamic Client Registration (DCR)**: ToolHome POSTs client metadata to the upstream's `registration_endpoint`. The server returns a client ID.
|
|
10
|
+
|
|
11
|
+
The method is controlled by `settings.urlClientId` per server:
|
|
12
|
+
|
|
13
|
+
- `true` (default) = URL-based
|
|
14
|
+
- `false` = DCR
|
|
15
|
+
- `undefined` = inherit global `TOOLHOME_OAUTH_URL_CLIENT_ID` (default `true`)
|
|
16
|
+
|
|
17
|
+
## Per-Server Configuration
|
|
18
|
+
|
|
19
|
+
Set via CLI:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
echo '{"settings":{"urlClientId":false}}' | toolhome server update <id> -
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or via the web console: Server edit form -> "OAuth client registration" dropdown.
|
|
26
|
+
|
|
27
|
+
## Provider Compatibility
|
|
28
|
+
|
|
29
|
+
| Provider | Recommended Method | Notes |
|
|
30
|
+
| -------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| **Cloudflare** | DCR (`urlClientId: false`) | URL-based fails: 503 fetching from proxied origin |
|
|
32
|
+
| **Notion** | DCR (`urlClientId: false`) | URL-based fails: "Invalid client" |
|
|
33
|
+
| **Linear** | DCR (`urlClientId: false`) | URL-based fails: "Invalid client" |
|
|
34
|
+
| **GitHub** | PAT (not OAuth) | OAuth server doesn't support DCR; metadata discovery requires auth. Use a Personal Access Token as a bearer credential |
|
|
35
|
+
| **Slack** | URL-based (default) | No DCR endpoint; URL-based should work |
|
|
36
|
+
| **Stripe** | URL-based (default) | No DCR endpoint |
|
|
37
|
+
| **Figma** | URL-based (default) | No DCR endpoint |
|
|
38
|
+
| **Sentry** | URL-based (default) | No DCR endpoint |
|
|
39
|
+
| **Supabase** | URL-based (default) | No DCR endpoint |
|
|
40
|
+
| **Vercel** | Not compatible | Only approves localhost callbacks; incompatible with remote gateway |
|
|
41
|
+
|
|
42
|
+
## Authorization Flow
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
toolhome credential authorize <name>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
1. Resolves credential by name (or ID)
|
|
49
|
+
2. Calls `POST /api/v1/credentials/:id/authorize`
|
|
50
|
+
3. Opens the authorization URL in the browser
|
|
51
|
+
4. Waits, polling credential status every 2s
|
|
52
|
+
5. Reports success, failure, or timeout (default 600s)
|
|
53
|
+
|
|
54
|
+
### Force Re-authorization
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
toolhome credential authorize <name> --force
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Clears the stored client information and re-registers. Use when switching registration methods or changing accounts.
|
|
61
|
+
|
|
62
|
+
## Troubleshooting OAuth
|
|
63
|
+
|
|
64
|
+
### "Incompatible auth server: does not support dynamic client registration"
|
|
65
|
+
|
|
66
|
+
The upstream doesn't have a `registration_endpoint`. Switch to URL-based:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
echo '{"settings":{"urlClientId":true}}' | toolhome server update <id> -
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### "Invalid client. The clientId provided does not match."
|
|
73
|
+
|
|
74
|
+
URL-based metadata was rejected by the upstream. Switch to DCR:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
echo '{"settings":{"urlClientId":false}}' | toolhome server update <id> -
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### "invalid_redirect_uri"
|
|
81
|
+
|
|
82
|
+
The upstream only approves specific redirect URIs (e.g., Vercel only allows `http://localhost:<port>/callback`). This is incompatible with a remote gateway. Use a PAT or keep the MCP in the harness locally.
|
|
83
|
+
|
|
84
|
+
### OAuth metadata fetch fails (503)
|
|
85
|
+
|
|
86
|
+
If the ToolHome domain is behind a CDN/proxy (e.g., Cloudflare), the upstream's auth server may fail to fetch the client metadata document. Fix: use DNS-only (grey cloud) for the domain, or switch to DCR.
|
|
87
|
+
|
|
88
|
+
### Credential shows "Expired"
|
|
89
|
+
|
|
90
|
+
OAuth access tokens expire (typically 1 hour). ToolHome refreshes them lazily on connection. The web console auto-refreshes expired OAuth credentials on page load. Manual refresh:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
toolhome credential test <id>
|
|
94
|
+
# or
|
|
95
|
+
toolhome server refresh <server-id>
|
|
96
|
+
```
|