Skip to content

docs: lead the README client example with a URL, not the server object - #3315

Merged
maxisbey merged 3 commits into
mainfrom
docs/readme-client-url-wording
Aug 16, 2026
Merged

docs: lead the README client example with a URL, not the server object#3315
maxisbey merged 3 commits into
mainfrom
docs/readme-client-url-wording

Conversation

@maxisbey

@maxisbey maxisbey commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Reworks the README's "A client in 10 lines" so the first client a reader sees connects the way a real program does: serve the server.py from the section above with uv run mcp run server.py --transport streamable-http, then Client("http://localhost:8000/mcp"). The closing sentence mentions stdio and custom transports and links to the Clients docs; in-memory is left to the Testing page.

Also fixes the mcp run --transport help text, which still said "stdio or sse" even though streamable-http is accepted (and is what the README now tells you to run).

Motivation and Context

Started as #3313 (calling a localhost URL a "remote server" read oddly). Looking at it more closely, the bigger problem was that the example imported the server object and connected in-process, then offered the URL as the variation. In-process is a testing convenience, not how anyone connects to a real server, so the landing example shouldn't lead with it.

Closes #3313

How Has This Been Tested?

Ran the README verbatim: extracted the server block, the mcp run ... --transport streamable-http line and the client block into a scratch directory, started the server with that exact command (listens on 127.0.0.1:8000/mcp), ran the client, got {'result': 3}. Also checked localhost vs 127.0.0.1, a second run against the same server, and that mcp run --help shows the new text. pre-commit run --files README.md src/mcp/cli/cli.py passes.

Breaking Changes

None.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

The docs site has the same lean in more places (the Clients section leads with in-memory, several "what Client accepts" lists put the server object first). That's a broader docs pass and is deliberately not in this PR.

AI Disclaimer

The sentence pointed at a localhost URL and called it a "remote server",
which reads oddly since nothing earlier in the README starts a server on
that port. Present the URL as an example and describe what actually
changes: the same client code talks to a server over HTTP.

Closes #3313

No-Verification-Needed: doc-only wording change in README.md
The "client in 10 lines" example imported the server object and connected
to it in-process, then offered a URL as the variation. In-process is a
testing technique, so this inverts it: serve the file you just wrote with
`mcp run server.py --transport streamable-http`, connect to it by URL, and
mention stdio and the in-memory test path in the closing sentence.

Also fix the `mcp run --transport` help text, which still said "stdio or
sse" although streamable-http is accepted and is what the README now uses.

Closes #3313
@maxisbey maxisbey changed the title docs: clarify client URL example wording in README docs: lead the README client example with a URL, not the server object Aug 16, 2026
@maxisbey
maxisbey marked this pull request as ready for review August 16, 2026 13:22
No-Verification-Needed: doc-only wording change in README.md
@maxisbey
maxisbey merged commit fc41dd5 into main Aug 16, 2026
32 checks passed
@maxisbey
maxisbey deleted the docs/readme-client-url-wording branch August 16, 2026 13:27

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional findings (outside current diff — PR may have been updated during review):

  • 🟡 src/mcp/cli/cli.py — [quality] pre-existing: mcp run --help still shows a stale docstring claiming a "Module approach: server.py - runs the module directly, expecting a server.run() call" that does not exist, right next to the option help this PR fixes for the same staleness

    Extended reasoning...

    The PR's stated goal is making mcp run --help accurate (it fixes the --transport line at src/mcp/cli/cli.py:314), but the command docstring shown in the same help output (lines 318-327) still misdescribes behavior: with server.py and no :object, run() never "runs the module directly, expecting a server.run() call" — it always imports the file, searches for a module-level mcp/server/app, and calls server.run(**kwargs) itself (lines 328-348). docs/run/index.md:113-122 documents the opposite of the docstring: "mcp run imports the file ... and calls run() on it ... Your if __name__ == \"__main__\": block never executes here". Concrete cost: users following the new README command who check mcp run --help read a description of a code path that does not exist, the same class of stale-help defect this PR was opened to fix; a user who writes a server.py that only calls run() inside main() gets "No server object found" despite the help saying their file shape is supported.

    Verification: nit (pre-existing docstring, but the diff edits the same help output). The claim is factually true. The run() docstring shown in mcp run --help (src/mcp/cli/cli.py:320-322) still says: "1. Module approach: server.py - runs the module directly, expecting a server.run() call." No such mode exists. Both file_spec forms take the identical path: src/mcp/cli/cli.py:328 `file, server_object = _pars

Comment thread README.md
Comment on lines 97 to 110
```python
import asyncio

from mcp import Client

from server import mcp


async def main() -> None:
async with Client(mcp) as client:
async with Client("http://localhost:8000/mcp") as client:
result = await client.call_tool("add", {"a": 1, "b": 2})
print(result.structured_content) # {'result': 3}


asyncio.run(main())
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [quality] nit: the rewritten README client example is an inline, untracked code block instead of using the repo's snippet-source mechanism (a docs_src/ module wrapped in <!-- snippet-source ... --> markers), which the server block directly above (lines 53-73, sourcing docs_src/index/tutorial001.py) already uses and which the pre-commit hook scripts/update_readme_snippets.py --check enforces; near-identical client code already lives in docs_src/client_transports/tutorial002.py.

Extended reasoning...

Concrete cost: the landing-page client example is the only code block in the README exempt from the repo's drift-prevention tooling — it is neither synced by the 'Check README snippets are up to date' pre-commit hook nor executed by the tests/docs_src suite that runs docs_src tutorial modules. When Client's constructor, call_tool signature, or structured_content shape next changes, the server block above will be caught and updated automatically while this rewritten client block silently goes stale, breaking the first client a reader copies. Fix at the right depth: add e.g. docs_src/index/tutorial002.py (mirroring docs_src/client_transports/tutorial002.py) with a matching tests/docs_src test and wrap the block in snippet-source markers. Note the inline pattern predates this PR (the old block was also inline), but this PR rewrites the block wholesale, so adopting the existing mechanism was the natural moment.

Verification: nit — README.md:97-110's rewritten client example is an inline code block with no <!-- snippet-source --> markers, while the server block directly above (README.md:53, <!-- snippet-source docs_src/index/tutorial001.py -->) uses the repo's snippet mechanism enforced by the pre-commit hook at .pre-commit-config.yaml:57-62 (readme-snippets, scripts/update_readme_snippets.py --check); the scri

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v2] Clarify "remote" wording in README client example

1 participant