MCP сървър с Python: Пълно ръководство за свързване на AI агенти с външни инструменти

Научете как да изградите MCP сървър с Python и FastMCP от нулата. Практическо ръководство с код за свързване на AI агенти с бази данни, API-та и външни инструменти чрез Model Context Protocol.

MCP сървър с Python: Пълно ръководство 2026

Въведение: Защо MCP променя правилата на играта за AI агентите

Ако разработвате AI приложения през 2026 г., почти сигурно вече сте се сблъсквали с този проблем: имате си чудесен LLM, който разсъждава блестящо, генерира код и анализира текст, но в момента, в който трябва да се свърже с база данни, API или файлова система — нещата стават... неудобни. Доскоро единственото решение беше ръчно писане на интеграции за всеки инструмент поотделно. Резултатът? Кошмар от N×M връзки — по една специална интеграция за всяка комбинация от модел и инструмент.

Честно казано, това беше изморително.

Model Context Protocol (MCP) решава точно този проблем. Създаден от Anthropic през ноември 2024 г. и вече предаден на Linux Foundation (чрез Agentic AI Foundation, с подкрепата на OpenAI, Google и Microsoft), MCP е отворен стандарт за комуникация между AI модели и външни системи. Аналогията, която всички обичат да ползват, е USB-C за AI — универсален конектор, който позволява на всяко AI приложение да говори с всяка външна система чрез единен протокол.

Числата са впечатляващи: към март 2026 г. FastMCP (основната Python библиотека за MCP) се изтегля над милион пъти на ден и захранва около 70% от MCP сървърите на всички езици. OpenAI, Google DeepMind, Microsoft и Salesforce вече ползват протокола в продуктите си.

В тази статия ще изградим MCP сървър от нулата с Python. Ще разберем как работи архитектурата, ще създадем реални инструменти за бази данни и API-та, и ще стигнем до продукционно разгръщане с автентикация и сигурност. Хайде да започнем.

Какво представлява Model Context Protocol (MCP)

MCP дефинира клиент-сървър архитектура с три основни компонента:

  • MCP Host — AI приложението (например Claude Desktop, Cursor, VS Code), което координира един или повече MCP клиенти
  • MCP Client — компонент, поддържащ връзка с MCP сървър и предаващ контекст на хоста
  • MCP Server — програма, която предоставя контекст (инструменти, ресурси, шаблони) на клиентите

Протоколът използва JSON-RPC 2.0 за обмен на съобщения. Ако ви звучи познато — да, вдъхновен е от Language Server Protocol (LSP), който реши подобен N×M проблем за код редактори и програмни езици.

Основните примитиви на MCP

Всеки MCP сървър може да предоставя три типа възможности:

  • Tools (Инструменти) — изпълними функции, които LLM може да извика (нещо като POST заявки). Примери: изпълнение на SQL заявка, изпращане на имейл, създаване на файл
  • Resources (Ресурси) — данни за четене, които LLM зарежда в контекста си (нещо като GET заявки). Примери: съдържание на файл, записи от база данни, конфигурации
  • Prompts (Шаблони) — предварително дефинирани шаблони за взаимодействие с LLM, улесняващи потребителите при конкретни задачи

Ключовата разлика между MCP сървър и обикновен REST API е в предназначението. MCP сървърът е проектиран специално за AI модели — предоставя метаданни и структурирани описания, които помагат на модела да разбере кои инструменти са налични, какво правят и кога да ги използва. Моделът сам решава какво да направи, вместо да разчита на твърдо зададени API извиквания. Това е голямата разлика.

Подготовка на средата за разработка

За изграждане на MCP сървър с Python ще ви трябват:

  • Python 3.10 или по-нова версия
  • uv (препоръчителен пакетен мениджър за Python) или pip
  • MCP клиент за тестване — Claude Desktop, Cursor или VS Code с Copilot

Нека инициализираме проекта:

# Инициализиране на проекта с uv
uv init mcp-demo-server
cd mcp-demo-server

# Добавяне на MCP SDK и FastMCP
uv add "mcp[cli]"

# Или с pip:
# pip install "mcp[cli]"

Можете да използвате и самостоятелния пакет FastMCP (версия 3.1.1 към март 2026 г.), който предлага допълнителни възможности извън официалния SDK:

# Самостоятелен FastMCP
uv add fastmcp

# Или с pip:
# pip install fastmcp

Първият ви MCP сървър: Стъпка по стъпка

