Cursor IDE умеет генерировать код, рефакторить, объяснять и дебажить. Но по умолчанию он видит только файлы в вашем проекте. Если нужно, чтобы агент сходил в Google Trends, проверил задачи в Jira или прочитал что-то из Notion, приходится копировать данные руками и вставлять в чат. Агент получается не особо автономным, каждый шаг требует вашего участия.

MCP даёт агенту инструменты — функции, которые тот вызывает сам, когда ему нужны внешние данные. Вместо «вот тебе CSV, проанализируй» вы пишете «проанализируй тренды по запросу X», и агент сам вызывает нужную функцию, получает данные и работает с ними.

Как устроен MCP

MCP — открытый протокол, который стандартизирует подключение инструментов к языковым моделям. До него каждый фреймворк делал по-своему: у LangChain свои tools, у OpenAI function calling, у Cursor свой формат. MCP ввёл единый стандарт.

MCP-сервер — программа, которая запускается локально и экспортирует инструменты через стандартный протокол. Каждый инструмент имеет имя, описание и схему параметров. Cursor видит список инструментов и вызывает нужный, когда считает это полезным для ответа.

Без MCP агент знает только файлы в проекте и ваше сообщение. С MCP он может запросить данные из внешнего API, прочитать документ из базы знаний, выполнить SQL-запрос, вызвать скрипт. Агент сам решает, какой инструмент вызвать, формирует запрос, получает ответ и продолжает работу.

Подключаем MCP-сервер к Cursor

Конфигурация живёт в .cursor/mcp.json в корне проекта:

{
  "mcpServers": {
    "google-trends": {
      "command": "python",
      "args": ["-m", "trends_server"],
      "env": {
        "SERPAPI_KEY": "your-key-here"
      }
    }
  }
}

Cursor запускает сервер как дочерний процесс, общается через stdin/stdout по протоколу MCP. После перезапуска Cursor видит инструменты сервера и может их использовать.

Можно подключить несколько серверов одновременно:

{
  "mcpServers": {
    "google-trends": {
      "command": "python",
      "args": ["-m", "trends_server"]
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_URL": "postgresql://user:pass@localhost:5432/mydb"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/docs"]
    }
  }
}

Три сервера: Google Trends для аналитики, PostgreSQL для запросов к базе, файловая система для чтения документов за пределами проекта. Агент видит инструменты всех трёх и комбинирует их в одном запросе.

Пишем MCP-сервер для Google Trends

MCP-сервер на Python через библиотеку mcp:

from mcp.server.fastmcp import FastMCP
from pytrends.request import TrendReq
import json

mcp = FastMCP("google-trends")
pytrends = TrendReq(hl="ru", tz=180)  # русский язык, московское время

@mcp.tool()
def get_interest_over_time(query: str, timeframe: str = "today 3-m") -> str:
    """Получить динамику интереса к запросу за период.
    
    Аргументы:
        query: поисковый запрос (например 'machine learning')
        timeframe: период ('today 3-m', 'today 12-m', '2024-01-01 2024-12-31')
    
    Возвращает JSON с данными по неделям.
    """
    pytrends.build_payload([query], timeframe=timeframe)
    df = pytrends.interest_over_time()
    if df.empty:
        return json.dumps({"error": f"Нет данных для '{query}'"})
    
    # Убираем колонку isPartial, она мешает анализу
    if "isPartial" in df.columns:
        df = df.drop(columns=["isPartial"])
    
    return df.to_json(date_format="iso")

@mcp.tool()
def get_related_queries(query: str) -> str:
    """Получить связанные запросы: топ (самые частые) и растущие (с наибольшим ростом).
    
    Аргументы:
        query: поисковый запрос
    
    Растущие запросы с пометкой 'Breakout' выросли более чем на 5000%.
    """
    pytrends.build_payload([query], timeframe="today 3-m")
    related = pytrends.related_queries()
    
    result = {}
    for key in related:
        rising = related[key].get("rising")
        top = related[key].get("top")
        result[key] = {
            "rising": rising.to_dict() if rising is not None else {},
            "top": top.to_dict() if top is not None else {},
        }
    return json.dumps(result, ensure_ascii=False, default=str)

