Session groups
मशीनी अनुवाद
यह page अंग्रेज़ी documentation से अपने-आप अनुवादित किया गया है, और अंग्रेज़ी page ही प्रामाणिक version है। अगर कुछ गलत लगे, तो अनुवाद page बताता है कि इसकी सूचना कैसे दें।
Client सिर्फ़ एक server से जुड़ता है। असली applications को अक्सर कई servers चाहिए होते हैं (search server, database server, कोई internal API) और फिर हर एक के लिए अलग connection और अलग tools की सूची संभालनी पड़ती है।
ClientSessionGroup एक अकेला object है जिसमें कई connections रहते हैं और जो उन सबकी expose की गई हर चीज़ को एक ही view में मिला देता है।
दो servers
दो साधारण servers से शुरू करें। इनका आपस में कोई लेना-देना नहीं है, इसलिए स्वाभाविक रूप से दोनों ने अपने tool का नाम search रखा:
from mcp.server import MCPServer
mcp = MCPServer("Library")
@mcp.tool()
def search(query: str) -> str:
"""Search the library catalog."""
return f"3 books match {query!r}."
@mcp.resource("library://hours")
def hours() -> str:
"""When the library is open."""
return "Mon-Fri 09:00-17:00"
from mcp.server import MCPServer
mcp = MCPServer("Web")
@mcp.tool()
def search(query: str) -> str:
"""Search the web."""
return f"12 pages match {query!r}."
एक group
ClientSessionGroup बनाएँ और हर server के लिए एक बार connect_to_server call करें:
import asyncio
from mcp import ClientSessionGroup, StdioServerParameters
async def main() -> None:
library = StdioServerParameters(command="uv", args=["run", "mcp", "run", "library_server.py"])
web = StdioServerParameters(command="uv", args=["run", "mcp", "run", "web_server.py"])
async with ClientSessionGroup() as group:
await group.connect_to_server(library)
await group.connect_to_server(web)
result = await group.call_tool("search", {"query": "model context protocol"})
print(result.structured_content)
if __name__ == "__main__":
asyncio.run(main())
connect_to_servertransport parameters लेता है, server object नहीं: subprocess शुरू करने के लिएStdioServerParameters(mcpसे), या पहले से किसी URL पर सुन रहे server के लिएStreamableHttpParameters/SseServerParameters(mcp.client.session_groupसे)।group.toolsहर जुड़े हुए server के tools काdict[str, Tool]है।group.resourcesऔरgroup.promptsका आकार भी यही है।group.call_tool(name, arguments)नाम खोजता है, वह session ढूँढता है जिसका यह tool है, और call आगे भेज देता है। आपको कभी बताना नहीं पड़ता कि कौन सा server।
Check
client.py को दोनों servers के साथ रखें और चलाएँ। दूसरा connect_to_server मना कर देता है:
mcp.shared.exceptions.MCPError: {'search'} already exist in group tools.
यह MCPError है, जो दूसरे server से कुछ भी register होने से पहले raise होता है। नाम पूरे
group में unique होना ज़रूरी है, और जिन दो servers पर आपका नियंत्रण नहीं है वे कभी न कभी टकराएँगे ही।
component_name_hook
इसे servers पर नहीं, group पर ठीक किया जाता है। (name, server_info) लेने वाला function pass करें, और group उसे हर उस नाम पर चलाता है जिसे वह register करता है:
import asyncio
from mcp import ClientSessionGroup, StdioServerParameters
from mcp.types import Implementation
def by_server(name: str, server_info: Implementation) -> str:
return f"{server_info.name}.{name}"
async def main() -> None:
library = StdioServerParameters(command="uv", args=["run", "mcp", "run", "library_server.py"])
web = StdioServerParameters(command="uv", args=["run", "mcp", "run", "web_server.py"])
async with ClientSessionGroup(component_name_hook=by_server) as group:
await group.connect_to_server(library)
await group.connect_to_server(web)
print(sorted(group.tools))
result = await group.call_tool("Web.search", {"query": "model context protocol"})
print(result.structured_content)
if __name__ == "__main__":
asyncio.run(main())
इसे फिर चलाएँ। print(sorted(group.tools)) अब दोनों दिखाता है:
['Library.search', 'Web.search']
- key आपकी है।
by_serverने इसेserver_info.nameसे बनाया, यानी वह नाम जिससे हरMCPServer(...)बनाया गया था। - अंदर का
Toolजस का तस है:group.tools["Web.search"].nameअब भी"search"है, औरcall_toolwire पर यही नाम भेजता है। prefix आपके process से बाहर कभी नहीं जाता। - बात सिर्फ़ tools की नहीं है। library का
hoursresourceLibrary.hoursनाम से register होता है।
Tip
hook हर server के हर नाम पर चलता है, सिर्फ़ टकराव पर नहीं: सिर्फ़-टकराव-पर-prefix जैसा कोई mode नहीं है। एक scheme चुनें और उसे हर जगह लागू होने दें।
servers जोड़ना और हटाना
connect_to_server वह ClientSession लौटाता है जो उसने खोला। अगर कभी उस server को हटाना हो तो इसे संभालकर रखें: await group.disconnect_from_server(session) उसके tools, resources और prompts group से हटा देता है।
अगर आपके पास पहले से जुड़ा हुआ ClientSession है (Client.session ऐसा ही एक है), तो नया transport खोलने के बजाय उसे await group.connect_with_session(server_info, session) को सौंप दें। यह उसी तरह aggregate करता है। group कभी ऐसा session बंद नहीं करता जो उसने खुद नहीं खोला। server_info component prefixes के लिए server का नाम देता है; 2026 पीढ़ी के connection पर client.server_info None हो सकता है (identity वैकल्पिक है), इसलिए उस स्थिति में अपना Implementation(name=..., version=...) pass करें।
Classic handshake
ClientSessionGroup Client पर नहीं, ClientSession पर बना है। हर connect_to_server classic initialize handshake चलाता है। यह Protocol versions में बताया गया server/discover probe कभी नहीं भेजता। हर MCP server वह handshake समझता है, इसलिए इससे किसी के साथ भी compatibility नहीं खोती; इसका मतलब बस इतना है कि group ऐसे server तक भी पुराने, धीमे रास्ते से पहुँचता है जो बेहतर कर सकता था।
सारांश
ClientSessionGroupकई server connections रखता है और उनके tools, resources और prompts को एक-एकdictमें मिला देता है।- हर server के लिए
connect_to_server(params)। यह transport parameters लेता है, कभी वह server object या URL नहीं जोClientलेता है। group.call_tool(name, arguments)आपके लिए call को उस server तक पहुँचाता है जिसका वह tool है।- नाम पूरे group में unique होने ज़रूरी हैं;
searchtool वाले दो servers अपने आप साथ नहीं रह सकते। component_name_hook=हर register किए गए नाम को फिर से लिखता है। dict key बदलती है, wire पर जाने वाला नाम नहीं।connect_with_sessionपहले से आपके पास मौजूद session जोड़ता है;disconnect_from_serverएक session हटाता है।
group कौन सा handshake बोलता है (और Client किस तेज़ handshake को तरजीह देता है), यही Protocol versions का विषय है।