# Initialize Handshake और Capabilities — MCP और Agent-to-Agent Protocols

Source: https://www.geekswithgeeks.com/hi/mcp-a2a/m-lifecycle

> देखें client और server protocol संस्करण और सुविधाओं पर कैसे सहमत होते हैं।

## नमस्ते कहें, सहमत हों, फिर काम करें

हर MCP session client के **initialize** request से शुरू होता है जिसमें उसका `protocolVersion`, `capabilities` (जैसे sampling या roots का समर्थन) और `clientInfo` होते हैं। Server उस संस्करण से उत्तर देता है जो वह उपयोग करेगा, अपनी **capabilities** (`tools`, `resources`, `prompts`, `listChanged` जैसे flags सहित) और `serverInfo` के साथ। फिर client **`notifications/initialized`** notification भेजता है और सामान्य traffic शुरू होता है। हर पक्ष **सिर्फ़ वही सुविधाएँ** उपयोग कर सकता है जो दोनों ने घोषित कीं; यह **capability negotiation** है, और नई सुविधाएँ आने पर protocols इसी तरह backward compatible रहते हैं। बाद में transport बंद करने पर session समाप्त होता है।

## बात करने के लिए एक server

यह छोटा server (आधिकारिक Python SDK, संस्करण 2.x से बना) एक tool, एक resource और एक prompt उपलब्ध कराता है। इसे `server.py` नाम से सहेजें। अगले उदाहरण इसे कच्चे JSON-RPC से चलाते हैं।

```python
from mcp.server.mcpserver import MCPServer

mcp = MCPServer("demo-orders")

@mcp.tool()
def get_order_status(order_id: str) -> dict:
    """Return the status of ONE order. order_id is exactly 6 digits."""
    if not (order_id.isdigit() and len(order_id) == 6):
        return {"error": "order_id must be exactly 6 digits"}
    return {"order_id": order_id, "status": "shipped"}

@mcp.resource("policy://refunds")
def refund_policy() -> str:
    """The refund policy text."""
    return "Refunds above 5000 rupees need approval."

@mcp.prompt()
def triage(ticket: str) -> str:
    """A prompt template for ticket triage."""
    return f"Classify this ticket as billing, technical or other: {ticket}"

if __name__ == "__main__":
    mcp.run("stdio")

```

## Server को हाथ से चलाना, चलाकर

मैंने यह पहले दिखाए असली server के विरुद्ध चलाया, virtual environment में आधिकारिक `mcp` Python SDK 2.2.0 के साथ; client पक्ष stdio पर कच्चा JSON-RPC है, SDK के बिना। Server को उसी folder में `server.py` नाम से सहेजें। SDK के नाम और डिफ़ॉल्ट संस्करणों के बीच बदलते हैं, इसलिए मौजूदा दस्तावेज़ देखें। Client `initialize`, फिर `initialized` notification भेजता है, फिर tools सूचीबद्ध करता है, वैध, अमान्य और ग़ायब arguments के साथ एक को बुलाता है, अज्ञात method आज़माता है, और एक resource व एक prompt पढ़ता है। Server protocol 2025-06-18 और capabilities `prompts`, `resources`, `tools` (साथ में `experimental` प्रविष्टि) रिपोर्ट करता है।

