Grupos de sesiones
Traducción automática
Esta página se tradujo automáticamente a partir de la documentación en inglés, y la página en inglés es la versión de referencia. Si algo no se lee bien, Traducciones explica cómo avisarnos.
Un Client se conecta a un servidor. Las aplicaciones reales suelen querer varios (un servidor de búsqueda, un servidor de base de datos, una API interna) y terminan haciendo malabares con una conexión y una lista de herramientas para cada uno.
ClientSessionGroup es un único objeto que mantiene muchas conexiones y reúne todo lo que exponen en una sola vista.
Dos servidores
Empieza con dos servidores normales. No tienen nada que ver entre sí, así que, como es natural, ambos llamaron search a su herramienta:
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}."
Un grupo
Crea un ClientSessionGroup y llama a connect_to_server una vez por servidor:
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_serverrecibe parámetros de transporte, no un objeto servidor:StdioServerParameters(demcp) para lanzar un subproceso, oStreamableHttpParameters/SseServerParameters(demcp.client.session_group) para un servidor que ya está escuchando en una URL.group.toolses undict[str, Tool]con las herramientas de todos los servidores conectados.group.resourcesygroup.promptstienen la misma forma.group.call_tool(name, arguments)busca el nombre, encuentra la sesión a la que pertenece y le reenvía la llamada. Nunca indicas qué servidor.
Check
Pon client.py junto a los dos servidores y ejecútalo. El segundo connect_to_server se niega:
mcp.shared.exceptions.MCPError: {'search'} already exist in group tools.
Es un MCPError, lanzado antes de que se registre nada del segundo servidor. Un nombre debe
ser único en todo el grupo, y dos servidores que no controlas acabarán chocando tarde o temprano.
component_name_hook
Esto se arregla en el grupo, no en los servidores. Pasa una función de (name, server_info) y el grupo la ejecuta sobre cada nombre que registra:
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())
Ejecútalo de nuevo. print(sorted(group.tools)) ahora muestra ambos:
['Library.search', 'Web.search']
- La clave es tuya.
by_serverla construyó a partir deserver_info.name, el nombre con el que se creó cadaMCPServer(...). - El
Toolque contiene queda intacto:group.tools["Web.search"].namesigue siendo"search", y ese es el nombre quecall_tooltransmite por el canal. El prefijo nunca sale de tu proceso. - No son solo las herramientas. El recurso
hoursde la biblioteca se registra comoLibrary.hours.
Tip
El hook se ejecuta sobre cada nombre de cada servidor, no solo en los conflictos: no hay un modo de prefijo solo en caso de colisión. Elige un esquema y deja que se aplique en todas partes.
Añadir y quitar servidores
connect_to_server devuelve la ClientSession que abrió. Guárdala si alguna vez quieres deshacerte de ese servidor: await group.disconnect_from_server(session) quita del grupo sus herramientas, recursos y prompts.
Si ya tienes una ClientSession conectada (Client.session lo es), pásala a await group.connect_with_session(server_info, session) en lugar de abrir un transporte nuevo. La agrega de la misma manera. El grupo nunca cierra una sesión que no abrió. server_info da nombre al servidor para los prefijos de los componentes; en una conexión de la generación 2026, client.server_info puede ser None (la identidad es opcional), así que en ese caso pasa tu propio Implementation(name=..., version=...).
El handshake clásico
ClientSessionGroup está construido sobre ClientSession, no sobre Client. Cada connect_to_server ejecuta el handshake clásico de initialize. Nunca envía el sondeo server/discover descrito en Versiones del protocolo. Todos los servidores MCP entienden ese handshake, así que esto no te cuesta compatibilidad con nada; solo significa que un grupo toma el camino más antiguo y lento hacia un servidor que podría hacerlo mejor.
Resumen
ClientSessionGroupmantiene muchas conexiones a servidores y reúne sus herramientas, recursos y prompts en undictpara cada tipo.connect_to_server(params)por servidor. Recibe parámetros de transporte, nunca el objeto servidor ni la URL que recibe unClient.group.call_tool(name, arguments)enruta por ti al servidor al que pertenece.- Los nombres deben ser únicos en todo el grupo; dos servidores con una herramienta
searchno pueden coexistir por sí solos. component_name_hook=reescribe cada nombre registrado. La clave del dict cambia; el nombre que se transmite por el canal, no.connect_with_sessionañade una sesión que ya tienes;disconnect_from_serverquita una.
El handshake que habla un grupo (y el más rápido que prefiere un Client) es el tema de Versiones del protocolo.