Skip to content

Commit ff6ca44

Browse files
authored
[FA-20} Adding direct execution and documentation (#11)
* feat: adding direct execution and documentation * docs: adding image of inspector * docs: fiixng path to iamge * docs: fixing formatting of block quote * chore: fixing pre-commit issues * docs: updating readme to include direct execution docs
1 parent d42890e commit ff6ca44

File tree

5 files changed

+144
-9
lines changed

5 files changed

+144
-9
lines changed

README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,12 @@ cd agent_uno
3434
uv run mcp install server.py
3535
```
3636

37+
> [!TIP]
38+
> The above command updates the MCP config in Claude desktop. Whilst Claude Desktop only supports `stdio` transport the server can be directly executed with communication via `sse` transport and HTTP requests. For documentation on how to do this see [direct_execution.md](docs/direct_execution.md).
39+
3740
> [!NOTE]
3841
> If you have Claude Desktop open when you run the above command, you will need to restart it for the server to be available.
3942
40-
> [!WARNING]
41-
> Common Issues:
42-
> 1. `ENOENT` error when opening Claude Desktop.
43-
> - This is due to Claude Desktop facing issues with running the server with a relative path to `uv`. To fix this, you need to change the `command` in the `claude_desktop_config.json` config to an absolute path. You can find the absolute path by running `which uv` in your terminal.
44-
> 2. Not having `coreutils` installed.
45-
> - This is required for the `realpath` command. You will see the following error in Claude logs: `realpath: command not found`. You can install it using `brew install coreutils`.
46-
4743
2. Interact with MCP server with Claude Desktop.
4844

4945
:chess_pawn: Agent vs. Stockfish Bot :robot::
@@ -59,3 +55,10 @@ uv run mcp install server.py
5955
2. Once the game has been created and the opponent has connected and made their first move, the agent will make their move.
6056

6157
> Once the game has been created the opponent will make the first move. Can you use the previous moves and the layout of the board to determine what an optimal next move will be and then make your own move playing continuously back and forth until completion? Please use the UCI chess standard for your moves, e.g., e2e4.
58+
59+
> [!WARNING]
60+
> Common Issues:
61+
> 1. `ENOENT` error when opening Claude Desktop.
62+
> - This is due to Claude Desktop facing issues with running the server with a relative path to `uv`. To fix this, you need to change the `command` in the `claude_desktop_config.json` config to an absolute path. You can find the absolute path by running `which uv` in your terminal.
63+
> 2. Not having `coreutils` installed.
64+
> - This is required for the `realpath` command. You will see the following error in Claude logs: `realpath: command not found`. You can install it using `brew install coreutils`.

agent_uno/server.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,17 @@ async def get_board() -> str:
172172
return cast(str, board.__str__())
173173

174174

175-
@mcp.tool(description="Get the current board as an ASCII representation.") # type: ignore
175+
@mcp.tool(
176+
description="""Get the current board as an ASCII representation and all previous
177+
moves."""
178+
) # type: ignore
176179
async def get_board_representation() -> BoardRepresentation | GameStateMsg:
177180
"""An endpoint for getting the current board as an ASCII representation."""
178181
board = await get_board()
179182
previous_moves = await get_previous_moves()
180183

181184
return BoardRepresentation(board=board, previous_moves=previous_moves)
185+
186+
187+
if __name__ == "__main__":
188+
mcp.run()

docs/direct_execution.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Direct Execution
2+
3+
## Inspector Tool
4+
5+
Currently testing of endpoints can be performed with the following command:
6+
7+
```bash
8+
uv run mcp dev server.py
9+
```
10+
11+
This will start a local server running `Inspector` than can be used to interact with the MCP tools.
12+
13+
![inspector](imgs/inspector.png)
14+
15+
## Under the hood
16+
17+
You can run the server directly with the following command:
18+
19+
```bash
20+
uv run mcp run server.py --transport sse
21+
```
22+
23+
> [!NOTE]
24+
> This will start a local MCP server on port `8000`.
25+
26+
Setting `sse` allows us to communicate with the server via HTTP using the `Server-Sent Events` protocol. This is a one-way communication channel from the server to the client. The client can send messages to the server using the `POST` method, but the server can only send messages to the client using the `GET` method.
27+
28+
We can establish an MCP client by making a request to the `sse` endpoint of the server:
29+
30+
```bash
31+
curl http://0.0.0.0:8000/sse
32+
```
33+
34+
This will return an output of the form:
35+
36+
```
37+
event: endpoint
38+
data: /messages/?session_id=<session_id>
39+
```
40+
41+
and then ping incrementally.
42+
43+
As per the MCP docmentation, a client-server lifecycle consists of three stages: connection, exchange, and termination.
44+
45+
> The lifecycle of an MCP connection involves three main stages:
46+
>
47+
> Initialization:
48+
>
49+
> * The client sends an initialize request, including its protocol version and capabilities.
50+
> * The server responds with its protocol version and capabilities.
51+
> * The client sends an initialized notification to acknowledge.
52+
> * Normal message exchange begins.
53+
>
54+
> Message Exchange: After initialization, clients and servers can exchange messages using these patterns:
55+
>
56+
> * Request-Response: The client sends a request, and the server responds.
57+
> * Notifications: Either side sends one-way messages (no response expected).
58+
>
59+
> Termination: The connection can be terminated in several ways:
60+
>
61+
> * Clean shutdown via a close() method.
62+
> * Transport disconnection.
63+
> * Error conditions.
64+
65+
### Initialisation Requests
66+
67+
1. Send an initialisation request.
68+
69+
```bash
70+
curl "http://0.0.0.0:8000/messages/?session_id=<session_id>" \
71+
-X POST \
72+
-H "Content-Type: application/json" \
73+
-d '{
74+
"method": "initialize",
75+
"params": {
76+
"protocolVersion": "2024-11-05",
77+
"capabilities": {
78+
"sampling": {},
79+
"roots": {
80+
"listChanged":true
81+
}
82+
},
83+
"clientInfo": {
84+
"name": "mcp-inspector",
85+
"version": "0.8.0"
86+
}
87+
},
88+
"jsonrpc":"2.0",
89+
"id":0
90+
}
91+
}'
92+
```
93+
94+
2. Send an initialisation notification.
95+
96+
```bash
97+
curl "http://0.0.0.0:8000/messages/?session_id=<session_id>" \
98+
-X POST \
99+
-H "Content-Type: application/json" \
100+
-d '{
101+
"method": "notifications/initialized",
102+
"jsonrpc": "2.0"
103+
}'
104+
```
105+
106+
Now the server and client are initialised and ready to exchange messages.
107+
108+
### Message Exchange
109+
110+
1. We can now start to interact with the server. Typically, the client might start by listing the tools.
111+
112+
```bash
113+
curl "http://0.0.0.0:8000/messages/?session_id=<session_id>" \
114+
-X POST \
115+
-H "Content-Type: application/json" \
116+
-d '{
117+
"method": "tools/list",
118+
"params": {},
119+
"jsonrpc": "2.0",
120+
"id": 1
121+
}'
122+
```

docs/imgs/inspector.png

111 KB
Loading

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies = [
1010
"mcp[cli]>=1.6.0",
1111
"pydantic>=2.11.1",
1212
"python-chess>=1.999",
13-
"python-dotenv (>=1.1.0,<2.0.0)"
13+
"python-dotenv (>=1.1.0,<2.0.0)",
1414
]
1515

1616
[dependency-groups]
@@ -99,6 +99,9 @@ extend-exclude = [".gitignore", "LICENSE", ".*"]
9999
[tool.typos.default.extend-words]
100100
center = "center"
101101
color = "color"
102+
initialization = "initialization"
103+
initialize = "initialize"
104+
initialized = "initialized"
102105

103106
[tool.typos.default]
104107
locale = "en-gb"

0 commit comments

Comments
 (0)