@mcp.tool()
def compare_queries(queries: list[str], timeframe: str = "today 3-m") -> str:
    """Сравнить до 5 запросов по динамике интереса.
    
    Аргументы:
        queries: список запросов для сравнения (максимум 5)
        timeframe: период
    
    Значения нормализованы: 100 = пик интереса, остальные относительно него.
    """
    if len(queries) > 5:
        return json.dumps({"error": "Максимум 5 запросов"})
    
    pytrends.build_payload(queries, timeframe=timeframe)
    df = pytrends.interest_over_time()
    
    if "isPartial" in df.columns:
        df = df.drop(columns=["isPartial"])
    
    return df.to_json(date_format="iso")

@mcp.tool()
def get_trending_searches(country: str = "russia") -> str:
    """Получить сегодняшние трендовые поисковые запросы в стране.
    
    Аргументы:
        country: страна ('russia', 'united_states', 'germany')
    """
    trending = pytrends.trending_searches(pn=country)
    return trending.to_json(force_ascii=False)

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

Четыре инструмента: динамика интереса, связанные запросы, сравнение, трендовые запросы дня. Docstring каждого инструмента подробный — Cursor показывает его агенту как описание, и чем точнее описание, тем лучше агент понимает, когда какой инструмент вызвать.

Устанавливаем:

pip install mcp pytrends

Прописываем в .cursor/mcp.json, перезапускаем Cursor. Пишем в чат: «Проанализируй тренды по "AI coding assistant", найди растущие запросы и сравни топ-3 между собой». Cursor сам вызовет get_interest_over_time, потом get_related_queries, выберет три самых растущих, вызовет compare_queries и выдаст анализ. Один промпт, три вызова инструментов, ноль копирования.

MCP-сервер для своей базы данных

Допустим, у вас PostgreSQL с метриками продукта. Можно использовать готовый @modelcontextprotocol/server-postgres, а можно написать свой с контролем над тем, какие запросы допустимы:

from mcp.server.fastmcp import FastMCP
import asyncpg
import json

mcp = FastMCP("product-metrics")

DB_URL = "postgresql://readonly:pass@localhost:5432/analytics"

@mcp.tool()
async def get_daily_signups(days: int = 30) -> str:
    """Получить количество регистраций по дням за последние N дней."""
    conn = await asyncpg.connect(DB_URL)
    try:
        rows = await conn.fetch("""
            SELECT date_trunc('day', created_at) as day, count(*) as signups
            FROM users
            WHERE created_at > now() - interval '$1 days'
            GROUP BY 1 ORDER BY 1
        """, days)
        return json.dumps([{"day": str(r["day"].date()), "signups": r["signups"]} for r in rows])
    finally:
        await conn.close()

@mcp.tool()
async def get_feature_usage(feature_name: str, days: int = 7) -> str:
    """Получить статистику использования фичи: DAU, количество событий, среднее на пользователя."""
    conn = await asyncpg.connect(DB_URL)
    try:
        rows = await conn.fetch("""
            SELECT 
                date_trunc('day', timestamp) as day,
                count(distinct user_id) as dau,
                count(*) as events,
                round(count(*)::numeric / nullif(count(distinct user_id), 0), 1) as avg_per_user
            FROM events
            WHERE feature = $1 AND timestamp > now() - interval '$2 days'
            GROUP BY 1 ORDER BY 1
        """, feature_name, days)
        return json.dumps([dict(r) for r in rows], default=str)
    finally:
        await conn.close()

@mcp.tool()
async def get_retention(cohort_month: str) -> str:
    """Получить retention когорты по месяцам. cohort_month в формате '2026-01'."""
    conn = await asyncpg.connect(DB_URL)
    try:
        rows = await conn.fetch("""
            SELECT 
                months_since_signup,
                count(distinct user_id) as active_users,
                round(100.0 * count(distinct user_id) / 
                    first_value(count(distinct user_id)) over (order by months_since_signup), 1) as retention_pct
            FROM user_activity_monthly
            WHERE cohort = $1
            GROUP BY 1 ORDER BY 1
        """, cohort_month)
        return json.dumps([dict(r) for r in rows], default=str)
    finally:
        await conn.close()

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

Подключение через read-only пользователя БД — агент может читать, но не может менять данные. В конфигурации:

{
  "mcpServers": {
    "product-metrics": {
      "command": "python",
      "args": ["-m", "metrics_server"],
      "env": {
        "DATABASE_URL": "postgresql://readonly:pass@localhost:5432/analytics"
      }
    }
  }
}

