Iedereen dissecteert MCP alsof het de Rosetta Stone van AI is. diagrammen! whitepapers! gedachteleiders maken TikToks! Maar waar, mijn lieve data druïden, zijn de werkelijke pakketten? nobody's showing the actual packets. Het is alsof je probeert chirurgie te leren van een motiverende poster.Zeker, het theoretische kader is *inspirerend*, maar ik wil het bloed en de darmen zien!Waar is de ruwe JSON?Waar zijn de stdin/stdout dumps?Hoe moet ik mijn creatie animeren als ik de bliksem niet eens kan zien? Het is alsof je probeert chirurgie te leren van een motiverende poster.Zeker, het theoretische kader is *inspirerend*, maar ik wil het bloed en de darmen zien!Waar is de ruwe JSON?Waar zijn de stdin/stdout dumps?Hoe moet ik mijn creatie animeren als ik de bliksem niet eens kan zien? Proberen om een protocol te leren zonder draad dumps is als proberen om te leren omheining van een PowerPoint. Give me the electrons or give me death. Nu we onze mantra hebben, laten we graven in! Is dit je businessmodel? Uw MCP Business Plan: Leer het MCP ??? (... een wonder gebeurt...) Deze winst Klinkt bekend? Natuurlijk doet het! Het is het start-up-equivalent van het omzetten van lood in goud. Alchemie, maar met veel meer JSON. Gelukkig... #Je bent niet alleen! Het lijkt erop dat strepen van inkt over dit zogenaamde Model Context Protocol zijn gegoten. Iedereen praat over LLM's evolueren, tool calling, function calling, bidirectioneel dit en de mogelijkheid dat. ik ben natuurlijk geen uitzondering. "What's this look like ON THE WIRE???" Het gehele protocol wordt gedocumenteerd op Ik wil geen filosofie, ik wil Ik wil me voelen als Dr. Frankenstein neigt naar mijn golem, bliksem en alles. modelcontextprotocol.io see Wee mij, een louter verblijfster onder de verlichten, totdat ik het zo opende! Eerste waarnemingen vanuit het veld MCP is heel, heel nieuw. Bloedende rand. Mogelijk nog steeds bloeden. Misschien op een dag, hele boeken zullen geschreven worden over de interne politiek, zoals een soort van digitale constitutionele conventie. Maar voorlopig staat er één ding boven alles op: Tool Calling is alles wat je nodig hebt Als we de weg zoomen, de weg in op deze enkele, kritische gebruikssituatie - We kunnen negeren a We kunnen vereenvoudigen tot we kijken naar het prachtige skelet van het systeem: slechts vier berichtentypen voor de output, en drie voor de input. (We zullen uitleggen waarom de nummers niet precies overeenkomen een beetje later.) tool invocation Lotte initialiseren initialiseren Tools / lijst Tools / oproep (en de 3 resultaten die terugkomen) Je kunt het hele protocol begrijpen door te weten over deze zeven berichten. De weersomstandigheden (van ) modelcontextprotocol.io modelcontextprotocol.io We zullen gebruiken — een eenvoudig MCP-server voorbeeld dat u kunt query voorspelling en waarschuwing gegevens. U kunt het vinden in hun GitHub hier: . weather.py https://github.com/modelcontextprotocol/quickstart-resources/blob/main/weather-server-python/weather.py Laten we praten over wat er eigenlijk gebeurt "op de draad" wanneer je met dit ding praat. Eerste uit: MCP is Dat betekent dat de spec niet uitmaakt hoe je verbinding maakt met de server. HTTPS? Web Sockets? Named pipes? Tapping in een oude Ethernet vampierkabel? Agnosticatie van vervoer. In de praktijk is de meest voorkomende methode om de server te starten als een subproces en te communiceren over en Dit geeft je een leuk klein privé-communicatie kanaal. (Technisch full-duplex, maar als je , we zullen het 1.5-duplex noemen om leuk te zijn). stdin stdout stderr Hoe berichten stromen MCP gebruikt JSON-RPC 2.0 over de draad. Dit geeft u een verzoek / antwoord protocol, plus kennisgevingen. Het is als een digitale telegramdienst waar elke regel een compleet pakket van betekenis is. Is dit in de spec? Soort van; niet echt. De spec laat het open. Maar deze newline-delimited JSON is het standaardidiome. De mythe van "stdin/stdout beschouwd als schadelijk" Ja, je kunt een aantal dramatische blogberichten vinden die beweren dat dit patroon "gevaarlijk" of "onbetrouwbaar" is. Lijkt angstaanjagend! we willen niet een brand in het laboratorium beginnen, toch? waarom zouden mensen dit zeggen als het niet waar was? Je ziet, in Ye Olden Times kunnen extra lange lijnen bufferoverstromingen veroorzaken (hello, Morris Worm). Gelukkig lijdt de meeste moderne software niet aan dit probleem (zo veel! Vingers gekruist!). Moderne JSON-parsers zijn zowel snel als veerkrachtig. Wilt u een 256 MB weerswaarschuwing sturen? Ga er gewoon voor. ... misschien doe je het niet elke seconde. Deze waarschuwingen komen meestal van mensen die handmatig bestandsdescriptoren in C. U doet dat niet. Een module die speciaal is ontworpen voor dit soort taken. subprocess # fork off an MCP subprocess import subprocess as sp # Redirect stderr to /dev/null stderr = sp.DEVNULL # Start the weather.py process process = sp.Popen( ["uv", "run", "weather.py"], stdin=sp.PIPE, stdout=sp.PIPE, stderr=stderr ) Alle native Python. geen extra pakketten. batterijen inbegrepen. De De module vervangt de I/O-stromen van het kind door pijpen, waardoor u volledige dominantie krijgt. subprocess Nu zijn we eindelijk klaar om protocol wetenschap te doen als een proper digital necromancer! Plot Twist: Het is verlegen eenvoudig MCP, in al zijn enterprise-robe-and-scepter regalia, is precies dit: YOU: "Hello, I speak robot." SERVER: "Delightful. I also speak robot." YOU: "Excellent, we both can speak robot!" YOU: "What tricks can you do?" SERVER: "I can juggle and summon storms." YOU: "Storm, please!" SERVER: "⛈️ As you wish." Dit hele protocol is slechts een zeer formele manier om iemand te vragen om iets te doen en bevestiging te krijgen dat ze het hebben gedaan. De rest is gewoon enterprise-grade ceremonie en glitterlijm rond deze prachtig eenvoudige handgreep. Zeven vriendelijke uitwisselingen. Dat is het. Stitching the Monster Together: een werkend prototype We gaan een weersserver voortbrengen en het ondervragen als een goede gekke wetenschapper. Tip #1: De beste manier om een protocol te begrijpen is om het te misbruiken totdat het schreeuwt, vervolgens patch het totdat het samenwerkt. Tip #1: De beste manier om een protocol te begrijpen is om het te misbruiken totdat het schreeuwt, vervolgens patch het totdat het samenwerkt. Tip #2: Als je je LLM's martelt, zal ik niet verantwoordelijk worden gehouden voor wat er met je gebeurt in The After Times When AI Taketh Over! Tip #2: Als je je LLM's martelt, zal ik niet verantwoordelijk worden gehouden voor wat er met je gebeurt in The After Times When AI Taketh Over! Stap 1: Maak kennis met onze digitale minion # Behold! We create life! # (fork off an MCP subprocess) import subprocess # Start the weather.py process # Use `uv run` to execute the script in the uv environment # Redirect stdin, stdout to PIPE for communication # Redirect stderr to DEVNULL to suppress error messages process = subprocess.Popen( ["uv", "run", "weather.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr) # Behold! We create life! process = subprocess.Popen( ["uv", "run", "weather.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL # Silence the screams ) De De module vervangt de I/O-stromen van het kind door pijpen, waardoor je volledige controle hebt over het gesprek.Het is prachtig eenvoudig: je hebt nu een toegewijd kinderproces bij je beck-and-call, klaar om alles uit te voeren wat je er op gooit. subprocess Je kunt zelfs signalen sturen om echt te laten zien wie de baas is. Onder normale omstandigheden, wanneer het ouderlijk proces vertrekt, gaat het kind met het schip naar beneden - dus je hoeft je geen zorgen te maken over zombie-processen die je systeem verstoppen (ja, meestal). : U zult merken dat we gebruiken om het proces te sporen. Dit is niet nodig, maar wordt snel de gouden standaard voor moderne Python-tools.Als je het nog niet hebt bekeken, moet je absoluut - het is een game-changer. Quick aside uv uv Als je nog steeds pip gebruikt, moeten we praten. Als je nog steeds pip gebruikt, moeten we praten. Stap 2: De ongemakkelijke eerste date Elke goede relatie begint met wederzijdse identificatie.We zullen beginnen met het aankondigen van onszelf (zoals een gentleman): # Define the initialize request init_request = { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": { "name": "MyMCPClient", "version": "1.0.0" } } } Dit is onze Het vertelt de server drie cruciale dingen: we spreken MCP, welke versie we gebruiken en welke mogelijkheden we naar de tafel brengen. Opening Salvo U zult merken dat dit het JSON-RPC 2.0-formaat volgt, en dat zal consistent zijn gedurende ons hele gesprek met de server. Let's fire it off. import json def send_mcp_request(process, request): """Sends a JSON-RPC request to the subprocess's stdin.""" json_request = json.dumps(request) + '\n' # Add newline delimiter process.stdin.write(json_request.encode('utf-8')) process.stdin.flush() # Ensure the data is sent immediately # 1. Send the initialize request print("Sending initialize request...") send_mcp_request(process, init_request) We moeten deze output zien: Sending initialize request... Nu, laten we horen wat de server tot nu toe over alles te zeggen heeft: def read_mcp_response(process): """Reads a JSON-RPC response from the subprocess's stdout.""" # Assuming the server sends one JSON object per line line = process.stdout.readline().decode('utf-8') if line: print(" . . . len is", len(line)) return json.loads(line) return None print("Sending initialized request...") send_mcp_request(process, notified_request) De server, beleefd, introduceert zichzelf terug: . . . len is 266 Received response after initialization:{'id': 1, 'jsonrpc': '2.0', 'result': {'capabilities': {'experimental': {}, 'prompts': {'listChanged': False}, 'resources': {'listChanged': False, 'subscribe': False}, 'tools': {'listChanged': False}}, 'protocolVersion': '2025-03-26', 'serverInfo': {'name': 'weather', 'version': '1.9.4'}}} "Hallo, ik ben een weerserver, ik zal mijn vaardigheden niet willekeurig veranderen in het midden van het gesprek, en ik zal je zeker niet geesten." Translation Het deelt protocolversie informatie en basisgegevens, maar de Sectie is de echte prijs. So, what's the server actually telling us here? capabilities We negeren de mogelijkheden voor deze demo, maar check dit uit: we abonneren op "listChanged" gebeurtenissen als onze server het type was om dynamische tools toe te voegen of te verwijderen. Er is eigenlijk een sneaky little pub / sub-systeem verborgen in het MCP-protocol - je kunt luisteren naar allerlei soorten gebeurtenissen. kon Dezelfde zaak met "prompts" en "bronnen" - we overslaan ze volledig. Het hele idee is dat verschillende systemen verschillende problemen beheren, dus je hoeft niet elk wiel opnieuw uit te vinden.Je kunt kiezen en kiezen welke delen van het protocol te implementeren, maar als je leuk wilt spelen met andere MCP-tools, zou je beter vasthouden aan de spec. API separation Alright, we're connected and ready to rock, right? Wrong. De server zit er nog steeds, tikt zijn digitale voet, wachtend op ons om de hand te voltooien.We moeten het "all good on our end" signaal sturen: notified_request = { "jsonrpc": "2.0", "method": "notifications/initialized" } Dat is de manier waarop JSON-RPC zegt "brand en vergeet" - geen verwachte of vereiste reactie. Denk aan het verzenden van een ACK-pakket: "Hey server, ik ben klaar om te rollen!" Notice the missing id notification Geen id betekent: "Reageer niet, ik zal vertrouwen dat je weet wat je moet doen met deze informatie." betekent: "Reageer niet, ik zal vertrouwen dat je weet wat je moet doen met deze informatie." niet id Ondertussen... terug op de ranch... (terug naar het verhaal!) Ondertussen... terug op de ranch... (terug naar het verhaal!) Vergeet niet dat de server, redelijk beleefd, al gereageerd met een manifest van zijn vermogens. Dus laten we bevestigen: Ja, we zijn echt klaar voor een feestje. # yes we are indeed ready to party # Acknowledge the server so it knows we approve print("// Sending initialized request...") send_mcp_request(process, notified_request) De server kan nu beginnen met het verwachten van verzoeken. Stap 3: “Show Me What You Got” Tijd om te zien wat speelgoed deze server bracht naar de speeltuin: tools_list_request = { "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": { } } # 2. Send the tools/list request print("// Sending tools/list request...") send_mcp_request(process, tools_list_request) We krijgen precies het resultaat dat we verwachtten...Perfect! // Sending tools/list request... Nu, laten we de output teruglezen... Tijd om te zien welke schatten we hebben ontdekt: # Read the server's response to the tools/list request tools_list_response = read_mcp_response(process) print("// Received tools list response:", end='') pprint(tools_list_response) En onze server toont trots zijn goederen: voorspellingen, waarschuwingen en andere meteorologische mislukkingen. . . . len is 732 // Received tools list response:{'id': 2, 'jsonrpc': '2.0', 'result': {'tools': [{'description': 'Get weather alerts for a US state.\n' '\n' ' Args:\n' ' state: Two-letter US state code ' '(e.g. CA, NY)\n' ' ', 'inputSchema': {'properties': {'state': {'title': 'State', 'type': 'string'}}, 'required': ['state'], 'title': 'get_alertsArguments', 'type': 'object'}, 'name': 'get_alerts'}, {'description': 'Get weather forecast for a location.\n' '\n' ' Args:\n' ' latitude: Latitude of the ' 'location\n' ' longitude: Longitude of the ' 'location\n' ' ', 'inputSchema': {'properties': {'latitude': {'title': 'Latitude', 'type': 'number'}, 'longitude': {'title': 'Longitude', 'type': 'number'}}, 'required': ['latitude', 'longitude'], 'title': 'get_forecastArguments', 'type': 'object'}, 'name': 'get_forecast'}]}} Whoa! dat is een van JSON! Oké, laten we in de goede dingen graven. Lotte Dat is onze goudmijn - elk object vertegenwoordigt een hulpmiddel dat de LLM kan aanroepen. (Plot twist: we kunnen ze ook noemen, wat precies is wat we nu doen!) See that tools Fun fact: De 'beschrijving' velden zijn hoe uw LLM beslist welke functie te bellen. denk er aan als Tinder voor tools, met uw AI kijkt naar zijn telefoon proberen te beslissen of u naar links of naar rechts wilt schuiven Fun fact: De 'beschrijving' velden zijn hoe uw LLM beslist welke functie te bellen. denk er aan als Tinder voor tools, met uw AI kijkt naar zijn telefoon proberen te beslissen of u naar links of naar rechts wilt schuiven : OpenAI probeerde dit oorspronkelijk te merken als "function calling" - wat... Maar ergens langs de weg besloot de industrie collectief "tools" koeler te klinken (of misschien toegankelijker?), en nu noemen we de hele dans "tool calling". One interesting side note Technisch Anatomy of a tool (pay attention, this is where the magic lives): naam: De werkelijke naam van de functie – hier is geen typos toegestaan! Dit is de definitieve, canonische naam van het instrument; we zullen het gebruiken om naar dit instrument te verwijzen wanneer we het bellen. Beschrijving: Gemakkelijk Engels voor de LLM om te lezen (dit is letterlijk waar de AI naar kijkt bij het beslissen of je je tool wilt gebruiken) inputSchema: JSON Schema om te bepalen welke parameters u nodig hebt OutputSchema: Conspicuously missing! Alles geeft gewoon een "grote string" terug en hoopt op het beste Naam Beschrijving Ingangsschema Uitgangsschema Waarom geen output schema? Omdat we allemaal in principe JSON teruggeven verpakt in strings en doen alsof het een ontwerpbeslissing is. Traditionele functies kunnen elk type retourneren, terwijl Unix command-line tools (wat de benaming enigszins impliceert) gewoon tekst uitspuiten. Sommige modellen hebben zelfs schakelaars om de JSON-uitvoer te dwingen, dus in theorie zou je LLM elke keer gestructureerde gegevens kunnen verwachten. Oké, we hebben onze toolbox geladen. laten we onze eerste MCP-tooloproep doen! Stap 4: Het moment van de waarheid Hoe dan ook, we hebben een lijst met hulpmiddelen, nu wat? laten we er een noemen! We selecteren een gereedschap. laten we kiezen om dingen eenvoudig te houden, omdat we geen breedtegraad en lengtegraad nodig hebben. Het zou een betere keuze zijn. get_alerts get_forecast tools_call_request = { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "get_alerts", "arguments": { "state": "TX" } } } Ik koos voor Texas omdat alles daar groter is, inclusief de weerrampen. Wacht, houd vast – waarom is het “tools/call” en niet “tool/call”? Eén Oké, zeker, "tool / call" klinkt meer natuurlijk in het Engels, maar blijkbaar wint consistentie met de andere eindpunten. Met al onze data duiven in een rij kunnen we nu op de Big Red Button drukken. # 3. Send the tools/call request print("// Sending tools/call request...") send_mcp_request(process, tools_call_request) # Read the server's response to the tools/call request tools_call_response = read_mcp_response(process) print("// Received tools call response:", end='') pprint(tools_call_response) [BEEP BEEP BOOP BOOP] (Dit is het geluid dat de grote rode knop maakt) ] [Drumroll please Het denken van de server ... verwerken ... en ... ] [And the crowd goes wild! Waarschuwingen, overstromingen, tornado's, de werken. Alles verpakt in gestructureerde JSON, net zoals uw therapeut besteld: (vernield, niemand wil 11 pagina's van JSON-afval zien) // Sending tools/call request... . . . len is 51305 // Received tools call response:{'id': 3, 'jsonrpc': '2.0', 'result': {'content': [{'text': '\n' 'Event: Flood Advisory\n' 'Area: Hidalgo, TX; Willacy, TX\n' 'Severity: Minor\n' 'Description: * WHAT...Flooding caused by ' 'excessive rainfall continues.\n' '\n' '* WHERE...A portion of Deep South Texas, ' 'including the following\n' 'counties, Hidalgo and Willacy.\n' '\n' '* WHEN...Until 245 PM CDT.\n' '\n' '* IMPACTS...Minor flooding in low-lying and ' 'poor drainage areas.\n' '\n' '* ADDITIONAL DETAILS...\n' '- At 205 PM CDT, Doppler radar indicated ' 'heavy rain due to\n' 'thunderstorms. Minor flooding is ongoing or ' 'expected to begin\n' 'shortly in the advisory area. Between 2 and ' '5 inches of rain\n' 'have fallen.\n' '- Additional rainfall amounts up to 1 inch ' 'are expected over\n' 'the area. This additional rain will result ' 'in minor flooding.\n' '- Some locations that will experience ' 'flooding include...\n' 'Harlingen, Elsa, Edcouch, La Villa, Lasara, ' 'La Villa High\n' 'School, Monte Alto, Jose Borrego Middle ' 'School, Satiago\n' 'Garcia Elementary School, Edcouch Police ' 'Department, Edcouch\n' 'City Hall, Edcouch Volunteer Fire ' 'Department, Edcouch-Elsa\n' 'High School, Laguna Seca, Carlos Truan ' 'Junior High School,\n' 'Elsa Police Department, Lyndon B Johnson ' 'Elementary School,\n' 'Elsa Public Library, Olivarez and Lasara ' 'Elementary School.\n' '- http://www.weather.gov/safety/flood\n' "Instructions: Turn around, don't drown when " 'encountering flooded roads. Most flood\n' '\n' 'The next statement will be issued Tuesday ' 'morning at 830 AM CDT.\n', 'type': 'text'}], 'isError': False}} Merk op dat - Controleer dit veld altijd, tenzij je geniet van het debuggen van mysterieuze mislukkingen om 3 uur 's ochtends. Victory! isError: false We krijgen schone stringgegevens terug (geen streaming om dingen ingewikkeld te maken), wat ons opties geeft. we konden deze weersgegevens analyseren en masseren voor de LLM, of gewoon de ruwe reactie doorgeven en het model laten uitzoeken. Maar als u iets geavanceerds bouwt, kan het voorbewerken van de output van de tool ongelooflijk krachtig zijn.U kunt het formatteren, filteren, combineren met andere gegevensbronnen of het omzetten in precies wat uw applicatie nodig heeft. We hebben met succes een MCP-server geregistreerd, de verbinding geïnitieerd, een tool geroepen en de resultaten verwerkt. And that's a wrap! The Full Monty: uw complete MCP-client Hier is het hele glorieuze ritueel in één oproepende cirkel: import subprocess import json from pprint import pprint def send_mcp_request(process, request): json_request = json.dumps(request) + '\n' process.stdin.write(json_request.encode('utf-8')) process.stdin.flush() def read_mcp_response(process): line = process.stdout.readline().decode('utf-8') return json.loads(line) if line else None requests = { 'init': { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": {"name": "MyMCPClient", "version": "1.0.0"} } }, 'initialized': { "jsonrpc": "2.0", "method": "notifications/initialized" }, 'list_tools': { "jsonrpc": "2.0", "id": 2, "method": "tools/list" }, 'call_tool': { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "get_alerts", "arguments": {"state": "TX"}} } } process = subprocess.Popen( ["uv", "run", "weather.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL ) try: send_mcp_request(process, requests['init']) pprint(read_mcp_response(process)) send_mcp_request(process, requests['initialized']) send_mcp_request(process, requests['list_tools']) tools = read_mcp_response(process) print("Available tools:", [t['name'] for t in tools['result']['tools']]) send_mcp_request(process, requests['call_tool']) result = read_mcp_response(process) print("Weather alert received:", len(result['result']['content'][0]['text']), "characters") finally: process.terminate() De grote openbaring You just built an MCP client using nothing but Python's standard library. Geen frameworks. Geen externe afhankelijkheden. Geen magie. Gewoon subprocespijpen en JSON – dezelfde tools die je hebt gehad sinds Python 2.7. Is dit "productie-ready"? Eerlijk gezegd? Niet helemaal – maar het is verrassend dichtbij. Of het nu Claude spreekt met je database, GPT-4 belt je API's, of een startup's "revolutionaire AI-werkstroomplatform" -onder alles, het is gewoon dit: Spawn process. Send JSON. Read JSON. Repeat. Het is alsof het ontdekken van de tovenaar van Oz is gewoon een man met een echt goed geluidsysteem. Het is alsof het ontdekken van de tovenaar van Oz is gewoon een man met een echt goed geluidsysteem. De volgende stappen naar waanzin Nu je de buik van het beest hebt gezien (in code), kun je: Bouw aangepaste MCP-servers die uw bod doen (niet langer wachten op iemand anders om de integratie te schrijven) Debug MCP-verbindingen zoals een netwerknecromancer wanneer ze onvermijdelijk breken op het slechtst mogelijke moment Ontwerp betere tools door precies te weten hoe LLM's uw metagegevens consumeren Schrijf betere tools zo onweerstaanbaar beschreven dat je LLM's verliefd worden Optimaliseer de hel uit alles omdat je het protocol overhead begrijpt Of gewoon automatiseren uw kat voeder. ik oordeel niet. De prachtige openbaring The miracle in step 2 of your business plan? It was you, all along. Het wonder in stap 2 van je businessplan? Ga iets vreemds bouwen. Wil je deze code in actie zien? Het volledige voorbeeld leeft hier: [https://gitlab.com/-/snippets/4864350] https://gitlab.com/-/snippets/4864350 https://gitlab.com/-/snippets/4864350?embedable=true