38 KiB
Сообщество и вклад
(Нажмите на изображение выше, чтобы посмотреть видео этого урока)
Обзор
Этот урок посвящён тому, как взаимодействовать с сообществом MCP, вносить вклад в экосистему MCP и следовать лучшим практикам совместной разработки. Понимание того, как участвовать в проектах MCP с открытым исходным кодом, важно для тех, кто хочет формировать будущее этой технологии.
Цели обучения
К концу этого урока вы сможете:
- Понять структуру сообщества и экосистемы MCP
- Эффективно участвовать в форумах и обсуждениях сообщества MCP
- Вносить вклад в репозитории MCP с открытым исходным кодом
- Создавать и делиться собственными инструментами и серверами MCP
- Следовать лучшим практикам разработки и сотрудничества в MCP
- Открывать ресурсы сообщества и фреймворки для разработки MCP
Экосистема сообщества MCP
Экосистема MCP состоит из различных компонентов и участников, которые совместно работают над развитием протокола.
Основные компоненты сообщества
- Поддерживающие основной протокол: Официальная GitHub организация Model Context Protocol поддерживает основные спецификации MCP и эталонные реализации
- Разработчики инструментов: Индивидуалы и команды, создающие инструменты и серверы MCP
- Поставщики интеграций: Компании, интегрирующие MCP в свои продукты и сервисы
- Конечные пользователи: Разработчики и организации, использующие MCP в своих приложениях
- Участники сообщества: Члены сообщества, которые вносят код, документацию или другие ресурсы
Ресурсы сообщества
Официальные каналы
- GitHub организация MCP
- Документация MCP
- Спецификация MCP
- Обсуждения на GitHub
- Репозиторий примеров и серверов MCP
Ресурсы сообщества, управляемые участниками
- Клиенты MCP – список клиентов, поддерживающих интеграции MCP
- Серверы сообщества MCP – растущий список серверов MCP, разработанных сообществом
- Awesome MCP Servers – курируемый список серверов MCP
- PulseMCP – центр сообщества и рассылка для поиска ресурсов MCP
- Discord сервер – общение с разработчиками MCP
- Реализации SDK на различных языках
- Блоги и руководства
Внесение вклада в MCP
Типы вклада
Экосистема MCP приветствует различные виды вклада:
-
Вклад в код:
- Улучшения основного протокола
- Исправления ошибок
- Реализации инструментов и серверов
- Библиотеки клиента/сервера на разных языках
-
Документация:
- Улучшение существующей документации
- Создание руководств и туториалов
- Переводы документации
- Создание примеров и демо-приложений
-
Поддержка сообщества:
- Ответы на вопросы на форумах и обсуждениях
- Тестирование и сообщение об ошибках
- Организация мероприятий сообщества
- Наставничество новых участников
Процесс внесения вклада: основной протокол
Чтобы внести вклад в основной MCP протокол или официальные реализации, следуйте принципам из официальных руководств по внесению вклада:
-
Простота и минимализм: Спецификация MCP поддерживает высокий барьер для добавления новых концепций. Легче добавить новую вещь, чем потом её удалить.
-
Конкретный подход: Изменения в спецификации должны основываться на конкретных задачах реализации, а не на гипотетических идеях.
-
Этапы предложения:
- Определение: исследуйте проблему, подтвердите, что другие пользователи MCP сталкиваются с похожей задачей
- Прототипирование: создайте пример решения и покажите его практическое применение
- Написание: на основе прототипа напишите предложение по спецификации
Настройка среды разработки
# Форкнуть репозиторий
git clone https://github.com/YOUR-USERNAME/modelcontextprotocol.git
cd modelcontextprotocol
# Установить зависимости
npm install
# Для изменений схемы, проверить и сгенерировать schema.json:
npm run check:schema:ts
npm run generate:schema
# Для изменений документации
npm run check:docs
npm run format
# Предварительный просмотр документации локально (по желанию):
npm run serve:docs
Пример: Внесение исправления ошибки
// Оригинальный код с ошибкой в typescript-sdk
export function validateResource(resource: unknown): resource is MCPResource {
if (!resource || typeof resource !== 'object') {
return false;
}
// Ошибка: Отсутствует проверка свойства
// Текущая реализация:
const hasName = 'name' in resource;
const hasSchema = 'schema' in resource;
return hasName && hasSchema;
}
// Исправленная реализация в вкладе
export function validateResource(resource: unknown): resource is MCPResource {
if (!resource || typeof resource !== 'object') {
return false;
}
// Улучшенная проверка
const hasName = 'name' in resource && typeof (resource as MCPResource).name === 'string';
const hasSchema = 'schema' in resource && typeof (resource as MCPResource).schema === 'object';
const hasDescription = !('description' in resource) || typeof (resource as MCPResource).description === 'string';
return hasName && hasSchema && hasDescription;
}
Пример: Добавление нового инструмента в стандартную библиотеку
# Пример вклада: инструмент обработки данных CSV для стандартной библиотеки MCP
from mcp_tools import Tool, ToolRequest, ToolResponse, ToolExecutionException
import pandas as pd
import io
import json
from typing import Dict, Any, List, Optional
class CsvProcessingTool(Tool):
"""
Tool for processing and analyzing CSV data.
This tool allows models to extract information from CSV files,
run basic analysis, and convert data between formats.
"""
def get_name(self):
return "csvProcessor"
def get_description(self):
return "Processes and analyzes CSV data"
def get_schema(self):
return {
"type": "object",
"properties": {
"csvData": {
"type": "string",
"description": "CSV data as a string"
},
"csvUrl": {
"type": "string",
"description": "URL to a CSV file (alternative to csvData)"
},
"operation": {
"type": "string",
"enum": ["summary", "filter", "transform", "convert"],
"description": "Operation to perform on the CSV data"
},
"filterColumn": {
"type": "string",
"description": "Column to filter by (for filter operation)"
},
"filterValue": {
"type": "string",
"description": "Value to filter for (for filter operation)"
},
"outputFormat": {
"type": "string",
"enum": ["json", "csv", "markdown"],
"default": "json",
"description": "Output format for the processed data"
}
},
"oneOf": [
{"required": ["csvData", "operation"]},
{"required": ["csvUrl", "operation"]}
]
}
async def execute_async(self, request: ToolRequest) -> ToolResponse:
try:
# Извлечь параметры
operation = request.parameters.get("operation")
output_format = request.parameters.get("outputFormat", "json")
# Получить данные CSV из прямых данных или URL
df = await self._get_dataframe(request)
# Обработать на основе запрошенной операции
result = {}
if operation == "summary":
result = self._generate_summary(df)
elif operation == "filter":
column = request.parameters.get("filterColumn")
value = request.parameters.get("filterValue")
if not column:
raise ToolExecutionException("filterColumn is required for filter operation")
result = self._filter_data(df, column, value)
elif operation == "transform":
result = self._transform_data(df, request.parameters)
elif operation == "convert":
result = self._convert_format(df, output_format)
else:
raise ToolExecutionException(f"Unknown operation: {operation}")
return ToolResponse(result=result)
except Exception as e:
raise ToolExecutionException(f"CSV processing failed: {str(e)}")
async def _get_dataframe(self, request: ToolRequest) -> pd.DataFrame:
"""Gets a pandas DataFrame from either CSV data or URL"""
if "csvData" in request.parameters:
csv_data = request.parameters.get("csvData")
return pd.read_csv(io.StringIO(csv_data))
elif "csvUrl" in request.parameters:
csv_url = request.parameters.get("csvUrl")
return pd.read_csv(csv_url)
else:
raise ToolExecutionException("Either csvData or csvUrl must be provided")
def _generate_summary(self, df: pd.DataFrame) -> Dict[str, Any]:
"""Generates a summary of the CSV data"""
return {
"columns": df.columns.tolist(),
"rowCount": len(df),
"columnCount": len(df.columns),
"numericColumns": df.select_dtypes(include=['number']).columns.tolist(),
"categoricalColumns": df.select_dtypes(include=['object']).columns.tolist(),
"sampleRows": json.loads(df.head(5).to_json(orient="records")),
"statistics": json.loads(df.describe().to_json())
}
def _filter_data(self, df: pd.DataFrame, column: str, value: str) -> Dict[str, Any]:
"""Filters the DataFrame by a column value"""
if column not in df.columns:
raise ToolExecutionException(f"Column '{column}' not found")
filtered_df = df[df[column].astype(str).str.contains(value)]
return {
"originalRowCount": len(df),
"filteredRowCount": len(filtered_df),
"data": json.loads(filtered_df.to_json(orient="records"))
}
def _transform_data(self, df: pd.DataFrame, params: Dict[str, Any]) -> Dict[str, Any]:
"""Transforms the data based on parameters"""
# Реализация будет включать различные преобразования
return {
"status": "success",
"message": "Transformation applied"
}
def _convert_format(self, df: pd.DataFrame, format: str) -> Dict[str, Any]:
"""Converts the DataFrame to different formats"""
if format == "json":
return {
"data": json.loads(df.to_json(orient="records")),
"format": "json"
}
elif format == "csv":
return {
"data": df.to_csv(index=False),
"format": "csv"
}
elif format == "markdown":
return {
"data": df.to_markdown(),
"format": "markdown"
}
else:
raise ToolExecutionException(f"Unsupported output format: {format}")
Руководство по внесению вклада
Чтобы успешно внести вклад в проекты MCP:
- Начинайте с малого: начинайте с документации, исправления ошибок или небольших улучшений
- Следуйте стилю: соблюдайте стиль кода и соглашения проекта
- Пишите тесты: добавляйте модульные тесты для ваших изменений кода
- Документируйте свою работу: добавляйте понятную документацию для новых функций или изменений
- Отправляйте целевые PR: делайте пулл-реквесты, сфокусированные на одной задаче или функции
- Работайте с отзывами: отвечайте на замечания по вашим изменениям
Пример рабочего процесса вклада
# Клонируйте репозиторий
git clone https://github.com/modelcontextprotocol/typescript-sdk.git
cd typescript-sdk
# Создайте новую ветку для вашего вклада
git checkout -b feature/my-contribution
# Внесите свои изменения
# ...
# Запустите тесты, чтобы убедиться, что ваши изменения не нарушают существующую функциональность
npm test
# Зафиксируйте изменения с описательным сообщением
git commit -am "Fix validation in resource handler"
# Отправьте свою ветку в ваш форк
git push origin feature/my-contribution
# Создайте пулл-реквест из вашей ветки в основной репозиторий
# Затем взаимодействуйте с отзывами и при необходимости дорабатывайте ваш PR
Создание и распространение серверов MCP
Один из самых ценных способов внести вклад в экосистему MCP — создавать и распространять собственные серверы MCP. Сообщество уже разработало сотни серверов для различных сервисов и сценариев использования.
Фреймворки для разработки серверов MCP
Доступно несколько фреймворков, облегчающих разработку серверов MCP:
-
Официальные SDK (соответствуют спецификации MCP 2025-11-25):
-
Фреймворки сообщества:
- MCP-Framework – создавать серверы MCP красиво и быстро на TypeScript
- MCP Declarative Java SDK – аннотациям управляемые серверы MCP на Java
- Quarkus MCP Server SDK – Java фреймворк для серверов MCP
- Next.js MCP Server Template – стартовый проект Next.js для серверов MCP
Создание распространяемых инструментов
Пример .NET: создание пакета с инструментами для распространения
// Create a new .NET library project
// dotnet new classlib -n McpFinanceTools
using Microsoft.Mcp.Tools;
using System.Threading.Tasks;
using System.Net.Http;
using System.Text.Json;
namespace McpFinanceTools
{
// Stock quote tool
public class StockQuoteTool : IMcpTool
{
private readonly HttpClient _httpClient;
public StockQuoteTool(HttpClient httpClient = null)
{
_httpClient = httpClient ?? new HttpClient();
}
public string Name => "stockQuote";
public string Description => "Gets current stock quotes for specified symbols";
public object GetSchema()
{
return new {
type = "object",
properties = new {
symbol = new {
type = "string",
description = "Stock symbol (e.g., MSFT, AAPL)"
},
includeHistory = new {
type = "boolean",
description = "Whether to include historical data",
default = false
}
},
required = new[] { "symbol" }
};
}
public async Task<ToolResponse> ExecuteAsync(ToolRequest request)
{
// Extract parameters
string symbol = request.Parameters.GetProperty("symbol").GetString();
bool includeHistory = false;
if (request.Parameters.TryGetProperty("includeHistory", out var historyProp))
{
includeHistory = historyProp.GetBoolean();
}
// Call external API (example)
var quoteResult = await GetStockQuoteAsync(symbol);
// Add historical data if requested
if (includeHistory)
{
var historyData = await GetStockHistoryAsync(symbol);
quoteResult.Add("history", historyData);
}
// Return formatted result
return new ToolResponse {
Result = JsonSerializer.SerializeToElement(quoteResult)
};
}
private async Task<Dictionary<string, object>> GetStockQuoteAsync(string symbol)
{
// Implementation would call a real stock API
// This is a simplified example
return new Dictionary<string, object>
{
["symbol"] = symbol,
["price"] = 123.45,
["change"] = 2.5,
["percentChange"] = 1.2,
["lastUpdated"] = DateTime.UtcNow
};
}
private async Task<object> GetStockHistoryAsync(string symbol)
{
// Implementation would get historical data
// Simplified example
return new[]
{
new { date = DateTime.Now.AddDays(-7).Date, price = 120.25 },
new { date = DateTime.Now.AddDays(-6).Date, price = 122.50 },
new { date = DateTime.Now.AddDays(-5).Date, price = 121.75 }
// More historical data...
};
}
}
}
// Create package and publish to NuGet
// dotnet pack -c Release
// dotnet nuget push bin/Release/McpFinanceTools.1.0.0.nupkg -s https://api.nuget.org/v3/index.json -k YOUR_API_KEY
Пример Java: создание пакета Maven для инструментов
// конфигурация pom.xml для общего пакета инструментов MCP
<!--
<project>
<groupId>com.example</groupId>
<artifactId>mcp-weather-tools</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.mcp</groupId>
<artifactId>mcp-server</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>github</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/username/mcp-weather-tools</url>
</repository>
</distributionManagement>
</project>
-->
package com.example.mcp.weather;
import com.mcp.tools.Tool;
import com.mcp.tools.ToolRequest;
import com.mcp.tools.ToolResponse;
import com.mcp.tools.ToolExecutionException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
public class WeatherForecastTool implements Tool {
private final HttpClient httpClient;
private final String apiKey;
public WeatherForecastTool(String apiKey) {
this.httpClient = HttpClient.newHttpClient();
this.apiKey = apiKey;
}
@Override
public String getName() {
return "weatherForecast";
}
@Override
public String getDescription() {
return "Gets weather forecast for a specified location";
}
@Override
public Object getSchema() {
Map<String, Object> schema = new HashMap<>();
// Определение схемы...
return schema;
}
@Override
public ToolResponse execute(ToolRequest request) {
try {
String location = request.getParameters().get("location").asText();
int days = request.getParameters().has("days") ?
request.getParameters().get("days").asInt() : 3;
// Вызов API погоды
Map<String, Object> forecast = getForecast(location, days);
// Формирование ответа
return new ToolResponse.Builder()
.setResult(forecast)
.build();
} catch (Exception ex) {
throw new ToolExecutionException("Weather forecast failed: " + ex.getMessage(), ex);
}
}
private Map<String, Object> getForecast(String location, int days) {
// Реализация будет вызывать API погоды
// Упрощённый пример
Map<String, Object> result = new HashMap<>();
// Добавить данные прогноза...
return result;
}
}
// Сборка и публикация с использованием Maven
// mvn clean package
// mvn deploy
Пример Python: публикация пакета на PyPI
# Структура каталога для пакета PyPI:
# mcp_nlp_tools/
# ├── LICENSE
# ├── README.md
# ├── setup.py
# ├── mcp_nlp_tools/
# │ ├── __init__.py
# │ ├── sentiment_tool.py
# │ └── translation_tool.py
# Пример setup.py
"""
from setuptools import setup, find_packages
setup(
name="mcp_nlp_tools",
version="0.1.0",
packages=find_packages(),
install_requires=[
"mcp_server>=1.0.0",
"transformers>=4.0.0",
"torch>=1.8.0"
],
author="Your Name",
author_email="your.email@example.com",
description="MCP tools for natural language processing tasks",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/username/mcp_nlp_tools",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.8",
)
"""
# Пример реализации инструмента NLP (sentiment_tool.py)
from mcp_tools import Tool, ToolRequest, ToolResponse, ToolExecutionException
from transformers import pipeline
import torch
class SentimentAnalysisTool(Tool):
"""MCP tool for sentiment analysis of text"""
def __init__(self, model_name="distilbert-base-uncased-finetuned-sst-2-english"):
# Загрузить модель анализа настроений
self.sentiment_analyzer = pipeline("sentiment-analysis", model=model_name)
def get_name(self):
return "sentimentAnalysis"
def get_description(self):
return "Analyzes the sentiment of text, classifying it as positive or negative"
def get_schema(self):
return {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "The text to analyze for sentiment"
},
"includeScore": {
"type": "boolean",
"description": "Whether to include confidence scores",
"default": True
}
},
"required": ["text"]
}
async def execute_async(self, request: ToolRequest) -> ToolResponse:
try:
# Извлечь параметры
text = request.parameters.get("text")
include_score = request.parameters.get("includeScore", True)
# Анализировать настроение
sentiment_result = self.sentiment_analyzer(text)[0]
# Отформатировать результат
result = {
"sentiment": sentiment_result["label"],
"text": text
}
if include_score:
result["score"] = sentiment_result["score"]
# Вернуть результат
return ToolResponse(result=result)
except Exception as e:
raise ToolExecutionException(f"Sentiment analysis failed: {str(e)}")
# Для публикации:
# python setup.py sdist bdist_wheel
# python -m twine upload dist/*
Лучшие практики распространения
При распространении инструментов MCP сообществу:
-
Полная документация:
- опишите цель, использование и примеры
- объясните параметры и возвращаемые значения
- задокументируйте внешние зависимости
-
Обработка ошибок:
- реализуйте надежную обработку ошибок
- предоставляйте полезные сообщения об ошибках
- корректно обрабатывайте крайние случаи
-
Производительность:
- оптимизируйте по скорости и использованию ресурсов
- внедряйте кэширование, если возможно
- учитывайте масштабируемость
-
Безопасность:
- используйте безопасные API-ключи и аутентификацию
- проверяйте и очищайте входные данные
- реализуйте лимиты запросов к внешним API
-
Тестирование:
- обеспечьте всестороннее покрытие тестами
- тестируйте с разными типами входных данных и крайними случаями
- документируйте процедуры тестирования
Сотрудничество сообщества и лучшие практики
Эффективное сотрудничество — ключ к процветающей экосистеме MCP.
Каналы коммуникации
- GitHub Issues и Discussions
- Microsoft Tech Community
- Discord и Slack каналы
- Stack Overflow (теги:
model-context-protocolилиmcp)
Код-ревью
При проверке вкладов в MCP обращайте внимание на:
- Ясность: Является ли код понятным и хорошо документированным?
- Корректность: Работает ли он как ожидается?
- Последовательность: Следует ли он проектным соглашениям?
- Полнота: Включены ли тесты и документация?
- Безопасность: Есть ли проблемы с безопасностью?
Совместимость версий
При разработке для MCP:
- Версионирование протокола: Соблюдайте версию протокола MCP, которую поддерживает ваш инструмент
- Совместимость клиента: Учитывайте обратную совместимость
- Совместимость сервера: Следуйте руководству по реализации серверов
- Совместимость с изменениями: Чётко документируйте любые критические изменения
Пример проекта сообщества: реестр инструментов MCP
Важный вклад сообщества — разработка публичного реестра инструментов MCP.
# Пример схемы для API реестра сообществ инструментов
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel, Field, HttpUrl
from typing import List, Optional
import datetime
import uuid
# Модели для реестра инструментов
class ToolSchema(BaseModel):
"""JSON Schema for a tool"""
type: str
properties: dict
required: List[str] = []
class ToolRegistration(BaseModel):
"""Information for registering a tool"""
name: str = Field(..., description="Unique name for the tool")
description: str = Field(..., description="Description of what the tool does")
version: str = Field(..., description="Semantic version of the tool")
schema: ToolSchema = Field(..., description="JSON Schema for tool parameters")
author: str = Field(..., description="Author of the tool")
repository: Optional[HttpUrl] = Field(None, description="Repository URL")
documentation: Optional[HttpUrl] = Field(None, description="Documentation URL")
package: Optional[HttpUrl] = Field(None, description="Package URL")
tags: List[str] = Field(default_factory=list, description="Tags for categorization")
examples: List[dict] = Field(default_factory=list, description="Example usage")
class Tool(ToolRegistration):
"""Tool with registry metadata"""
id: uuid.UUID = Field(default_factory=uuid.uuid4)
created_at: datetime.datetime = Field(default_factory=datetime.datetime.now)
updated_at: datetime.datetime = Field(default_factory=datetime.datetime.now)
downloads: int = Field(default=0)
rating: float = Field(default=0.0)
ratings_count: int = Field(default=0)
# FastAPI приложение для реестра
app = FastAPI(title="MCP Tool Registry")
# База данных в памяти для этого примера
tools_db = {}
@app.post("/tools", response_model=Tool)
async def register_tool(tool: ToolRegistration):
"""Register a new tool in the registry"""
if tool.name in tools_db:
raise HTTPException(status_code=400, detail=f"Tool '{tool.name}' already exists")
new_tool = Tool(**tool.dict())
tools_db[tool.name] = new_tool
return new_tool
@app.get("/tools", response_model=List[Tool])
async def list_tools(tag: Optional[str] = None):
"""List all registered tools, optionally filtered by tag"""
if tag:
return [tool for tool in tools_db.values() if tag in tool.tags]
return list(tools_db.values())
@app.get("/tools/{tool_name}", response_model=Tool)
async def get_tool(tool_name: str):
"""Get information about a specific tool"""
if tool_name not in tools_db:
raise HTTPException(status_code=404, detail=f"Tool '{tool_name}' not found")
return tools_db[tool_name]
@app.delete("/tools/{tool_name}")
async def delete_tool(tool_name: str):
"""Delete a tool from the registry"""
if tool_name not in tools_db:
raise HTTPException(status_code=404, detail=f"Tool '{tool_name}' not found")
del tools_db[tool_name]
return {"message": f"Tool '{tool_name}' deleted"}
Основные выводы
- Сообщество MCP разнообразно и приветствует различные виды вклада
- Вклад в MCP может быть от улучшений протокола до создания собственных инструментов
- Следование руководствам по вкладу увеличивает шансы на принятие вашего PR
- Создание и распространение инструментов MCP — ценный способ развития экосистемы
- Сотрудничество сообщества важно для роста и улучшения MCP
Упражнение
- Определите область в экосистеме MCP, где вы могли бы внести вклад исходя из ваших навыков и интересов
- Форкните репозиторий MCP и настройте локальную среду разработки
- Создайте небольшое улучшение, исправление ошибки или инструмент, полезный сообществу
- Задокументируйте ваш вклад с соответствующими тестами и документацией
- Отправьте пулл-реквест в соответствующий репозиторий
Дополнительные ресурсы
Что дальше
Далее: Уроки раннего внедрения
Отказ от ответственности:
Этот документ был переведен с использованием сервиса автоматического перевода Co-op Translator. Несмотря на наши усилия обеспечить точность, имейте в виду, что автоматический перевод может содержать ошибки или неточности. Оригинальный документ на исходном языке следует считать авторитетным источником. Для важной информации рекомендуется использовать профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные толкования, возникшие в результате использования данного перевода.
