This lesson focuses on how to engage with the MCP community, contribute to the MCP ecosystem, and follow best practices for collaborative development.
Understanding how to participate in open-source MCP projects is essential for those looking to shape the future of this technology.
By the end of this lesson, you will be able to:
The MCP ecosystem consists of various components and participants that work together to advance the protocol.
1. Core Protocol Maintainers: The official Model Context Protocol GitHub organization maintains the core MCP specifications and reference implementations
2. Tool Developers: Individuals and teams that create MCP tools and servers
3. Integration Providers: Companies that integrate MCP into their products and services
4. End Users: Developers and organizations that use MCP in their applications
5. Contributors: Community members who contribute code, documentation, or other resources
The MCP ecosystem welcomes various types of contributions:
1. Code Contributions:
- Core protocol enhancements
- Bug fixes
- Tool and server implementations
- Client/server libraries in different languages
2. Documentation:
- Improving existing documentation
- Creating tutorials and guides
- Translating documentation
- Creating examples and sample applications
3. Community Support:
- Answering questions on forums and discussions
- Testing and reporting issues
- Organizing community events
- Mentoring new contributors
To contribute to the core MCP protocol or official implementations, follow these principles from the official contributing guidelines:
1. Simplicity and Minimalism: The MCP specification maintains a high bar for adding new concepts. It's easier to add things to a specification than to remove them.
2. Concrete Approach: Specification changes should be based on specific implementation challenges, not speculative ideas.
3. Stages of a Proposal:
- Define: Explore the problem space, validate that other MCP users face a similar issue
- Prototype: Build an example solution and demonstrate its practical application
- Write: Based on the prototype, write a specification proposal
# Fork the repository
git clone https://github.com/YOUR-USERNAME/modelcontextprotocol.git
cd modelcontextprotocol
# Install dependencies
npm install
# For schema changes, validate and generate schema.json:
npm run check:schema:ts
npm run generate:schema
# For documentation changes
npm run check:docs
npm run format
# Preview documentation locally (optional):
npm run serve:docs
// Original code with bug in the typescript-sdk
export function validateResource(resource: unknown): resource is MCPResource {
if (!resource || typeof resource !== 'object') {
return false;
}
// Bug: Missing property validation
// Current implementation:
const hasName = 'name' in resource;
const hasSchema = 'schema' in resource;
return hasName && hasSchema;
}
// Fixed implementation in a contribution
export function validateResource(resource: unknown): resource is MCPResource {
if (!resource || typeof resource !== 'object') {
return false;
}
// Improved validation
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;
}
# Example contribution: A CSV data processing tool for the MCP standard library
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:
# Extract parameters
operation = request.parameters.get("operation")
output_format = request.parameters.get("outputFormat", "json")
# Get CSV data from either direct data or URL
df = await self._get_dataframe(request)
# Process based on requested operation
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"""
# Implementation would include various transformations
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}")
To make a successful contribution to MCP projects:
1. Start Small: Begin with documentation, bug fixes, or small enhancements
2. Follow the Style Guide: Adhere to the coding style and conventions of the project
3. Write Tests: Include unit tests for your code contributions
4. Document Your Work: Add clear documentation for new features or changes
5. Submit Targeted PRs: Keep pull requests focused on a single issue or feature
6. Engage with Feedback: Be responsive to feedback on your contributions
# Clone the repository
git clone https://github.com/modelcontextprotocol/typescript-sdk.git
cd typescript-sdk
# Create a new branch for your contribution
git checkout -b feature/my-contribution
# Make your changes
# ...
# Run tests to ensure your changes don't break existing functionality
npm test
# Commit your changes with a descriptive message
git commit -am "Fix validation in resource handler"
# Push your branch to your fork
git push origin feature/my-contribution
# Create a pull request from your branch to the main repository
# Then engage with feedback and iterate on your PR as needed
One of the most valuable ways to contribute to the MCP ecosystem is by creating and sharing custom MCP servers. The community has already developed hundreds of servers for various services and use cases.
Several frameworks are available to simplify MCP server development:
1. Official SDKs (aligned with MCP Specification 2025-11-25):
- C# SDK
- Go SDK
- Java SDK
- Rust SDK
2. Community Frameworks:
- MCP-Framework - Build MCP servers with elegance and speed in TypeScript
- MCP Declarative Java SDK - Annotation-driven MCP servers with Java
- Quarkus MCP Server SDK - Java framework for MCP servers
- Next.js MCP Server Template - Starter Next.js project for MCP servers
// 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
// pom.xml configuration for a shareable MCP tool package
<!--
<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<>();
// Schema definition...
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;
// Call weather API
Map<String, Object> forecast = getForecast(location, days);
// Build response
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) {
// Implementation would call weather API
// Simplified example
Map<String, Object> result = new HashMap<>();
// Add forecast data...
return result;
}
}
// Build and publish using Maven
// mvn clean package
// mvn deploy
# Directory structure for a PyPI package:
# mcp_nlp_tools/
# ├── LICENSE
# ├── README.md
# ├── setup.py
# ├── mcp_nlp_tools/
# │ ├── __init__.py
# │ ├── sentiment_tool.py
# │ └── translation_tool.py
# Example 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",
)
"""
# Example NLP tool implementation (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"):
# Load the sentiment analysis model
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:
# Extract parameters
text = request.parameters.get("text")
include_score = request.parameters.get("includeScore", True)
# Analyze sentiment
sentiment_result = self.sentiment_analyzer(text)[0]
# Format result
result = {
"sentiment": sentiment_result["label"],
"text": text
}
if include_score:
result["score"] = sentiment_result["score"]
# Return result
return ToolResponse(result=result)
except Exception as e:
raise ToolExecutionException(f"Sentiment analysis failed: {str(e)}")
# To publish:
# python setup.py sdist bdist_wheel
# python -m twine upload dist/*
When sharing MCP tools with the community:
1. Complete Documentation:
- Document purpose, usage, and examples
- Explain parameters and return values
- Document any external dependencies
2. Error Handling:
- Implement robust error handling
- Provide useful error messages
- Handle edge cases gracefully
3. Performance Considerations:
- Optimize for both speed and resource usage
- Implement caching when appropriate
- Consider scalability
4. Security:
- Use secure API keys and authentication
- Validate and sanitize inputs
- Implement rate limiting for external API calls
5. Testing:
- Include comprehensive test coverage
- Test with different input types and edge cases
- Document test procedures
Effective collaboration is key to a thriving MCP ecosystem.
model-context-protocol or mcp)When reviewing MCP contributions:
1. Clarity: Is the code clear and well-documented?
2. Correctness: Does it work as expected?
3. Consistency: Does it follow project conventions?
4. Completeness: Are tests and documentation included?
5. Security: Are there any security concerns?
When developing for MCP:
1. Protocol Versioning: Adhere to the MCP protocol version your tool supports
2. Client Compatibility: Consider backward compatibility
3. Server Compatibility: Follow server implementation guidelines
4. Breaking Changes: Clearly document any breaking changes
An important community contribution could be developing a public registry for MCP tools.
# Example schema for a community tool registry API
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel, Field, HttpUrl
from typing import List, Optional
import datetime
import uuid
# Models for the tool registry
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 application for the registry
app = FastAPI(title="MCP Tool Registry")
# In-memory database for this example
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"}
1. Identify an area in the MCP ecosystem where you could make a contribution based on your skills and interests
2. Fork the MCP repository and set up a local development environment
3. Create a small enhancement, bug fix, or tool that would benefit the community
4. Document your contribution with proper tests and documentation
5. Submit a pull request to the appropriate repository
---
_(위 이미지를 클릭하여 이 수업의 영상을 시청하세요)_
이 수업은 MCP 커뮤니티와 소통하는 방법, MCP 생태계에 기여하는 방법, 그리고 협업 개발을 위한 모범 사례를 다룹니다. 오픈 소스 MCP 프로젝트에 참여하는 방법을 이해하는 것은 이 기술의 미래를 형성하려는 분들에게 필수적입니다.
이 수업을 마치면 다음을 할 수 있습니다:
MCP 생태계는 프로토콜을 발전시키기 위해 함께 일하는 다양한 구성 요소와 참여자로 이루어져 있습니다.
1. 핵심 프로토콜 유지 관리자: 공식 Model Context Protocol GitHub 조직은 핵심 MCP 명세와 참조 구현을 유지합니다
2. 도구 개발자: MCP 도구와 서버를 만드는 개인 및 팀
3. 통합 제공자: 자사의 제품과 서비스에 MCP를 통합하는 회사들
4. 최종 사용자: 애플리케이션에서 MCP를 사용하는 개발자와 조직
5. 기여자: 코드, 문서 또는 기타 리소스를 기여하는 커뮤니티 멤버
MCP 생태계는 다양한 유형의 기여를 환영합니다:
1. 코드 기여:
- 핵심 프로토콜 개선
- 버그 수정
- 도구 및 서버 구현
- 다양한 언어의 클라이언트/서버 라이브러리
2. 문서화:
- 기존 문서 개선
- 튜토리얼 및 가이드 작성
- 문서 번역
- 예제 및 샘플 애플리케이션 작성
3. 커뮤니티 지원:
- 포럼 및 토론에서 질문에 답변
- 테스트 및 이슈 보고
- 커뮤니티 이벤트 조직
- 신규 기여자 멘토링
핵심 MCP 프로토콜 또는 공식 구현에 기여하려면, 공식 기여 가이드라인의 원칙을 따르세요:
1. 단순함과 최소주의: MCP 명세는 새 개념 추가에 높은 기준을 유지합니다. 명세에 항목을 추가하는 것보다 삭제하는 것이 더 어렵습니다.
2. 구체적 접근법: 명세 변경은 투기적 아이디어가 아니라 구체적 구현 문제에 기반해야 합니다.
3. 제안 단계:
- 정의: 문제 영역 탐색, 다른 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
// 타입스크립트 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;
}
# 예제 기여: MCP 표준 라이브러리를 위한 CSV 데이터 처리 도구
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")
# 직접 데이터 또는 URL에서 CSV 데이터 가져오기
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 프로젝트에 성공적으로 기여하려면:
1. 작게 시작: 문서, 버그 수정 또는 작은 향상부터 시작하세요
2. 스타일 가이드 준수: 프로젝트의 코드 스타일과 규칙을 따르세요
3. 테스트 작성: 코드 기여에 단위 테스트 포함
4. 작업 문서화: 새로운 기능이나 변경 사항에 대해 명확한 문서 추가
5. 타겟 PR 제출: 하나의 문제 또는 기능에 집중한 풀 리퀘스트 유지
6. 피드백 참여: 기여에 대한 피드백에 적극적으로 응답
# 저장소를 복제하세요
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 서버 개발을 단순화하는 다양한 프레임워크가 있습니다:
1. 공식 SDK (MCP 명세 2025-11-25에 맞춤):
- C# SDK
- Go SDK
- Java SDK
- Rust SDK
2. 커뮤니티 프레임워크:
- MCP-Framework - TypeScript로 우아하고 빠르게 MCP 서버 구축
- MCP 선언적 Java SDK - Java로 주석 기반 MCP 서버 개발
- Quarkus MCP 서버 SDK - MCP 서버용 Java 프레임워크
- Next.js MCP 서버 템플릿 - MCP 서버를 위한 Next.js 스타터 프로젝트
// 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
// 공유 가능한 MCP 도구 패키지를 위한 pom.xml 구성
<!--
<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
# 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 도구를 커뮤니티와 공유할 때:
1. 완전한 문서화:
- 목적, 사용법 및 예제 문서화
- 매개변수 및 반환값 설명
- 외부 종속성 문서화
2. 오류 처리:
- 견고한 오류 처리 구현
- 유용한 오류 메시지 제공
- 가장자리 케이스 우아하게 처리
3. 성능 고려:
- 속도와 자원 사용 최적화
- 적절할 때 캐싱 구현
- 확장성 고려
4. 보안:
- 안전한 API 키 및 인증 사용
- 입력값 검증 및 정제
- 외부 API 호출에 대한 속도 제한 구현
5. 테스트:
- 포괄적인 테스트 커버리지 포함
- 다양한 입력 유형 및 가장자리 케이스 테스트
- 테스트 절차 문서화
효과적인 협업은 번창하는 MCP 생태계의 핵심입니다.
model-context-protocol 또는 mcp)MCP 기여를 검토할 때:
1. 명확성: 코드가 명확하고 잘 문서화되었나?
2. 정확성: 기대대로 작동하는가?
3. 일관성: 프로젝트 규칙을 따르는가?
4. 완성도: 테스트와 문서가 포함되었나?
5. 보안: 보안 문제가 있는가?
MCP용 개발 시:
1. 프로토콜 버전 관리: 도구가 지원하는 MCP 프로토콜 버전 준수
2. 클라이언트 호환성: 이전 버전과의 호환성 고려
3. 서버 호환성: 서버 구현 가이드라인 준수
4. 파괴적 변경: 파괴적 변경 사항을 명확히 문서화
중요한 커뮤니티 기여로 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"}
1. 본인의 역량과 관심사에 기반해 MCP 생태계에서 기여할 영역을 찾아보세요
2. MCP 저장소를 포크하고 로컬 개발 환경을 설정하세요
3. 커뮤니티에 도움이 될 작은 향상, 버그 수정 또는 도구를 만드세요
4. 적절한 테스트와 문서화로 기여 내용을 문서화하세요
5. 적절한 저장소에 풀 리퀘스트를 제출하세요
---
다음: 초기 도입의 교훈
---
면책 조항:
이 문서는 AI 번역 서비스 Co-op Translator를 사용하여 번역되었습니다.
정확성을 위해 노력하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있음을 유의하시기 바랍니다.
원본 문서의 원어 버전이 권위 있는 출처로 간주되어야 합니다.
중요한 정보의 경우 전문 인력에 의한 번역을 권장합니다.
이 번역의 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.