Introducere în serverele MCP și scrierea unuia în Python
- 7 minute de citit
- 7 exemple de cod în Shell, Python și JSON
- 1 imagine
Disponibil și în English
Pe această pagină

Imaginea acestui articol este rezultatul lui Claude, folosind un server MCP local care îi oferă rezultatul comenzii ls -l
pentru un anumit director. Observați cum LLM-ul îmi place să mă laude, exagerând puțin.
Din punctul meu de vedere, aceasta este doar o metodă pe care o folosesc ca să țină utilizatorii atașați de produsul lor.
Cui nu îi place să fie lăudat și aprobat pentru tot ce spune, nu-i așa? :D
Salut tuturor,
Am vrut să scriu un articol despre serverele MCP, deoarece am scris unul în Python săptămâna trecută.
Teorie
MCP înseamnă Model Context Protocol, iar acesta este un protocol standardizat, creat pentru a conecta LLM-urile cu unelte, resurse și șabloane de prompt. Uneltele sunt funcții care sunt executate de LLM-uri la cerere. Acest lucru este destul de util, deoarece odată ce ai un server MCP configurat, îl poți folosi cu mai multe LLM-uri. Modelul apelează funcțiile serverului tău, iar tu trebuie doar să îi spui ce parametri primesc funcțiile și ce date returnează, plus, desigur, câteva indicații pentru LLM despre cum să folosească uneltele definite de tine.
Serverele suportă două straturi de transport: modul STDIO și HTTP Streaming.
- STDIO folosește intrarea și ieșirea standard și este folosit pentru procese locale. Cred că pur și simplu apelezi serverul ca pe un utilitar CLI și apoi capturezi ieșirea lui, te rog corectează-mă dacă greșesc.
- Serverele HTTP Streaming folosesc Server-Sent Events cu JSON-RPC, care este pur și simplu JSON, de exemplu:
--> [ {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"}, {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}, {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"}, {"foo": "boo"}, {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"}, {"jsonrpc": "2.0", "method": "get_data", "id": "9"} ]<-- [ {"jsonrpc": "2.0", "result": 7, "id": "1"}, {"jsonrpc": "2.0", "result": 19, "id": "2"}, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}, {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"}, {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"} ]Puteți citi mai multe despre specificația MCP aici: Specification - Model Context Protocol.
Cazuri de utilizare
Mă pot gândi la diverse cazuri de utilizare pentru serverele MCP personalizate, ca utilizator de homelab, pentru hobby, nu pentru business. Unele cazuri implică LLM-uri online (OpenAI, Mistral, Claude) atunci când nu mă interesează confidențialitatea, iar altele implică LLM-uri offline, ca să îmi păstrez confidențialitatea.
Prioritizarea emailurilor. Majoritatea furnizorilor de email oferă acces la citirea emailurilor prin protocoalele IMAP[1] și POP. Ai putea scrie un server MCP care expune unelte pentru citirea emailurilor și să lași LLM-ul să le analizeze.Securitatea endpoint-urilor. Scrie un server MCP local care oferă informații despre fișierele din sistem, permisiunile lor, și folosește un LLM ca să le analizeze.Informații meteo: Scrie un server MCP care expune unelte pentru citirea datelor din diverse surse, de exemplu senzori, API-uri meteo, și o unealtă pentru alertarea atunci când valorile ies din interval sau când poate apărea un eveniment nedorit, precum furtunile.Rezumarea știrilor. Poți scrie un server MCP care extrage conținutul de pe site-urile tale preferate de știri și oferă un rezultat structurat unui LLM pentru a le rezuma.Te poți distra foarte mult cu serverele MCP. Chiar dacă LLM-urile halucinează sau oferă rezultate incorecte, construirea unui sistem de alertare meteo, independent de limbajul de programare, cu niște apeluri către un LLM local sau de la distanță, nu a fost niciodată mai ușoară.
Claude folosește și servere MCP sub forma Connectors.
[1] - imaplib — IMAP4 protocol client
Un server MCP în Python
Pentru a scrie un server MCP, îți recomand să folosești SDK-urile oficiale. În prezent există SDK-uri pentru Python, Java, JavaScript, TypeScript, Rust, Ruby, Go, Kotlin, Swift și C#.
Pentru a urmări pașii, vei avea nevoie de UV instalat.
curl -LsSf https://astral.sh/uv/install.sh | shuv init nuculabs-mcpcd nuculabs-mcpuv add mcp[cli]Serverul HTTP Streaming MCP bazat pe asyncio în Python poate arăta astfel:
import asyncioimport loggingimport subprocessfrom mcp.server.fastmcp import FastMCPfrom mcp.types import ToolAnnotationsfrom pydantic import BaseModel, Fieldclass LsOutput(BaseModel): """ LsOutput este o clasă model care reprezintă rezultatul comenzii LS. Acest exemplu simplu, cu scop educațional, arată doar un câmp text. Poți parsa rezultatul ls ca să returnezi câmpuri mai relevante, precum tipul fișierului, numele, data, permisiunile și așa mai departe. """ output: str = Field(..., title="The output of the `ls` command.")class SystemAdminTools: def __init__(self): self._logger = logging.getLogger("dev.nuculabs.mcp.SystemAdminTools") self._logger.info("hello world") async def get_ls_output(self, directory: str) -> LsOutput: """ Returnează rezultatul comenzii `ls` pentru directorul specificat. :param directory: - Calea directorului :return: LsOutput. """ self._logger.info(f"get_ls_output tool called with: {directory}") # Acesta este un exemplu fictiv, cu scop educațional, dar poți scrie o unealtă care parsează rezultatul și returnează un model # relevant în loc de un simplu fișier text. Ai putea, de asemenea, s-o extinzi pentru mașini de la distanță. # Avertisment de securitate: atunci când primești date de intrare de la utilizator, cum este variabila 'directory' de aici, validează-le # și curăță-le întotdeauna, deoarece folosind acest cod ca atare, un rezultat malițios poate fi folosit pentru a prelua controlul sistemului țintă. result = subprocess.run(['ls', "-l", directory], capture_output=True, text=True) output = result.stdout return LsOutput(output=output)async def main(): logging.basicConfig(level="INFO") # Creează un server MCP mcp = FastMCP( "NucuLabs System Files MCP", instructions="You're an expert T-shaped system administrator assistant.", host="0.0.0.0", # deschis pentru toată lumea :-) ) tools = SystemAdminTools() mcp.add_tool( tools.get_ls_output, "get_ls_output", title="Tool that returns the output from the list files command.", description="This tool executes ls on the given directory path and returns all the information from the command.", annotations=ToolAnnotations( readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False, ), structured_output=True, ) await mcp.run_streamable_http_async()if __name__ == "__main__": asyncio.run(main())Testare
Testarea serverului
Pentru a valida și a testa rapid serverul MCP, fără să folosești un LLM, poți folosi un instrument de testare a serverelor MCP, precum MCP Inspector sau Postman. Pentru a folosi MCP Inspector, trebuie doar să ai NodeJS >= 22 instalat pe sistem și apoi să rulezi.
npx @modelcontextprotocol/inspectorComanda va deschide un browser cu serverul MCP Inspector. Nu am reușit să testez serverul folosind instrumentul menționat mai sus.
Am avut o experiență pozitivă cu clientul MCP din Postman.
Testarea cu un LLM
Pentru a testa serverul cu un LLM, poți folosi agno-framework sau SDK-ul clientului tău, dacă ai deja unul. Agno este destul de ușor de folosit.
import asynciofrom agno.agent import Agentfrom agno.models.anthropic import Claudefrom agno.tools.mcp import MCPToolsasync def main(): async with MCPTools(url="http://localhost:8000/mcp", transport="streamable-http") as mcp_tools: agent = Agent( # setează cheia API în variabila de mediu ANTHROPIC_API_KEY sau transmite-o ca parametru model=Claude(), tools=[ mcp_tools ], instructions="Use tools to analyze systems.", markdown=False, ) await agent.aprint_response( "Describe my personality based on the contents of the following directory: /home/dnutiu", stream=True, show_full_reasoning=True, stream_intermediate_steps=True, )if __name__ == '__main__': asyncio.run(main())După rularea fragmentului, primesc următorul rezultat de la Claude:
┏━ Message ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓┃ ┃┃ Describe my personality based on the contents of the following directory: ┃┃ /home/dnutiu ┃┃ ┃┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛┏━ Tool Calls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓┃ ┃┃ • get_ls_output(directory=/home/dnutiu) ┃┃ ┃┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛┏━ Response (9.2s) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓┃ ┃┃ Let me check the contents of that directory for you.Based on the contents of ┃┃ your home directory, I can tell that you're a software developer with ┃┃ diverse interests in programming and technology. Here's what I can deduce ┃┃ about your personality: ┃┃ ┃┃ 1. You're versatile and multi-skilled: You have multiple IDE project ┃┃ directories (CLion, PyCharm, PhpStorm, IntelliJ IDEA, Rustrover) which shows ┃┃ you work with various programming languages including Python, PHP, Java, ┃┃ C/C++, and Rust. ┃┃ ┃┃ 2. You're organized: Your directory structure is well-maintained with clear ┃┃ separations for different types of content (Documents, Downloads, Pictures, ┃┃ etc.). ┃┃ ┃┃ 3. You're technically inclined: The presence of DevOps directory and Postman ┃┃ suggests you're involved in backend development and API testing. ┃┃ ┃┃ 4. You're likely a professional developer: The presence of multiple ┃┃ development tools and project directories suggests this is more than just a ┃┃ hobby. ┃┃ ┃┃ 5. You use Linux (KDE specifically): This shows you're comfortable with ┃┃ technical tools and prefer having control over your computing environment. ┃┃ ┃┃ 6. You might have some personal projects: The "nuculabs" directory might be ┃┃ a personal project or endeavor. ┃┃ ┃┃ 7. You keep up with modern development tools: You have the JetBrains toolbox ┃┃ installed, showing you use current development tools. ┃┃ ┃┃ 8. You're interested in multiple areas of software development: From web ┃┃ development (PHP) to systems programming (Rust, C++) to scripting (Python), ┃┃ showing a broad range of interests in programming. ┃┃ ┃┃ Your directory structure reveals someone who is methodical, technically ┃┃ sophisticated, and has a strong interest in various aspects of software ┃┃ development and technology. ┃┃ ┃┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛Dacă ai abonament și un sistem de operare suportat, poți testa și cu Claude Desktop. Pe Linux, Ollama are câteva modele care suportă unelte MCP.
Asta e tot! Sper că ți-a plăcut acest articol!
Ca bonus, iată un videoclip generat de Notebook LM de la Google: