docs: refresh translations, and translate pages in parallel (#3458)
This commit is contained in:
parent
08a3bc8eaf
commit
fd66270926
6 changed files with 4821 additions and 2277 deletions
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [9e7b9a1710e5aeba, b74ca4c1d2ddddee, fa8714e61bf90c5a, 04db67a886b7271c, 857690fb8f876800]
|
||||
sections: [9e7b9a1710e5aeba, 66a2e9acc9101d54, d3d25aa802f5145a, 04db67a886b7271c, 857690fb8f876800]
|
||||
tool: 1
|
||||
---
|
||||
# Caching hints {#caching-hints}
|
||||
|
|
@ -30,7 +30,7 @@ server खुद कुछ भी cache नहीं करता। ये fiel
|
|||
|
||||
low-level `Server` पर handlers अपने results खुद बनाते हैं, और `ttl_ms` / `cache_scope` result models पर बस fields हैं। जो handler इन्हें explicitly set करता है, वह constructor map पर हमेशा भारी पड़ता है, field दर field:
|
||||
|
||||
```python title="server.py" hl_lines="10 16"
|
||||
```python title="server.py" hl_lines="11 17"
|
||||
--8<-- "docs_src/caching/tutorial002.py"
|
||||
```
|
||||
|
||||
|
|
@ -44,10 +44,24 @@ paginated lists पर एक सावधानी: protocol की माँ
|
|||
|
||||
2026-07-28 session पर `Client` आपके लिए hints का पालन करता है: इसमें built-in response cache है, जो default रूप से चालू रहता है। जो result `ttlMs` के साथ आता है, वह store हो जाता है, और उस TTL के भीतर वैसा ही call cache से serve होता है, बिना round trip के। जिस result में **कोई** hint नहीं होता, वह cache नहीं होता: बिना hint वाले results को `CacheConfig.default_ttl_ms` मिलता है, जिसका default `0` है (तुरंत stale), इसलिए जो server कुछ भी declare नहीं करता, उसे ठीक वैसा ही call-दर-call traffic दिखता है जैसा हमेशा दिखता था।
|
||||
|
||||
```python title="client.py" hl_lines="33 35 38"
|
||||
इसे होते हुए देखने के लिए, पिछले section की `server.py` को uvicorn से serve करें (उसकी आखिरी line ASGI app बनाती है)। handler जब भी सच में चलता है, एक line print करता है:
|
||||
|
||||
```console
|
||||
uvicorn server:app --port 8000
|
||||
```
|
||||
|
||||
```python title="client.py" hl_lines="20 23 28"
|
||||
--8<-- "docs_src/caching/tutorial003.py"
|
||||
```
|
||||
|
||||
दूसरे terminal से `python client.py` चलाएँ। यह वे hints print करता है जो पहले result में आए थे, handler का `ttlMs` और उसके बगल में map का `cacheScope`:
|
||||
|
||||
```text
|
||||
1000 public
|
||||
```
|
||||
|
||||
बाकी कहानी server का terminal बताता है: uvicorn के request logs के बीच `tools/list served` तीन बार दिखता है।
|
||||
|
||||
चार calls, तीन fetches। दूसरे call को fresh entry मिली और वह server तक पहुँचा ही नहीं; (inject की गई) clock को TTL से आगे बढ़ाने पर तीसरे ने फिर से fetch किया; चौथे ने `cache_mode="refresh"` कहा। यह kwarg पाँचों caching verbs पर मौजूद है (`list_tools`, `list_prompts`, `list_resources`, `list_resource_templates`, `read_resource`):
|
||||
|
||||
* `"use"` (default) fresh entry हो तो उसे serve करता है, और न हो तो fetch करके store करता है।
|
||||
|
|
@ -56,7 +70,7 @@ paginated lists पर एक सावधानी: protocol की माँ
|
|||
|
||||
एक नियम `"use"` से ऊपर है: **`meta` वाले calls हमेशा server तक पहुँचते हैं।** जिस request में `meta` set हो (progress token, tracing fields), उसे wire request की उम्मीद होती है, इसलिए `cache_mode="use"` में उसे `"refresh"` माना जाता है: cache read छोड़ दिया जाता है, और fetch किया गया result फिर भी cache की entry की जगह ले लेता है। `"bypass"` और explicit `"refresh"` हमेशा की तरह ही बर्ताव करते हैं।
|
||||
|
||||
caching पूरी तरह बंद करने के लिए `Client(server, cache=None)` से construct करें: हर call फिर से round trip है, और `cache_mode`, भले ही अब भी स्वीकार होता है, कुछ नहीं करता।
|
||||
caching पूरी तरह बंद करने के लिए `Client` construct करते समय `cache=None` pass करें: हर call फिर से round trip है, और `cache_mode`, भले ही अब भी स्वीकार होता है, कुछ नहीं करता।
|
||||
|
||||
scope का पालन भी अपने आप होता है: `"private"` entries cache के *partition* (नीचे देखें) से बँधी होती हैं, जबकि `"public"` वाली चाहें तो ज़्यादा व्यापक sharing चुन सकती हैं। और जिन entries का नाम notifications लेते हैं, ठीक उनके लिए **notifications TTL पर भारी पड़ते हैं**: `list_changed` notification मेल खाती cached listing को evict कर देता है, और `resources/updated` ठीक उसी URI के तहत store किए गए cached read को evict करता है, चाहे वे कितने भी fresh रहे हों। 2026-07-28 connection पर ये notifications `subscriptions/listen` stream पर आते हैं जिसे आप `client.listen(...)` से खोलते हैं, और eviction आपके watcher को event दिखने से पहले पूरा हो जाता है; **[Subscriptions](subscriptions.md)** वही page है।
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [adf3c545b5be46b6, 916cd3ab1c03f461, e9be7a8d0eb0a456, 565890a636288ecf, 6af7e49db9129ec3, 06b0238c174186af, 90c6043be435fcb0]
|
||||
sections: [adf3c545b5be46b6, 916cd3ab1c03f461, 32ef568335dd95a7, 565890a636288ecf, 6af7e49db9129ec3, 06b0238c174186af, 0abc5ea5cb7ff6b3]
|
||||
tool: 1
|
||||
---
|
||||
# Client callbacks {#client-callbacks}
|
||||
|
|
@ -63,7 +63,7 @@ result.content # [TextContent(type='text', text='Card issued to Ada Lovelace.')
|
|||
`Client(...)` call पर `mode="legacy"` असल में काम कर रहा है। default रूप से `Client(...)` modern
|
||||
protocol path negotiate करता है, और उस path में server-से-client requests के लिए कोई back-channel नहीं है:
|
||||
आपका callback चलने से पहले ही `ctx.elicit` fail हो जाता है। यह transport तय नहीं करता; negotiated
|
||||
protocol तय करता है, in-memory में भी और URL पर भी। जब भी आपके client को ऐसी किसी request का जवाब देना हो,
|
||||
protocol तय करता है। जब भी आपके client को ऐसी किसी request का जवाब देना हो,
|
||||
`mode="legacy"` तय करें; इस page के पीछे का हर test यही करता है। पूरी जानकारी **[Protocol versions](../protocol-versions.md)** में है।
|
||||
|
||||
2026-07-28 session पर callback बेकार नहीं होता, उसे input अलग तरीके से मिलता है: जब कोई tool
|
||||
|
|
@ -149,6 +149,6 @@ result.structured_content # {'result': ['elicitation']}
|
|||
* **callback register करना ही capability घोषित करना है।** इसके बिना SDK आपकी ओर से server की request ठुकरा देता है और पूरा call `MCPError` के साथ fail हो जाता है।
|
||||
* server पूछने से पहले `ctx.session.check_client_capability(...)` से पता कर लेता है।
|
||||
* `sampling_callback` और `list_roots_callback` इसी तरह काम करते हैं लेकिन deprecated features को serve करते हैं; modern servers इनकी जगह multi-round-trip requests इस्तेमाल करते हैं।
|
||||
* `logging_callback` और `message_handler` को notifications मिलती हैं। वे कुछ घोषित नहीं करते।
|
||||
* `logging_callback` और `message_handler` को notifications मिलते हैं। वे कुछ घोषित नहीं करते।
|
||||
|
||||
`Client(...)` का पहला argument transport object है। हर प्रकार की जानकारी **[Client transports](transports.md)** में है।
|
||||
`Client(...)` का पहला argument transport चुनता है। हर प्रकार की जानकारी **[Client transports](transports.md)** में है।
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [ebef1e7a0df854f4, 8355cfaf1f76c9d5, 8e79141fc2985342, 46bdb07c7537e8a5, 80ce41579825a6fa, 5f0fa90494de8f65, 83d10514eaa62fa5, 9190555aa39a5d28, 84a4c9d8bf14dddb, 927d71cf40b58c30]
|
||||
sections: [ebef1e7a0df854f4, 7e16449f66e7dfd6, eeb0682f7d2a1079, 5713f0196a34e6e7, 0e844597859e4248, 3a97d9195ddcc92e, 1da08c483e59c141, 84702cc6e0a1fd42, 8dee7a31c86ffc5c, 83a5bce168ef23d7]
|
||||
tool: 1
|
||||
---
|
||||
# Client {#the-client}
|
||||
|
|
@ -11,13 +11,23 @@ translation:
|
|||
|
||||
## आपका पहला client {#your-first-client}
|
||||
|
||||
```python title="client.py" hl_lines="14-18"
|
||||
client को बात करने के लिए server चाहिए। इस page का हर उदाहरण इसी Bookshop से connect करता है। इसे `server.py` के नाम से save करें और HTTP पर चलता छोड़ दें:
|
||||
|
||||
```python title="server.py"
|
||||
--8<-- "docs_src/client/tutorial001.py"
|
||||
```
|
||||
|
||||
ऊपर वाला server सिर्फ़ इसलिए है ताकि connect करने के लिए कुछ हो। client वे पाँच highlighted lines हैं।
|
||||
```console
|
||||
uv run mcp run server.py --transport streamable-http
|
||||
```
|
||||
|
||||
* `Client(mcp)` को **server object ही** दिया गया है। यही in-memory transport है: न subprocess, न port, न HTTP। इस page का हर उदाहरण, और आपका लिखा हर test, इसी तरह connect करता है।
|
||||
इससे server `http://localhost:8000/mcp` पर serve होता है। client अपना अलग program है। इसे `client.py` के नाम से save करें और दूसरे terminal में `python client.py` चलाएँ:
|
||||
|
||||
```python title="client.py" hl_lines="7-11"
|
||||
--8<-- "docs_src/client/tutorial001_client.py"
|
||||
```
|
||||
|
||||
* `Client("http://localhost:8000/mcp")` को **URL** दिया गया है, इसलिए यह अभी शुरू किए गए server से Streamable HTTP पर connect करता है।
|
||||
* `async with` ही **lifecycle** है। इसमें enter करते ही connect और negotiate होता है; बाहर निकलते ही disconnect। कोई `connect()` / `close()` जोड़ी नहीं है, और block खत्म होने के बाद `Client` दोबारा इस्तेमाल नहीं हो सकता।
|
||||
* block के अंदर connection की जानकारी पहले से सादी properties के रूप में मौजूद है।
|
||||
|
||||
|
|
@ -25,10 +35,10 @@ translation:
|
|||
|
||||
`Client` एक positional argument लेता है और उसके type से transport तय करता है:
|
||||
|
||||
* `MCPServer` (या low-level `Server`) instance: **in-process** connect होता है।
|
||||
* URL string (`Client("http://localhost:8000/mcp")`): Streamable HTTP, production वाला रास्ता।
|
||||
* `StdioServerParameters`: वह command जो **subprocess** के रूप में launch होता है, और जिससे उसके stdin और stdout के ज़रिए बात होती है।
|
||||
* URL string (`Client("http://localhost:8000/mcp")`): Streamable HTTP, वह transport जिसके पीछे आप deploy करते हैं।
|
||||
* `StdioServerParameters`: वह command जो local **subprocess** के रूप में launch होता है, और जिससे उसके stdin और stdout के ज़रिए बात होती है।
|
||||
* **transport**: कोई भी चीज़ जिसे आप `async with ... as (read, write)` कर सकें, जैसे आपके अपने HTTP client के ऊपर `streamable_http_client(url, http_client=...)`।
|
||||
* `MCPServer` (या low-level `Server`) instance: **in-process** connect होता है, न subprocess, न port। यह tests के लिए है, और **[Testing](../get-started/testing.md)** इसी पर आगे बढ़ता है।
|
||||
|
||||
इस page की बाकी हर चीज़ चारों में एक जैसी है। Headers, subprocesses, timeouts और `Transport` protocol का अपना अलग page है: **[Client transports](transports.md)**।
|
||||
|
||||
|
|
@ -49,11 +59,11 @@ translation:
|
|||
|
||||
## tools की सूची लेना {#listing-tools}
|
||||
|
||||
```python title="client.py" hl_lines="15-20"
|
||||
```python title="client.py" hl_lines="8-13"
|
||||
--8<-- "docs_src/client/tutorial002.py"
|
||||
```
|
||||
|
||||
`list_tools()` एक `ListToolsResult` लौटाता है; tools `.tools` में हैं। हर एक वह पूरी definition है जो host किसी model को देगा:
|
||||
`list_tools()` एक `ListToolsResult` लौटाता है; tools `.tools` में हैं। हर एक वह पूरी definition है जो host किसी model को देगा। यह पहला है:
|
||||
|
||||
```python
|
||||
tool.name # 'search_books'
|
||||
|
|
@ -77,6 +87,8 @@ tool.description # 'Search the catalog by title or author.'
|
|||
|
||||
UI को argument form दिखाने के लिए, और model को valid arguments बनाने के लिए, जो कुछ चाहिए वह सब इसी schema में है।
|
||||
|
||||
दूसरा tool, `lookup_book`, बिना `title=` के register हुआ था, इसलिए उसका `tool.title` `None` है।
|
||||
|
||||
!!! tip
|
||||
`title` optional है, इसलिए किसी इंसान को tools दिखाने वाले UI को चुनना पड़ता है: `title` हो तो वही,
|
||||
नहीं तो `name`। `from mcp.shared.metadata_utils import get_display_name` ठीक यही करता है,
|
||||
|
|
@ -86,7 +98,7 @@ UI को argument form दिखाने के लिए, और model को
|
|||
|
||||
`call_tool(name, arguments)` tool चलाता है और आपको `CallToolResult` वापस देता है।
|
||||
|
||||
```python title="client.py" hl_lines="27-34"
|
||||
```python title="client.py" hl_lines="9-16"
|
||||
--8<-- "docs_src/client/tutorial003.py"
|
||||
```
|
||||
|
||||
|
|
@ -142,7 +154,7 @@ result.is_error # False
|
|||
|
||||
resource verbs जोड़ियों में आते हैं: सूची लेने के दो तरीके, पढ़ने का एक।
|
||||
|
||||
```python title="client.py" hl_lines="22-31"
|
||||
```python title="client.py" hl_lines="9-18"
|
||||
--8<-- "docs_src/client/tutorial004.py"
|
||||
```
|
||||
|
||||
|
|
@ -156,7 +168,7 @@ client को यह भी बताया जा सकता है कि
|
|||
|
||||
## Prompts {#prompts}
|
||||
|
||||
```python title="client.py" hl_lines="15-20"
|
||||
```python title="client.py" hl_lines="8-13"
|
||||
--8<-- "docs_src/client/tutorial005.py"
|
||||
```
|
||||
|
||||
|
|
@ -181,7 +193,7 @@ host ये messages सीधे model को दे देता है। प
|
|||
|
||||
जिस server में completion handler हो वह user के type करते-करते prompt और resource-template arguments autocomplete कर सकता है।
|
||||
|
||||
```python title="client.py" hl_lines="27-31"
|
||||
```python title="client.py" hl_lines="9-13"
|
||||
--8<-- "docs_src/client/tutorial006.py"
|
||||
```
|
||||
|
||||
|
|
@ -194,21 +206,21 @@ host ये messages सीधे model को दे देता है। प
|
|||
|
||||
हर `list_*` method एक `cursor=` keyword लेता है और हर result में `next_cursor` होता है। जब `next_cursor` `None` हो, आपके पास सब कुछ है।
|
||||
|
||||
```python title="client.py" hl_lines="22-30"
|
||||
```python title="client.py" hl_lines="7-15"
|
||||
--8<-- "docs_src/client/tutorial007.py"
|
||||
```
|
||||
|
||||
यह loop हर server के साथ सही है। `MCPServer` सब कुछ एक ही page में लौटाता है, इसलिए `next_cursor` `None` होता है और loop एक बार चलता है, यही वजह है कि ज़्यादातर code इसे कभी लिखता ही नहीं। जो servers सच में page करते हैं, और cursors जिन नियमों का पालन करते हैं, वे **[Pagination](../advanced/pagination.md)** में हैं।
|
||||
`list_all_tools` हर server के साथ सही है। `MCPServer` सब कुछ एक ही page में लौटाता है, इसलिए `next_cursor` `None` होता है और loop एक बार चलता है, यही वजह है कि ज़्यादातर code इसे कभी लिखता ही नहीं। जो servers सच में page करते हैं, और cursors जिन नियमों का पालन करते हैं, वे **[Pagination](../advanced/pagination.md)** में हैं।
|
||||
|
||||
## tests में {#in-tests}
|
||||
|
||||
बिना process और बिना port वाला `Client(mcp)` अपने आप में server के लिए test harness है।
|
||||
इस page की हर `client.py` HTTP के ज़रिए `server.py` तक पहुँची। test में आप network छोड़ देते हैं और `Client` को server object ही दे देते हैं: `from server import mcp`, फिर `Client(mcp)`। न process, न port, और ऊपर का हर method वैसे ही काम करता है।
|
||||
|
||||
इसी के लिए एक constructor flag बना है: `Client(mcp, raise_exceptions=True)`। इसका असर सिर्फ़ in-memory connections पर होता है, और **[Testing](../get-started/testing.md)** वह page है जो इसे समझाता है और इसके चारों ओर पूरा pattern बनाता है।
|
||||
इसी के लिए एक constructor flag बना है: `Client(mcp, raise_exceptions=True)`। इसका असर सिर्फ़ in-process connections पर होता है, और **[Testing](../get-started/testing.md)** वह page है जो इसे समझाता है और इसके चारों ओर पूरा pattern बनाता है।
|
||||
|
||||
## सारांश {#recap}
|
||||
|
||||
* `Client(x)` server object से in-memory connect होता है, URL string से Streamable HTTP पर, और बाकी किसी भी चीज़ से transport के ज़रिए।
|
||||
* `Client(x)` URL string से Streamable HTTP पर connect होता है, `StdioServerParameters` के लिए subprocess launch करता है, transport में सीधे enter करता है, और tests में server object ही ले लेता है।
|
||||
* `async with` ही पूरा lifecycle है। इसके अंदर `server_capabilities` और `protocol_version` पहले से भरे होते हैं; server दे तो `server_info` और `instructions` भी।
|
||||
* `list_tools()` आपको हर tool का `name`, `title`, `description` और `input_schema` देता है।
|
||||
* `call_tool()` model के लिए `content`, आपके code के लिए `structured_content`, और `is_error` लौटाता है। raise करने वाला tool एक result है, exception नहीं।
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [c6899d3892bd9fa0, 79372cff3cc48a88, 63878d29e87c3e73, 13175843d3588af4, e7e2b9fd516f77de, 758f06399b513c1f, a05d7278487d610b]
|
||||
sections: [c6899d3892bd9fa0, 79372cff3cc48a88, c2dae1ebe2ebd543, 13175843d3588af4, df06056fb16b3846, 758f06399b513c1f, a05d7278487d610b]
|
||||
tool: 1
|
||||
---
|
||||
# OAuth clients {#oauth-clients}
|
||||
|
|
@ -81,18 +81,20 @@ authorization code flow को इंसान की ज़रूरत ठी
|
|||
|
||||
जब `Client` पहली बार request भेजता है, server `401` लौटाता है। provider कमान संभाल लेता है:
|
||||
|
||||
1. **Discovery.** यह `WWW-Authenticate` header पढ़ता है, `/.well-known/oauth-protected-resource` से server का Protected Resource Metadata लाता है, पता करता है कि कौन सा authorization server इस resource की रक्षा करता है, और **उस** server का metadata लाता है।
|
||||
1. **Discovery.** यह `WWW-Authenticate` header पढ़ता है, `/.well-known/oauth-protected-resource` से server का Protected Resource Metadata लाता है, पता करता है कि कौन सा authorization server इस resource की रक्षा करता है, और **उस** server का metadata लाता है। (कोई पुराना server जो resource metadata publish नहीं करता, उससे इसके बजाय उसके अपने origin पर authorization server metadata माँगा जाता है।) दोनों ही सूरतों में metadata को अपने `issuer` के रूप में उसी server का नाम देना होगा जिसके लिए उसे लाया गया था; इसके अलावा कुछ भी हो तो मना कर दिया जाता है।
|
||||
2. **Registration.** storage में कुछ नहीं है? यह आपके `OAuthClientMetadata` के साथ आपको dynamically register करता है और नतीजा store कर लेता है।
|
||||
3. **Authorization.** यह PKCE pair और `state` बनाता है, authorization URL तैयार करता है, आपके `redirect_handler` को await करता है, फिर code के लिए आपके `callback_handler` को await करता है।
|
||||
4. **Exchange.** यह code के बदले `OAuthToken` लेता है, उसे store करता है, और आपकी मूल request को `Authorization: Bearer ...` के साथ दोबारा भेजता है।
|
||||
|
||||
उसके बाद यह शांत रहता है। tokens storage से आते हैं, expire हुआ access token refresh token से refresh हो जाता है, और सिर्फ़ तब जब इनमें से कुछ काम नहीं करता, यह flow फिर से चलाता है।
|
||||
|
||||
इन सभी requests पर transport का एक नियम लागू होता है: जिस MCP request के अंदर ये चलती हैं उसी की तरह, ये किसी redirect को सिर्फ़ तभी follow करती हैं जब वह उसी origin पर रहे और method वही रखे (जैसे trailing-slash वाला 307/308), और किसी भी दूसरे redirect को ऐसे मानती हैं जैसे उस URL ने जवाब ही नहीं दिया।
|
||||
|
||||
आपने इसमें से कुछ नहीं लिखा। दो keyword arguments बचते हैं (`client_metadata_url` और `validate_resource_url`), और इस file को दोनों में से किसी की ज़रूरत नहीं। `client_metadata_url` जानने लायक है; इसका अपना section नीचे है।
|
||||
|
||||
### इसे आज़माएँ {#try-it}
|
||||
|
||||
इन docs के ज़्यादातर उदाहरण आप in-memory `Client(server)` से जाँच सकते हैं। यह नहीं: इस flow का पूरा मतलब ही HTTP `401` है, और in-memory client व उसके server के बीच कोई HTTP होता ही नहीं।
|
||||
in-memory `Client(server)`, जिसे आपके tests इस्तेमाल करते हैं, यहाँ किसी काम का नहीं: इस flow का पूरा मतलब ही HTTP `401` है, और in-memory client व उसके server के बीच कोई HTTP होता ही नहीं।
|
||||
|
||||
repository में live version मौजूद है। `examples/servers/simple-auth/` एक standalone authorization server और एक protected MCP server चलाता है; `examples/clients/simple-auth-client/` इसी page का client है, छोटी CLI में बढ़ा हुआ। उसकी README में दो commands हैं: servers शुरू करें, client को उनके सामने चलाएँ, और चारों चरण अपनी आँखों के सामने होते देखें।
|
||||
|
||||
|
|
@ -110,13 +112,14 @@ URL HTTPS होना चाहिए और उसका path root न हो;
|
|||
|
||||
`ClientCredentialsOAuthProvider` वही `httpx2.Auth` है, बस इंसान के बिना:
|
||||
|
||||
```python title="client.py" hl_lines="4 27-33"
|
||||
```python title="client.py" hl_lines="4 27-34"
|
||||
--8<-- "docs_src/oauth_clients/tutorial002.py"
|
||||
```
|
||||
|
||||
क्या बदला:
|
||||
|
||||
* न `OAuthClientMetadata`, न handlers। आप `client_id` और `client_secret` देते हैं; provider उनके इर्द-गिर्द एक न्यूनतम `client_credentials` registration बनाता है और dynamic registration पूरी तरह छोड़ देता है।
|
||||
* `issuer` उस authorization server का नाम बताता है जिसने वे credentials जारी किए; वही `issuer` value इस्तेमाल करें जो उसका `/.well-known/oauth-authorization-server` document लौटाता है। discovery अब भी ऊपर बताए तरीके से चलती है, लेकिन token requests हमेशा सिर्फ़ **उसी** issuer के metadata से बनती हैं; अगर MCP server कहीं और इशारा करता है, तो flow इसके बजाय `OAuthFlowError` के साथ रुक जाता है। इसे छोड़ देना deprecated है और 3.0 में यह ज़रूरी हो जाएगा (**[Deprecated features](../deprecated.md#deprecated-sdk-helpers)** देखें); तब तक provider warning देता है और discovery को जो भी authorization server मिलता है, उसे इस्तेमाल करता है।
|
||||
* `scope` space से अलग की गई string है, OAuth का wire format।
|
||||
* आगे का सब कुछ बिल्कुल वही है: वही `TokenStorage`, वही `httpx2.AsyncClient(auth=...)`, वही `streamable_http_client`।
|
||||
|
||||
|
|
@ -129,7 +132,7 @@ default रूप से secret token request पर HTTP Basic auth के र
|
|||
एक और provider `mcp.client.auth.extensions.client_credentials` में रहता है:
|
||||
**`PrivateKeyJWTOAuthProvider`**, उन clients के लिए जो shared secret के बजाय JWT से
|
||||
authenticate करते हैं (`private_key_jwt`, key-pair और workload-identity वाला रूप)। यह उसी
|
||||
pattern पर चलता है: एक बनाएँ, `auth=` पर लगाएँ। उसी module में
|
||||
pattern पर चलता है: एक बनाएँ (यह भी वही optional `issuer` लेता है), `auth=` पर लगाएँ। उसी module में
|
||||
`SignedJWTParameters` और `static_assertion_provider` भी हैं, दो helpers जो इसका assertion बनाते हैं।
|
||||
|
||||
बिना इंसान वाली एक और स्थिति है: client किसी enterprise का है जिसका identity provider, न कि user, तय करता है कि वह किन MCP servers तक पहुँच सकता है। वह अलग grant है, अपने trust model और अपने page के साथ, **[Identity assertion](identity-assertion.md)**।
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [09c857a25a9dc37a, 43bc6a76a243a50e, 0a716022a88768df, 4b7f78042bfcfff7, c112662e61b03315, 58974ba1f489a8b4, d18adbdbb835ea73]
|
||||
sections: [09c857a25a9dc37a, 43bc6a76a243a50e, 0a716022a88768df, 4b7f78042bfcfff7, c112662e61b03315, 58974ba1f489a8b4, ed4d17e894864056]
|
||||
tool: 1
|
||||
---
|
||||
# Session groups {#session-groups}
|
||||
|
|
@ -78,7 +78,7 @@ translation:
|
|||
## सारांश {#recap}
|
||||
|
||||
* `ClientSessionGroup` कई server connections रखता है और उनके tools, resources और prompts को एक-एक `dict` में मिला देता है।
|
||||
* हर server के लिए `connect_to_server(params)`। यह transport parameters लेता है, कभी वह server object या URL नहीं जो `Client` लेता है।
|
||||
* हर server के लिए `connect_to_server(params)`। यह transport parameters लेता है, कभी वह URL या `Transport` नहीं जो `Client` लेता है।
|
||||
* `group.call_tool(name, arguments)` आपके लिए call को उस server तक पहुँचाता है जिसका वह tool है।
|
||||
* नाम पूरे group में unique होने ज़रूरी हैं; `search` tool वाले दो servers अपने आप साथ नहीं रह सकते।
|
||||
* `component_name_hook=` हर register किए गए नाम को फिर से लिखता है। dict key बदलती है, wire पर जाने वाला नाम नहीं।
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
translation:
|
||||
sections: [9cac816674181eb0, 0700f337babcd4dd, 2bde0dd58cdf00f5, 40b4916d82eaf1d4, 3d0832f39b0d7059, dfa4446556badef0, 5bd93be2ab2ecb9c]
|
||||
sections: [9cac816674181eb0, 7c157764133fea1f, 40b4916d82eaf1d4, 10d151f2cc75317f, 3d0832f39b0d7059, 92742ba36533633d, 0aeca6145e7bd302]
|
||||
tool: 1
|
||||
---
|
||||
# Client transports {#client-transports}
|
||||
|
|
@ -11,30 +11,15 @@ translation:
|
|||
|
||||
हर transport का **server** वाला पक्ष (`mcp.run()` क्या करता है और आप क्या deploy करते हैं) **[अपना server चलाना](../run/index.md)** में है।
|
||||
|
||||
## Memory में {#in-memory}
|
||||
|
||||
server object ही पास करें:
|
||||
|
||||
```python title="client.py" hl_lines="14"
|
||||
--8<-- "docs_src/client_transports/tutorial001.py"
|
||||
```
|
||||
|
||||
न कोई subprocess, न कोई port, न wire पर कोई bytes। client और server एक ही process में दो objects हैं, और call फिर भी असली protocol layer से होकर जाती है: `search_books` ठीक वैसे ही list, validate और invoke होता है जैसे HTTP पर होता।
|
||||
|
||||
इससे यह एक साथ दो काम करता है:
|
||||
|
||||
* **Test harness।** इस documentation का हर उदाहरण इसी तरीके से चलाया जाता है, और **[Testing](../get-started/testing.md)** page पूरा pattern इसी के इर्द-गिर्द बनाता है।
|
||||
* **Embedding API।** जो application खुद server बनाता है, उसे उसके tools call करने के लिए network hop की ज़रूरत नहीं।
|
||||
|
||||
## Streamable HTTP {#streamable-http}
|
||||
|
||||
URL string पास करें और आपको **Streamable HTTP** मिलता है, वह transport जिसके पीछे आप deploy करते हैं:
|
||||
URL string पास करें और आपको **Streamable HTTP** मिलता है, वह transport जिसके पीछे आप deploy करते हैं और जिसे सबसे पहले चुनना चाहिए:
|
||||
|
||||
```python title="client.py" hl_lines="5"
|
||||
--8<-- "docs_src/client_transports/tutorial002.py"
|
||||
```
|
||||
|
||||
पूरा production client बस इतना ही है। `Client` आपके लिए URL को `streamable_http_client(...)` में लपेट देता है, एक `httpx2.AsyncClient` के ऊपर जो MCP की ज़रूरत के हिसाब से configure किया गया है: `follow_redirects=True`, connect/write/pool के लिए 30 सेकंड का timeout, और 300 सेकंड का read timeout, क्योंकि server response stream को खुला रख सकता है।
|
||||
पूरा production client बस इतना ही है। `Client` आपके लिए URL को `streamable_http_client(...)` में लपेट देता है, एक `httpx2.AsyncClient` के ऊपर जो MCP की ज़रूरत के हिसाब से configure किया गया है: connect/write/pool के लिए 30 सेकंड का timeout, और 300 सेकंड का read timeout, क्योंकि server response stream को खुला रख सकता है।
|
||||
|
||||
!!! check
|
||||
जो `Client` आपने बनाया है वह connected **नहीं** है। बनाने से सिर्फ़ transport चुना जाता है;
|
||||
|
|
@ -50,7 +35,7 @@ URL string पास करें और आपको **Streamable HTTP** मि
|
|||
|
||||
जैसे ही आपको `Authorization` header, cookie, proxy, mTLS या कोई अलग timeout चाहिए, `httpx2.AsyncClient` खुद बनाएँ और उसे `streamable_http_client` को दें:
|
||||
|
||||
```python title="client.py" hl_lines="8-14"
|
||||
```python title="client.py" hl_lines="8-13"
|
||||
--8<-- "docs_src/client_transports/tutorial003.py"
|
||||
```
|
||||
|
||||
|
|
@ -80,9 +65,30 @@ environment variables set करें या अपने `httpx2.AsyncClient`
|
|||
!!! info
|
||||
`httpx2` जाना-पहचाना `httpx` API ही रखता है, इसलिए अगर आप `httpx` जानते हैं तो यहाँ auth,
|
||||
proxies, event hooks, retries और connection limits कैसे करने हैं, यह आप पहले से जानते हैं। SDK न ऊपर से कुछ जोड़ता है, न कुछ
|
||||
हटाता है। OAuth भी यहीं जुड़ता है:
|
||||
हटाता है, सिवाय [redirect handling](#redirects) के। OAuth भी यहीं जुड़ता है:
|
||||
`httpx2.AsyncClient(auth=OAuthClientProvider(...))`। वह पूरा flow **[OAuth clients](oauth-clients.md)** में है।
|
||||
|
||||
### Redirects {#redirects}
|
||||
|
||||
transport उसी URL से जुड़ता है जो आपने दिया, और सिर्फ़ उसी origin से।
|
||||
|
||||
* जो `307`/`308` redirect उसी scheme, host और port पर रहता है, उसे follow किया जाता है, और उसी host पर `http://` → `https://` को भी। आम `/mcp` → `/mcp/` वाला trailing-slash redirect इसी में आ जाता है।
|
||||
* कहीं और जाने वाला redirect follow **नहीं** किया जाता। call इस error के साथ fail होती है:
|
||||
|
||||
```text
|
||||
MCPError: Redirect to https://other.example.com/mcp not followed; use that URL as the endpoint if it is the intended server
|
||||
```
|
||||
|
||||
अगर वह URL वही server है जो आप चाहते थे, तो उसे अपने config में डालें। अगर नहीं, तो server या उसके आगे लगा कोई proxy गलत configure है।
|
||||
|
||||
यह आपके पास किए गए किसी भी `httpx2.AsyncClient` पर लागू होता है: MCP requests के लिए उसकी `follow_redirects` setting नहीं देखी जाती, किसी भी दिशा में। SDK के OAuth providers अपनी requests पर यही नियम लागू करते हैं।
|
||||
|
||||
!!! tip
|
||||
`Redirect to http://… not followed: it would downgrade this HTTPS endpoint to plain HTTP` का मतलब है कि
|
||||
server किसी ऐसे TLS-terminating proxy के पीछे है जिसके बारे में उसे पता नहीं, और वह `http://` redirects जारी कर रहा है।
|
||||
इसे server पर ठीक किया जाता है (**[Deploy & scale](../run/deploy.md#behind-a-tls-terminating-proxy)**),
|
||||
या ठीक वही `https://…/` URL इस्तेमाल करके जो message सुझाता है।
|
||||
|
||||
## stdio {#stdio}
|
||||
|
||||
**stdio** server एक subprocess है। client उसे launch करता है, उसके stdin पर JSON-RPC लिखता है और उसके stdout से JSON-RPC पढ़ता है। desktop host आपकी machine पर server इसी तरह चलाता है: host यही code **है**, बस ऊपर एक UI के साथ, और **[असली host से जुड़ें](../get-started/real-host.md)** यही रिश्ता host की तरफ़ से, एक config file के रूप में दिखाता है।
|
||||
|
|
@ -105,6 +111,18 @@ child का stderr आपके stderr पर जाता है। उसे
|
|||
जिस server को API key चाहिए, उसे वह वहाँ नहीं मिलेगी। उसे `env=` से explicitly पास करें; वे
|
||||
variables allow-list के ऊपर merge हो जाते हैं। ऊपर `BOOKSHOP_API_KEY` यही कर रहा है।
|
||||
|
||||
## Memory में {#in-memory}
|
||||
|
||||
test में न कुछ deploy करना है, न कुछ launch करना। server object ही पास करें:
|
||||
|
||||
```python hl_lines="14"
|
||||
--8<-- "docs_src/client_transports/tutorial001.py"
|
||||
```
|
||||
|
||||
न कोई subprocess, न कोई port, न wire पर कोई bytes। client और server एक ही process में दो objects हैं, और call फिर भी असली protocol layer से होकर जाती है: `search_books` ठीक वैसे ही list, validate और invoke होता है जैसे HTTP पर होता। **[Testing](../get-started/testing.md)** पूरा pattern इसी के इर्द-गिर्द बनाता है।
|
||||
|
||||
यही रूप embedding API का काम भी करता है: जो application खुद server बनाता है, वह बिना network hop के उसके tools call कर सकता है।
|
||||
|
||||
## SSE {#sse}
|
||||
|
||||
`mcp.client.sse` का `sse_client(url)` वह HTTP transport है जिसकी जगह Streamable HTTP ने ली। जो server अब भी इसे बोलता है, उससे बात करने के लिए इसे उसी तरह wrap करें, `Client(sse_client("http://localhost:8000/sse"))`, और इस पर कुछ नया न बनाएँ।
|
||||
|
|
@ -113,15 +131,16 @@ child का stderr आपके stderr पर जाता है। उसे
|
|||
|
||||
`Client` के लिए ऊपर की सभी चीज़ें एक ही हैं।
|
||||
|
||||
**transport** कोई भी async context manager है जो message streams का `(read, write)` जोड़ा yield करता है: औपचारिक रूप से, `mcp.client` का `Transport` protocol। `Client` अपने argument को type से resolve करता है: server object in-process जुड़ता है, `str` `streamable_http_client(url)` बन जाता है, `StdioServerParameters` `stdio_client(params)` बन जाता है, और बाकी सब कुछ सीधे transport के रूप में enter किया जाता है। यही आख़िरी नियम वजह है कि `stdio_client(...)`, `streamable_http_client(...)` और `sse_client(...)` सब उसी एक slot में बैठते हैं, और यही वजह है कि आप अपना खुद का भी लिख सकते हैं।
|
||||
**transport** कोई भी async context manager है जो message streams का `(read, write)` जोड़ा yield करता है: औपचारिक रूप से, `mcp.client` का `Transport` protocol। `Client` अपने argument को type से resolve करता है: `str` `streamable_http_client(url)` बन जाता है, `StdioServerParameters` `stdio_client(params)` बन जाता है, server object in-process जुड़ता है, और बाकी सब कुछ सीधे transport के रूप में enter किया जाता है। यही आख़िरी नियम वजह है कि `stdio_client(...)`, `streamable_http_client(...)` और `sse_client(...)` सब उसी एक slot में बैठते हैं, और यही वजह है कि आप अपना खुद का भी लिख सकते हैं।
|
||||
|
||||
## सारांश {#recap}
|
||||
|
||||
* `Client(mcp)` (server object) memory में जुड़ता है। इसे tests और embedding के लिए इस्तेमाल करें।
|
||||
* `Client("http://.../mcp")` (URL) Streamable HTTP पर जुड़ता है, जो production transport है।
|
||||
* Headers, auth, proxies और timeouts उस `httpx2.AsyncClient` पर होने चाहिए जो आप `streamable_http_client(url, http_client=...)` को पास करते हैं। कोई `headers=` keyword नहीं है।
|
||||
* Redirects सिर्फ़ URL के अपने origin के भीतर follow होते हैं (trailing-slash वाला `307`/`308`), और उसी host पर `http`→`https`। बाकी सब `Redirect to … not followed` के साथ fail होता है; final URL configure करें।
|
||||
* stdio है `Client(StdioServerParameters(...))`। इसे खुद `stdio_client(...)` में सिर्फ़ तब wrap करें जब child का stderr कहीं और भेजना हो।
|
||||
* subprocess को allow-list वाला environment मिलता है, आपका नहीं; `env=` उसमें जोड़ता है।
|
||||
* `Client(mcp)` (server object) memory में जुड़ता है। इसे tests में इस्तेमाल करें, या server को उसी application में embed करने के लिए जिसने उसे बनाया।
|
||||
* transport वह हर चीज़ है जिस पर आप `async with x as (read, write)` कर सकें। जो कुछ server object, URL या `StdioServerParameters` नहीं है, `Client` उसे सीधे उसी protocol को सौंप देता है।
|
||||
* `Client` बनाने से transport चुना जाता है। `async with` उसे खोलता है।
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue