@claudinho/mcp 0.8.5 → 0.8.7
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/dist/index.js +60 -21
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -302,8 +302,8 @@ var ES = {
|
|
|
302
302
|
"bracket.invalidStage": "La fase debe ser una de: R32, R16, QF, SF, 3P, F",
|
|
303
303
|
"bracket.unknownStage": 'Fase desconocida "{stage}". Usa R32, R16, QF, SF, 3P o F.',
|
|
304
304
|
"bracket.slot.groupWinner": "Ganador del grupo {group}",
|
|
305
|
-
"bracket.slot.groupSecond": "2
|
|
306
|
-
"bracket.slot.third": "3
|
|
305
|
+
"bracket.slot.groupSecond": "2\xBA del grupo {group}",
|
|
306
|
+
"bracket.slot.third": "3\xBA ({groups})",
|
|
307
307
|
"bracket.slot.winner": "Ganador {stage} {n}",
|
|
308
308
|
"bracket.slot.loser": "Perdedor {stage} {n}",
|
|
309
309
|
"bracket.slot.tbd": "Por definir",
|
|
@@ -3094,17 +3094,24 @@ function participant(team, status) {
|
|
|
3094
3094
|
function tbd(label) {
|
|
3095
3095
|
return { label, flag: "\u{1F3F3}\uFE0F", status: "tbd" };
|
|
3096
3096
|
}
|
|
3097
|
+
function confirmedLiveParticipant(team) {
|
|
3098
|
+
if (!team || team.flag === "\u{1F3F3}\uFE0F") return void 0;
|
|
3099
|
+
return participant(team, "confirmed");
|
|
3100
|
+
}
|
|
3097
3101
|
function winnerLabel(ctx, stage, index) {
|
|
3098
3102
|
return t(ctx.lang, "bracket.slot.winner", {
|
|
3099
3103
|
stage: stageLabelI18n(ctx.lang, stage),
|
|
3100
3104
|
n: String(index)
|
|
3101
3105
|
});
|
|
3102
3106
|
}
|
|
3103
|
-
function resolveSlot(ref, ctx) {
|
|
3107
|
+
function resolveSlot(ref, ctx, liveTeam) {
|
|
3108
|
+
const liveParticipant = confirmedLiveParticipant(liveTeam);
|
|
3104
3109
|
switch (ref.kind) {
|
|
3105
3110
|
case "seed":
|
|
3111
|
+
if (liveParticipant) return liveParticipant;
|
|
3106
3112
|
return tbd(ref.label);
|
|
3107
3113
|
case "group": {
|
|
3114
|
+
if (liveParticipant) return liveParticipant;
|
|
3108
3115
|
if (!ctx.standingsDegraded && hasGroupStarted(ref.group, ctx.tables)) {
|
|
3109
3116
|
const team = teamFromStandings(ref.group, ref.position, ctx.tables);
|
|
3110
3117
|
if (team) {
|
|
@@ -3116,6 +3123,7 @@ function resolveSlot(ref, ctx) {
|
|
|
3116
3123
|
return tbd(label);
|
|
3117
3124
|
}
|
|
3118
3125
|
case "third":
|
|
3126
|
+
if (liveParticipant) return liveParticipant;
|
|
3119
3127
|
return tbd(t(ctx.lang, "bracket.slot.third", { groups: ref.groups.join("/") }));
|
|
3120
3128
|
case "winner": {
|
|
3121
3129
|
const node = ctx.nodesByKey.get(matchKey(ref.stage, ref.index));
|
|
@@ -3124,6 +3132,7 @@ function resolveSlot(ref, ctx) {
|
|
|
3124
3132
|
const winner = resolveWinner(match);
|
|
3125
3133
|
if (winner) return participant(winner, "confirmed");
|
|
3126
3134
|
}
|
|
3135
|
+
if (liveParticipant) return liveParticipant;
|
|
3127
3136
|
return tbd(winnerLabel(ctx, ref.stage, ref.index));
|
|
3128
3137
|
}
|
|
3129
3138
|
case "loser": {
|
|
@@ -3133,6 +3142,7 @@ function resolveSlot(ref, ctx) {
|
|
|
3133
3142
|
const loser = resolveLoser(match);
|
|
3134
3143
|
if (loser) return participant(loser, "confirmed");
|
|
3135
3144
|
}
|
|
3145
|
+
if (liveParticipant) return liveParticipant;
|
|
3136
3146
|
return tbd(
|
|
3137
3147
|
t(ctx.lang, "bracket.slot.loser", {
|
|
3138
3148
|
stage: stageLabelI18n(ctx.lang, ref.stage),
|
|
@@ -3170,8 +3180,8 @@ function buildBracketView(topology, matches, tables, standingsDegraded, liveDegr
|
|
|
3170
3180
|
stage: node.stage,
|
|
3171
3181
|
index: node.index,
|
|
3172
3182
|
kickoff: match.kickoff,
|
|
3173
|
-
home: resolveSlot(node.home, ctx),
|
|
3174
|
-
away: resolveSlot(node.away, ctx),
|
|
3183
|
+
home: resolveSlot(node.home, ctx, match.home),
|
|
3184
|
+
away: resolveSlot(node.away, ctx, match.away),
|
|
3175
3185
|
match
|
|
3176
3186
|
};
|
|
3177
3187
|
});
|
|
@@ -3830,6 +3840,22 @@ async function marketFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Dat
|
|
|
3830
3840
|
const next = nextFixtureForTeam(code, { from: now });
|
|
3831
3841
|
return { match: next, degraded: false };
|
|
3832
3842
|
}
|
|
3843
|
+
async function getNextFixtureForTeam(adapter, code, now = /* @__PURE__ */ new Date()) {
|
|
3844
|
+
const base = allFixtures();
|
|
3845
|
+
let matches = base;
|
|
3846
|
+
let degraded = true;
|
|
3847
|
+
let liveById;
|
|
3848
|
+
try {
|
|
3849
|
+
const live = adapter.fetchWindow ? await adapter.fetchWindow(KNOCKOUT_WINDOW_START, KNOCKOUT_WINDOW_END) : [];
|
|
3850
|
+
matches = mergeLive(base, live);
|
|
3851
|
+
degraded = false;
|
|
3852
|
+
liveById = new Set(live.map((m) => m.id));
|
|
3853
|
+
} catch {
|
|
3854
|
+
}
|
|
3855
|
+
const fixture = nextFixtureForTeam(code, { from: now, fixtures: matches });
|
|
3856
|
+
const source = fixture && liveById?.has(fixture.id) ? adapter.name : void 0;
|
|
3857
|
+
return { fixture, degraded, source };
|
|
3858
|
+
}
|
|
3833
3859
|
async function getMatchById(adapter, id) {
|
|
3834
3860
|
const base = allFixtures().find((m) => m.id === id);
|
|
3835
3861
|
if (!base) return { match: void 0, degraded: false };
|
|
@@ -4665,7 +4691,7 @@ ${matchList(todays, "No matches scheduled.", opts)}`;
|
|
|
4665
4691
|
if (degraded) text += "\n\n(Live scores unavailable \u2014 showing the bundled schedule.)";
|
|
4666
4692
|
const marketSignals = await reliableMarketData(args, todays);
|
|
4667
4693
|
return {
|
|
4668
|
-
text: withDisclaimer(text, source),
|
|
4694
|
+
text: withDisclaimer(text, source, args.lang),
|
|
4669
4695
|
data: {
|
|
4670
4696
|
date,
|
|
4671
4697
|
degraded,
|
|
@@ -4683,7 +4709,7 @@ async function toolGetLive(args = {}) {
|
|
|
4683
4709
|
const text = degraded ? "Live scores unavailable right now \u2014 could not reach the data provider." : `Live now:
|
|
4684
4710
|
${matchList(matches, "No matches in play right now.", opts)}`;
|
|
4685
4711
|
return {
|
|
4686
|
-
text: withDisclaimer(text, source),
|
|
4712
|
+
text: withDisclaimer(text, source, args.lang),
|
|
4687
4713
|
data: { degraded, source: source ?? null, count: matches.length, matches }
|
|
4688
4714
|
};
|
|
4689
4715
|
}
|
|
@@ -4704,7 +4730,7 @@ async function toolGetMatch(args) {
|
|
|
4704
4730
|
${marketBlock(marketSignal, match).join("\n")}` : base;
|
|
4705
4731
|
if (degraded) text += "\n\n(Live state unavailable \u2014 showing the scheduled fixture.)";
|
|
4706
4732
|
return {
|
|
4707
|
-
text: withDisclaimer(text, liveSource),
|
|
4733
|
+
text: withDisclaimer(text, liveSource, args.lang),
|
|
4708
4734
|
data: {
|
|
4709
4735
|
degraded,
|
|
4710
4736
|
source: liveSource ?? null,
|
|
@@ -4720,14 +4746,14 @@ async function toolGetStandings(args) {
|
|
|
4720
4746
|
const g = args.group?.toUpperCase();
|
|
4721
4747
|
const msg = g ? `No group "${g}". Groups are A\u2013L.` : "No standings available.";
|
|
4722
4748
|
return {
|
|
4723
|
-
text: withDisclaimer(degraded ? `${msg} (Live standings unavailable.)` : msg, source),
|
|
4749
|
+
text: withDisclaimer(degraded ? `${msg} (Live standings unavailable.)` : msg, source, args.lang),
|
|
4724
4750
|
data: { degraded, source: source ?? null, tables: args.group ? null : [] }
|
|
4725
4751
|
};
|
|
4726
4752
|
}
|
|
4727
4753
|
let text = shaped.map((t2) => standingsTable(t2.group, t2.standings)).join("\n\n");
|
|
4728
4754
|
if (degraded) text += "\n\n(Live standings unavailable \u2014 showing the group roster.)";
|
|
4729
4755
|
return {
|
|
4730
|
-
text: withDisclaimer(text, source),
|
|
4756
|
+
text: withDisclaimer(text, source, args.lang),
|
|
4731
4757
|
data: { degraded, source: source ?? null, tables: args.group ? shaped[0] ?? null : shaped }
|
|
4732
4758
|
};
|
|
4733
4759
|
}
|
|
@@ -4773,18 +4799,23 @@ async function standingsResourceText(group, adapter) {
|
|
|
4773
4799
|
}
|
|
4774
4800
|
async function toolGetNextFixture(args) {
|
|
4775
4801
|
const code = args.team.toUpperCase();
|
|
4776
|
-
const fixture
|
|
4802
|
+
const { fixture, degraded, source } = await getNextFixtureForTeam(
|
|
4803
|
+
resolveAdapter(args),
|
|
4804
|
+
code,
|
|
4805
|
+
args.now ?? /* @__PURE__ */ new Date()
|
|
4806
|
+
);
|
|
4777
4807
|
if (!fixture) {
|
|
4808
|
+
const msg = degraded ? `Couldn't reach the data provider \u2014 no upcoming fixture confirmed for ${code}.` : `No upcoming fixture found for ${code}.`;
|
|
4778
4809
|
return {
|
|
4779
|
-
text: withDisclaimer(
|
|
4780
|
-
data: { team: code, fixture: null }
|
|
4810
|
+
text: withDisclaimer(msg, void 0, args.lang),
|
|
4811
|
+
data: { team: code, fixture: null, degraded }
|
|
4781
4812
|
};
|
|
4782
4813
|
}
|
|
4783
4814
|
const opts = fmtOpts(args);
|
|
4784
4815
|
return {
|
|
4785
4816
|
text: withDisclaimer(`Next up for ${code}:
|
|
4786
|
-
${matchLine(fixture, opts)}
|
|
4787
|
-
data: { team: code, fixture }
|
|
4817
|
+
${matchLine(fixture, opts)}`, source, args.lang),
|
|
4818
|
+
data: { team: code, fixture, degraded }
|
|
4788
4819
|
};
|
|
4789
4820
|
}
|
|
4790
4821
|
async function toolGetMarketSignal(args) {
|
|
@@ -5002,7 +5033,11 @@ async function toolGetShareSnippet(args) {
|
|
|
5002
5033
|
}
|
|
5003
5034
|
if (args.team) {
|
|
5004
5035
|
const code = args.team.toUpperCase();
|
|
5005
|
-
const fixture
|
|
5036
|
+
const { fixture, degraded: degraded2, source: source2 } = await getNextFixtureForTeam(
|
|
5037
|
+
resolveAdapter(args),
|
|
5038
|
+
code,
|
|
5039
|
+
args.now ?? /* @__PURE__ */ new Date()
|
|
5040
|
+
);
|
|
5006
5041
|
const matches = fixture ? [fixture] : [];
|
|
5007
5042
|
const teamName = fixture ? fixture.home.code === code ? fixture.home.name : fixture.away.name : code;
|
|
5008
5043
|
return shareResult(
|
|
@@ -5013,7 +5048,11 @@ async function toolGetShareSnippet(args) {
|
|
|
5013
5048
|
title: `Next up for ${teamName}`,
|
|
5014
5049
|
matches,
|
|
5015
5050
|
marketSignals: await signalsFor(matches),
|
|
5016
|
-
|
|
5051
|
+
// Attribute the provider only when the overlay resolved the tie; parity
|
|
5052
|
+
// with get_next_fixture (a static group fixture carries no source).
|
|
5053
|
+
source: source2,
|
|
5054
|
+
degraded: degraded2,
|
|
5055
|
+
emptyNote: degraded2 ? `Couldn't reach the data provider \u2014 no upcoming fixture confirmed for ${code}.` : `No upcoming fixture found for ${code}.`,
|
|
5017
5056
|
installLine: `npx @claudinho/cli next ${code}`,
|
|
5018
5057
|
tz: args.tz,
|
|
5019
5058
|
locale: args.lang
|
|
@@ -5046,7 +5085,7 @@ async function toolGetShareSnippet(args) {
|
|
|
5046
5085
|
|
|
5047
5086
|
// src/server.ts
|
|
5048
5087
|
var SERVER_NAME = "claudinho";
|
|
5049
|
-
var SERVER_VERSION = "0.8.
|
|
5088
|
+
var SERVER_VERSION = "0.8.7";
|
|
5050
5089
|
var VOICE = asFlavorLevel(process.env.CLAUDINHO_FLAVOR) === "off" ? "" : `
|
|
5051
5090
|
Voice: when relaying scores, narrate with lively, regionally-appropriate football-commentary energy in the user's language. Each match line may end with a short exclamation ("\u2014 \xA1GOOOOL!") \u2014 use it as a tone cue. Keep every fact exact; never invent details and never impersonate or name a real commentator.`;
|
|
5052
5091
|
var INSTRUCTIONS = `Claudinho serves live scores, fixtures, and group standings for the 2026 men's football tournament.
|
|
@@ -5140,10 +5179,10 @@ function buildServer() {
|
|
|
5140
5179
|
"get_next_fixture",
|
|
5141
5180
|
{
|
|
5142
5181
|
title: "Next fixture for a team",
|
|
5143
|
-
description: "A team's next
|
|
5182
|
+
description: "A team's next match, live-resolved: a confirmed knockout tie (Round of 32 onward) is read from the live overlay, group fixtures from the bundled schedule. Use a 3-letter code, e.g. MEX, BRA, USA. Falls back to the bundled schedule if the provider is unreachable.",
|
|
5144
5183
|
inputSchema: { team: teamArg.describe("3-letter team code, e.g. MEX"), ...commonArgs },
|
|
5145
|
-
// Read-only
|
|
5146
|
-
annotations: { readOnlyHint: true, openWorldHint:
|
|
5184
|
+
// Read-only; overlays live provider data for knockout pairings, so open-world.
|
|
5185
|
+
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5147
5186
|
},
|
|
5148
5187
|
async (args) => toContent(await toolGetNextFixture(args))
|
|
5149
5188
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinho/mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"mcpName": "io.github.arturogarrido/claudinho",
|
|
5
5
|
"description": "MCP server for the 2026 men's football tournament — live scores, fixtures, standings, read-only prediction-market signals, and paste-ready match cards. Works with Claude Code, Cursor, Codex, Windsurf, Zed. Not affiliated with FIFA or Anthropic.",
|
|
6
6
|
"type": "module",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"tsup": "^8.0.0",
|
|
58
58
|
"typescript": "^5.7.0",
|
|
59
59
|
"vitest": "^4.1.9",
|
|
60
|
-
"@claudinho/core": "0.8.
|
|
60
|
+
"@claudinho/core": "0.8.7"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsup",
|