football-docs 0.2.1 → 0.3.0
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/data/docs.db +0 -0
- package/dist/index.js +73 -0
- package/package.json +1 -1
package/data/docs.db
CHANGED
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -279,6 +279,79 @@ server.tool("request_update", "Request that a provider's documentation be added,
|
|
|
279
279
|
qdb.close();
|
|
280
280
|
}
|
|
281
281
|
});
|
|
282
|
+
// Tool: resolve_entity
|
|
283
|
+
const REEP_API = "https://reep-api.rahulkeerthi2-95d.workers.dev";
|
|
284
|
+
server.tool("resolve_entity", "Resolve a football entity (player, team, or coach) to get cross-provider IDs. Use when you need to map between Transfermarkt, FBref, Sofascore, Opta, and other provider IDs, or when you need to look up a player/team/coach by name.", {
|
|
285
|
+
name: z.string().optional().describe("Entity name to search for (e.g. 'Cole Palmer', 'Arsenal'). Fuzzy match on name and aliases."),
|
|
286
|
+
provider: z.string().optional().describe("Source provider for ID resolution (e.g. 'transfermarkt', 'fbref', 'sofascore', 'opta', 'soccerway')"),
|
|
287
|
+
id: z.string().optional().describe("ID from the source provider to resolve to all other IDs"),
|
|
288
|
+
qid: z.string().optional().describe("Wikidata QID for direct lookup (e.g. 'Q99760796')"),
|
|
289
|
+
type: z.enum(["player", "team", "coach"]).optional().describe("Filter results by entity type"),
|
|
290
|
+
}, { readOnlyHint: true, destructiveHint: false, openWorldHint: true }, async ({ name, provider, id, qid, type }) => {
|
|
291
|
+
let url;
|
|
292
|
+
if (qid) {
|
|
293
|
+
url = `${REEP_API}/lookup?qid=${encodeURIComponent(qid)}`;
|
|
294
|
+
}
|
|
295
|
+
else if (provider && id) {
|
|
296
|
+
url = `${REEP_API}/resolve?provider=${encodeURIComponent(provider)}&id=${encodeURIComponent(id)}`;
|
|
297
|
+
}
|
|
298
|
+
else if (name) {
|
|
299
|
+
url = `${REEP_API}/search?name=${encodeURIComponent(name)}&limit=10`;
|
|
300
|
+
if (type)
|
|
301
|
+
url += `&type=${encodeURIComponent(type)}`;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
return {
|
|
305
|
+
isError: true,
|
|
306
|
+
content: [{
|
|
307
|
+
type: "text",
|
|
308
|
+
text: "Provide at least one of: name, qid, or provider+id. Examples:\n- name: 'Cole Palmer'\n- provider: 'transfermarkt', id: '568177'\n- qid: 'Q99760796'",
|
|
309
|
+
}],
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const resp = await fetch(url);
|
|
314
|
+
if (!resp.ok) {
|
|
315
|
+
return {
|
|
316
|
+
isError: true,
|
|
317
|
+
content: [{ type: "text", text: `Reep API error: ${resp.status} ${resp.statusText}` }],
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
const data = await resp.json();
|
|
321
|
+
if (!data.results?.length) {
|
|
322
|
+
return {
|
|
323
|
+
content: [{ type: "text", text: "No entities found matching the query." }],
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
const formatted = data.results.map((e) => {
|
|
327
|
+
const ids = e.external_ids;
|
|
328
|
+
const idLines = ids
|
|
329
|
+
? Object.entries(ids).map(([k, v]) => ` ${k}: ${v}`).join("\n")
|
|
330
|
+
: " (none)";
|
|
331
|
+
const bio = [
|
|
332
|
+
e.date_of_birth && `DOB: ${e.date_of_birth}`,
|
|
333
|
+
e.nationality && `Nationality: ${e.nationality}`,
|
|
334
|
+
e.position && `Position: ${e.position}`,
|
|
335
|
+
e.height_cm && `Height: ${e.height_cm}cm`,
|
|
336
|
+
e.country && `Country: ${e.country}`,
|
|
337
|
+
e.stadium && `Stadium: ${e.stadium}`,
|
|
338
|
+
].filter(Boolean).join(" | ");
|
|
339
|
+
return `### ${e.name_en} (${e.type})\nWikidata: ${e.qid}${e.aliases_en ? `\nAliases: ${e.aliases_en}` : ""}${bio ? `\n${bio}` : ""}\nProvider IDs:\n${idLines}`;
|
|
340
|
+
}).join("\n\n");
|
|
341
|
+
return {
|
|
342
|
+
content: [{
|
|
343
|
+
type: "text",
|
|
344
|
+
text: `Found ${data.results.length} result(s):\n\n${formatted}`,
|
|
345
|
+
}],
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
return {
|
|
350
|
+
isError: true,
|
|
351
|
+
content: [{ type: "text", text: `Failed to reach Reep API: ${err instanceof Error ? err.message : String(err)}` }],
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
});
|
|
282
355
|
// ── Start ───────────────────────────────────────────────────────────────
|
|
283
356
|
async function main() {
|
|
284
357
|
const transport = new StdioServerTransport();
|
package/package.json
CHANGED