Теперь в Cursor можно писать: «Покажи retention январской когорты и сравни с использованием фичи onboarding за последний месяц». Агент вызовет get_retention("2026-01") и get_feature_usage("onboarding", 30), получит данные и проанализирует корреляцию.

Связка с LangGraph: многошаговый агент

Cursor с MCP хорош для разовых запросов. LangGraph описывает граф, где каждый узел может вызывать инструменты. MCP-инструменты подключаются через ToolNode:

from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode
from langchain_anthropic import ChatAnthropic
from langchain_core.tools import tool

# Инструменты (те же, что в MCP-сервере, но как LangChain tools)
@tool
def get_trends(query: str) -> str:
    """Получить данные Google Trends."""
    pytrends.build_payload([query], timeframe="today 3-m")
    return pytrends.interest_over_time().to_json()

@tool
def get_related(query: str) -> str:
    """Получить связанные запросы."""
    pytrends.build_payload([query], timeframe="today 3-m")
    related = pytrends.related_queries()
    rising = related[query].get("rising")
    return rising.to_json() if rising is not None else "{}"

@tool
def compare(queries: list[str]) -> str:
    """Сравнить до 5 запросов."""
    pytrends.build_payload(queries[:5], timeframe="today 3-m")
    return pytrends.interest_over_time().to_json()

tools = [get_trends, get_related, compare]

# Состояние графа
class State(TypedDict):
    messages: list
    iteration: int

# LLM с инструментами
llm = ChatAnthropic(model="claude-sonnet-4-20250514").bind_tools(tools)

def analyst(state: State) -> dict:
    """Узел-аналитик: решает, какой инструмент вызвать."""
    response = llm.invoke(state["messages"])
    return {"messages": state["messages"] + [response]}

def should_continue(state: State) -> str:
    """Условное ребро: есть ли вызовы инструментов?"""
    last = state["messages"][-1]
    if hasattr(last, "tool_calls") and last.tool_calls:
        return "tools"
    return "end"

# Сборка графа
workflow = StateGraph(State)
workflow.add_node("analyst", analyst)
workflow.add_node("tools", ToolNode(tools))

workflow.add_edge(START, "analyst")
workflow.add_conditional_edges("analyst", should_continue, {"tools": "tools", "end": END})
workflow.add_edge("tools", "analyst")  # после вызова инструмента — обратно к аналитику

agent = workflow.compile()

# Запуск
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "Найди растущие темы в области 'AI coding' и сравни топ-3"
    }],
    "iteration": 0,
})

Граф работает в цикле: аналитик решает, какой инструмент вызвать, ToolNode вызывает, результат возвращается аналитику, он решает, нужно ли ещё, и так пока не будет достаточно данных для ответа.

Три уровня использования одних и тех же инструментов. Cursor с MCP для быстрых вопросов в чате. LangGraph с теми же инструментами для многошаговых сценариев. Cursor как IDE для разработки и отладки самого агента.


MCP не делает агента умнее, он делает его полезнее. Модель та же, но вместо работы в вакууме она получает доступ к реальным данным: трендам, метрикам, базе, документам. Написать свой MCP-сервер — дело на пару часов, а эффект ощутимый: один промпт вместо пяти минут копирования данных из разных источников. Если добавить сверху LangGraph, получается агент, который не просто отвечает на вопрос, а проводит многошаговый анализ и сам решает, когда копнуть глубже.

Если у вас есть чем поделиться, пишите в комментариях.

В продолжение темы сегодня вечером, 6 мая в 20:00, пройдет бесплатный открытый урок на тему «LangGraph + MCP в Cursor IDE: создаем автономного агента для глубокого анализа Google Trends».

На занятии разберем, как связать LangGraph, MCP и Cursor IDE в одном прикладном сценарии: от подключения инструментов до агента, который ищет аномалии в Google Trends, сравнивает запросы и помогает находить темы с быстрым ростом интереса. Заодно можно будет посмотреть на формат обучения, познакомиться с экспертом курса «Разработка ИИ-агентов» Артёмом Ревой и задать вопросы. Записаться на урок.

Полный список бесплатных уроков мая смотрите в дайджесте.

Комментарии (1)


  1. eldarkorneev
    06.05.2026 06:56

    Спасибо, актуально и очень кстати.
    Если потребуется, можно приходить в лс с вопросами?