@elfa-ai/mcp 1.0.0 → 1.0.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/CHANGELOG.md +10 -1
- package/README.md +6 -1
- package/dist/index.js +64 -18
- package/manifest.json +22 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.0.
|
|
3
|
+
## 1.0.2
|
|
4
|
+
|
|
5
|
+
Fixes found by running every tool against a live API.
|
|
6
|
+
|
|
7
|
+
- `elfa_status` returned the raw key-status payload, which includes the API key itself, the account email and internal identifiers. It now reports only tier, limits, usage, scopes and expiry, and surfaces the reason when the key lookup fails
|
|
8
|
+
- Default timeout raised to 120s. The LLM-backed endpoints regularly take longer than 30s, so they timed out before returning
|
|
9
|
+
- Retries now default to 0. A timed-out request to a credit-charging endpoint was retried three times and billed each time, so a failed call could cost four times its price
|
|
10
|
+
- `elfa_narratives` reports how many mentions matched, and says so when the summariser returns nothing, instead of an unexplained empty list
|
|
11
|
+
|
|
12
|
+
## 1.0.1
|
|
4
13
|
|
|
5
14
|
First release of the TypeScript server, published as `@elfa-ai/mcp`.
|
|
6
15
|
|
package/README.md
CHANGED
|
@@ -40,9 +40,14 @@ Ask *"what's trending in crypto right now?"* to confirm it works.
|
|
|
40
40
|
| --- | --- | --- |
|
|
41
41
|
| `ELFA_API_KEY` | yes | Authenticates every request |
|
|
42
42
|
| `ELFA_HMAC_SECRET` | no | Signs Auto requests. Needed only to connect an exchange, or to run a query whose action places an order |
|
|
43
|
-
| `ELFA_TIMEOUT` | no | Request timeout in ms, default `
|
|
43
|
+
| `ELFA_TIMEOUT` | no | Request timeout in ms, default `120000` |
|
|
44
|
+
| `ELFA_RETRIES` | no | Retries on failure, default `0` |
|
|
44
45
|
| `ELFA_MCP_MAX_RESPONSE_CHARS` | no | Response size ceiling, default `60000` |
|
|
45
46
|
|
|
47
|
+
The timeout is high and retries are off on purpose. The interpretation endpoints are LLM-backed and can take over a minute, and they cost credits per attempt, so a silent retry would bill you again for a call you never saw. Raise `ELFA_RETRIES` only if you are calling the cheap measurement endpoints.
|
|
48
|
+
|
|
49
|
+
Some MCP clients apply their own timeout, often around 60 seconds. `elfa_narratives` and `elfa_chat` can exceed that; the request still completes and is still charged, even if the client gives up first.
|
|
50
|
+
|
|
46
51
|
Without `ELFA_HMAC_SECRET` everything still works except exchange linking and order-placing queries — those return a message telling you what to set.
|
|
47
52
|
|
|
48
53
|
## Tools
|
package/dist/index.js
CHANGED
|
@@ -67,6 +67,7 @@ function buildDeps(config, overrides = {}) {
|
|
|
67
67
|
const sdk = new ElfaSDK({
|
|
68
68
|
elfaApiKey: apiKey,
|
|
69
69
|
timeout: config.timeout,
|
|
70
|
+
retries: config.retries,
|
|
70
71
|
...hmacSecret ? { hmacSecret } : {},
|
|
71
72
|
...config.baseUrl ? { baseUrl: config.baseUrl } : {}
|
|
72
73
|
});
|
|
@@ -80,13 +81,19 @@ function buildDeps(config, overrides = {}) {
|
|
|
80
81
|
// src/config.ts
|
|
81
82
|
var DEFAULT_PORT = 3e3;
|
|
82
83
|
var DEFAULT_HOST = "127.0.0.1";
|
|
83
|
-
var DEFAULT_TIMEOUT =
|
|
84
|
+
var DEFAULT_TIMEOUT = 12e4;
|
|
85
|
+
var DEFAULT_RETRIES = 0;
|
|
84
86
|
var DEFAULT_MAX_RESPONSE_CHARS = 6e4;
|
|
85
87
|
function num(value, fallback) {
|
|
86
88
|
if (!value) return fallback;
|
|
87
89
|
const parsed = Number(value);
|
|
88
90
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
89
91
|
}
|
|
92
|
+
function count(value, fallback) {
|
|
93
|
+
if (!value) return fallback;
|
|
94
|
+
const parsed = Number(value);
|
|
95
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
96
|
+
}
|
|
90
97
|
function list(value) {
|
|
91
98
|
if (!value) return [];
|
|
92
99
|
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
@@ -102,6 +109,7 @@ function loadConfig(env = process.env) {
|
|
|
102
109
|
hmacSecret: env.ELFA_HMAC_SECRET || void 0,
|
|
103
110
|
baseUrl: env.ELFA_BASE_URL || void 0,
|
|
104
111
|
timeout: num(env.ELFA_TIMEOUT, DEFAULT_TIMEOUT),
|
|
112
|
+
retries: count(env.ELFA_RETRIES, DEFAULT_RETRIES),
|
|
105
113
|
maxResponseChars: num(
|
|
106
114
|
env.ELFA_MCP_MAX_RESPONSE_CHARS,
|
|
107
115
|
DEFAULT_MAX_RESPONSE_CHARS
|
|
@@ -119,7 +127,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
119
127
|
// package.json
|
|
120
128
|
var package_default = {
|
|
121
129
|
name: "@elfa-ai/mcp",
|
|
122
|
-
version: "1.0.
|
|
130
|
+
version: "1.0.2",
|
|
123
131
|
description: "Model Context Protocol server for the Elfa API - crypto social intelligence and the Auto condition engine",
|
|
124
132
|
license: "MIT",
|
|
125
133
|
author: "Elfa Team",
|
|
@@ -1043,7 +1051,7 @@ function registerNarratives(server, deps) {
|
|
|
1043
1051
|
"elfa_narratives",
|
|
1044
1052
|
{
|
|
1045
1053
|
title: "Narratives",
|
|
1046
|
-
description: "Written narrative analysis with source links, for when counts are not enough. 5 credits per call, so prefer elfa_trending or elfa_mentions when metrics will do. scope=market extracts the narratives moving the market. scope=keywords summarises events for keywords you supply.",
|
|
1054
|
+
description: "Written narrative analysis with source links, for when counts are not enough. 5 credits per call, so prefer elfa_trending or elfa_mentions when metrics will do. scope=market extracts the narratives moving the market. scope=keywords summarises events for keywords you supply, and can take over a minute to return.",
|
|
1047
1055
|
inputSchema: {
|
|
1048
1056
|
scope: z11.enum(["market", "keywords"]).default("market").describe("market is a broad sweep. keywords needs the keywords argument."),
|
|
1049
1057
|
keywords: z11.string().optional().describe("Up to 5 comma separated keywords for scope=keywords."),
|
|
@@ -1058,7 +1066,9 @@ function registerNarratives(server, deps) {
|
|
|
1058
1066
|
outputSchema: {
|
|
1059
1067
|
scope: z11.string(),
|
|
1060
1068
|
notice: z11.string(),
|
|
1061
|
-
items: z11.array(z11.record(z11.unknown()))
|
|
1069
|
+
items: z11.array(z11.record(z11.unknown())),
|
|
1070
|
+
matched: z11.number().nullable(),
|
|
1071
|
+
note: z11.string().nullable()
|
|
1062
1072
|
},
|
|
1063
1073
|
annotations: {
|
|
1064
1074
|
readOnlyHint: true,
|
|
@@ -1090,15 +1100,19 @@ function registerNarratives(server, deps) {
|
|
|
1090
1100
|
searchType: args.searchType
|
|
1091
1101
|
})
|
|
1092
1102
|
);
|
|
1103
|
+
const items2 = asArray(
|
|
1104
|
+
response2.data
|
|
1105
|
+
).map((entry) => ({
|
|
1106
|
+
summary: entry.summary,
|
|
1107
|
+
sources: asArray(entry.sourceLinks)
|
|
1108
|
+
}));
|
|
1109
|
+
const matched = response2.metadata?.total ?? null;
|
|
1093
1110
|
return {
|
|
1094
1111
|
scope: args.scope,
|
|
1095
1112
|
notice: UNTRUSTED_NOTICE,
|
|
1096
|
-
items:
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
summary: entry.summary,
|
|
1100
|
-
sources: asArray(entry.sourceLinks)
|
|
1101
|
-
}))
|
|
1113
|
+
items: items2,
|
|
1114
|
+
matched,
|
|
1115
|
+
note: items2.length === 0 && matched ? `Matched ${matched} mentions but produced no summary. Try a narrower keyword set or a different time window.` : null
|
|
1102
1116
|
};
|
|
1103
1117
|
}
|
|
1104
1118
|
const response = await deps.sdk.getTrendingNarratives(
|
|
@@ -1108,15 +1122,18 @@ function registerNarratives(server, deps) {
|
|
|
1108
1122
|
maxTweetsPerNarrative: args.maxTweetsPerNarrative
|
|
1109
1123
|
})
|
|
1110
1124
|
);
|
|
1125
|
+
const items = asArray(
|
|
1126
|
+
response.data?.trending_narratives
|
|
1127
|
+
).map((entry) => ({
|
|
1128
|
+
narrative: entry.narrative,
|
|
1129
|
+
sources: asArray(entry.source_links)
|
|
1130
|
+
}));
|
|
1111
1131
|
return {
|
|
1112
1132
|
scope: args.scope,
|
|
1113
1133
|
notice: UNTRUSTED_NOTICE,
|
|
1114
|
-
items
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
narrative: entry.narrative,
|
|
1118
|
-
sources: asArray(entry.source_links)
|
|
1119
|
-
}))
|
|
1134
|
+
items,
|
|
1135
|
+
matched: response.data?.metadata?.total_tweets ?? null,
|
|
1136
|
+
note: items.length === 0 ? "No narratives were produced for this window. Try timeFrame=week." : null
|
|
1120
1137
|
};
|
|
1121
1138
|
});
|
|
1122
1139
|
}
|
|
@@ -1125,6 +1142,33 @@ function registerNarratives(server, deps) {
|
|
|
1125
1142
|
|
|
1126
1143
|
// src/tools/status.ts
|
|
1127
1144
|
import { z as z12 } from "zod";
|
|
1145
|
+
var REPORTED = [
|
|
1146
|
+
"tier",
|
|
1147
|
+
"status",
|
|
1148
|
+
"isExpired",
|
|
1149
|
+
"expiresAt",
|
|
1150
|
+
"billingMode",
|
|
1151
|
+
"usage",
|
|
1152
|
+
"limits",
|
|
1153
|
+
"remainingRequests",
|
|
1154
|
+
"dailyRequestLimit",
|
|
1155
|
+
"monthlyRequestLimit",
|
|
1156
|
+
"requestsPerMinute",
|
|
1157
|
+
"allowOverage",
|
|
1158
|
+
"bonusCredits",
|
|
1159
|
+
"depositCredits",
|
|
1160
|
+
"spendCapCredits",
|
|
1161
|
+
"athenaEnabled",
|
|
1162
|
+
"hmacEnabled",
|
|
1163
|
+
"scopes"
|
|
1164
|
+
];
|
|
1165
|
+
function summarise(data) {
|
|
1166
|
+
const out = {};
|
|
1167
|
+
for (const field of REPORTED) {
|
|
1168
|
+
if (data[field] !== void 0) out[field] = data[field];
|
|
1169
|
+
}
|
|
1170
|
+
return out;
|
|
1171
|
+
}
|
|
1128
1172
|
function registerStatus(server, deps) {
|
|
1129
1173
|
server.registerTool(
|
|
1130
1174
|
"elfa_status",
|
|
@@ -1134,7 +1178,8 @@ function registerStatus(server, deps) {
|
|
|
1134
1178
|
inputSchema: {},
|
|
1135
1179
|
outputSchema: {
|
|
1136
1180
|
reachable: z12.boolean(),
|
|
1137
|
-
key: z12.record(z12.unknown()).nullable()
|
|
1181
|
+
key: z12.record(z12.unknown()).nullable(),
|
|
1182
|
+
problem: z12.string().nullable()
|
|
1138
1183
|
},
|
|
1139
1184
|
annotations: {
|
|
1140
1185
|
readOnlyHint: true,
|
|
@@ -1150,7 +1195,8 @@ function registerStatus(server, deps) {
|
|
|
1150
1195
|
]);
|
|
1151
1196
|
return {
|
|
1152
1197
|
reachable: ping.status === "fulfilled",
|
|
1153
|
-
key: status.status === "fulfilled" ? status.value.data : null
|
|
1198
|
+
key: status.status === "fulfilled" ? summarise(status.value.data) : null,
|
|
1199
|
+
problem: status.status === "rejected" ? describeError(status.reason) : null
|
|
1154
1200
|
};
|
|
1155
1201
|
})
|
|
1156
1202
|
);
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"server": {
|
|
3
3
|
"name": "elfa",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"docs": "https://docs.elfa.ai",
|
|
6
6
|
"spec": "https://docs.elfa.ai/swagger/swagger.json",
|
|
7
7
|
"specScope": "/v2"
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"idempotentHint": true,
|
|
19
19
|
"openWorldHint": false
|
|
20
20
|
},
|
|
21
|
-
"operations": [
|
|
21
|
+
"operations": [
|
|
22
|
+
"ping-v2",
|
|
23
|
+
"getApiKeyStatus-v2"
|
|
24
|
+
]
|
|
22
25
|
},
|
|
23
26
|
{
|
|
24
27
|
"name": "elfa_mentions",
|
|
@@ -65,7 +68,10 @@
|
|
|
65
68
|
"idempotentHint": true,
|
|
66
69
|
"openWorldHint": false
|
|
67
70
|
},
|
|
68
|
-
"operations": [
|
|
71
|
+
"operations": [
|
|
72
|
+
"getTrendingNarratives-v2",
|
|
73
|
+
"getEventSummary-v2"
|
|
74
|
+
]
|
|
69
75
|
},
|
|
70
76
|
{
|
|
71
77
|
"name": "elfa_account_stats",
|
|
@@ -78,7 +84,9 @@
|
|
|
78
84
|
"idempotentHint": true,
|
|
79
85
|
"openWorldHint": false
|
|
80
86
|
},
|
|
81
|
-
"operations": [
|
|
87
|
+
"operations": [
|
|
88
|
+
"getAccountSmartStats-v2"
|
|
89
|
+
]
|
|
82
90
|
},
|
|
83
91
|
{
|
|
84
92
|
"name": "elfa_chat",
|
|
@@ -91,7 +99,9 @@
|
|
|
91
99
|
"idempotentHint": false,
|
|
92
100
|
"openWorldHint": false
|
|
93
101
|
},
|
|
94
|
-
"operations": [
|
|
102
|
+
"operations": [
|
|
103
|
+
"chat-v2"
|
|
104
|
+
]
|
|
95
105
|
},
|
|
96
106
|
{
|
|
97
107
|
"name": "elfa_auto_build",
|
|
@@ -104,7 +114,9 @@
|
|
|
104
114
|
"idempotentHint": false,
|
|
105
115
|
"openWorldHint": false
|
|
106
116
|
},
|
|
107
|
-
"operations": [
|
|
117
|
+
"operations": [
|
|
118
|
+
"auto-chat-v2"
|
|
119
|
+
]
|
|
108
120
|
},
|
|
109
121
|
{
|
|
110
122
|
"name": "elfa_auto_validate",
|
|
@@ -117,7 +129,10 @@
|
|
|
117
129
|
"idempotentHint": true,
|
|
118
130
|
"openWorldHint": false
|
|
119
131
|
},
|
|
120
|
-
"operations": [
|
|
132
|
+
"operations": [
|
|
133
|
+
"auto-validate-query-v2",
|
|
134
|
+
"auto-validate-query-draft-v2"
|
|
135
|
+
]
|
|
121
136
|
},
|
|
122
137
|
{
|
|
123
138
|
"name": "elfa_auto_query",
|
package/package.json
CHANGED