विषय पर बढ़ें

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 रखा:

library_server.py
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"
web_server.py
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 करें:

client.py
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_server transport 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 करता है:

client.py
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_tool wire पर यही नाम भेजता है। prefix आपके process से बाहर कभी नहीं जाता।
  • बात सिर्फ़ tools की नहीं है। library का hours resource Library.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 होने ज़रूरी हैं; search tool वाले दो servers अपने आप साथ नहीं रह सकते।
  • component_name_hook= हर register किए गए नाम को फिर से लिखता है। dict key बदलती है, wire पर जाने वाला नाम नहीं।
  • connect_with_session पहले से आपके पास मौजूद session जोड़ता है; disconnect_from_server एक session हटाता है।

group कौन सा handshake बोलता है (और Client किस तेज़ handshake को तरजीह देता है), यही Protocol versions का विषय है।