equisense-research-mcp 0.3.0 → 0.3.1

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.
Files changed (3) hide show
  1. package/README.md +11 -28
  2. package/index.js +10 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -14,30 +14,13 @@ Published on npm: [`equisense-research-mcp`](https://www.npmjs.com/package/equis
14
14
 
15
15
  ## Quick start
16
16
 
17
- ### 1. Mint a token
17
+ ### 1. Generate a token (self-serve)
18
18
 
19
- The MCP authenticates via a 90-day HMAC bearer token, byte-identical to a logged-in `ES_AUTH` session cookie. Mint it via the admin endpoint (admin-IP-restricted in prod via nginx; reachable on localhost in dev):
19
+ Log in to the EquiSense web app and open **Settings Claude → Connect Claude**. You get a **research-scoped, individually-revocable** token, shown once. Copy it (the web UI even pre-fills the full config block for you).
20
20
 
21
- ```bash
22
- # Prod (must be on an admin-allowlisted IP)
23
- curl -X POST "https://equisense.ai/api/v1/admin/auth/mint-mcp-token?phoneNumber=9876543210"
24
-
25
- # Dev
26
- curl -X POST "http://localhost:8080/api/v1/admin/auth/mint-mcp-token?phoneNumber=9876543210"
27
- ```
28
-
29
- Response:
30
- ```json
31
- {
32
- "token": "<payload>.<sig>",
33
- "expiresAt": 1777777777,
34
- "userId": "user-abc",
35
- "phone": "9876543210",
36
- "ttlSeconds": 7776000
37
- }
38
- ```
21
+ The token authenticates as `Authorization: Bearer <token>` and is limited to the research API — it cannot trade, change account settings, or mint further tokens. Revoke it any time from the same Settings page; revocation takes effect immediately.
39
22
 
40
- Copy the `token`. Treat it like a password.
23
+ > The old admin endpoint `POST /api/v1/admin/auth/mint-mcp-token` is **deprecated** — it issued full-account session tokens with no per-token revocation. Use Settings → Claude instead.
41
24
 
42
25
  ### 2. Register the MCP with Claude Code
43
26
 
@@ -46,7 +29,7 @@ Copy the `token`. Treat it like a password.
46
29
  ```bash
47
30
  claude mcp add equisense-research --scope local \
48
31
  --env EQUISENSE_BASE_URL=https://equisense.ai \
49
- --env EQUISENSE_MCP_TOKEN='<token from step 1>' \
32
+ --env EQUISENSE_MCP_TOKEN='<token from Settings → Claude>' \
50
33
  -- npx -y equisense-research-mcp
51
34
  ```
52
35
 
@@ -84,14 +67,15 @@ You should get back `{ answer, companyName, isin, detectedIntent, followUpQuesti
84
67
  |---|---|---|
85
68
  | `EQUISENSE_BASE_URL` | `http://localhost:8080` | Backend root URL |
86
69
  | `EQUISENSE_TIMEOUT_MS` | `90000` | Per-request timeout (research queries can take 30–90s) |
87
- | `EQUISENSE_MCP_TOKEN` | **required** | HMAC bearer token. Treat like a password. |
70
+ | `EQUISENSE_MCP_TOKEN` | **required** | Scoped bearer token from Settings → Claude. Treat like a password. |
88
71
 
89
72
  ## Security notes
90
73
 
91
- - The minted token grants **full session access** for 90 days, scope-equivalent to a logged-in browser session for that user. Not scoped to research-only.
92
- - There is no per-token revocation in v1. The only way to invalidate a token early is to rotate the global `auth.token.secret` (which logs out every user).
74
+ - The token is **research-scoped** it can only call the research API (`/api/v1/research/*`), enforced by the backend registering its authenticator only on those paths. It cannot trade, change account settings, or mint further tokens.
75
+ - The token is **individually revocable** from Settings → Claude. Revocation is immediate: a revoked token gets a `401` on the next call, with no signature-only fallback.
76
+ - Tokens last 90 days. The wrapper also sends the token as a legacy `Cookie: ES_AUTH` header so older admin-minted session tokens keep working during migration; new scoped tokens authenticate via `Authorization: Bearer`.
93
77
  - Never commit the token. Never log it. Never paste it into chat.
94
- - Each `ask_equisense` call counts against the represented user's `AI_EQUITY_RESEARCH` daily quota — same metering as the web UI.
78
+ - Each `ask_equisense` call counts against the user's `AI_EQUITY_RESEARCH` daily quota — same metering as the web UI.
95
79
 
96
80
  ---
97
81
 
@@ -128,12 +112,11 @@ The Java app (Spring Boot 3.1) is too old for the Spring AI MCP server starter (
128
112
  | Symptom | Likely cause | Fix |
129
113
  |---|---|---|
130
114
  | `FATAL: EQUISENSE_MCP_TOKEN env var is required` on startup | Env var unset or empty | Pass `--env EQUISENSE_MCP_TOKEN=...` to `claude mcp add` |
131
- | `Auth failed (HTTP 401) ... re-mint via /api/v1/admin/auth/mint-mcp-token` | Token > 90 days old OR `auth.token.secret` rotated | Re-mint and update the env |
115
+ | `Auth failed (HTTP 401)` | Token expired, revoked, or `auth.token.secret` rotated | Generate a fresh token in Settings → Claude and update the env |
132
116
  | `AI_EQUITY_RESEARCH quota exhausted (HTTP 402)` | Daily quota hit | Wait until tomorrow OR upgrade the user's plan |
133
117
  | `Rate limited (HTTP 429)` | Transient | Retry in a few seconds |
134
118
  | `Forbidden (HTTP 403)` | User doesn't have `AI_EQUITY_RESEARCH` feature | Check the user's license/plan |
135
119
  | Hangs > 90s with no response | Backend research query timed out | Bump `EQUISENSE_TIMEOUT_MS`; check backend logs |
136
- | `403` minting in prod | Your IP isn't admin-allowlisted | SSH to prod box and mint from there, or have an admin mint for you |
137
120
 
138
121
  ## License
139
122
 
package/index.js CHANGED
@@ -178,7 +178,7 @@ function createServer() {
178
178
  const server = new Server(
179
179
  {
180
180
  name: "equisense-research",
181
- version: "0.3.0",
181
+ version: "0.3.1",
182
182
  },
183
183
  {
184
184
  capabilities: {
@@ -187,21 +187,20 @@ function createServer() {
187
187
  },
188
188
  );
189
189
 
190
- // Capture the client identity once the initialize handshake completes, so
191
- // callRest can forward it as X-MCP-Client for auto-naming the connection.
192
- server.oninitialized = () => {
193
- try {
194
- clientName = server.getClientVersion()?.name || null;
195
- } catch {
196
- clientName = null;
197
- }
198
- };
199
-
200
190
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
201
191
  tools: TOOLS,
202
192
  }));
203
193
 
204
194
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
195
+ // Capture the client identity here rather than via the `initialized`
196
+ // notification: a tool call can only arrive after initialize has completed,
197
+ // so getClientVersion() is reliably populated by now. The notification
198
+ // callback raced the first call (it could fire after the call's fetch had
199
+ // already built its headers), leaving the connection un-named on first use.
200
+ try {
201
+ clientName = server.getClientVersion()?.name || clientName;
202
+ } catch { /* leave clientName as-is */ }
203
+
205
204
  const { name, arguments: args } = request.params;
206
205
  const handler = TOOL_HANDLERS[name];
207
206
  if (!handler) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "equisense-research-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "MCP server wrapper for the EquiSense AI equity-research API. Exposes a single ask_equisense tool that proxies POST /api/v1/research/ask, authenticated via a scoped, revocable token minted in Settings → Claude.",
5
5
  "type": "module",
6
6
  "main": "index.js",