@pipeworx/mcp-emarket-storage 0.1.1 → 0.1.3
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 +2 -2
- package/package.json +3 -3
- package/server.json +1 -1
- package/src/index.ts +58 -3
- package/src/server.ts +5 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Italian regulated company disclosures direct from eMarket Storage (Teleborsa)
|
|
|
5
5
|
built to fix the months-long lag in the community ESEF index for current-year
|
|
6
6
|
Italian filings.
|
|
7
7
|
|
|
8
|
-
Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to
|
|
8
|
+
Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1807+ live data sources. This is an independent, unofficial integration — not affiliated with, endorsed by, or published by the upstream provider.
|
|
9
9
|
|
|
10
10
|
## Tools
|
|
11
11
|
|
|
@@ -155,7 +155,7 @@ directly, instead of just this one's:
|
|
|
155
155
|
}
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
Both URLs reach the same gateway and the same
|
|
158
|
+
Both URLs reach the same gateway and the same 1807+ data sources. The
|
|
159
159
|
only difference is which pack's tools are listed **directly**; `ask_pipeworx`
|
|
160
160
|
reaches all of them from either one.
|
|
161
161
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipeworx/mcp-emarket-storage",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Italian regulated disclosures direct from eMarket Storage (Teleborsa) — keyless, same-day-fresh.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@cloudflare/workers-types": "^4.20260405.1"
|
|
27
27
|
},
|
|
28
28
|
"pipeworx": {
|
|
29
|
-
"sourceHash": "v1-
|
|
30
|
-
"sourceCommit": "
|
|
29
|
+
"sourceHash": "v1-26ae9c1d6b57c813a86250d479b99472a4aa1d088e3e59bf741bc60283698186",
|
|
30
|
+
"sourceCommit": "8dbe088fb6f9d2c88f934173742329b4e20a67d6"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.pipeworx-io/emarket-storage",
|
|
4
4
|
"title": "Emarket Storage",
|
|
5
5
|
"description": "Italian regulated disclosures direct from eMarket Storage (Teleborsa) — keyless, same-day-fresh.",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.3",
|
|
7
7
|
"websiteUrl": "https://pipeworx.io/packs/emarket-storage",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/pipeworx-io/mcp-emarket-storage",
|
package/src/index.ts
CHANGED
|
@@ -452,7 +452,42 @@ async function fetchWithTimeout(
|
|
|
452
452
|
),
|
|
453
453
|
);
|
|
454
454
|
}
|
|
455
|
-
|
|
455
|
+
// Fleet #2382. Everything that isn't a timeout/abort here is a genuine
|
|
456
|
+
// NETWORK-LEVEL failure — DNS resolution, connection refused, TLS handshake,
|
|
457
|
+
// Cloudflare's own "Network connection lost." — meaning `fetch()` itself
|
|
458
|
+
// threw and no HTTP response of any kind was ever received. Until this fix
|
|
459
|
+
// that raw exception was rethrown VERBATIM: a bare `TypeError: fetch failed`
|
|
460
|
+
// (or the Workers-runtime equivalent) names no upstream, carries no class
|
|
461
|
+
// token, and reads exactly like a defect in OUR code — because it says
|
|
462
|
+
// nothing about the call at all. It landed in `error`, the tier that means
|
|
463
|
+
// "Pipeworx has a defect", for every one of the (at the time of writing)
|
|
464
|
+
// ~470 packs that call this helper directly with no wrapper of their own.
|
|
465
|
+
//
|
|
466
|
+
// `dexscreener` hit this independently (fleet #1579) and fixed it with a
|
|
467
|
+
// bespoke per-pack try/catch around `fetchWithTimeout`. That fix is correct
|
|
468
|
+
// but only covers one pack; every other caller of this shared helper still
|
|
469
|
+
// leaked the raw exception. Moving the same fix HERE — the one place that
|
|
470
|
+
// already carries the timeout case — covers every pack that uses
|
|
471
|
+
// `fetchWithTimeout` without a wrapper, for free, and without widening
|
|
472
|
+
// `classifyToolError`'s regex list: the fix is giving the message a proper
|
|
473
|
+
// `upstream_down:` token at the point the two facts (no response was ever
|
|
474
|
+
// received, and which host we were trying to reach) are actually in hand,
|
|
475
|
+
// not teaching the classifier to guess from prose after the fact.
|
|
476
|
+
//
|
|
477
|
+
// Safe on the same grounds as the timeout branch above: no argument a
|
|
478
|
+
// caller passes can make `fetch()` itself throw a connection-level error,
|
|
479
|
+
// so this is always an availability failure, never a caller mistake. Same
|
|
480
|
+
// `markInternalOrigin` treatment — an origin we run that never answered is
|
|
481
|
+
// still ours, not a third party's outage.
|
|
482
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
483
|
+
throw new Error(
|
|
484
|
+
markInternalOrigin(
|
|
485
|
+
`upstream_down: could not reach ${name} at all (${raw.slice(0, 160)}). ` +
|
|
486
|
+
`No request reached ${name}, so this says NOTHING about whether the arguments you passed ` +
|
|
487
|
+
'are valid — do not re-check them on the strength of this error. Retry shortly.',
|
|
488
|
+
url,
|
|
489
|
+
),
|
|
490
|
+
);
|
|
456
491
|
}
|
|
457
492
|
}
|
|
458
493
|
|
|
@@ -664,6 +699,16 @@ const normalize = (s: string): string =>
|
|
|
664
699
|
* exact (4) > prefix (3) > whole-word (2) > substring (1). Ties break by shortest
|
|
665
700
|
* name — the primary entity (e.g. "Apple Inc." over "Apple Hospitality REIT").
|
|
666
701
|
* Returns only items that match at all, best first. Pure (no I/O).
|
|
702
|
+
*
|
|
703
|
+
* `prefix` requires a WORD BOUNDARY (`n.startsWith(q + ' ')`), not a bare
|
|
704
|
+
* `startsWith`. A bare `startsWith` let "ZOOM" claim "ZOOMCAR HOLDINGS INC" at
|
|
705
|
+
* the SAME tier as "Apple" claiming "APPLE INC." — "Zoomcar" is a different
|
|
706
|
+
* word that happens to begin with the same letters, not the brand name plus a
|
|
707
|
+
* corporate-form suffix. That conflation is what sent resolve_entity("Zoom")
|
|
708
|
+
* to Zoomcar and resolve_entity("Audi") to AudioEye Inc (fleet #2776's
|
|
709
|
+
* mis-resolution fixture) — both now correctly fall through to the weaker
|
|
710
|
+
* `substring` tier instead of tying with a genuine word-boundary prefix hit
|
|
711
|
+
* like "Palantir" -> "Palantir Technologies Inc." (fleet #3100).
|
|
667
712
|
*/
|
|
668
713
|
function rankMatches<T>(
|
|
669
714
|
query: string,
|
|
@@ -679,7 +724,7 @@ function rankMatches<T>(
|
|
|
679
724
|
let kind: MatchKind | null = null;
|
|
680
725
|
let score = 0;
|
|
681
726
|
if (n === q) { kind = 'exact'; score = 4; }
|
|
682
|
-
else if (n.startsWith(q)) { kind = 'prefix'; score = 3; }
|
|
727
|
+
else if (n.startsWith(`${q} `)) { kind = 'prefix'; score = 3; }
|
|
683
728
|
else if (n.includes(` ${q} `) || n.endsWith(` ${q}`)) { kind = 'word'; score = 2; }
|
|
684
729
|
else if (n.includes(q)) { kind = 'substring'; score = 1; }
|
|
685
730
|
if (kind) scored.push({ item, kind, score, len: name.length });
|
|
@@ -696,7 +741,15 @@ interface SecEntity {
|
|
|
696
741
|
cik_padded: string;
|
|
697
742
|
company_name: string;
|
|
698
743
|
matched_by: 'ticker' | 'company_name';
|
|
699
|
-
|
|
744
|
+
/**
|
|
745
|
+
* The `rankMatches` kind that won, when `matched_by` is `'company_name'`
|
|
746
|
+
* (a ticker hit has no kind — it did not go through ranking at all). Lets a
|
|
747
|
+
* caller tell a word-boundary PREFIX hit ("Palantir" -> "Palantir
|
|
748
|
+
* Technologies Inc.") from a weaker `word`/`substring` guess, which
|
|
749
|
+
* `matched_by: 'company_name'` alone cannot (fleet #3100).
|
|
750
|
+
*/
|
|
751
|
+
matched_kind?: MatchKind;
|
|
752
|
+
alternatives?: { ticker: string; company_name: string; cik: string; kind: MatchKind }[];
|
|
700
753
|
}
|
|
701
754
|
|
|
702
755
|
const SEC_TICKERS_URL = 'https://www.sec.gov/files/company_tickers.json';
|
|
@@ -732,10 +785,12 @@ async function resolveSecEntity(
|
|
|
732
785
|
const ranked = rankMatches(query, rows, (r) => r.title);
|
|
733
786
|
if (ranked.length) {
|
|
734
787
|
const best = toEntity(ranked[0].item, 'company_name');
|
|
788
|
+
best.matched_kind = ranked[0].kind;
|
|
735
789
|
const alts = ranked.slice(1, 4).map((m) => ({
|
|
736
790
|
ticker: m.item.ticker,
|
|
737
791
|
company_name: m.item.title,
|
|
738
792
|
cik: String(m.item.cik_str),
|
|
793
|
+
kind: m.kind,
|
|
739
794
|
}));
|
|
740
795
|
if (alts.length) best.alternatives = alts;
|
|
741
796
|
return best;
|
package/src/server.ts
CHANGED
|
@@ -8,8 +8,9 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
8
8
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
9
9
|
import pack from './index.js';
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
const server = new Server(
|
|
12
|
-
{ name: '@pipeworx/mcp-emarket-storage', version: '0.1.
|
|
13
|
+
{ name: '@pipeworx/mcp-emarket-storage', version: '0.1.3' },
|
|
13
14
|
{ capabilities: { tools: {} } },
|
|
14
15
|
);
|
|
15
16
|
|
|
@@ -24,7 +25,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
24
25
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
25
26
|
const { name, arguments: args } = request.params;
|
|
26
27
|
try {
|
|
27
|
-
const
|
|
28
|
+
const callArgs = { ...((args ?? {}) as Record<string, unknown>) };
|
|
29
|
+
|
|
30
|
+
const result = await pack.callTool(name, callArgs);
|
|
28
31
|
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
29
32
|
} catch (err) {
|
|
30
33
|
return {
|