Skip to content
Pedro Luis Soto Santos, Home
Back to home

pyplAI-MCPPersonal project. Open-source MCP server.

pyplAI’s search, as a tool for any LLM.

An MCP server that puts pyplAI’s algorithms in the hands of assistants like Claude. The model plays, asks for an analysis of each position and explains its move with the numbers from the search. In Phantom, where the opponent’s stones are hidden, the analysis only uses what the player knows.

games, one with hidden information
3
benchmark games with Llama 3.2 3B
960

Code on GitHub

Built with Python, MCP, Pydantic, and pyplAI.

The problem

Language models reason in words, but they don’t search. Ask one to play Ultimate tic-tac-toe and it will explain its moves well and choose them badly. pyplAI, my bachelor’s thesis, does the opposite: it searches, but explains nothing.

I wanted to bring the two together with the Model Context Protocol (MCP), the standard that lets assistants like Claude use external tools: the model plays, asks pyplAI to analyse the position and explains its move with the numbers from the search.

Seven tools and a game with hidden information

The server exposes pyplAI as seven tools: list the games and their rules, start a game, get the state, play, analyse the position and end the game. The key one is analyze_position: it runs a search from the model’s position and returns its legal moves ranked by the share of simulated games they win. This is a real response in Ultimate:

{
  "algorithm": "mcts",
  "metric": "win_rate",
  "best_move": "B1:a3",
  "moves": [
    {"move": "B1:a3", "visits": 121, "value": 0.4711},
    {"move": "B1:c1", "visits": 70, "value": 0.4357},
    {"move": "B1:c3", "visits": 89, "value": 0.4326}
  ],
  "iterations": 777,
  "seconds": 2.001
}

Phantom is where the design matters. It is four in a row on a 4 × 4 board where you can’t see your opponent’s stones. A perfect-information search would read the hidden stones from the game state and cheat, so the server only offers pyplAI’s ISMCTS variants, which sample where those stones could be from what the player knows. A test plays whole games and checks that nothing the player receives reveals a hidden stone.

Claude playing

Claude Desktop during a game of Phantom: Claude calls play_move with the move c2 and then analyze_position, which recommends b3 with 61% simulated wins.
A real game from Claude Desktop, with the tool calls expanded. The conversation is in Spanish.

This is how it looks from Claude Desktop: Claude analyses each position, plays the recommended move and explains why with the numbers from the analysis. In this game of Phantom against MO-ISMCTS it won in four moves (full conversation).

Trying it with a real client uncovered two bugs the tests had missed. The model had no way to read the rules, which were published as an MCP resource rather than a tool, so I added get_rules. And at the end of some Phantom games the server described the last move wrongly; a test now reproduces that ending.

How much does search help a small model?

One game is an anecdote. To measure it, I wrote an agent that acts as the MCP client and lets Llama 3.2 3B play unattended, served locally with Ollama on my laptop’s 4 GB GPU. Four players compete in each game: Llama alone, Llama with analyze_position, the search alone as the ceiling and random moves as the floor. 960 games in total.

Results of 960 games, by game and playerOn its own, Llama 3.2 3B loses 100% of its games of tic-tac-toe and Ultimate. With the search tool its tic-tac-toe losses fall to 31%, but in Ultimate it wins no games, while the search alone wins 33 of 40. In Phantom it wins 57% and loses 42% alone; with search it wins 45% and loses 27%.Tic-tac-toe, against MCTSLlama alone Llama alone: 100% losses (100 of 100) Llama + search Llama + search: 3% wins (3 of 100) Llama + search: 66% draws (66 of 100) Llama + search: 31% losses (31 of 100) Search alone Search alone: 100% draws (100 of 100) Random Random: 8% draws (8 of 100) Random: 92% losses (92 of 100) Ultimate, against MCTSLlama alone Llama alone: 100% losses (40 of 40) Llama + search Llama + search: 8% draws (3 of 40) Llama + search: 93% losses (37 of 40) Search alone Search alone: 83% wins (33 of 40) Search alone: 8% draws (3 of 40) Search alone: 10% losses (4 of 40) Random Random: 100% losses (40 of 40) Phantom, against MO-ISMCTSLlama alone Llama alone: 57% wins (57 of 100) Llama alone: 1% draws (1 of 100) Llama alone: 42% losses (42 of 100) Llama + search Llama + search: 45% wins (45 of 100) Llama + search: 28% draws (28 of 100) Llama + search: 27% losses (27 of 100) Search alone Search alone: 48% wins (48 of 100) Search alone: 32% draws (32 of 100) Search alone: 20% losses (20 of 100) Random Random: 1% wins (1 of 100) Random: 25% draws (25 of 100) Random: 74% losses (74 of 100)
Results of 960 games, by game and player. 100 games per player in tic-tac-toe and Phantom, and 40 in Ultimate. Data: the repository’s benchmark.
View the data
GamePlayerGamesWinsDrawsLosses
Tic-tac-toeLlama alone1000%0%100%
Tic-tac-toeLlama + search1003%66%31%
Tic-tac-toeSearch alone1000%100%0%
Tic-tac-toeRandom1000%8%92%
UltimateLlama alone400%0%100%
UltimateLlama + search400%8%93%
UltimateSearch alone4083%8%10%
UltimateRandom400%0%100%
PhantomLlama alone10057%1%42%
PhantomLlama + search10045%28%27%
PhantomSearch alone10048%32%20%
PhantomRandom1001%25%74%
  • On its own, the model plays the perfect-information games no better than chance. It loses all 100 games of tic-tac-toe and all 40 of Ultimate. It almost never tries an illegal move: the problem is choosing, not following the rules.
  • In tic-tac-toe, search cuts its losses from 100% to 31%. It analysed before every move but played the recommended one only 80% of the time. In the 34 games where it followed every recommendation it drew all 34; all 31 losses came from games where it overrode the search.
  • In Ultimate it does not improve: it wins no games and loses 37 of 40, while the search alone wins 33 of 40. It analysed before 67% of its moves and followed the analysis 60% of the time when it did, but never for a whole game.
  • Phantom is different. On its own it already wins 57% of its games, though it loses 42%. With search it loses 27%, close to the 20% of the search alone.

The takeaway: the tool helps a small model as much as the model trusts it. The method, the numbers with confidence intervals and the code to repeat it are in the repository’s benchmark.

What I learned

  • A local model is infrastructure too. Qwen3 4B kept reasoning even with reasoning turned off and took 16 minutes for one game of tic-tac-toe, so I switched to Llama 3.2 3B. Llama sometimes fell into a loop of text (one reply ran to 42,000 tokens), so I capped each reply at 512 tokens; and when Ollama briefly lost the connection to its own process, I added retries. Because results are saved game by game, every interruption resumed where it had stopped.
  • Measure what explains the result, not just the result. The win rate said the tool did little in Ultimate. Recording whether the model followed the recommendation explained why.
  • Design the tools for the model. Errors the model can fix, like an illegal move, come back as readable errors listing the legal moves. And only the protocol travels over standard output: pyplAI 1.1 added analiza() to return the search statistics as data instead of printing them.