@chessceo/mcp 0.48.2 → 0.49.1

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 CHANGED
@@ -1,23 +1,27 @@
1
1
  # @chessceo/mcp
2
2
 
3
- Model Context Protocol server for [chess.ceo](https://chess.ceo) — 11.7M+ games, ~1.5M FIDE player profiles, opening preparation, live broadcasts. Lets Claude, Cursor, and any other MCP host answer chess questions directly against real data instead of hallucinating.
3
+ Model Context Protocol server for [chess.ceo](https://chess.ceo) — 11.7M+ games, ~1.5M FIDE player profiles, opening preparation, live broadcasts, cloud engine analysis, and (signed-in) a full read/write prep-file workflow. Lets Claude, Cursor, and any other MCP host answer chess questions directly against real data instead of hallucinating.
4
4
 
5
- No API key. No auth. No state. Free to use.
5
+ Player/game lookups need no API key or auth. Cloud engines and prep-file tools need a `mcp_...` bearer token (see Auth below).
6
6
 
7
7
  ## What it can do
8
8
 
9
- The server exposes 8 tools that mirror the public GET API surface at `chess.ceo`:
9
+ 49 tools as of v0.49.0, mirroring the `chess.ceo` API surface. A few of the most-used:
10
10
 
11
11
  | Tool | What it answers |
12
12
  |---|---|
13
13
  | `search_player` | "Find FIDE ID for Magnus Carlsen" |
14
14
  | `get_player_profile` | "How strong is X, what do they play, who have they beaten" |
15
- | `get_player_preparation` | "What does X play against 1.e4? What's their win rate with the Najdorf?" |
15
+ | `prepare_opponent` + `get_prep_position` | "What does X play against 1.e4? What's their win rate with the Najdorf?" |
16
16
  | `get_position_stats` | "From this position, which move scores best in the 11.7M-game database?" |
17
17
  | `get_head_to_head` | "What's the record between X and Y?" |
18
- | `list_live_tournaments` | "What's being broadcast live right now?" |
19
- | `list_tournament_players` | "Who's playing in tournament T?" |
20
- | `list_player_live_tournaments` | "Is X playing anywhere right now?" |
18
+ | `list_live_tournaments` / `list_tournament_players` / `list_player_live_tournaments` | "What's being broadcast live right now? Who's playing? Is X in it?" |
19
+ | `cloud_analyse` | "Run Stockfish + Lc0 on this position on my rented GPU instance" |
20
+ | `read_prep_file` / `add_line` / `add_move` / `apply_mutations` | Read and edit your own repertoire/course PGNs stored server-side |
21
+ | `auto_evaluate` / `deep_analyse` | Kick off a long-running engine-evaluation job over a whole prep file, poll it, cancel it |
22
+ | `read_docs` | Bundled guides (engine usage, opening prep, prep-file conventions, PGN authoring, summary authoring) |
23
+
24
+ Full tool inventory with categories lives in [`CLAUDE.md`](CLAUDE.md) under "Tools cheatsheet" — that's the maintained source of truth; this table is illustrative, not exhaustive.
21
25
 
22
26
  ## Install (Claude Desktop)
23
27
 
@@ -62,6 +66,25 @@ This repo is also a [Claude Code plugin marketplace](https://code.claude.com/doc
62
66
 
63
67
  Claude Code will pull the plugin from GitHub and wire the MCP server automatically. Enable "Sync automatically" in the marketplace UI if you want future updates fetched on push.
64
68
 
69
+ ## Auth (for cloud engines and prep files)
70
+
71
+ Read-only chess data — player search, profiles, position stats, head-to-head, live tournaments — needs nothing. Cloud engine tools and your own prep-file tools (list/read/create/edit) need a `mcp_...` bearer token.
72
+
73
+ - **Local (`npx`/Claude Desktop/Cursor):** set `CHESSCEO_TOKEN` in the server's `env` block:
74
+ ```json
75
+ {
76
+ "mcpServers": {
77
+ "chessceo": {
78
+ "command": "npx",
79
+ "args": ["-y", "@chessceo/mcp"],
80
+ "env": { "CHESSCEO_TOKEN": "mcp_..." }
81
+ }
82
+ }
83
+ }
84
+ ```
85
+ Get a token from your chess.ceo account settings.
86
+ - **Remote (`mcp.chess.ceo/mcp`):** no config needed — calling an authed tool without a token triggers the host's normal OAuth flow (claude.ai, ChatGPT connectors) automatically.
87
+
65
88
  ## Try it
66
89
 
67
90
  Ask your model:
@@ -109,7 +132,7 @@ In Claude Desktop, edit `claude_desktop_config.json`:
109
132
  }
110
133
  ```
111
134
 
112
- Same 8 tools, same data, zero-install. Useful when the host can't spawn subprocesses (e.g. Claude.ai web, Claude mobile, ChatGPT connectors).
135
+ Same tools, same data, zero-install. Bearer-authed tools (cloud engines, prep files) go through this host's OAuth flow instead of a config-file token. Useful when the host can't spawn subprocesses (e.g. Claude.ai web, Claude mobile, ChatGPT connectors).
113
136
 
114
137
  ## Self-host the HTTP transport
115
138
 
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ import { getNodeByPath, resolveFromNodeOrFen, storeEvalOnNode, } from "./analysi
29
29
  import { findPositionInCourses, readCourseAtPosition, runSfEval } from "./courses.js";
30
30
  import { applyBatchMutations, applyMutation, argNodeId, } from "./prep/mutations.js";
31
31
  import { listNodes, listTranspositions, readPrepFile, } from "./prep/read.js";
32
- import { createPrepFile, findPositionInFiles, listCollections, listPrepFiles, searchPrepFiles, } from "./prep/library.js";
32
+ import { createCollection, createPrepFile, findPositionInFiles, listCollections, listPrepFiles, searchPrepFiles, } from "./prep/library.js";
33
33
  import { convertAvailableMovesToSAN, normalizeSourceForBackend, stripPositionResponse, trimGamesMovetext, } from "./response_transforms.js";
34
34
  // Tools that require an MCP token — cloud engine + prep-file tools
35
35
  // operate on the caller's own account so we can't service them
@@ -42,6 +42,7 @@ const AUTHED_TOOLS = new Set([
42
42
  "stop_cloud_engine",
43
43
  "cloud_analyse",
44
44
  "list_collections",
45
+ "create_collection",
45
46
  "list_prep_files",
46
47
  "search_prep_files",
47
48
  "find_position_in_files",
@@ -437,6 +438,8 @@ async function callToolInner(name, args) {
437
438
  return readCourseAtPosition(args);
438
439
  case "list_collections":
439
440
  return listCollections(args);
441
+ case "create_collection":
442
+ return createCollection(args);
440
443
  case "list_prep_files":
441
444
  return listPrepFiles(args);
442
445
  case "search_prep_files":
@@ -53,8 +53,11 @@ export async function searchPrepFiles(args) {
53
53
  if (!q)
54
54
  throw new Error("query required");
55
55
  const raw = await authedRequest("GET", `${PGN_BASE}/games/search?q=${encodeURIComponent(q)}&limit=100`);
56
- const data = unwrap(raw);
57
- const games = data?.games ?? [];
56
+ // Unlike list_prep_files' {games:[...]} envelope, the cross-collection
57
+ // search handler (RespondPaginated) puts the array straight into `data` —
58
+ // `data?.games` was always undefined here, so this silently returned []
59
+ // for every query/position regardless of real matches (found 2026-09-11).
60
+ const games = unwrap(raw) ?? [];
58
61
  return { query: q, prep_files: games.map(projectGameRow) };
59
62
  }
60
63
  export async function findPositionInFiles(args) {
@@ -63,14 +66,31 @@ export async function findPositionInFiles(args) {
63
66
  const resolved = await resolveFromNodeOrFen(args);
64
67
  const fen = resolved.fen;
65
68
  const raw = await authedRequest("GET", `${PGN_BASE}/games/search?position=${encodeURIComponent(fen)}&limit=100`);
66
- const data = unwrap(raw);
67
- const games = data?.games ?? [];
69
+ // See searchPrepFiles above — RespondPaginated's `data` is the array itself.
70
+ const games = unwrap(raw) ?? [];
68
71
  return {
69
72
  fen,
70
73
  match_count: games.length,
71
74
  prep_files: games.map(projectGameRow),
72
75
  };
73
76
  }
77
+ export async function createCollection(args) {
78
+ const title = String(args.title || "").trim();
79
+ if (!title)
80
+ throw new Error("title is required");
81
+ const folderPath = typeof args.folder_path === "string" ? args.folder_path.trim() : undefined;
82
+ const raw = await authedRequest("POST", PGN_BASE, {
83
+ title,
84
+ ...(folderPath ? { folderPath } : {}),
85
+ });
86
+ const collection = unwrap(raw);
87
+ return {
88
+ ok: true,
89
+ id: collection.id,
90
+ title: collection.title,
91
+ folder_path: collection.folderPath,
92
+ };
93
+ }
74
94
  export async function createPrepFile(args) {
75
95
  const collectionId = typeof args.collection_id === "string" ? args.collection_id.trim() : "";
76
96
  if (!collectionId) {
package/dist/tools.js CHANGED
@@ -466,6 +466,27 @@ export const TOOLS = [
466
466
  required: ["id"],
467
467
  },
468
468
  },
469
+ {
470
+ name: "create_collection",
471
+ description: "Create a new, empty PGN collection (a folder of prep files) — NOT a prep file itself. Use this when the user asks for a new file/course and `list_collections` shows nothing suitable to put it in; then call `create_prep_file` with the returned `id`.\n\n" +
472
+ "**Check `list_collections` first** — a duplicate folder with a slightly different name is the common failure mode here, same as `create_prep_file`.\n\n" +
473
+ "`folder_path` is optional (root if omitted) but should almost always be set — an ungrouped pile of top-level collections is exactly what this tool exists to avoid creating.\n\n" +
474
+ "Response: `{ok, id, title, folder_path}` — pass `id` to `create_prep_file` as `collection_id`.",
475
+ inputSchema: {
476
+ type: "object",
477
+ properties: {
478
+ title: {
479
+ type: "string",
480
+ description: "Collection name, shown in the user's file browser. Example: 'Sicilian Rauzer'.",
481
+ },
482
+ folder_path: {
483
+ type: "string",
484
+ description: "Virtual folder path, e.g. '/AI Organized/Sicilian Rauzer'. Omit for root.",
485
+ },
486
+ },
487
+ required: ["title"],
488
+ },
489
+ },
469
490
  {
470
491
  name: "create_prep_file",
471
492
  description: "Create a new (empty) prep file in the specified collection. `name` becomes the Event PGN tag. You then extend it with mutation tools (add_move, set_comment, …).\n\n" +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chessceo/mcp",
3
- "version": "0.48.2",
3
+ "version": "0.49.1",
4
4
  "description": "Model Context Protocol server for chess.ceo — 11.7M+ games, ~1.5M FIDE player profiles, opening preparation, live broadcasts.",
5
5
  "type": "module",
6
6
  "bin": {