Достатъчно теория. Нека създадем MCP сървър, който предоставя инструменти за работа с бази данни. Започваме с минимален пример и после ще го разширим.

Минимален MCP сървър

from mcp.server.fastmcp import FastMCP

# Създаване на MCP сървър
mcp = FastMCP("DemoServer", json_response=True)

# Регистриране на инструмент
@mcp.tool()
def add(a: int, b: int) -> int:
    """Събиране на две числа"""
    return a + b

# Регистриране на динамичен ресурс
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Персонализиран поздрав"""
    return f"Здравейте, {name}! Добре дошли в MCP сървъра."

# Регистриране на шаблон
@mcp.prompt()
def summarize(text: str) -> str:
    """Шаблон за обобщаване на текст"""
    return f"Моля, обобщи следния текст в 3 изречения:\n\n{text}"

# Стартиране със stdio транспорт (за локално тестване)
if __name__ == "__main__":
    mcp.run(transport="stdio")

Забележете колко просто е — декорирате обикновени Python функции с @mcp.tool(), @mcp.resource() или @mcp.prompt(), и FastMCP автоматично генерира JSON схемата, валидацията и документацията. Типовите анотации на Python директно се превръщат в описания на параметрите за LLM. Никакъв допълнителен boilerplate.

Свързване с Claude Desktop

За да тествате сървъра, конфигурирайте го в Claude Desktop. Отворете файла claude_desktop_config.json и добавете:

{
  "mcpServers": {
    "demo-server": {
      "command": "uv",
      "args": [
        "--directory",
        "/абсолютен/път/до/mcp-demo-server",
        "run",
        "server.py"
      ]
    }
  }
}

След рестартиране на Claude Desktop, AI асистентът автоматично ще открие наличните инструменти и ще може да ги използва при нужда. Лично на мен ми отнемат буквално секунди — а удовлетворението от „AI-то ми вижда инструментите" е трудно за описване.

Реален пример: MCP сървър за PostgreSQL база данни

Минималният пример е добър за старт, но нека изградим нещо по-сериозно — MCP сървър, който дава на AI агент достъп до PostgreSQL база данни за четене и анализ.

import asyncpg
from mcp.server.fastmcp import FastMCP
from contextlib import asynccontextmanager
from typing import Any

# Конфигурация на сървъра
DATABASE_URL = "postgresql://user:password@localhost:5432/mydb"

mcp = FastMCP("PostgreSQL Explorer", json_response=True)

# Управление на връзката с базата данни чрез lifespan
@asynccontextmanager
async def get_db_pool():
    pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10)
    try:
        yield pool
    finally:
        await pool.close()

# Инструмент за изпълнение на SELECT заявки (само за четене)
@mcp.tool()
async def query_database(sql: str) -> list[dict[str, Any]]:
    """Изпълнява SELECT заявка към PostgreSQL базата данни.
    ВАЖНО: Само SELECT заявки са разрешени за безопасност.
    Примери: SELECT * FROM users LIMIT 10
    """
    # Валидация — само SELECT заявки
    normalized = sql.strip().upper()
    if not normalized.startswith("SELECT"):
        return [{"error": "Само SELECT заявки са разрешени."}]

    # Блокиране на опасни ключови думи
    dangerous_keywords = ["DROP", "DELETE", "INSERT", "UPDATE", "ALTER", "TRUNCATE"]
    for keyword in dangerous_keywords:
        if keyword in normalized:
            return [{"error": f"Заявката съдържа забранена операция: {keyword}"}]

    async with get_db_pool() as pool:
        async with pool.acquire() as conn:
            rows = await conn.fetch(sql)
            return [dict(row) for row in rows]

# Ресурс за списък с таблиците
@mcp.resource("database://tables")
async def list_tables() -> str:
    """Списък на всички таблици в базата данни"""
    async with get_db_pool() as pool:
        async with pool.acquire() as conn:
            rows = await conn.fetch("""
                SELECT table_name, table_type
                FROM information_schema.tables
                WHERE table_schema = 'public'
                ORDER BY table_name
            """)
            result = "Таблици в базата данни:\n"
            for row in rows:
                result += f"- {row['table_name']} ({row['table_type']})\n"
            return result

# Ресурс за схемата на конкретна таблица
@mcp.resource("database://schema/{table_name}")
async def get_table_schema(table_name: str) -> str:
    """Описание на колоните за дадена таблица"""
    # Защита от SQL инжекция — валидиране на името
    if not table_name.isidentifier():
        return "Невалидно име на таблица."

    async with get_db_pool() as pool:
        async with pool.acquire() as conn:
            rows = await conn.fetch("""
                SELECT column_name, data_type, is_nullable, column_default
                FROM information_schema.columns
                WHERE table_name = $1 AND table_schema = 'public'
                ORDER BY ordinal_position
            """, table_name)
            result = f"Схема на таблица '{table_name}':\n"
            for row in rows:
                nullable = "NULL" if row["is_nullable"] == "YES" else "NOT NULL"
                result += f"- {row['column_name']}: {row['data_type']} {nullable}\n"
            return result

# Шаблон за анализ на данни
@mcp.prompt()
def analyze_table(table_name: str) -> str:
    """Шаблон за пълен анализ на таблица от базата данни"""
    return f"""Анализирай таблица '{table_name}' от базата данни. Следвай тези стъпки:
