@claudinho/mcp 0.8.14 → 0.8.16
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 -1
- package/dist/index.js +114 -29
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -54,7 +54,8 @@ Then just ask your agent naturally — it picks the right tool and answers with
|
|
|
54
54
|
|
|
55
55
|
All tools are **read-only** (`readOnlyHint`) and accept optional `tz`, `lang`
|
|
56
56
|
(`en`/`es`/`pt`/`fr`), and `flavor` (`off`/`subtle`/`full`). Every response carries
|
|
57
|
-
human-readable text **and** structured
|
|
57
|
+
human-readable text **and** structured content, validated against each tool's
|
|
58
|
+
declared `outputSchema`.
|
|
58
59
|
|
|
59
60
|
Resources: `standings://{group}`, `fixtures://{date}`. Prompts: `tournament_today`,
|
|
60
61
|
and `my_team` (give it a 3-letter team code; combines next fixture, standings, and
|
package/dist/index.js
CHANGED
|
@@ -3116,7 +3116,7 @@ function winnerLabel(ctx, stage, index) {
|
|
|
3116
3116
|
n: String(index)
|
|
3117
3117
|
});
|
|
3118
3118
|
}
|
|
3119
|
-
function resolveSlot(ref, ctx, liveTeam) {
|
|
3119
|
+
function resolveSlot(ref, ctx, liveTeam, fixtureInMergedSet = false) {
|
|
3120
3120
|
const liveParticipant = confirmedLiveParticipant(liveTeam);
|
|
3121
3121
|
switch (ref.kind) {
|
|
3122
3122
|
case "seed":
|
|
@@ -3138,23 +3138,27 @@ function resolveSlot(ref, ctx, liveTeam) {
|
|
|
3138
3138
|
if (liveParticipant) return liveParticipant;
|
|
3139
3139
|
return tbd(t(ctx.lang, "bracket.slot.third", { groups: ref.groups.join("/") }));
|
|
3140
3140
|
case "winner": {
|
|
3141
|
-
const node = ctx.nodesByKey.get(matchKey(ref.stage, ref.index));
|
|
3142
|
-
const match = node ? ctx.matchesById.get(node.matchId) : void 0;
|
|
3143
|
-
if (match) {
|
|
3144
|
-
const winner = resolveWinner(match);
|
|
3145
|
-
if (winner) return participant(winner, "confirmed");
|
|
3146
|
-
}
|
|
3147
3141
|
if (liveParticipant) return liveParticipant;
|
|
3142
|
+
if (!fixtureInMergedSet) {
|
|
3143
|
+
const node = ctx.nodesByKey.get(matchKey(ref.stage, ref.index));
|
|
3144
|
+
const match = node ? ctx.matchesById.get(node.matchId) : void 0;
|
|
3145
|
+
if (match) {
|
|
3146
|
+
const winner = resolveWinner(match);
|
|
3147
|
+
if (winner) return participant(winner, "confirmed");
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3148
3150
|
return tbd(winnerLabel(ctx, ref.stage, ref.index));
|
|
3149
3151
|
}
|
|
3150
3152
|
case "loser": {
|
|
3151
|
-
const node = ctx.nodesByKey.get(matchKey(ref.stage, ref.index));
|
|
3152
|
-
const match = node ? ctx.matchesById.get(node.matchId) : void 0;
|
|
3153
|
-
if (match) {
|
|
3154
|
-
const loser = resolveLoser(match);
|
|
3155
|
-
if (loser) return participant(loser, "confirmed");
|
|
3156
|
-
}
|
|
3157
3153
|
if (liveParticipant) return liveParticipant;
|
|
3154
|
+
if (!fixtureInMergedSet) {
|
|
3155
|
+
const node = ctx.nodesByKey.get(matchKey(ref.stage, ref.index));
|
|
3156
|
+
const match = node ? ctx.matchesById.get(node.matchId) : void 0;
|
|
3157
|
+
if (match) {
|
|
3158
|
+
const loser = resolveLoser(match);
|
|
3159
|
+
if (loser) return participant(loser, "confirmed");
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3158
3162
|
return tbd(
|
|
3159
3163
|
t(ctx.lang, "bracket.slot.loser", {
|
|
3160
3164
|
stage: stageLabelI18n(ctx.lang, ref.stage),
|
|
@@ -3177,6 +3181,7 @@ function buildBracketView(topology, matches, tables, standingsDegraded, liveDegr
|
|
|
3177
3181
|
if (want && stage !== want) continue;
|
|
3178
3182
|
const nodes = topology.matches.filter((n) => n.stage === stage);
|
|
3179
3183
|
const matchViews = nodes.map((node) => {
|
|
3184
|
+
const fixtureInMergedSet = matchesById.has(node.matchId);
|
|
3180
3185
|
const match = matchesById.get(node.matchId) ?? {
|
|
3181
3186
|
id: node.matchId,
|
|
3182
3187
|
stage: node.stage,
|
|
@@ -3192,8 +3197,8 @@ function buildBracketView(topology, matches, tables, standingsDegraded, liveDegr
|
|
|
3192
3197
|
stage: node.stage,
|
|
3193
3198
|
index: node.index,
|
|
3194
3199
|
kickoff: match.kickoff,
|
|
3195
|
-
home: resolveSlot(node.home, ctx, match.home),
|
|
3196
|
-
away: resolveSlot(node.away, ctx, match.away),
|
|
3200
|
+
home: resolveSlot(node.home, ctx, match.home, fixtureInMergedSet),
|
|
3201
|
+
away: resolveSlot(node.away, ctx, match.away, fixtureInMergedSet),
|
|
3197
3202
|
match
|
|
3198
3203
|
};
|
|
3199
3204
|
});
|
|
@@ -4035,8 +4040,8 @@ function marketProbabilityText(signal, match) {
|
|
|
4035
4040
|
}
|
|
4036
4041
|
function marketAttributionText(signal) {
|
|
4037
4042
|
const time = utcHhmm(signal.asOf);
|
|
4038
|
-
const
|
|
4039
|
-
return time ? `${
|
|
4043
|
+
const src2 = `Source: ${marketSourceLabel(signal.source)}`;
|
|
4044
|
+
return time ? `${src2} \xB7 updated ${time}` : src2;
|
|
4040
4045
|
}
|
|
4041
4046
|
function marketLine(signal, match) {
|
|
4042
4047
|
return `Market: ${marketProbabilityText(signal, match)} \xB7 ${marketSourceLabel(
|
|
@@ -4534,8 +4539,8 @@ function formatShareBracket(input, options = {}) {
|
|
|
4534
4539
|
}
|
|
4535
4540
|
}
|
|
4536
4541
|
const footer = [];
|
|
4537
|
-
const
|
|
4538
|
-
if (
|
|
4542
|
+
const src2 = input.source ?? input.view.source;
|
|
4543
|
+
if (src2) footer.push(t(locale, "live.data", { source: liveSourceLabel(src2) }));
|
|
4539
4544
|
footer.push(
|
|
4540
4545
|
[includeHashtag ? SHARE_HASHTAG : "", SHARE_DISCLAIMER].filter(Boolean).join(" \xB7 ")
|
|
4541
4546
|
);
|
|
@@ -5114,7 +5119,7 @@ async function toolGetShareSnippet(args) {
|
|
|
5114
5119
|
|
|
5115
5120
|
// src/server.ts
|
|
5116
5121
|
var SERVER_NAME = "claudinho";
|
|
5117
|
-
var SERVER_VERSION = "0.8.
|
|
5122
|
+
var SERVER_VERSION = "0.8.16";
|
|
5118
5123
|
var VOICE = asFlavorLevel(process.env.CLAUDINHO_FLAVOR) === "off" ? "" : `
|
|
5119
5124
|
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.`;
|
|
5120
5125
|
var INSTRUCTIONS = `Claudinho serves live scores, fixtures, and group standings for the 2026 men's football tournament.
|
|
@@ -5131,12 +5136,84 @@ var commonArgs = {
|
|
|
5131
5136
|
lang: z.string().optional().describe("Locale for formatting: en, es, pt, fr (other locales fall back to en)"),
|
|
5132
5137
|
flavor: flavorArg.optional().describe("Commentary flair: off, subtle, full (default: full)")
|
|
5133
5138
|
};
|
|
5139
|
+
var teamRef = z.object({ code: z.string(), name: z.string(), flag: z.string() }).partial().passthrough();
|
|
5140
|
+
var scorePair = z.object({ home: z.number(), away: z.number() }).partial().passthrough();
|
|
5141
|
+
var matchOut = z.object({
|
|
5142
|
+
id: z.string(),
|
|
5143
|
+
stage: z.string().optional(),
|
|
5144
|
+
group: z.string().nullable().optional(),
|
|
5145
|
+
kickoff: z.string().optional(),
|
|
5146
|
+
venue: z.string().optional(),
|
|
5147
|
+
home: teamRef.optional(),
|
|
5148
|
+
away: teamRef.optional(),
|
|
5149
|
+
score: scorePair.nullable().optional(),
|
|
5150
|
+
shootout: scorePair.optional(),
|
|
5151
|
+
status: z.string().optional(),
|
|
5152
|
+
minute: z.number().nullable().optional(),
|
|
5153
|
+
winnerCode: z.string().optional()
|
|
5154
|
+
}).passthrough();
|
|
5155
|
+
var anyObj = z.object({}).passthrough();
|
|
5156
|
+
var src = z.string().nullable();
|
|
5157
|
+
var todayOut = {
|
|
5158
|
+
date: z.string(),
|
|
5159
|
+
degraded: z.boolean(),
|
|
5160
|
+
source: src,
|
|
5161
|
+
count: z.number(),
|
|
5162
|
+
matches: z.array(matchOut),
|
|
5163
|
+
marketSignals: z.record(anyObj).optional()
|
|
5164
|
+
};
|
|
5165
|
+
var liveOut = { degraded: z.boolean(), source: src, count: z.number(), matches: z.array(matchOut) };
|
|
5166
|
+
var matchDetailOut = {
|
|
5167
|
+
match: matchOut.nullable(),
|
|
5168
|
+
degraded: z.boolean().optional(),
|
|
5169
|
+
source: src.optional(),
|
|
5170
|
+
marketSignal: anyObj.nullable().optional()
|
|
5171
|
+
};
|
|
5172
|
+
var standingsOut = {
|
|
5173
|
+
degraded: z.boolean(),
|
|
5174
|
+
source: src,
|
|
5175
|
+
tables: z.union([anyObj, z.array(anyObj), z.null()])
|
|
5176
|
+
};
|
|
5177
|
+
var bracketOut = {
|
|
5178
|
+
view: anyObj.nullable(),
|
|
5179
|
+
degraded: z.boolean().optional(),
|
|
5180
|
+
standingsDegraded: z.boolean().optional(),
|
|
5181
|
+
source: src.optional()
|
|
5182
|
+
};
|
|
5183
|
+
var nextOut = { team: z.string(), fixture: matchOut.nullable(), degraded: z.boolean() };
|
|
5184
|
+
var marketOut = {
|
|
5185
|
+
matchId: z.string().nullable().optional(),
|
|
5186
|
+
team: z.string().optional(),
|
|
5187
|
+
date: z.string().optional(),
|
|
5188
|
+
degraded: z.boolean().optional(),
|
|
5189
|
+
informationalOnly: z.boolean(),
|
|
5190
|
+
signal: anyObj.nullable().optional(),
|
|
5191
|
+
signals: z.array(anyObj).optional()
|
|
5192
|
+
};
|
|
5193
|
+
var shareOut = {
|
|
5194
|
+
kind: z.string(),
|
|
5195
|
+
target: z.string().optional(),
|
|
5196
|
+
snippet: z.string().optional(),
|
|
5197
|
+
// absent on the bracket "unknown stage" error branch
|
|
5198
|
+
source: src.optional(),
|
|
5199
|
+
informationalOnly: z.boolean().optional(),
|
|
5200
|
+
degraded: z.boolean().optional(),
|
|
5201
|
+
style: z.string().optional(),
|
|
5202
|
+
team: z.string().optional(),
|
|
5203
|
+
group: z.string().optional(),
|
|
5204
|
+
stage: z.string().optional(),
|
|
5205
|
+
tables: z.union([anyObj, z.array(anyObj), z.null()]).optional(),
|
|
5206
|
+
view: anyObj.nullable().optional(),
|
|
5207
|
+
matches: z.array(matchOut).optional(),
|
|
5208
|
+
marketSignals: z.record(anyObj).optional()
|
|
5209
|
+
};
|
|
5134
5210
|
function toContent(r) {
|
|
5135
5211
|
return {
|
|
5136
5212
|
content: [
|
|
5137
5213
|
{ type: "text", text: r.text },
|
|
5138
5214
|
{ type: "text", text: "```json\n" + JSON.stringify(r.data, null, 2) + "\n```" }
|
|
5139
|
-
]
|
|
5215
|
+
],
|
|
5216
|
+
structuredContent: r.data
|
|
5140
5217
|
};
|
|
5141
5218
|
}
|
|
5142
5219
|
function buildServer() {
|
|
@@ -5154,7 +5231,8 @@ function buildServer() {
|
|
|
5154
5231
|
...commonArgs
|
|
5155
5232
|
},
|
|
5156
5233
|
// Read-only; reaches an external data provider for the live overlay.
|
|
5157
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5234
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5235
|
+
outputSchema: todayOut
|
|
5158
5236
|
},
|
|
5159
5237
|
async (args) => toContent(await toolGetToday(args))
|
|
5160
5238
|
);
|
|
@@ -5164,7 +5242,8 @@ function buildServer() {
|
|
|
5164
5242
|
title: "Live matches",
|
|
5165
5243
|
description: "Only matches in play right now \u2014 each with current score and minute (empty when nothing is live). Use during matches for in-play state; for a full day's schedule including upcoming and finished, use get_today. tz/lang/flavor affect formatting only.",
|
|
5166
5244
|
inputSchema: { ...commonArgs },
|
|
5167
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5245
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5246
|
+
outputSchema: liveOut
|
|
5168
5247
|
},
|
|
5169
5248
|
async (args) => toContent(await toolGetLive(args))
|
|
5170
5249
|
);
|
|
@@ -5174,7 +5253,8 @@ function buildServer() {
|
|
|
5174
5253
|
title: "Match detail",
|
|
5175
5254
|
description: "One match by its id, with live score/minute overlaid when it's in play. Get the id from get_today or get_live; to find a team's match without an id, use get_next_fixture. tz/lang/flavor affect formatting.",
|
|
5176
5255
|
inputSchema: { id: z.string().describe("Match id"), ...commonArgs },
|
|
5177
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5256
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5257
|
+
outputSchema: matchDetailOut
|
|
5178
5258
|
},
|
|
5179
5259
|
async (args) => toContent(await toolGetMatch(args))
|
|
5180
5260
|
);
|
|
@@ -5187,7 +5267,8 @@ function buildServer() {
|
|
|
5187
5267
|
group: groupArg.optional().describe("Group letter A\u2013L (omit for all)"),
|
|
5188
5268
|
...commonArgs
|
|
5189
5269
|
},
|
|
5190
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5270
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5271
|
+
outputSchema: standingsOut
|
|
5191
5272
|
},
|
|
5192
5273
|
async (args) => toContent(await toolGetStandings(args))
|
|
5193
5274
|
);
|
|
@@ -5200,7 +5281,8 @@ function buildServer() {
|
|
|
5200
5281
|
stage: z.enum(["R32", "R16", "QF", "SF", "3P", "F"]).optional().describe("Knockout round to show (omit for the full bracket)"),
|
|
5201
5282
|
...commonArgs
|
|
5202
5283
|
},
|
|
5203
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5284
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5285
|
+
outputSchema: bracketOut
|
|
5204
5286
|
},
|
|
5205
5287
|
async (args) => toContent(await toolGetBracket(args))
|
|
5206
5288
|
);
|
|
@@ -5211,7 +5293,8 @@ function buildServer() {
|
|
|
5211
5293
|
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.",
|
|
5212
5294
|
inputSchema: { team: teamArg.describe("3-letter team code, e.g. MEX"), ...commonArgs },
|
|
5213
5295
|
// Read-only; overlays live provider data for knockout pairings, so open-world.
|
|
5214
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5296
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5297
|
+
outputSchema: nextOut
|
|
5215
5298
|
},
|
|
5216
5299
|
async (args) => toContent(await toolGetNextFixture(args))
|
|
5217
5300
|
);
|
|
@@ -5229,7 +5312,8 @@ function buildServer() {
|
|
|
5229
5312
|
...commonArgs
|
|
5230
5313
|
},
|
|
5231
5314
|
// Read-only; reaches an external prediction-market data provider.
|
|
5232
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5315
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5316
|
+
outputSchema: marketOut
|
|
5233
5317
|
},
|
|
5234
5318
|
async (args) => toContent(await toolGetMarketSignal(args))
|
|
5235
5319
|
);
|
|
@@ -5253,7 +5337,8 @@ function buildServer() {
|
|
|
5253
5337
|
...commonArgs
|
|
5254
5338
|
},
|
|
5255
5339
|
// Read-only; may reach the live/market data providers (live/today/match).
|
|
5256
|
-
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
5340
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
5341
|
+
outputSchema: shareOut
|
|
5257
5342
|
},
|
|
5258
5343
|
async (args) => toContent(await toolGetShareSnippet(args))
|
|
5259
5344
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinho/mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.16",
|
|
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,10 +57,11 @@
|
|
|
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.16"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsup",
|
|
64
|
+
"build:mcpb": "pnpm run build && node scripts/build-mcpb.mjs",
|
|
64
65
|
"dev": "tsup --watch",
|
|
65
66
|
"test": "vitest run",
|
|
66
67
|
"typecheck": "tsc --noEmit",
|