You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: make the first-steps capabilities check a real client too
The reader's first Client in the docs was still an inline Client(mcp)
against the imported server object. Serve server.py over HTTP and connect
by URL from a docs_src client file instead, like the rest of the docs now
do, and move the in-memory mention into the pointer to Testing.
Copy file name to clipboardExpand all lines: docs/get-started/first-steps.md
+16-18Lines changed: 16 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,7 +12,7 @@ Three words you'll see on every page from here on:
12
12
* A **client** lives inside the host and speaks MCP. The host runs one client per server it's connected to.
13
13
* A **server** is what you build with this SDK. It exposes things to clients. It never talks to the model directly.
14
14
15
-
You write the server. Hosts are someone else's product. The SDK also gives you a `Client`, the same class a host would use to reach a server by URL or launch it as a subprocess. On this page you'll use it in memory to inspect the server you just wrote, which is also how you'll test it.
15
+
You write the server. Hosts are someone else's product. The SDK also gives you a `Client`, the same class a host would use to reach a server by URL or launch it as a subprocess. It shows up later on this page, and it is also how you'll test your servers.
16
16
17
17
## The three primitives
18
18
@@ -78,22 +78,20 @@ You saw three tabs in the Inspector. How did it know there were three?
78
78
79
79
When a client connects, the server declares its **capabilities**: which families of requests it will answer. The client uses that declaration to decide what to even ask for. You never wrote it; `MCPServer` declares it for you.
80
80
81
-
Look at it yourself. For a quick check like this, `Client` accepts the server object directly and connects to it **in memory** (no subprocess, no port):
82
-
83
-
```python
84
-
import asyncio
85
-
86
-
from mcp import Client
87
-
88
-
from server import mcp
81
+
Look at it yourself. Leave `server.py` running over HTTP in one terminal:
89
82
83
+
```console
84
+
uv run mcp run server.py --transport streamable-http
@@ -113,9 +111,9 @@ That dictionary is your server's declared **capabilities**. It's the first thing
113
111
Notice what isn't there. `completions` (argument autocomplete for resource templates and prompts) needs a handler you write, this server doesn't have one, so the capability is absent and a well-behaved client won't ask. That's the rule for everything optional: register the thing and the capability appears; **[Completions](../servers/completions.md)** proves it.
114
112
115
113
!!! info
116
-
`Client(mcp)` is how you'll test your servers, and it gets a whole page: **[Testing](testing.md)**.
117
-
To connect to a server that is actually running, you hand `Client`a URL or a
That `client.py` is a complete MCP client, and **[The Client](../client/index.md)** is its page.
115
+
In a test you skip the terminal and the port and hand `Client`the server object itself,
116
+
`Client(mcp)`. That gets a whole page too: **[Testing](testing.md)**.
119
117
120
118
## What you did not write
121
119
@@ -124,7 +122,7 @@ Look back over this page. You wrote three small Python functions. You did **not*
124
122
* A JSON Schema. `a: int, b: int`*is* the schema for `add`.
125
123
* A request handler. `tools/list`, `resources/read`, `prompts/get`: all served for you.
126
124
* A capability declaration. `MCPServer` made it for you.
127
-
* A line of protocol. The version negotiation, the JSON-RPC framing, the capability exchange: all of it happened inside `mcp dev` and `Client(mcp)`, and you never saw it.
125
+
* A line of protocol. The version negotiation, the JSON-RPC framing, the capability exchange: all of it happened inside `mcp dev` and `client.py`, and you never saw it.
128
126
129
127
That ratio is the whole point of the SDK.
130
128
@@ -135,6 +133,6 @@ That ratio is the whole point of the SDK.
135
133
* One decorator per primitive: `@mcp.tool()`, `@mcp.resource(uri)`, `@mcp.prompt()`. Name, description, and schema come from the function.
136
134
* A URI with a `{param}` makes a resource **template**, listed separately from concrete resources.
137
135
* The server's **capabilities** are declared for you, and a client only asks for what a server declares.
138
-
*`Client(mcp)`connects to the server object in memory: your test harness from day one.
136
+
*`Client("http://localhost:8000/mcp")`talks to your running server. Hand it the server object instead, `Client(mcp)`, and it is your test harness from day one.
139
137
140
138
Next up is **[Connect to a real host](real-host.md)**: this server inside Claude Desktop or an IDE, for real. Then **[Testing](testing.md)**: one page, one in-memory client, and you're never guessing whether it works. After that, each primitive gets its own page, starting with the one the model drives: **[Tools](../servers/tools.md)**.
0 commit comments