football-docs 0.6.1 → 0.6.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 +35 -21
- package/data/docs.db +0 -0
- package/dist/crawl.js +59 -1
- package/dist/index.js +24 -4
- package/dist/tools.d.ts +12 -1
- package/dist/tools.js +309 -18
- package/docs/_reference/skillcorner-crunch-help/getting-started-api-access-dynamic-events.md +134 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-api-access-our-tracking-data.md +160 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-best-practice-analysis-guidance.md +16 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-dynamic-events-check.md +33 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-explore-game-intelligence-data-1.md +37 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-explore-game-intelligence-data.md +29 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-first-requests.md +99 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-generate-visual-reports.md +90 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-make-your-first-queries.md +92 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-off-ball-run-sportscode-xml.md +32 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-on-ball-engagement-video-definitio.md +15 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-python-retrieve-dynamic-events-fil.md +102 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-python-retrieve-game-intelligence-.md +158 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-python-sync-your-database-with-ski.md +192 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-run-detection-and-classification.md +131 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-skill-corner-tracking-data.md +82 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-skillcorner-python-client.md +70 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started-using-skillcorner-api.md +146 -0
- package/docs/_reference/skillcorner-crunch-help/getting-started.md +43 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-coordinates-distance-speeds-and-directi.md +149 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-dynamic-events-csv-specifications.md +15 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-forward-momentum.md +13 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-game-intelligence-v2-metrics.md +17 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-in-possession-package-content.md +19 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-line-breaking-passes.md +103 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-off-ball-run-dynamic-events.md +197 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-overcoming-pressure.md +105 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-passing-metrics-1.md +144 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-passing-moment-frame-selection.md +19 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-peak-sprint-velocity.md +26 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-phases-of-play-video-definitions.md +15 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-physical-data-glossary.md +127 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries-running-off-ball-metrics-1.md +135 -0
- package/docs/_reference/skillcorner-crunch-help/glossaries.md +43 -0
- package/docs/_reference/skillcorner-crunch-help/index.md +33 -0
- package/docs/_reference/skillcorner-crunch-help/models-general-concepts-pass-completion-probabilit.md +15 -0
- package/docs/_reference/skillcorner-crunch-help/models-general-concepts-passing-option.md +30 -0
- package/docs/_reference/skillcorner-crunch-help/models-general-concepts-physical-load-prediction-m.md +63 -0
- package/docs/_reference/skillcorner-crunch-help/models-general-concepts-pressure-detection.md +46 -0
- package/docs/_reference/skillcorner-crunch-help/models-general-concepts-pressure-intensity.md +80 -0
- package/docs/_reference/skillcorner-crunch-help/models-general-concepts-threat.md +40 -0
- package/docs/_reference/skillcorner-crunch-help/models-general-concepts.md +37 -0
- package/docs/_reference/skillcorner-crunch-help/product-updates-1-changelog-2025.md +57 -0
- package/docs/_reference/skillcorner-crunch-help/product-updates-1-game-intelligence-v2-migration.md +64 -0
- package/docs/_reference/skillcorner-crunch-help/product-updates-1-product-updates.md +200 -0
- package/docs/_reference/skillcorner-crunch-help/product-updates-1.md +25 -0
- package/docs/_reference/skillcorner-crunch-help/tool-box-api-data-version.md +255 -0
- package/docs/_reference/skillcorner-crunch-help/tool-box-data-availability.md +55 -0
- package/docs/_reference/skillcorner-crunch-help/tool-box-python-event-tracking-synchronization-1.md +442 -0
- package/docs/_reference/skillcorner-crunch-help/tool-box-python-event-tracking-synchronization.md +276 -0
- package/docs/_reference/skillcorner-crunch-help/tool-box-python-off-ball-runs-radar-plots.md +69 -0
- package/docs/_reference/skillcorner-crunch-help/tool-box-rule-based-event-synchronisation.md +44 -0
- package/docs/_reference/skillcorner-crunch-help/tool-box.md +35 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data-averaging-per-match-per-even.md +179 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data-benchmarking-normalisation.md +27 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data-data-quality-standards.md +45 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data-physical-data-glossary-1-1.md +54 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data-physical-data-glossary-1.md +25 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data-pitch-modelisation.md +27 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data-playing-time-info.md +133 -0
- package/docs/_reference/skillcorner-crunch-help/working-with-the-data.md +43 -0
- package/docs/floodlight/compendium-0-compendium.md +21 -0
- package/docs/floodlight/compendium-1-data.md +54 -0
- package/docs/floodlight/compendium-2-design.md +49 -0
- package/docs/floodlight/compendium-3-time.md +57 -0
- package/docs/floodlight/compendium-4-space.md +137 -0
- package/docs/floodlight/compendium-5-identifier.md +63 -0
- package/docs/floodlight/core-code.md +85 -0
- package/docs/floodlight/core-core.md +39 -0
- package/docs/floodlight/core-definitions.md +128 -0
- package/docs/floodlight/core-events.md +177 -0
- package/docs/floodlight/core-pitch.md +87 -0
- package/docs/floodlight/core-property.md +107 -0
- package/docs/floodlight/core-teamsheet.md +86 -0
- package/docs/floodlight/core-xy.md +192 -0
- package/docs/floodlight/guides-contrib-manual.md +462 -0
- package/docs/floodlight/guides-getting-started.md +194 -0
- package/docs/floodlight/guides-tutorial-analysis.md +245 -0
- package/docs/floodlight/guides-tutorial-matchsheets.md +439 -0
- package/docs/floodlight/index.md +17 -0
- package/docs/floodlight/io-datasets.md +365 -0
- package/docs/floodlight/io-dfl.md +107 -0
- package/docs/floodlight/io-io.md +131 -0
- package/docs/floodlight/io-kinexon.md +119 -0
- package/docs/floodlight/io-opta.md +49 -0
- package/docs/floodlight/io-secondspectrum.md +121 -0
- package/docs/floodlight/io-skillcorner.md +40 -0
- package/docs/floodlight/io-sportradar.md +35 -0
- package/docs/floodlight/io-statsbomb.md +61 -0
- package/docs/floodlight/io-statsperform.md +239 -0
- package/docs/floodlight/io-tracab.md +78 -0
- package/docs/floodlight/io-utils.md +59 -0
- package/docs/floodlight/metrics-entropy.md +36 -0
- package/docs/floodlight/metrics-metrics.md +15 -0
- package/docs/floodlight/metrics-trajectory-clustering.md +51 -0
- package/docs/floodlight/metrics-zone-aggregation.md +116 -0
- package/docs/floodlight/models-geometry.md +411 -0
- package/docs/floodlight/models-kinematics.md +251 -0
- package/docs/floodlight/models-kinetics.md +137 -0
- package/docs/floodlight/models-models.md +89 -0
- package/docs/floodlight/models-space.md +202 -0
- package/docs/floodlight/transforms-filter.md +412 -0
- package/docs/floodlight/transforms-interpolation.md +230 -0
- package/docs/floodlight/transforms-permutation.md +36 -0
- package/docs/floodlight/transforms-spatial.md +54 -0
- package/docs/floodlight/transforms-temporal.md +42 -0
- package/docs/floodlight/transforms-transforms.md +57 -0
- package/docs/floodlight/utils-types.md +13 -0
- package/docs/floodlight/utils-utils.md +17 -0
- package/docs/floodlight/vis-pitches.md +111 -0
- package/docs/floodlight/vis-positions.md +129 -0
- package/docs/floodlight/vis-vis.md +19 -0
- package/docs/fotmob/identity-surfaces.md +3 -4
- package/docs/free-sources/contextual-story-joins.md +110 -0
- package/docs/free-sources/overview.md +60 -13
- package/docs/free-sources/understat.md +15 -6
- package/docs/free-sources/xg-timelines.md +123 -0
- package/docs/impect/identity-surfaces.md +3 -4
- package/docs/kloppy/event-derived-metrics.md +337 -0
- package/docs/kloppy/tracking-rendering.md +420 -0
- package/docs/mplsoccer/visualizations.md +363 -6
- package/docs/opta/charting-game-state.md +216 -0
- package/docs/opta/charting-lineups.md +90 -0
- package/docs/opta/charting-passmaps.md +130 -0
- package/docs/opta/charting-set-pieces.md +106 -0
- package/docs/opta/charting-shot-placement.md +233 -0
- package/docs/opta/event-types.md +44 -0
- package/docs/opta/identity-surfaces.md +4 -4
- package/docs/opta/qualifiers.md +16 -7
- package/docs/skillcorner/identity-surfaces.md +4 -4
- package/docs/skillcorner/physical-data.md +35 -0
- package/docs/socceraction/spadl.md +21 -0
- package/docs/soccerdata/data-sources.md +37 -0
- package/docs/soccerdonna/identity-surfaces.md +6 -6
- package/docs/sportmonks/charting-season-stories.md +125 -0
- package/docs/sportmonks/data-model.md +35 -12
- package/docs/sportmonks/event-types.md +1 -1
- package/docs/sportmonks/identity-surfaces.md +4 -4
- package/docs/sportradar/api-access.md +75 -0
- package/docs/sportradar/api-endpoints.md +92 -0
- package/docs/sportradar/charting-and-stories.md +57 -0
- package/docs/sportradar/data-model.md +84 -0
- package/docs/sportradar/integration-notes.md +58 -0
- package/docs/statsbomb/charting-lineups.md +79 -0
- package/docs/statsbomb/identity-surfaces.md +5 -4
- package/docs/statsbomb/player-mapping.md +6 -7
- package/docs/thesportsdb/api-access.md +68 -0
- package/docs/thesportsdb/api-endpoints.md +55 -0
- package/docs/thesportsdb/identity-surfaces.md +49 -0
- package/docs/thesportsdb/livescore.md +70 -0
- package/docs/transfermarkt/identity-surfaces.md +51 -6
- package/docs/transferroom/charting-availability.md +74 -0
- package/docs/wyscout/charting-analysis-metrics.md +124 -0
- package/docs/wyscout/identity-surfaces.md +4 -4
- package/package.json +3 -2
- package/providers.json +128 -3
package/README.md
CHANGED
|
@@ -4,19 +4,26 @@ Searchable football data provider and tooling documentation for AI coding agents
|
|
|
4
4
|
|
|
5
5
|
**Who it's for:** Developers and analysts who use AI coding tools (Claude Code, Cursor, VS Code Copilot) to work with football data. Works with any tool that supports MCP.
|
|
6
6
|
|
|
7
|
-
**What it does:** Gives your AI agent a searchable index of documentation for
|
|
7
|
+
**What it does:** Gives your AI agent a searchable index of documentation for 20 football data providers and tools — event types, qualifier IDs, coordinate systems, API endpoints, data models, identity surfaces, and cross-provider comparisons for the data providers (StatsBomb, Opta, Wyscout, Impect, SkillCorner, Sportradar, TheSportsDB, FMDB Pro, TransferRoom, and more), plus the open-source libraries people build with (kloppy, mplsoccer, socceraction, soccerdata, floodlight, and more). Your agent looks up the real docs instead of guessing from training data.
|
|
8
8
|
|
|
9
9
|
**Why not just let the AI figure it out?** LLMs get football data specifics wrong constantly — Opta qualifier IDs, StatsBomb coordinate ranges, API endpoint URLs, library method signatures. These are mutable facts that change across versions. football-docs gives the agent verified, sourced documentation with provenance tracking so you know where every answer came from.
|
|
10
10
|
|
|
11
|
+
## Strategy
|
|
12
|
+
|
|
13
|
+
football-docs is intended to be a community-owned, source-transparent Context7
|
|
14
|
+
for football data. The public operating contract is in
|
|
15
|
+
[STRATEGY.md](STRATEGY.md): what belongs here, what must stay out, how we handle
|
|
16
|
+
public-safe provider facts, and how contributors should prove retrieval quality.
|
|
17
|
+
|
|
11
18
|
## Provider identity facts
|
|
12
19
|
|
|
13
20
|
football-docs is the public source for provider identity-surface facts: access
|
|
14
21
|
shape, ID schemes, matching fields, provider quirks, and provenance rules.
|
|
15
|
-
Curated
|
|
16
|
-
register state. They should say whether a fact comes from public docs,
|
|
17
|
-
page evidence, licensed feed shape, or a reviewed public-safe
|
|
18
|
-
must not include private paths, credentials, scraper state,
|
|
19
|
-
salts, or raw restricted payloads.
|
|
22
|
+
Curated provider identity notes belong here when they can be stated without
|
|
23
|
+
private register state. They should say whether a fact comes from public docs,
|
|
24
|
+
public page evidence, licensed feed shape, or a reviewed public-safe
|
|
25
|
+
observation, and must not include private paths, credentials, scraper state,
|
|
26
|
+
action ledgers, mint salts, or raw restricted payloads.
|
|
20
27
|
|
|
21
28
|
MCP ([Model Context Protocol](https://modelcontextprotocol.io)) is a standard for connecting AI coding tools to external data sources.
|
|
22
29
|
|
|
@@ -78,11 +85,15 @@ Add to `claude_desktop_config.json`:
|
|
|
78
85
|
| Tool | Description |
|
|
79
86
|
|------|-------------|
|
|
80
87
|
| `search_docs` | Full-text search across all provider docs. Filter by provider. Results include provenance (source URL, version). |
|
|
88
|
+
| `resolve_provider_id` | Resolve provider names and aliases to canonical indexed provider keys before searching. |
|
|
89
|
+
| `get_provider_docs` | Retrieve docs for a resolved provider, optionally filtered by topic or category. |
|
|
81
90
|
| `list_providers` | List all indexed providers and their doc coverage. |
|
|
82
91
|
| `compare_providers` | Compare how different providers handle the same concept. |
|
|
83
|
-
| `request_update` | Request a new provider, flag outdated docs, or suggest a better doc source.
|
|
92
|
+
| `request_update` | Request a new provider, flag outdated docs, or suggest a better doc source. Queues locally and points to the matching public GitHub issue template. |
|
|
84
93
|
| `resolve_entity` | Resolve players, teams, or coaches to cross-provider IDs via the Reep API. |
|
|
85
94
|
|
|
95
|
+
Provider filters use the indexed provider keys shown by `list_providers`, but common aliases are accepted. Examples: `fbref`, `understat`, `ClubElo`, `football-data.co.uk`, and `engsoccerdata` search `free-sources`; `Sofascore` and `ESPN` search `soccerdata`; `FMDB` searches `fmdb-pro`; `Transfer Room` searches `transferroom`; `Hudl Wyscout` searches `wyscout`; `Stats Perform` / `Opta F24` / `WhoScored` search `opta`; `Metrica`, `Sportec` / `DFL`, and `TRACAB` search `databallpy`; `Second Spectrum` searches `kloppy`; `SportRadar API` / `Soccer Extended` search `sportradar`; `The Sports DB` / `TSDB` search `thesportsdb`; `StatsBomb Open Data` searches `statsbomb`.
|
|
96
|
+
|
|
86
97
|
## Example queries
|
|
87
98
|
|
|
88
99
|
- "What is Opta qualifier 76?" (big chance)
|
|
@@ -97,32 +108,35 @@ Add to `claude_desktop_config.json`:
|
|
|
97
108
|
|
|
98
109
|
| Provider | Chunks | Categories |
|
|
99
110
|
|----------|--------|------------|
|
|
100
|
-
| StatsBomb |
|
|
101
|
-
| Wyscout |
|
|
102
|
-
| kloppy |
|
|
103
|
-
|
|
|
111
|
+
| StatsBomb | 237 | event-types, data-model, coordinate-system, api-access, api-endpoints, charting-lineups, xg-model, iq-metrics, player/team stats, player-mapping, identity-surfaces |
|
|
112
|
+
| Wyscout | 164 | event-types, data-model, coordinate-system, api-access, api-endpoints, charting-analysis-metrics, glossary, identity-surfaces |
|
|
113
|
+
| kloppy | 126 | data-model, usage, provider-mapping, tracking-rendering, event-derived-metrics |
|
|
114
|
+
| floodlight | 145 | core data objects, io parsers (Tracab, DFL, Kinexon, Opta, SkillCorner, StatsBomb, StatsPerform, Second Spectrum), transforms, metrics, models, visualisation, guides |
|
|
115
|
+
| SportMonks | 85 | event-types, data-model, api-access, charting-season-stories, identity-surfaces |
|
|
104
116
|
| databallpy | 63 | data-model, overview, usage |
|
|
105
|
-
| mplsoccer |
|
|
117
|
+
| mplsoccer | 64 | overview, pitch-types, visualizations |
|
|
106
118
|
| Impect | 58 | api-access, api-endpoints, data-model, event-types, coordinate-system, concepts, identity-surfaces |
|
|
107
|
-
| SkillCorner |
|
|
108
|
-
| Free sources |
|
|
109
|
-
| soccerdata |
|
|
110
|
-
| TransferRoom |
|
|
111
|
-
| Opta |
|
|
119
|
+
| SkillCorner | 52 | api-access, api-endpoints, data-model, physical-data, coordinate-system, concepts, identity-surfaces |
|
|
120
|
+
| Free sources | 62 | overview, fbref, understat, contextual-story-joins, xg-timelines |
|
|
121
|
+
| soccerdata | 41 | overview, data-sources, usage |
|
|
122
|
+
| TransferRoom | 43 | api-access, api-endpoints, charting-availability, data-model, identity-surfaces |
|
|
123
|
+
| Opta | 74 | event-types, qualifiers, coordinate-system, api-access, charting-game-state, charting-lineups, charting-passmaps, charting-set-pieces, charting-shot-placement, identity-surfaces |
|
|
112
124
|
| FMDB Pro | 36 | api-access, api-endpoints, data-model, identity-surfaces |
|
|
113
|
-
|
|
|
125
|
+
| Sportradar | 29 | api-access, api-endpoints, data-model, charting-and-stories, integration-notes |
|
|
126
|
+
| socceraction | 27 | SPADL format, VAEP, Expected Threat |
|
|
127
|
+
| TheSportsDB | 18 | api-access, api-endpoints, livescore, identity-surfaces |
|
|
114
128
|
| FotMob | 7 | identity-surfaces |
|
|
115
129
|
| Soccerdonna | 7 | identity-surfaces |
|
|
116
|
-
| Transfermarkt |
|
|
130
|
+
| Transfermarkt | 8 | identity-surfaces |
|
|
117
131
|
|
|
118
|
-
**1,
|
|
132
|
+
**1,346 searchable chunks** across 20 providers and tools.
|
|
119
133
|
|
|
120
134
|
## Contributing
|
|
121
135
|
|
|
122
136
|
Contributions are welcome from everyone. There are three ways to help:
|
|
123
137
|
|
|
124
138
|
1. **Open an issue** — [request a new provider](https://github.com/withqwerty/football-docs/issues/new/choose), [flag outdated docs](https://github.com/withqwerty/football-docs/issues/new/choose), or [suggest a better doc source](https://github.com/withqwerty/football-docs/issues/new/choose)
|
|
125
|
-
2. **Use the `request_update` tool** — AI agents can flag outdated or missing docs directly via the MCP server, which queues requests
|
|
139
|
+
2. **Use the `request_update` tool** — AI agents can flag outdated or missing docs directly via the MCP server, which queues requests locally and points to the matching public GitHub issue template
|
|
126
140
|
3. **Open a PR** — fix errors, add new providers, or improve existing docs
|
|
127
141
|
|
|
128
142
|
**You don't need to be an expert.** See **[CONTRIBUTING.md](CONTRIBUTING.md)** for the full guide.
|
package/data/docs.db
CHANGED
|
Binary file
|
package/dist/crawl.js
CHANGED
|
@@ -30,6 +30,58 @@ const turndown = new TurndownService({
|
|
|
30
30
|
codeBlockStyle: "fenced",
|
|
31
31
|
bulletListMarker: "-",
|
|
32
32
|
});
|
|
33
|
+
// Sphinx (and other Pygments-based renderers) mark up code blocks as bare
|
|
34
|
+
// <pre> containing syntax-highlighting <span>s, not <pre><code>. Turndown's
|
|
35
|
+
// built-in fenced-code rule only matches <pre><code>, so these fall through
|
|
36
|
+
// to plain-text handling where markdown-escaping mangles identifiers (e.g.
|
|
37
|
+
// `read_position_data_json` becomes `read\_position\_data\_json`). Read
|
|
38
|
+
// textContent directly to bypass that escaping.
|
|
39
|
+
turndown.addRule("preBlock", {
|
|
40
|
+
filter: "pre",
|
|
41
|
+
replacement: (_content, node) => {
|
|
42
|
+
const code = node.textContent?.replace(/\n+$/, "") ?? "";
|
|
43
|
+
if (!code.trim())
|
|
44
|
+
return "";
|
|
45
|
+
const parentClass = node.parentElement?.getAttribute?.("class") ?? "";
|
|
46
|
+
const langMatch = parentClass.match(/highlight-(\w+)/);
|
|
47
|
+
const lang = langMatch && langMatch[1] !== "default" ? langMatch[1] : "";
|
|
48
|
+
return `\n\n\`\`\`${lang}\n${code}\n\`\`\`\n\n`;
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
// Sphinx marks up identifiers/parameter names/default values in signatures
|
|
52
|
+
// with <span class="pre"> (a "don't word-wrap" hint, not semantic <code>).
|
|
53
|
+
// Same escaping problem as above — render as inline code instead.
|
|
54
|
+
turndown.addRule("sphinxPreSpan", {
|
|
55
|
+
filter: (node) => node.nodeName === "SPAN" &&
|
|
56
|
+
(node.getAttribute?.("class") ?? "")
|
|
57
|
+
.split(/\s+/)
|
|
58
|
+
.includes("pre"),
|
|
59
|
+
replacement: (_content, node) => `\`${node.textContent ?? ""}\``,
|
|
60
|
+
});
|
|
61
|
+
// Turndown escapes every underscore in plain text nodes by default (guarding
|
|
62
|
+
// against accidental markdown emphasis), including identifiers that carry no
|
|
63
|
+
// code markup at all — e.g. Sphinx renders parameter/return names in
|
|
64
|
+
// "Variables:" lists as plain `<strong>essential_missing</strong>`, no <code>
|
|
65
|
+
// or .pre span in sight. Since this corpus exists for full-text search rather
|
|
66
|
+
// than pixel-perfect rendering, an escaped underscore that breaks substring
|
|
67
|
+
// matches on the real identifier is worse than the rare accidental italics.
|
|
68
|
+
const defaultEscape = turndown.escape.bind(turndown);
|
|
69
|
+
turndown.escape = (text) => defaultEscape(text).replace(/\\_/g, "_");
|
|
70
|
+
// Turndown's built-in image rule escapes alt text via a private module-level
|
|
71
|
+
// helper, not the overridable `escape` method above, so alt text (often just
|
|
72
|
+
// the image's own filename, e.g. "pitch_positive.png") still comes out with
|
|
73
|
+
// escaped underscores. Same fix, applied to this one rule directly.
|
|
74
|
+
turndown.addRule("unescapedImageAlt", {
|
|
75
|
+
filter: "img",
|
|
76
|
+
replacement: (_content, node) => {
|
|
77
|
+
const el = node;
|
|
78
|
+
const alt = el.getAttribute?.("alt") ?? "";
|
|
79
|
+
const src = el.getAttribute?.("src") ?? "";
|
|
80
|
+
const title = el.getAttribute?.("title");
|
|
81
|
+
const titlePart = title ? ` "${title.replace(/"/g, '\\"')}"` : "";
|
|
82
|
+
return src ? `` : "";
|
|
83
|
+
},
|
|
84
|
+
});
|
|
33
85
|
// ── HTML → Markdown ──────────────────────────────────────────────────
|
|
34
86
|
/**
|
|
35
87
|
* Extract main content from an HTML page and convert to markdown.
|
|
@@ -43,7 +95,13 @@ export function htmlToMarkdown(html, url) {
|
|
|
43
95
|
? html
|
|
44
96
|
: html.replace(/(<head[^>]*>)/i, `$1<base href="${url}">`);
|
|
45
97
|
const { document } = parseHTML(htmlWithBase);
|
|
46
|
-
|
|
98
|
+
// classesToPreserve keeps class="pre" (Sphinx's no-wrap marker for inline
|
|
99
|
+
// literals) alive through Readability's cleanup, so the sphinxPreSpan
|
|
100
|
+
// Turndown rule above can still detect and unescape it.
|
|
101
|
+
const reader = new Readability(document, {
|
|
102
|
+
charThreshold: 100,
|
|
103
|
+
classesToPreserve: ["pre"],
|
|
104
|
+
});
|
|
47
105
|
const article = reader.parse();
|
|
48
106
|
if (!article?.content)
|
|
49
107
|
return null;
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
17
17
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
18
|
import Database from "better-sqlite3";
|
|
19
19
|
import { z } from "zod";
|
|
20
|
-
import { compareProviders, listProviders, requestUpdate, resolveEntity, searchDocs, } from "./tools.js";
|
|
20
|
+
import { compareProviders, getProviderDocs, listProviders, requestUpdate, resolveEntity, resolveProviderId, searchDocs, } from "./tools.js";
|
|
21
21
|
export { sanitiseFtsQuery } from "./tools.js";
|
|
22
22
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
23
|
const DB_PATH = resolve(__dirname, "..", "data", "docs.db");
|
|
@@ -78,24 +78,44 @@ export function createFootballDocsServer() {
|
|
|
78
78
|
version: PKG_VERSION,
|
|
79
79
|
});
|
|
80
80
|
server.tool("search_docs", "Search football data provider documentation. Use for finding event types, qualifier IDs, API endpoints, coordinate systems, data models, and cross-provider mappings. Returns the most relevant documentation chunks.", {
|
|
81
|
-
query: z.string().describe("Search query. Examples: 'Opta goal qualifier', 'StatsBomb shot event type', 'coordinate system differences', 'xG qualifier ID', 'SportMonks fixture endpoint'"),
|
|
81
|
+
query: z.string().describe("Search query. Examples: 'Opta goal qualifier', 'StatsBomb shot event type', 'coordinate system differences', 'xG qualifier ID', 'SportMonks fixture endpoint', 'FMDB Pro players endpoint'"),
|
|
82
82
|
provider: z
|
|
83
83
|
.string()
|
|
84
84
|
.optional()
|
|
85
|
-
.describe("
|
|
85
|
+
.describe("Optional provider filter. Use list_providers for indexed provider keys. Common aliases such as fbref, understat, ClubElo, football-data.co.uk, engsoccerdata, Sofascore, ESPN, FMDB, TransferRoom, Hudl Wyscout, Stats Perform, Opta F24, WhoScored, Metrica, Sportec/DFL, TRACAB, Second Spectrum, SportRadar API, Soccer Extended, TheSportsDB, and TSDB are accepted."),
|
|
86
86
|
max_results: z
|
|
87
87
|
.number()
|
|
88
88
|
.optional()
|
|
89
89
|
.default(10)
|
|
90
90
|
.describe("Maximum number of results to return (default 10)"),
|
|
91
91
|
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => withDocsDb((db) => searchDocs(db, args)));
|
|
92
|
+
server.tool("resolve_provider_id", "Resolve a football data provider name or alias to the canonical football-docs provider key before searching. Use when users mention brands, vendors, products, or aliases such as Stats Perform, Opta F24, Hudl Wyscout, Second Spectrum, FMDB, Transfer Room, FBref, Sofascore, or TheSportsDB.", {
|
|
93
|
+
query: z
|
|
94
|
+
.string()
|
|
95
|
+
.describe("Provider name, brand, product, or alias to resolve to a canonical provider key."),
|
|
96
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => withDocsDb((db) => resolveProviderId(db, args)));
|
|
97
|
+
server.tool("get_provider_docs", "Retrieve documentation for a resolved provider, optionally filtered by topic or indexed category. Use after resolve_provider_id when you know which provider to inspect and want provenance-bearing docs.", {
|
|
98
|
+
provider: z
|
|
99
|
+
.string()
|
|
100
|
+
.describe("Provider key or alias. Use resolve_provider_id first when the provider name is ambiguous."),
|
|
101
|
+
topic: z.string().optional().describe("Optional topic to search within this provider's docs."),
|
|
102
|
+
category: z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe("Optional indexed category to restrict results, such as api-endpoints, qualifiers, identity-surfaces, or tracking-rendering."),
|
|
106
|
+
max_results: z
|
|
107
|
+
.number()
|
|
108
|
+
.optional()
|
|
109
|
+
.default(10)
|
|
110
|
+
.describe("Maximum number of provider docs to return (default 10)."),
|
|
111
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => withDocsDb((db) => getProviderDocs(db, args)));
|
|
92
112
|
server.tool("list_providers", "List all indexed football data providers, their document count, and coverage categories. Use to understand what documentation is available. Call this first to see what providers are indexed before searching.", {}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async () => withDocsDb((db) => listProviders(db)));
|
|
93
113
|
server.tool("compare_providers", "Compare what two or more providers offer for a specific data type or concept. For example: 'How do Opta and StatsBomb represent shot events differently?'", {
|
|
94
114
|
topic: z.string().describe("The concept to compare across providers. Examples: 'shot events', 'coordinate systems', 'xG', 'pass types'"),
|
|
95
115
|
providers: z
|
|
96
116
|
.array(z.string())
|
|
97
117
|
.optional()
|
|
98
|
-
.describe("Providers to compare. If omitted, compares all indexed providers."),
|
|
118
|
+
.describe("Providers to compare. If omitted, compares all indexed providers. Use list_providers for indexed keys; common aliases such as ClubElo, football-data.co.uk, engsoccerdata, Sofascore, ESPN, StatsBomb Open Data, Opta F24, WhoScored, SkillCorner, Metrica, Sportec/DFL, TRACAB, Second Spectrum, SportRadar API, Soccer Extended, TheSportsDB, and TSDB are accepted."),
|
|
99
119
|
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (args) => withDocsDb((db) => compareProviders(db, args)));
|
|
100
120
|
server.tool("request_update", "Request that a provider's documentation be added, updated, or recrawled. Use when you notice docs are outdated, a provider is missing, or you know of a better documentation source. Requests are queued for review.", {
|
|
101
121
|
type: z.enum(["new_provider", "recrawl", "flag_outdated", "suggest_source"]).describe("Type of request: new_provider (add a new tool/library), recrawl (refresh existing docs), flag_outdated (mark docs as stale), suggest_source (recommend a better doc source like llms.txt)"),
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type Database from "better-sqlite3";
|
|
2
|
-
export declare const TOOL_NAMES: readonly ["search_docs", "list_providers", "compare_providers", "request_update", "resolve_entity"];
|
|
2
|
+
export declare const TOOL_NAMES: readonly ["search_docs", "resolve_provider_id", "get_provider_docs", "list_providers", "compare_providers", "request_update", "resolve_entity"];
|
|
3
3
|
type TextContent = {
|
|
4
4
|
type: "text";
|
|
5
5
|
text: string;
|
|
@@ -13,6 +13,15 @@ export type SearchDocsArgs = {
|
|
|
13
13
|
provider?: string;
|
|
14
14
|
max_results?: number;
|
|
15
15
|
};
|
|
16
|
+
export type ResolveProviderIdArgs = {
|
|
17
|
+
query: string;
|
|
18
|
+
};
|
|
19
|
+
export type GetProviderDocsArgs = {
|
|
20
|
+
provider: string;
|
|
21
|
+
topic?: string;
|
|
22
|
+
category?: string;
|
|
23
|
+
max_results?: number;
|
|
24
|
+
};
|
|
16
25
|
export type CompareProvidersArgs = {
|
|
17
26
|
topic: string;
|
|
18
27
|
providers?: string[];
|
|
@@ -38,6 +47,8 @@ export type ResolveEntityArgs = {
|
|
|
38
47
|
* like "Opta qualifier 76" to match docs that contain those tokens separately.
|
|
39
48
|
*/
|
|
40
49
|
export declare function sanitiseFtsQuery(query: string): string;
|
|
50
|
+
export declare function resolveProviderId(db: Database.Database, args: ResolveProviderIdArgs): ToolResponse;
|
|
51
|
+
export declare function getProviderDocs(db: Database.Database, args: GetProviderDocsArgs): ToolResponse;
|
|
41
52
|
export declare function searchDocs(db: Database.Database, args: SearchDocsArgs): ToolResponse;
|
|
42
53
|
export declare function listProviders(db: Database.Database): ToolResponse;
|
|
43
54
|
export declare function compareProviders(db: Database.Database, args: CompareProvidersArgs): ToolResponse;
|