```python
import json, subprocess, sys

proc = subprocess.Popen([sys.executable, "server.py"], stdin=subprocess.PIPE,
                        stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True)

def send(msg):
    proc.stdin.write(json.dumps(msg) + "\n"); proc.stdin.flush()

def call(id_, method, params=None):
    send({"jsonrpc": "2.0", "id": id_, "method": method, **({"params": params} if params is not None else {})})
    return json.loads(proc.stdout.readline())

init = call(1, "initialize", {"protocolVersion": "2025-06-18", "capabilities": {},
                              "clientInfo": {"name": "demo-client", "version": "0.1"}})
print("server:", init["result"]["serverInfo"]["name"], "| protocol:", init["result"]["protocolVersion"])
print("capabilities:", sorted(init["result"]["capabilities"]))
send({"jsonrpc": "2.0", "method": "notifications/initialized"})     # a notification: no id, no reply

tools = call(2, "tools/list")["result"]["tools"]
print("tools:", [t["name"] for t in tools])
print("input schema:", json.dumps(tools[0]["inputSchema"]))

ok = call(3, "tools/call", {"name": "get_order_status", "arguments": {"order_id": "481516"}})
print("call ok     :", ok["result"]["content"][0]["text"], "| isError:", ok["result"].get("isError"))
bad = call(4, "tools/call", {"name": "get_order_status", "arguments": {"order_id": "12"}})
print("call bad id :", bad["result"]["content"][0]["text"])
missing = call(5, "tools/call", {"name": "get_order_status", "arguments": {}})
print("missing arg :", "isError" , missing["result"].get("isError"), "|", missing["result"]["content"][0]["text"][:60].replace(chr(10), " "))
unknown = call(6, "no/such/method")
print("unknown     :", unknown["error"]["code"], unknown["error"]["message"])

res = call(7, "resources/list")["result"]["resources"]
print("resources:", [r["uri"] for r in res])
print("read:", call(8, "resources/read", {"uri": "policy://refunds"})["result"]["contents"][0]["text"])
pr = call(9, "prompts/get", {"name": "triage", "arguments": {"ticket": "I was charged twice"}})
print("prompt:", pr["result"]["messages"][0]["content"]["text"])
proc.stdin.close(); proc.wait()

```

Output:

```
server: demo-orders | protocol: 2025-06-18
capabilities: ['experimental', 'prompts', 'resources', 'tools']
tools: ['get_order_status']
input schema: {"properties": {"order_id": {"title": "Order Id", "type": "string"}}, "required": ["order_id"], "type": "object", "title": "get_order_statusArguments"}
call ok     : {
  "order_id": "481516",
  "status": "shipped"
} | isError: False
call bad id : {
  "error": "order_id must be exactly 6 digits"
}
missing arg : isError True | Error executing tool get_order_status: 1 validation error fo
unknown     : -32601 Method not found
resources: ['policy://refunds']
read: Refunds above 5000 rupees need approval.
prompt: Classify this ticket as billing, technical or other: I was charged twice
```

## Capability negotiation, चलाकर

मैंने यह सादे Python 3 (सिर्फ़ standard library) से चलाया। सिर्फ़ वही सुविधाएँ उपयोग योग्य हैं जो दोनों पक्षों ने घोषित कीं: client capabilities के बिना सिर्फ़ `tools` और `resources` चलते हैं; sampling के लिए client का घोषित करना और server का चाहना ज़रूरी है; जिस client ने `roots` घोषित नहीं किया उससे माँगना अनदेखा होता है।

```python
def negotiate(client_caps, server_caps):
    """Use only features that BOTH sides declared during initialize."""
    usable = []
    if "tools" in server_caps:
        usable.append("tools")
    if "resources" in server_caps:
        usable.append("resources")
    if "sampling" in client_caps and server_caps.get("wants_sampling"):
        usable.append("sampling (server asks the client's model)")
    if "roots" in client_caps and server_caps.get("wants_roots"):
        usable.append("roots")
    return usable

print(negotiate({}, {"tools": {}, "resources": {}}))
print(negotiate({"sampling": {}}, {"tools": {}, "wants_sampling": True}))
print(negotiate({"sampling": {}}, {"tools": {}, "wants_roots": True}))

```

Output:

```
['tools', 'resources']
['tools', "sampling (server asks the client's model)"]
['tools']
```

**Quiz:** Server के initialize का उत्तर देने के ठीक बाद क्या होता है?

- [ ] फिर कुछ नहीं हो सकता
- [ ] Session हटा दिया जाता है
- [ ] मॉडल दोबारा प्रशिक्षित होता है
- [x] Client notifications/initialized भेजता है और सामान्य traffic शुरू होता है

*Answer:* Client notifications/initialized भेजता है और सामान्य traffic शुरू होता है. initialized notification handshake पूरा करता है।
