Content hash: 061107c4ad0bc9bc831f03db611a8bfd303e1c5bd5fb2ee52977add0cb40f36a
#!/usr/bin/env python3
"""Minimal MCP client: connect to a server, list tools, call one.
Uses the mcp Python SDK. Run against any MCP server (stdio or HTTP).
"""
from __future__ import annotations
import asyncio
import sys
try:
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
except ImportError:
print("Install: pip install mcp", file=sys.stderr)
sys.exit(1)
async def connect_and_explore(command: str, args: list[str]) -> None:
"""Connect over stdio, initialize, list tools, call one."""
params = StdioServerParameters(command=command, args=args)
async with stdio_client(params) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
# 1. Initialize handshake (REQUIRED before any discovery)
init_result = await session.initialize()
print(f"Connected. Server: {init_result.server_info.name}")
print(f"Protocol version: {init_result.protocol_version}")
# 2. Discover tools (with pagination support)
tools_result = await session.list_tools()
tools = tools_result.tools
print(f"\nTools ({len(tools)}):")
for t in tools:
sig = ", ".join(
f"{k}: {v.get('type','?')}" for k, v in t.inputSchema.get("properties", {}).items()
)
print(f" • {t.name}({sig}) — {t.description[:60]}")
# Check for cursor-based pagination
next_cursor = getattr(tools_result, "nextCursor", None)
while next_cursor:
more = await session.list_tools(cursor=next_cursor)
for t in more.tools:
print(f" • {t.name} (paginated)")
next_cursor = getattr(more, "nextCursor", None)
# 3. Call the first tool (if any exist)
if tools:
first = tools[0]
print(f"\n=== Calling: {first.name} ===")
result = await session.call_tool(first.name, arguments={})
for item in result.content:
if hasattr(item, "text"):
print(f" text: {item.text[:200]}")
elif hasattr(item, "type") and item.type == "image":
print(f" [image: {len(item.data)} bytes]")
else:
print(f" [content: {item}]")
print("\n=== Done - session closed ===")
async def main() -> None:
if len(sys.argv) < 2:
print("Usage: python mcp_client_example.py <command> [args...]")
print("Example: python mcp_client_example.py python server.py")
sys.exit(2)
command = sys.argv[1]
args = sys.argv[2:]
try:
async with asyncio.timeout(30):
await connect_and_explore(command, args)
except TimeoutError:
print("Timeout: server may not be responding", file=sys.stderr)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
if __name__ == "__main__":
asyncio.run(main())