@candledottv/mcp 0.6.0 → 0.6.2
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 +14 -10
- package/dist/index.js +21 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# @candledottv/mcp
|
|
2
2
|
|
|
3
3
|
An MCP (Model Context Protocol) server for the Candle agent rail. It exposes Candle's REST API as
|
|
4
|
-
|
|
4
|
+
fifteen tools over stdio, so an MCP-capable agent can launch tokens (optionally seeded with a dev
|
|
5
5
|
buy in the same call), trade, convert between base assets (including across chains), read market
|
|
6
6
|
and feed data, report on-chain activity, and check an agent profile without hand-rolling HTTP
|
|
7
7
|
calls.
|
|
8
8
|
|
|
9
9
|
## Try it without a key
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
production): `candle_get_market`, `candle_get_feed`, `candle_token_forensics`,
|
|
13
|
-
`candle_get_agent_profile`. Install the
|
|
14
|
-
server with no `env` block at all and those
|
|
11
|
+
Five tools are read-only and need nothing but `CANDLE_API_URL` (which already defaults to
|
|
12
|
+
production): `candle_get_market`, `candle_get_feed`, `candle_token_forensics`,
|
|
13
|
+
`candle_get_agent_profile`, and `candle_resolve_token`. Install the
|
|
14
|
+
server with no `env` block at all and those five work immediately:
|
|
15
15
|
|
|
16
16
|
```json
|
|
17
17
|
{
|
|
@@ -31,7 +31,7 @@ Environment below -- or skip env editing entirely: install the Candle CLI
|
|
|
31
31
|
environment.
|
|
32
32
|
|
|
33
33
|
`CANDLE_MCP_TOOLS` (optional) is a comma-separated allowlist of tool names; only those register.
|
|
34
|
-
Unset means all
|
|
34
|
+
Unset means all fifteen. An unknown name fails startup with the valid names in the message, rather
|
|
35
35
|
than silently registering the wrong surface. `candle mcp --read-only` / `--tools` set this for
|
|
36
36
|
you.
|
|
37
37
|
|
|
@@ -68,9 +68,9 @@ tools, getting a key, funding the embedded wallet, and idempotent retries, see
|
|
|
68
68
|
non-loopback host. For a trusted local endpoint that is not loopback, such as a devcontainer
|
|
69
69
|
reaching its host; not for anything that leaves the machine.
|
|
70
70
|
- `CANDLE_AGENT_API_KEY` -- an agent API key (`cndl_live_...` / `cndl_test_...`), issued from a
|
|
71
|
-
Candle account's agent settings page.
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
Candle account's agent settings page. Required by every tool except the five read-only ones
|
|
72
|
+
listed above, which includes the account-scoped reads (`candle_get_wallets`,
|
|
73
|
+
`candle_execution_status`, `candle_get_operation`) as well as the writes; those five
|
|
74
74
|
work without it, so the server is useful the moment it is installed and only asks for a key when
|
|
75
75
|
you try to write. `candle_trade` additionally needs the key's `swap:write` scope server-side,
|
|
76
76
|
which is opt-in only and never granted by omission, see `docs/mcp-launch-and-seed.md` in the
|
|
@@ -93,6 +93,10 @@ tools, getting a key, funding the embedded wallet, and idempotent retries, see
|
|
|
93
93
|
| `candle_swap` | Swap between base assets | `POST /api/v1/agent/swap` | `CANDLE_AGENT_API_KEY` (`swap:write`) |
|
|
94
94
|
| `candle_transfer` | Transfer an asset | `POST /api/v1/agent/transfer` | `CANDLE_AGENT_API_KEY` (`transfer:write`) |
|
|
95
95
|
| `candle_sweep` | Sweep a wallet to one destination | One `POST /api/v1/agent/transfer` per asset, `amountRaw: "max"` | `CANDLE_AGENT_API_KEY` (`transfer:write`) |
|
|
96
|
+
| `candle_resolve_token` | Turn a bare mint or contract address into Candle's market for it | `GET /api/v1/markets/:chain/:mint` | none |
|
|
97
|
+
| `candle_get_wallets` | The account's embedded wallets, one per chain, with delegation state | `GET /api/v1/agent/wallets/embedded` | `CANDLE_AGENT_API_KEY` |
|
|
98
|
+
| `candle_execution_status` | One call before trading: wallets to spend from, tier, and whether trading is possible | Composes the wallet and tier reads | `CANDLE_AGENT_API_KEY` |
|
|
99
|
+
| `candle_get_operation` | Look up a trade or launch by the id its write used, and whether it landed | `GET /api/v1/trade/agent/jobs/:clientId` or `/api/v1/launch/headless/jobs/:clientId` | `CANDLE_AGENT_API_KEY` |
|
|
96
100
|
|
|
97
101
|
### Transfers and sweeps
|
|
98
102
|
|
|
@@ -109,7 +113,7 @@ explicitly. Assets with nothing spendable report `empty`; a failed asset never s
|
|
|
109
113
|
## Errors
|
|
110
114
|
|
|
111
115
|
This package never reinterprets an error body, and that body is not one uniform shape across all
|
|
112
|
-
|
|
116
|
+
fifteen tools:
|
|
113
117
|
|
|
114
118
|
- `candle_launch_token`, `candle_get_market`, and `candle_get_feed` hit endpoints that use the
|
|
115
119
|
structured envelope `{ success: false, error: { code, message, ... } }`. Branch on `error.code`.
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,24 @@ function isLoopbackHost(hostname) {
|
|
|
17
17
|
return true;
|
|
18
18
|
return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host);
|
|
19
19
|
}
|
|
20
|
+
function isPrivateHost(hostname) {
|
|
21
|
+
const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
22
|
+
if (!host.includes(".") && !host.includes(":"))
|
|
23
|
+
return true;
|
|
24
|
+
if (/\.(local|internal|home\.arpa)$/.test(host))
|
|
25
|
+
return true;
|
|
26
|
+
if (/^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host))
|
|
27
|
+
return true;
|
|
28
|
+
if (/^192\.168\.\d{1,3}\.\d{1,3}$/.test(host))
|
|
29
|
+
return true;
|
|
30
|
+
if (/^172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}$/.test(host))
|
|
31
|
+
return true;
|
|
32
|
+
if (/^169\.254\.\d{1,3}\.\d{1,3}$/.test(host))
|
|
33
|
+
return true;
|
|
34
|
+
if (/^f[cd][0-9a-f]{2}:/.test(host))
|
|
35
|
+
return true;
|
|
36
|
+
return /^fe[89ab][0-9a-f]:/.test(host);
|
|
37
|
+
}
|
|
20
38
|
function assertTransportSecurity(apiUrl, env) {
|
|
21
39
|
let parsed;
|
|
22
40
|
try {
|
|
@@ -31,9 +49,9 @@ function assertTransportSecurity(apiUrl, env) {
|
|
|
31
49
|
}
|
|
32
50
|
if (isLoopbackHost(parsed.hostname))
|
|
33
51
|
return;
|
|
34
|
-
if (env.CANDLE_ALLOW_INSECURE_HTTP?.trim())
|
|
52
|
+
if (env.CANDLE_ALLOW_INSECURE_HTTP?.trim() && isPrivateHost(parsed.hostname))
|
|
35
53
|
return;
|
|
36
|
-
throw new Error(`Refusing to send credentials in the clear to ${parsed.origin}. Set CANDLE_API_URL to an https:// ` + "URL, or set CANDLE_ALLOW_INSECURE_HTTP=1 if this really is a trusted local endpoint.");
|
|
54
|
+
throw new Error(`Refusing to send credentials in the clear to ${parsed.origin}. Set CANDLE_API_URL to an https:// ` + (isPrivateHost(parsed.hostname) ? "URL, or set CANDLE_ALLOW_INSECURE_HTTP=1 if this really is a trusted local endpoint." : "URL. CANDLE_ALLOW_INSECURE_HTTP does not apply here: it covers private networks only, " + "and this is a public address."));
|
|
37
55
|
}
|
|
38
56
|
function resolveConfig(env = process.env) {
|
|
39
57
|
const apiUrl = env.CANDLE_API_URL?.trim() || DEFAULT_API_URL;
|
|
@@ -769,7 +787,7 @@ function registerTools(server, env = process.env) {
|
|
|
769
787
|
}
|
|
770
788
|
|
|
771
789
|
// src/version.ts
|
|
772
|
-
var SERVER_VERSION = "0.6.
|
|
790
|
+
var SERVER_VERSION = "0.6.2";
|
|
773
791
|
|
|
774
792
|
// src/server.ts
|
|
775
793
|
function createCandleMcpServer(env = process.env) {
|