@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 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` and `x-elfa-hmac-secret` request headers, falling back to the environment. Set `ELFA_MCP_ALLOWED_ORIGINS` to a comma separated allowlist when exposing it publicly.
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(what) {
22
- if (what === "apiKey") {
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, and ELFA_HMAC_SECRET if this action requires signing.`;
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("apiKey"));
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: "3.0.0",
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. Queries whose action is not a plain notification also need request signing.",
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", "pacifica"];
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. Some Auto mutations need ELFA_HMAC_SECRET set; notification-only ones do not.
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
- ...config.allowedOrigins.length > 0 ? { allowedOrigins: config.allowedOrigins, enableDnsRebindingProtection: true } : {}
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": "3.0.0",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elfa-ai/mcp",
3
- "version": "3.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Model Context Protocol server for the Elfa API - crypto social intelligence and the Auto condition engine",
5
5
  "license": "MIT",
6
6
  "author": "Elfa AI",