@pipeworx/mcp-emarket-storage 0.1.2 → 0.1.4
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 +32 -4
- 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 1819+ 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 1819+ 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.4",
|
|
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-2960ffa7f8d2253e830ed8e2c253d574f3aacded6fe241b9780a8159767a0737",
|
|
30
|
+
"sourceCommit": "a03f96ed672b8c149593c64ecbf30280cabf084c"
|
|
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.4",
|
|
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
|
@@ -699,6 +699,16 @@ const normalize = (s: string): string =>
|
|
|
699
699
|
* exact (4) > prefix (3) > whole-word (2) > substring (1). Ties break by shortest
|
|
700
700
|
* name — the primary entity (e.g. "Apple Inc." over "Apple Hospitality REIT").
|
|
701
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).
|
|
702
712
|
*/
|
|
703
713
|
function rankMatches<T>(
|
|
704
714
|
query: string,
|
|
@@ -714,7 +724,7 @@ function rankMatches<T>(
|
|
|
714
724
|
let kind: MatchKind | null = null;
|
|
715
725
|
let score = 0;
|
|
716
726
|
if (n === q) { kind = 'exact'; score = 4; }
|
|
717
|
-
else if (n.startsWith(q)) { kind = 'prefix'; score = 3; }
|
|
727
|
+
else if (n.startsWith(`${q} `)) { kind = 'prefix'; score = 3; }
|
|
718
728
|
else if (n.includes(` ${q} `) || n.endsWith(` ${q}`)) { kind = 'word'; score = 2; }
|
|
719
729
|
else if (n.includes(q)) { kind = 'substring'; score = 1; }
|
|
720
730
|
if (kind) scored.push({ item, kind, score, len: name.length });
|
|
@@ -731,7 +741,15 @@ interface SecEntity {
|
|
|
731
741
|
cik_padded: string;
|
|
732
742
|
company_name: string;
|
|
733
743
|
matched_by: 'ticker' | 'company_name';
|
|
734
|
-
|
|
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 }[];
|
|
735
753
|
}
|
|
736
754
|
|
|
737
755
|
const SEC_TICKERS_URL = 'https://www.sec.gov/files/company_tickers.json';
|
|
@@ -767,10 +785,12 @@ async function resolveSecEntity(
|
|
|
767
785
|
const ranked = rankMatches(query, rows, (r) => r.title);
|
|
768
786
|
if (ranked.length) {
|
|
769
787
|
const best = toEntity(ranked[0].item, 'company_name');
|
|
788
|
+
best.matched_kind = ranked[0].kind;
|
|
770
789
|
const alts = ranked.slice(1, 4).map((m) => ({
|
|
771
790
|
ticker: m.item.ticker,
|
|
772
791
|
company_name: m.item.title,
|
|
773
792
|
cik: String(m.item.cik_str),
|
|
793
|
+
kind: m.kind,
|
|
774
794
|
}));
|
|
775
795
|
if (alts.length) best.alternatives = alts;
|
|
776
796
|
return best;
|
|
@@ -1137,8 +1157,14 @@ async function searchDisclosures(args: Record<string, unknown>): Promise<unknown
|
|
|
1137
1157
|
const issuers = await getAziendaMap();
|
|
1138
1158
|
const ranked = rankMatches(companyQuery, issuers, (e) => e.name);
|
|
1139
1159
|
if (ranked.length === 0) {
|
|
1160
|
+
// A name that matches no issuer is a normal "no match" outcome, not a
|
|
1161
|
+
// tool failure: until 2026-10-16 it was returned as a top-level `error`
|
|
1162
|
+
// and booked as OUR error on every unknown company (6 of 20 calls in one
|
|
1163
|
+
// day). found:false is the shape the gateway classifies as empty.
|
|
1140
1164
|
return {
|
|
1141
|
-
|
|
1165
|
+
found: false,
|
|
1166
|
+
reason: 'no_match',
|
|
1167
|
+
message: `"${companyQuery}" does not match any eMarket Storage issuer.`,
|
|
1142
1168
|
note: "This pack only covers issuers that disclose through eMarket Storage. A separate mechanism, 1INFO, covers a different set of Italian issuers (e.g. IREN, SOMEC) and is not included here — try oneinfo-storage's oneinfo_search_disclosures instead.",
|
|
1143
1169
|
};
|
|
1144
1170
|
}
|
|
@@ -1146,7 +1172,9 @@ async function searchDisclosures(args: Record<string, unknown>): Promise<unknown
|
|
|
1146
1172
|
const tiedAtTop = ranked.filter((r) => r.score === top.score);
|
|
1147
1173
|
if (tiedAtTop.length > 1) {
|
|
1148
1174
|
return {
|
|
1149
|
-
|
|
1175
|
+
found: false,
|
|
1176
|
+
reason: 'ambiguous_match',
|
|
1177
|
+
message: `"${companyQuery}" matches more than one eMarket Storage issuer equally well — pass azienda_id or a more specific company name.`,
|
|
1150
1178
|
candidates: tiedAtTop.slice(0, 10).map((r) => ({ azienda_id: r.item.id, company: r.item.name })),
|
|
1151
1179
|
};
|
|
1152
1180
|
}
|
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.4' },
|
|
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 {
|