@elfa-ai/mcp 3.0.0 → 4.1.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/CHANGELOG.md +43 -0
- package/README.md +22 -9
- package/dist/index.js +23 -50
- package/manifest.json +8 -18
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.1.0
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
- **DNS rebinding protection is now armed by default on the HTTP transport.** `enableDnsRebindingProtection` was only passed when `ELFA_MCP_ALLOWED_ORIGINS` was set, and that variable is unset in the documented local run (`ELFA_MCP_TRANSPORT=http npx -y @elfa-ai/mcp`), so the control shipped present but disarmed. The transport accepted any `Host` and any `Origin` while holding `ELFA_API_KEY`, which let a page the user visits re-point its own hostname at `127.0.0.1` and reach `tools/list` and `tools/call` at that process's own privilege — including the `auto_*` tools that spend credits. Binding to `127.0.0.1` was never a mitigation, because the victim's browser is already on loopback.
|
|
8
|
+
|
|
9
|
+
Setting the origin allowlist did not close it either. `allowedOrigins` was passed but `allowedHosts` never was, and the SDK guards each check with its own `length > 0` test, so `Host` validation never ran. An origin allowlist cannot carry this alone: a rebound request is same-origin and sends no `Origin` header, which leaves `Host` as the only header still naming the attacker's domain.
|
|
10
|
+
|
|
11
|
+
Refs GHSA-w48q-cv73-mx4w / CVE-2025-66414. Reported by mcpdone.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`ELFA_MCP_ALLOWED_HOSTS`**, a comma separated `Host` allowlist. It defaults to the loopback names the server binds — `ELFA_MCP_HOST:PORT`, `localhost:PORT` and `127.0.0.1:PORT` — so the documented local run is closed with no configuration.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **Action required for hosted deployments.** The host allowlist fails closed, so a deployment answering on any `Host` other than the loopback names the server binds now returns `403` until it sets `ELFA_MCP_ALLOWED_HOSTS`. That covers a public domain, a reverse proxy, and a container that maps the port to a different one than the server binds, since the default is derived from `ELFA_MCP_PORT`.
|
|
20
|
+
|
|
21
|
+
A minor rather than a major, because nothing about the interaction with this server changes: the eleven tools, their arguments, the stdio transport and every client-facing contract are untouched. A self-hosted HTTP deployment needs one environment variable.
|
|
22
|
+
|
|
23
|
+
**Migration:** set `ELFA_MCP_ALLOWED_HOSTS` to the host values the deployment serves, for example `ELFA_MCP_ALLOWED_HOSTS=mcp.example.com`. The stdio transport is unaffected and needs no change.
|
|
24
|
+
|
|
25
|
+
## 4.0.0
|
|
26
|
+
|
|
27
|
+
### Removed
|
|
28
|
+
|
|
29
|
+
- **`ELFA_HMAC_SECRET` and request signing are gone.** Elfa no longer documents HMAC signing for `/v2/auto/*` — the API key alone authenticates every route, including mutations. Removed here: the `ELFA_HMAC_SECRET` environment variable, the `x-elfa-hmac-secret` request header on the HTTP transport, the `elfa_hmac_secret` field in the Claude Desktop bundle, and the registry entry in `server.json`.
|
|
30
|
+
|
|
31
|
+
**Migration:** unset `ELFA_HMAC_SECRET` and stop sending `x-elfa-hmac-secret`. Neither is read any more. Nothing replaces them.
|
|
32
|
+
|
|
33
|
+
- **The client-side signing gate is gone.** `auto_query_write` and `auto_draft` no longer inspect a query's action shape and pre-reject it before sending. Every action type Elfa documents for API-key Auto — `notify`, `telegram_bot`, `webhook`, `llm` — is accepted with the API key alone, so the gate could only produce false rejections.
|
|
34
|
+
|
|
35
|
+
- **`hmacEnabled` is no longer reported by `api_status`.** The field was removed from the key-status response, so surfacing it would report something the API no longer sends.
|
|
36
|
+
|
|
37
|
+
- **`pacifica` is no longer a valid `auto_validate` exchange.** The documented enum for `method=symbol` is now `hyperliquid`, `gmx`, `binance`.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- **Spec refreshed to `2.6.3`** from `2.5.0`. A credit is now $0.0145, so the x402 reference prices move to $0.0145 (1 credit), $0.0725 (5 credits) and $0.261 (18 credits). Accounts already on PAYG keep $0.009 per credit until 28 September 2026, 16:00 UTC.
|
|
42
|
+
- **`getMarketEvents-v2` is recorded as deliberately unexposed.** It is limited to select Enterprise customers and the published operation takes no parameters, so there is no usable tool surface. Eleven tools, unchanged.
|
|
43
|
+
- Install troubleshooting no longer claims a `403` on an Auto call means Auto is not enabled in the portal. There is no separate Auto enablement step; a new API key can call `/v2/auto/*` immediately.
|
|
44
|
+
- `SECURITY.md` now states that the API key is read from the environment on stdio and can arrive per request as `x-elfa-api-key` over HTTP, and refers to the tools by their current names.
|
|
45
|
+
|
|
3
46
|
## 3.0.0
|
|
4
47
|
|
|
5
48
|
### Removed
|
package/README.md
CHANGED
|
@@ -48,7 +48,6 @@ Ask *"what's trending in crypto right now?"* to confirm it works.
|
|
|
48
48
|
| Variable | Required | Purpose |
|
|
49
49
|
| --- | --- | --- |
|
|
50
50
|
| `ELFA_API_KEY` | yes | Authenticates every request |
|
|
51
|
-
| `ELFA_HMAC_SECRET` | no | Signs Auto mutations when signing is required. Notification-only query mutations do not need it |
|
|
52
51
|
| `ELFA_TIMEOUT` | no | Request timeout in ms, default `120000` |
|
|
53
52
|
| `ELFA_RETRIES` | no | Retries on failure, default `0` |
|
|
54
53
|
| `ELFA_MCP_MAX_RESPONSE_CHARS` | no | Response size ceiling, default `60000` |
|
|
@@ -58,8 +57,6 @@ The timeout is high and retries are off on purpose. The interpretation endpoints
|
|
|
58
57
|
|
|
59
58
|
Some MCP clients apply their own timeout, often around 60 seconds. `narratives` and `market_chat` can exceed that; the request still completes and is still charged, even if the client gives up first.
|
|
60
59
|
|
|
61
|
-
Without `ELFA_HMAC_SECRET` notification-only Auto mutations still work. Anything else returns a message telling you what to set.
|
|
62
|
-
|
|
63
60
|
## Tools
|
|
64
61
|
|
|
65
62
|
<!-- tools:start -->
|
|
@@ -69,10 +66,10 @@ Without `ELFA_HMAC_SECRET` notification-only Auto mutations still work. Anything
|
|
|
69
66
|
| Tool | Mode | Cost | What it does |
|
|
70
67
|
| --- | --- | --- | --- |
|
|
71
68
|
| `api_status` | read | Free | Check API key tier, credit usage and remaining requests. Also confirms the API is reachable. |
|
|
72
|
-
| `mentions` | read | 1 per call | Social mentions from X and Telegram. mode=top ranks a ticker's mentions by engagement, mode=search filters by keyword or account, mode=news returns the token news feed. |
|
|
69
|
+
| `mentions` | read | 1 per call | Social mentions from X and Telegram. mode=top ranks a ticker's mentions by engagement, mode=search filters by keyword or account, mode=news returns the token news feed, which is X posts from accounts tagged as news sources rather than articles from news outlets. |
|
|
73
70
|
| `trending` | read | 1 per call | What is gaining social attention. scope=tokens for tickers, scope=contracts_twitter or scope=contracts_telegram for contract addresses. |
|
|
74
71
|
| `narratives` | read | 5 per call | Written narrative analysis with source links. scope=market extracts market-wide narratives, scope=keywords summarises events for specific keywords. |
|
|
75
|
-
| `account_stats` | read | 1 per call | Smart follower and engagement stats for an X account. |
|
|
72
|
+
| `account_stats` | read | 1 per call | Smart follower and engagement stats for an X account. Legacy: it still works, but will be removed on 28 October 2026. |
|
|
76
73
|
| `market_chat` | read | Varies by speed | Ask for written market analysis. Supports conversational chat, macro overview, quick summary, token intro, token analysis and account analysis. |
|
|
77
74
|
| `auto_build` | read | 1 plus LLM usage | Turn a plain-language monitoring request into an EQL query. Returns a draft to validate and activate, it does not activate anything itself. |
|
|
78
75
|
| `auto_validate` | read | Free | Check EQL syntax and get a cost estimate before activating, or check that a symbol has market data on a venue. |
|
|
@@ -82,12 +79,10 @@ Without `ELFA_HMAC_SECRET` notification-only Auto mutations still work. Anything
|
|
|
82
79
|
|
|
83
80
|
Not exposed as tools:
|
|
84
81
|
|
|
82
|
+
- `getMarketEvents-v2` — Available only to select Enterprise customers, and the published operation takes no parameters. Contact sales@elfa.ai for access.
|
|
85
83
|
- `chat-stream-v2` — A tool call returns one result, so streaming adds nothing. market_chat covers the same analysis.
|
|
86
84
|
- `auto-stream-queries-v2` — Long lived streams have no tool equivalent. Poll with auto_query.
|
|
87
85
|
- `auto-stream-query-v2` — Long lived streams have no tool equivalent. Poll with auto_query.
|
|
88
|
-
- `auto-list-exchanges-v2` — Exchange connections are no longer part of the documented Auto surface.
|
|
89
|
-
- `auto-connect-exchange-v2` — Exchange connections are no longer part of the documented Auto surface.
|
|
90
|
-
- `auto-disconnect-exchange-v2` — Exchange connections are no longer part of the documented Auto surface.
|
|
91
86
|
|
|
92
87
|
<!-- tools:end -->
|
|
93
88
|
|
|
@@ -128,7 +123,25 @@ The same server runs over Streamable HTTP for hosted deployments:
|
|
|
128
123
|
ELFA_MCP_TRANSPORT=http ELFA_MCP_PORT=3000 npx -y @elfa-ai/mcp
|
|
129
124
|
```
|
|
130
125
|
|
|
131
|
-
It is stateless — no sessions, one server instance per request, safe behind a load balancer. Credentials come from `x-elfa-api-key`
|
|
126
|
+
It is stateless — no sessions, one server instance per request, safe behind a load balancer. Credentials come from the `x-elfa-api-key` request header, falling back to the environment.
|
|
127
|
+
|
|
128
|
+
DNS rebinding protection is on by default. The server accepts only the loopback names it binds — `localhost:PORT` and `127.0.0.1:PORT` — which covers the local run above and nothing else. Any deployment that answers on a different `Host` must list the values it serves:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
ELFA_MCP_ALLOWED_HOSTS=mcp.example.com
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
That includes a public domain, a reverse proxy, and a container that maps the port to a different one than the server binds. A `Host` the list does not cover is rejected with 403.
|
|
135
|
+
|
|
136
|
+
| Variable | Required | Purpose |
|
|
137
|
+
| --- | --- | --- |
|
|
138
|
+
| `ELFA_MCP_TRANSPORT` | no | `http` to serve over Streamable HTTP, default `stdio` |
|
|
139
|
+
| `ELFA_MCP_HOST` | no | Bind address, default `127.0.0.1` |
|
|
140
|
+
| `ELFA_MCP_PORT` | no | Bind port, default `3000` |
|
|
141
|
+
| `ELFA_MCP_ALLOWED_HOSTS` | no | Comma separated `Host` allowlist, defaults to the loopback names bound |
|
|
142
|
+
| `ELFA_MCP_ALLOWED_ORIGINS` | no | Comma separated `Origin` allowlist |
|
|
143
|
+
|
|
144
|
+
Set `ELFA_MCP_ALLOWED_ORIGINS` as well when browsers call the server directly. It complements the host allowlist rather than replacing it: a rebound request is same origin, so it carries no `Origin` header for that list to check, and the `Host` header is the only one still naming the attacker's domain.
|
|
132
145
|
|
|
133
146
|
## Safety
|
|
134
147
|
|
package/dist/index.js
CHANGED
|
@@ -18,11 +18,8 @@ function messageOf(error) {
|
|
|
18
18
|
if (typeof error === "string") return error;
|
|
19
19
|
return "Unknown error";
|
|
20
20
|
}
|
|
21
|
-
function missingCredential(
|
|
22
|
-
|
|
23
|
-
return `No Elfa API key configured. Set ELFA_API_KEY in the MCP server environment, or send it as an x-elfa-api-key header when using the HTTP transport. Get a key at ${DOCS}.`;
|
|
24
|
-
}
|
|
25
|
-
return `This action requires request signing. Set ELFA_HMAC_SECRET in the MCP server environment, then retry. Notification-only Auto queries work without it. See ${DOCS}/auto/api-key-auth.`;
|
|
21
|
+
function missingCredential() {
|
|
22
|
+
return `No Elfa API key configured. Set ELFA_API_KEY in the MCP server environment, or send it as an x-elfa-api-key header when using the HTTP transport. Get a key at ${DOCS}.`;
|
|
26
23
|
}
|
|
27
24
|
function describeError(error) {
|
|
28
25
|
const status = statusOf(error);
|
|
@@ -31,7 +28,7 @@ function describeError(error) {
|
|
|
31
28
|
case 400:
|
|
32
29
|
return `Request rejected as invalid: ${detail}. Check the argument values and retry.`;
|
|
33
30
|
case 401:
|
|
34
|
-
return `Authentication failed: ${detail}. Verify ELFA_API_KEY
|
|
31
|
+
return `Authentication failed: ${detail}. Verify ELFA_API_KEY.`;
|
|
35
32
|
case 402:
|
|
36
33
|
return `Out of credits: ${detail}. Top up or upgrade the plan, then retry.`;
|
|
37
34
|
case 403:
|
|
@@ -60,21 +57,18 @@ var CredentialError = class extends Error {
|
|
|
60
57
|
};
|
|
61
58
|
function buildDeps(config, overrides = {}) {
|
|
62
59
|
const apiKey = overrides.apiKey ?? config.apiKey;
|
|
63
|
-
const hmacSecret = overrides.hmacSecret ?? config.hmacSecret;
|
|
64
60
|
if (!apiKey) {
|
|
65
|
-
throw new CredentialError(missingCredential(
|
|
61
|
+
throw new CredentialError(missingCredential());
|
|
66
62
|
}
|
|
67
63
|
const sdk = new ElfaSDK({
|
|
68
64
|
elfaApiKey: apiKey,
|
|
69
65
|
timeout: config.timeout,
|
|
70
66
|
retries: config.retries,
|
|
71
|
-
...hmacSecret ? { hmacSecret } : {},
|
|
72
67
|
...config.baseUrl ? { baseUrl: config.baseUrl } : {},
|
|
73
68
|
...config.extraHeaders ? { headers: config.extraHeaders } : {}
|
|
74
69
|
});
|
|
75
70
|
return {
|
|
76
71
|
sdk,
|
|
77
|
-
hasHmac: Boolean(hmacSecret),
|
|
78
72
|
maxResponseChars: config.maxResponseChars
|
|
79
73
|
};
|
|
80
74
|
}
|
|
@@ -125,8 +119,8 @@ function loadConfig(env = process.env) {
|
|
|
125
119
|
port: num(env.ELFA_MCP_PORT, DEFAULT_PORT),
|
|
126
120
|
host: env.ELFA_MCP_HOST || DEFAULT_HOST,
|
|
127
121
|
allowedOrigins: list(env.ELFA_MCP_ALLOWED_ORIGINS),
|
|
122
|
+
allowedHosts: list(env.ELFA_MCP_ALLOWED_HOSTS),
|
|
128
123
|
apiKey: env.ELFA_API_KEY || void 0,
|
|
129
|
-
hmacSecret: env.ELFA_HMAC_SECRET || void 0,
|
|
130
124
|
baseUrl: env.ELFA_BASE_URL || void 0,
|
|
131
125
|
extraHeaders: headers(env.ELFA_EXTRA_HEADERS),
|
|
132
126
|
timeout: num(env.ELFA_TIMEOUT, DEFAULT_TIMEOUT),
|
|
@@ -148,7 +142,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
148
142
|
// package.json
|
|
149
143
|
var package_default = {
|
|
150
144
|
name: "@elfa-ai/mcp",
|
|
151
|
-
version: "
|
|
145
|
+
version: "4.1.0",
|
|
152
146
|
description: "Model Context Protocol server for the Elfa API - crypto social intelligence and the Auto condition engine",
|
|
153
147
|
license: "MIT",
|
|
154
148
|
author: "Elfa AI",
|
|
@@ -337,29 +331,6 @@ function pickDefined(input) {
|
|
|
337
331
|
}
|
|
338
332
|
return out;
|
|
339
333
|
}
|
|
340
|
-
var NOTIFICATION_ACTIONS = /* @__PURE__ */ new Set(["notify", "telegram_bot", "webhook"]);
|
|
341
|
-
function isRecord(value) {
|
|
342
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
343
|
-
}
|
|
344
|
-
function isNotificationAction(action) {
|
|
345
|
-
if (!isRecord(action)) return false;
|
|
346
|
-
if (typeof action.type !== "string") return false;
|
|
347
|
-
if (NOTIFICATION_ACTIONS.has(action.type)) return true;
|
|
348
|
-
if (action.type === "llm") {
|
|
349
|
-
if (!isRecord(action.params)) return false;
|
|
350
|
-
if (!isRecord(action.params.callback)) return false;
|
|
351
|
-
const callbackAction = action.params.callback.action;
|
|
352
|
-
if (!isRecord(callbackAction)) return false;
|
|
353
|
-
return typeof callbackAction.type === "string" && NOTIFICATION_ACTIONS.has(callbackAction.type);
|
|
354
|
-
}
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
function requiresSignature(query) {
|
|
358
|
-
if (!isRecord(query)) return true;
|
|
359
|
-
const actions = query.actions;
|
|
360
|
-
if (!Array.isArray(actions) || actions.length === 0) return true;
|
|
361
|
-
return !actions.every(isNotificationAction);
|
|
362
|
-
}
|
|
363
334
|
|
|
364
335
|
// src/tools/account.ts
|
|
365
336
|
function registerAccountStats(server, deps) {
|
|
@@ -367,7 +338,7 @@ function registerAccountStats(server, deps) {
|
|
|
367
338
|
"account_stats",
|
|
368
339
|
{
|
|
369
340
|
title: "Account stats",
|
|
370
|
-
description: "Smart follower and engagement stats for an X account. 1 credit per call. Use it to judge whether an account's reach is real before weighting what it posts.",
|
|
341
|
+
description: "Smart follower and engagement stats for an X account. 1 credit per call. Use it to judge whether an account's reach is real before weighting what it posts. Returns raw metrics, not a reputation score, so the signal is in the ratios. Legacy: it still works today and keeps working until 28 October 2026, when it will be removed, and it is not being extended before then. Build new work on mentions with mode=search, which returns the posting account alongside each post's engagement metrics.",
|
|
371
342
|
inputSchema: {
|
|
372
343
|
username: z2.string().describe("X username, with or without the @.")
|
|
373
344
|
},
|
|
@@ -486,9 +457,6 @@ function registerAutoDraft(server, deps) {
|
|
|
486
457
|
if (!args.query) {
|
|
487
458
|
return fail("method=upsert needs a query. Build one with auto_build.");
|
|
488
459
|
}
|
|
489
|
-
if (requiresSignature(args.query) && !deps.hasHmac) {
|
|
490
|
-
return fail(missingCredential("hmacSecret"));
|
|
491
|
-
}
|
|
492
460
|
}
|
|
493
461
|
const needsId = args.method === "get" || args.method === "delete" || args.method === "convert";
|
|
494
462
|
if (needsId && !args.draftId) {
|
|
@@ -656,7 +624,7 @@ function registerAutoQueryWrite(server, deps) {
|
|
|
656
624
|
"auto_query_write",
|
|
657
625
|
{
|
|
658
626
|
title: "Write Auto queries",
|
|
659
|
-
description: "Activate, cancel or delete an Auto query. Creating costs 5 credits plus LLM usage, cancel and delete are free. An activated query runs unattended and fires its action without asking again, so validate it with auto_validate and confirm the cost and the action with the user before calling this.
|
|
627
|
+
description: "Activate, cancel or delete an Auto query. Creating costs 5 credits plus LLM usage, cancel and delete are free. An activated query runs unattended and fires its action without asking again, so validate it with auto_validate and confirm the cost and the action with the user before calling this.",
|
|
660
628
|
inputSchema: {
|
|
661
629
|
method: z6.enum(["create", "cancel", "delete"]).describe(
|
|
662
630
|
"create activates a new query. cancel stops an active one. delete removes one that has already finished."
|
|
@@ -682,9 +650,6 @@ function registerAutoQueryWrite(server, deps) {
|
|
|
682
650
|
if (!args.query) {
|
|
683
651
|
return fail("method=create needs a query. Build one with auto_build.");
|
|
684
652
|
}
|
|
685
|
-
if (requiresSignature(args.query) && !deps.hasHmac) {
|
|
686
|
-
return fail(missingCredential("hmacSecret"));
|
|
687
|
-
}
|
|
688
653
|
} else if (!args.queryId) {
|
|
689
654
|
return fail(`method=${args.method} needs queryId. Find one with auto_query.`);
|
|
690
655
|
}
|
|
@@ -708,7 +673,7 @@ function registerAutoQueryWrite(server, deps) {
|
|
|
708
673
|
|
|
709
674
|
// src/tools/autoValidate.ts
|
|
710
675
|
import { z as z7 } from "zod";
|
|
711
|
-
var EXCHANGES = ["hyperliquid", "gmx", "binance"
|
|
676
|
+
var EXCHANGES = ["hyperliquid", "gmx", "binance"];
|
|
712
677
|
function registerAutoValidate(server, deps) {
|
|
713
678
|
server.registerTool(
|
|
714
679
|
"auto_validate",
|
|
@@ -869,7 +834,7 @@ function registerMentions(server, deps) {
|
|
|
869
834
|
"mentions",
|
|
870
835
|
{
|
|
871
836
|
title: "Mentions",
|
|
872
|
-
description: "Social mentions from X and Telegram. 1 credit per call. Returns engagement metrics and a link per post, not the post text. mode=top ranks one ticker's mentions by engagement. mode=search filters by keywords or by account. mode=news returns the token news feed.",
|
|
837
|
+
description: "Social mentions from X and Telegram. 1 credit per call. Returns engagement metrics and a link per post, not the post text. mode=top ranks one ticker's mentions by engagement. mode=search filters by keywords or by account. mode=news returns the token news feed, which is X posts from accounts tagged as news sources rather than articles from news outlets.",
|
|
873
838
|
inputSchema: {
|
|
874
839
|
mode: z9.enum(["top", "search", "news"]).describe(
|
|
875
840
|
"top needs ticker. search needs keywords or accountName. news is a feed and needs neither."
|
|
@@ -1116,7 +1081,6 @@ var REPORTED = [
|
|
|
1116
1081
|
"depositCredits",
|
|
1117
1082
|
"spendCapCredits",
|
|
1118
1083
|
"athenaEnabled",
|
|
1119
|
-
"hmacEnabled",
|
|
1120
1084
|
"scopes"
|
|
1121
1085
|
];
|
|
1122
1086
|
function summarise(data) {
|
|
@@ -1242,7 +1206,7 @@ var INSTRUCTIONS = `Elfa gives you crypto social intelligence plus Auto, a condi
|
|
|
1242
1206
|
|
|
1243
1207
|
Start cheap. trending, mentions and account_stats cost 1 credit. narratives costs 5 and market_chat costs more, so reach for them only when metrics are not enough. If a call fails on auth or credits, check api_status.
|
|
1244
1208
|
|
|
1245
|
-
Auto is a three step flow: auto_build drafts EQL from plain language, auto_validate checks it and returns the cost, auto_query_write activates it. Never activate without showing the user the estimated cost and the action that will fire.
|
|
1209
|
+
Auto is a three step flow: auto_build drafts EQL from plain language, auto_validate checks it and returns the cost, auto_query_write activates it. Never activate without showing the user the estimated cost and the action that will fire.
|
|
1246
1210
|
|
|
1247
1211
|
Auto has no push channel here. Poll auto_query with method=get and wait for pollAfterSeconds between calls.
|
|
1248
1212
|
|
|
@@ -1279,6 +1243,14 @@ function jsonRpcError(res, status, message) {
|
|
|
1279
1243
|
id: null
|
|
1280
1244
|
});
|
|
1281
1245
|
}
|
|
1246
|
+
function defaultAllowedHosts(config) {
|
|
1247
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
1248
|
+
for (const name of [config.host, "localhost", "127.0.0.1", "[::1]"]) {
|
|
1249
|
+
hosts.add(`${name}:${config.port}`);
|
|
1250
|
+
if (config.port === 80) hosts.add(name);
|
|
1251
|
+
}
|
|
1252
|
+
return [...hosts];
|
|
1253
|
+
}
|
|
1282
1254
|
function createHttpApp(config) {
|
|
1283
1255
|
const app = express();
|
|
1284
1256
|
app.disable("x-powered-by");
|
|
@@ -1305,12 +1277,13 @@ function createHttpApp(config) {
|
|
|
1305
1277
|
let transport;
|
|
1306
1278
|
try {
|
|
1307
1279
|
const deps = buildDeps(config, {
|
|
1308
|
-
apiKey: header(req, "x-elfa-api-key")
|
|
1309
|
-
hmacSecret: header(req, "x-elfa-hmac-secret")
|
|
1280
|
+
apiKey: header(req, "x-elfa-api-key")
|
|
1310
1281
|
});
|
|
1311
1282
|
server = createServer(deps);
|
|
1312
1283
|
transport = new StreamableHTTPServerTransport({
|
|
1313
|
-
|
|
1284
|
+
enableDnsRebindingProtection: true,
|
|
1285
|
+
allowedHosts: config.allowedHosts.length > 0 ? config.allowedHosts : defaultAllowedHosts(config),
|
|
1286
|
+
...config.allowedOrigins.length > 0 ? { allowedOrigins: config.allowedOrigins } : {}
|
|
1314
1287
|
});
|
|
1315
1288
|
res.on("close", () => {
|
|
1316
1289
|
void transport?.close();
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"server": {
|
|
3
3
|
"name": "elfa",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.1.0",
|
|
5
5
|
"docs": "https://docs.elfa.ai",
|
|
6
6
|
"spec": "https://docs.elfa.ai/swagger/swagger.json",
|
|
7
7
|
"specScope": "/v2"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
{
|
|
27
27
|
"name": "mentions",
|
|
28
28
|
"title": "Mentions",
|
|
29
|
-
"summary": "Social mentions from X and Telegram. mode=top ranks a ticker's mentions by engagement, mode=search filters by keyword or account, mode=news returns the token news feed.",
|
|
29
|
+
"summary": "Social mentions from X and Telegram. mode=top ranks a ticker's mentions by engagement, mode=search filters by keyword or account, mode=news returns the token news feed, which is X posts from accounts tagged as news sources rather than articles from news outlets.",
|
|
30
30
|
"credits": "1 per call",
|
|
31
31
|
"annotations": {
|
|
32
32
|
"readOnlyHint": true,
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
{
|
|
77
77
|
"name": "account_stats",
|
|
78
78
|
"title": "Account stats",
|
|
79
|
-
"summary": "Smart follower and engagement stats for an X account.",
|
|
79
|
+
"summary": "Smart follower and engagement stats for an X account. Legacy: it still works, but will be removed on 28 October 2026.",
|
|
80
80
|
"credits": "1 per call",
|
|
81
81
|
"annotations": {
|
|
82
82
|
"readOnlyHint": true,
|
|
@@ -193,6 +193,11 @@
|
|
|
193
193
|
}
|
|
194
194
|
],
|
|
195
195
|
"unexposed": [
|
|
196
|
+
{
|
|
197
|
+
"operationId": "getMarketEvents-v2",
|
|
198
|
+
"reason": "restricted",
|
|
199
|
+
"note": "Available only to select Enterprise customers, and the published operation takes no parameters. Contact sales@elfa.ai for access."
|
|
200
|
+
},
|
|
196
201
|
{
|
|
197
202
|
"operationId": "chat-stream-v2",
|
|
198
203
|
"reason": "sse",
|
|
@@ -207,21 +212,6 @@
|
|
|
207
212
|
"operationId": "auto-stream-query-v2",
|
|
208
213
|
"reason": "sse",
|
|
209
214
|
"note": "Long lived streams have no tool equivalent. Poll with auto_query."
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
"operationId": "auto-list-exchanges-v2",
|
|
213
|
-
"reason": "not-advertised",
|
|
214
|
-
"note": "Exchange connections are no longer part of the documented Auto surface."
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
"operationId": "auto-connect-exchange-v2",
|
|
218
|
-
"reason": "not-advertised",
|
|
219
|
-
"note": "Exchange connections are no longer part of the documented Auto surface."
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
"operationId": "auto-disconnect-exchange-v2",
|
|
223
|
-
"reason": "not-advertised",
|
|
224
|
-
"note": "Exchange connections are no longer part of the documented Auto surface."
|
|
225
215
|
}
|
|
226
216
|
]
|
|
227
217
|
}
|
package/package.json
CHANGED