1. Първо провери схемата на таблицата чрез ресурса database://schema/{table_name}
2. Изпълни SELECT COUNT(*) за да видиш броя на записите
3. Покажи примерни записи с LIMIT 5
4. Обобщи структурата и характеристиките на данните"""

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

Този сървър дава на AI агента способност да разглежда структурата на базата данни, да изпълнява заявки за четене и да анализира данни — всичко с вградена защита срещу деструктивни операции и SQL инжекции. Доста солидна основа, нали?

Реален пример: MCP сървър за REST API интеграция

Другият супер честест сценарий е свързване на AI агент към REST API — вътрешен или външен. Ето пример с интеграция към GitHub API:

import httpx
from mcp.server.fastmcp import FastMCP
from typing import Any
import os

mcp = FastMCP("GitHub Integration", json_response=True)

GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "")
BASE_URL = "https://api.github.com"

def github_headers() -> dict[str, str]:
    return {
        "Authorization": f"Bearer {GITHUB_TOKEN}",
        "Accept": "application/vnd.github.v3+json",
        "User-Agent": "MCP-GitHub-Server"
    }

@mcp.tool()
async def list_repo_issues(
    owner: str,
    repo: str,
    state: str = "open",
    limit: int = 10
) -> list[dict[str, Any]]:
    """Списък на issues от GitHub хранилище.
    Параметри:
    - owner: собственик на хранилището (напр. 'anthropics')
    - repo: име на хранилището (напр. 'claude-code')
    - state: 'open', 'closed' или 'all'
    - limit: максимален брой резултати (1-100)
    """
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{BASE_URL}/repos/{owner}/{repo}/issues",
            headers=github_headers(),
            params={"state": state, "per_page": min(limit, 100)}
        )
        response.raise_for_status()
        issues = response.json()
        return [
            {
                "number": issue["number"],
                "title": issue["title"],
                "state": issue["state"],
                "author": issue["user"]["login"],
                "created_at": issue["created_at"],
                "labels": [l["name"] for l in issue["labels"]]
            }
            for issue in issues
        ]

@mcp.tool()
async def search_code(
    query: str,
    language: str = "",
    limit: int = 5
) -> list[dict[str, Any]]:
    """Търсене на код в GitHub.
    Параметри:
    - query: текст за търсене в код
    - language: филтър по език (напр. 'python', 'typescript')
    - limit: максимален брой резултати
    """
    search_query = query
    if language:
        search_query += f" language:{language}"

    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{BASE_URL}/search/code",
            headers=github_headers(),
            params={"q": search_query, "per_page": min(limit, 30)}
        )
        response.raise_for_status()
        data = response.json()
        return [
            {
                "repository": item["repository"]["full_name"],
                "path": item["path"],
                "url": item["html_url"]
            }
            for item in data.get("items", [])
        ]

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

С този подход можете бързо да обвиете практически всеки REST API в MCP сървър — от Jira и Slack до вътрешни бизнес системи. Красотата е, че веднъж написан, сървърът работи с всеки MCP-съвместим клиент.

Транспортни механизми: stdio срещу Streamable HTTP

MCP поддържа два основни транспортни механизма и изборът между тях зависи от контекста на използване.

stdio (Standard Input/Output)

  • Идеален за локална разработка и тестване
  • Комуникацията е синхронна и бърза
  • Не изисква мрежова конфигурация или автентикация
  • Личните ви данни за достъп остават на вашата машина
  • Важно: Никога не пишете в stdout в stdio-базирани сървъри — това ще повреди JSON-RPC съобщенията (попадал съм на този бъг повече пъти, отколкото бих искал да призная)

Streamable HTTP

  • Препоръчителен за продукционна среда
  • Използва единична HTTP крайна точка за GET и POST заявки
  • Поддържа SSE (Server-Sent Events) за стрийминг на отговори
  • Управление на сесии, възстановяване при прекъсване и OAuth интеграция
  • Замени остарелия HTTP+SSE транспорт от март 2025 г.

Ето как да преминете от stdio към Streamable HTTP:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP(
    "Production Server",
    json_response=True,
    stateless_http=True  # Оптимално за мащабиране с множество работници
)

@mcp.tool()
def process_data(input_text: str) -> str:
    """Обработка на текстови данни"""
    return f"Обработен: {input_text.upper()}"

if __name__ == "__main__":
    # Streamable HTTP транспорт за продукционна среда
    mcp.run(transport="streamable-http")

За стартиране с множество работници използвайте uvicorn:

# Стартиране с 4 работника за паралелна обработка
uvicorn server:mcp --host 0.0.0.0 --port 8000 --workers 4

Автентикация и сигурност за продукция

Когато разгръщате MCP сървър в продукционна среда, сигурността е абсолютно критична. Не подценявайте този аспект — MCP сървърите имат реален достъп до системи: бази данни, API-та, файлови системи. Ето основните подходи за защита.

OAuth 2.1 автентикация (препоръчително)

Официалният MCP SDK предоставя пълна поддръжка на OAuth 2.1:

from pydantic import AnyHttpUrl
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
from mcp.server.fastmcp import FastMCP

class JWTTokenVerifier(TokenVerifier):
    """Верификатор на JWT токени"""
    async def verify_token(self, token: str) -> AccessToken | None:
        try:
            # Декодиране и валидиране на JWT токена
            import jwt
            payload = jwt.decode(
                token,
                key="your-secret-key",
                algorithms=["HS256"]
            )
            return AccessToken(
                token=token,
                client_id=payload.get("client_id", ""),
                scopes=payload.get("scopes", []),
                expires_at=payload.get("exp")
            )
        except jwt.InvalidTokenError:
            return None

mcp = FastMCP(
    "Secure API Server",
    json_response=True,
    token_verifier=JWTTokenVerifier(),
    auth=AuthSettings(
        issuer_url=AnyHttpUrl("https://auth.example.com"),
        resource_server_url=AnyHttpUrl("https://mcp.example.com"),
        required_scopes=["read", "tools"],
    ),
)

@mcp.tool()
async def get_sensitive_data(query: str) -> dict:
    """Достъп до чувствителни данни (изисква автентикация)"""
    return {"data": f"Резултат за: {query}"}

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

Добри практики за сигурност

Следвайте OWASP MCP Top 10 препоръките — ето най-важните:

  1. Принцип на минималните привилегии — давайте на всеки сървър минимално необходимия достъп. Ако сървърът трябва само да чете от базата данни — използвайте read-only потребител. Без изключения
  2. Използвайте secrets manager — никога не записвайте API ключове в MCP конфигурацията. Използвайте HashiCorp Vault, AWS Secrets Manager или нещо подобно
  3. Стартирайте сървъри в изолирана среда — контейнери или sandbox-и за сървъри с висок риск (файлова система, терминал, бази данни)
  4. Логвайте всяко действие — записвайте кой клиент е извикал кой инструмент с какви аргументи. Ще ви трябва при дебъгване
  5. Защита от prompt injection — валидирайте входните данни и не позволявайте на потребителски вход да манипулира поведението на инструментите

Разгръщане с Nginx и TLS

За продукционно разгръщане зад обратен прокси, Streamable HTTP транспортът изисква специфична Nginx конфигурация заради SSE стрийминга. Ето конфигурация, която работи:

server {
    listen 443 ssl;
    server_name mcp.example.com;

    ssl_certificate /etc/ssl/certs/mcp.crt;
    ssl_certificate_key /etc/ssl/private/mcp.key;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Connection "";

        # Критично за SSE стрийминг
        proxy_buffering off;
        proxy_cache off;

        # Таймаути за дълготрайни SSE връзки
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Двете най-важни настройки тук са proxy_buffering off и proxy_cache off — без тях SSE стриймингът просто няма да работи коректно.

Кога да използвате MCP и кога — не

MCP не е универсален отговор на всичко. Ето кратък и честен справочник.

Използвайте MCP когато:

  • Основният потребител на интеграцията е AI модел или агент
  • Имате 3 или повече интеграции, които трябва да работят заедно
  • Искате да използвате един сървър с множество AI клиенти (Claude, ChatGPT, Cursor)
  • Изграждате автономни AI агенти, които трябва динамично да избират инструменти

Не използвайте MCP когато:

  • Нуждаете се от обикновен уеб API за не-AI приложения — REST/GraphQL си е достатъчен
  • Имате единична, проста интеграция — директно API извикване е по-лесно и по-бързо
  • Приложението ви не включва LLM компонент изобщо

Екосистема и готови MCP сървъри

Добрата новина е, че не е нужно да пишете всичко от нулата. Към 2026 г. вече съществуват стотици готови MCP сървъри за най-популярните услуги:

  • Бази данни: PostgreSQL, Supabase, DynamoDB, MindsDB
  • Код и DevOps: GitHub, Git, Docker, Azure DevOps
  • Комуникация: Slack, Gmail, Microsoft Teams
  • Облак: AWS, Azure, Google Cloud
  • Бизнес: Stripe, Jira, Salesforce, HubSpot

Можете да разгледате пълния регистър на mcpservers.org или в официалното GitHub хранилище на MCP. Преди да пишете свой сървър, проверете дали вече не съществува такъв — често има.

Често задавани въпроси

Каква е разликата между MCP сървър и REST API?

REST API е предназначен за общо потребление от уеб и мобилни приложения. MCP сървърът е специално проектиран за AI модели — предоставя структурирани описания на инструментите, метаданни и контекст, които помагат на модела да реши кога и как да ги използва. Ако основният потребител е AI — изберете MCP. За традиционно приложение — REST/GraphQL.

Мога ли да използвам MCP с OpenAI, Claude и други модели едновременно?

Да, и точно в това е цялата идея. Един MCP сървър работи с всеки съвместим клиент — Claude Desktop, ChatGPT, Cursor, VS Code Copilot, IBM BeeAI и много други. Изграждате сървъра веднъж и го използвате навсякъде. OpenAI официално приеха MCP през март 2025 г., а Google DeepMind последваха малко след това.

Безопасно ли е да давам на AI агент достъп до базата ми данни чрез MCP?

С правилните предпазни мерки — да. Използвайте read-only потребител за базата данни, валидирайте заявките (само SELECT), блокирайте опасни ключови думи, логвайте всяко действие и стартирайте сървъра в изолирана среда. За продукция задължително добавете OAuth автентикация и TLS криптиране. Между другото, Supabase препоръчва да използвате MCP само с разработъчни (не продукционни) бази данни — добър съвет за начало.

Какъв е препоръчителният транспорт за продукционна среда?

Streamable HTTP — без въпрос. Той е стандартът за продукционни разгръщания от март 2025 г. Поддържа управление на сесии, възстановяване при прекъсване, OAuth интеграция и мащабиране с множество работници чрез uvicorn. Stdio е подходящ само за локално тестване.

Какви са текущите ограничения на MCP през 2026 г.?

Въпреки широкото приемане, MCP все още се развива активно. Основните предизвикателства: сигурностните практики все още се стандартизират (следете OWASP MCP Top 10), не всички AI клиенти поддържат всички MCP функции еднакво, и няма официален регистър за верификация на сървъри — внимавайте за подправени такива. Пътната карта за 2026 г. се фокусира върху корпоративна готовност: одитни следи, SSO интеграция и конфигурационна преносимост.

Article changelog (1)
  • — SEO meta refreshed (title and description updated)
За Автора Yuki Tanaka

Yuki is a former Stripe data engineer (2017-2022) who spent her last eighteen months there building the internal Airflow-to-dbt migration tooling used by the revenue team. She left to join a 12-person AI startup as employee #4, where she shipped a LangChain-based contract-review pipeline now processing roughly 40,000 documents a month for mid-market legal teams. She's deep on the retrieval side: chunking strategies that don't shred tables, hybrid BM25+dense rerankers, and the surprisingly hard problem of evaluating RAG quality without paying for human raters. Her PR adding parent-document retriever support to LlamaIndex's PostgreSQL store landed in late 2024. Nine years in data and ML platform work. Based in Seattle, mostly writes Python, reluctantly writes TypeScript when n8n forces her hand.