(Bonyeza picha hapo juu kutazama video ya somo hili)
Somo hili linazingatia mbinu za hali ya juu za maendeleo, upimaji, na ueneaji wa seva na vipengele vya MCP katika mazingira ya uzalishaji. Kadiri mifumo ya MCP inavyoongezeka kwa ugumu na umuhimu, kufuata mifumo iliyowekwa kunahakikisha kuaminika, urahisi wa matengenezo, na mwingiliano. Somo hili linakusanya hekima ya vitendo iliyopatikana kutoka kwa utekelezaji halisi wa MCP ili kukuongoza katika kuunda seva imara, yenye ufanisi kwa rasilimali, viamsha, na zana bora.
Mwisho wa somo hili, utaweza:
- Kutumia mbinu bora za tasnia katika usanifu wa seva na vipengele vya MCP
- Kuunda mikakati kamili ya upimaji kwa seva za MCP
- Kubuni mifumo bora, inayorudiwa ya mtiririko wa kazi kwa programu tata za MCP
- Kutekeleza usimamizi sahihi wa makosa, kurekodi kumbukumbu, na ufuatiliaji katika seva za MCP
- Kuboresha utekelezaji wa MCP kwa ufanisi, usalama, na urahisi wa matengenezo
Kabla ya kuingia katika mbinu maalum za utekelezaji, ni muhimu kuelewa kanuni msingi zinazowaongoza maendeleo ya MCP yenye ufanisi:
-
Mawasiliano Yaliyopangwa Sanifu: MCP hutumia JSON-RPC 2.0 kama msingi wake, ikitoa muundo thabiti kwa maombi, majibu, na usimamizi wa makosa katika utekelezaji wote.
-
Ubunifu Unaomzingatia Mtumiaji: Kila wakati weka mbele idhini, udhibiti, na uwazi wa mtumiaji katika utekelezaji wako wa MCP.
-
Usalama Kwanza: Tekeleza hatua imara za usalama ikiwa ni pamoja na utambulisho, idhini, uthibitishaji, na kipimo cha kiwango cha maombi.
-
Mimambo ya Kihusianisho: Buni seva zako za MCP kwa njia ya moduli, ambapo kila zana na rasilimali inakuwa na kusudi wazi na lengo.
-
Mawasiliano ya Kidumu: Tumia uwezo wa MCP kudumisha hali kati ya maombi mengi kwa mazungumzo yaliyo na muktadha zaidi.
Mazoea bora yafuatayo yanatokana na nyaraka rasmi za Itifaki ya Muktadha wa Mfano:
-
Idhini na Udhibiti wa Mtumiaji: Ikiwa daima inahitaji idhini wazi ya mtumiaji kabla ya kupata data au kufanya shughuli. Toa udhibiti wazi juu ya data inayoshirikiwa na vitendo vinavyoruhusiwa.
-
Faragha ya Data: Weka wazi data ya mtumiaji tu kwa idhini ya wazi na uilinde kwa udhibiti wa upatikanaji unaofaa. Linda dhidi ya usambazaji wa data usioidhinishwa.
-
Usalama wa Zana: Takikisha idhini wazi ya mtumiaji kabla ya kuitisha zana yoyote. Hakikisha watumiaji wanaelewa kazi za kila zana na zingatia mipaka imara ya usalama.
-
Udhibiti wa Ruhusa za Zana: Sanidi ni zana gani modeli inaruhusiwa kutumia wakati wa kikao, kuhakikisha zana zilizoidhinishwa tu ndizo zinapatikana.
-
Utambulisho: Hitaji utambulisho unaofaa kabla ya kutoa ruhusa ya kutumia zana, rasilimali, au shughuli nyeti kwa kutumia funguo za API, tokeni za OAuth, au njia nyingine salama za uthibitishaji.
-
Uhakiki wa Vigezo: Fanya uhakikisho wa vigezo vya kila uitikaji wa zana ili kuzuia pembejeo zisizotakikana au hatari kufikia utekelezaji wa zana.
-
Kipimo cha Kiwango cha Maombi: Tekeleza kipimo cha kiwango cha maombi ili kuzuia matumizi mabaya na kuhakikisha matumizi ya haki ya rasilimali za seva.
-
Mjadala wa Uwezo: Wakati wa usanidi wa muunganisho, badilishana taarifa kuhusu vipengele vinavyotegemewa, matoleo ya itifaki, zana, na rasilimali zilizopo.
-
Ubunifu wa Zana: Unda zana zenye lengo wazi zinazozingatia kazi moja vizuri, badala ya zana kubwa zinazoshughulikia masuala mengi.
-
Usimamizi wa Makosa: Tekeleza ujumbe wa makosa na nambari zilizopangwa ili kusaidia kutambua matatizo, kushughulikia kushindwa kwa upole, na kutoa maoni yanayoweza kuchukuliwa hatua.
-
Kurekodi Kumbukumbu: Sanidi kumbukumbu zilizoandaliwa kwa ukaguzi, utatuzi wa matatizo, na ufuatiliaji wa mwingiliano wa itifaki.
-
Ufuatiliaji wa Maendeleo: Kwa shughuli zenye mzunguko mrefu, toa taarifa za maendeleo ili kuwezesha matumizi ya kiolesura vinavyojibu haraka.
-
Kuahirisha Maombi: Ruhusu wateja kuahirisha maombi yaliyomo safarini ambayo hayahitajiki tena au yanachukua muda mrefu sana.
Kwa habari za kisasa zaidi kuhusu mazoea bora ya MCP, rejelea:
- MCP Documentation
- MCP Specification (2025-11-25)
- GitHub Repository
- Security Best Practices
- OWASP MCP Top 10 - Hatari za usalama na vile vya kuzizuia
- MCP Security Summit Workshop (Sherpa) - Mafunzo ya usalama ya vitendo
Kila zana ya MCP inapaswa kuwa na kusudi wazi na lengo. Badala ya kuunda zana kubwa zinazojaribu kushughulikia masuala mengi, tengeneza zana maalum zinazobobea katika kazi maalum.
// A focused tool that does one thing well
public class WeatherForecastTool : ITool
{
private readonly IWeatherService _weatherService;
public WeatherForecastTool(IWeatherService weatherService)
{
_weatherService = weatherService;
}
public string Name => "weatherForecast";
public string Description => "Gets weather forecast for a specific location";
public ToolDefinition GetDefinition()
{
return new ToolDefinition
{
Name = Name,
Description = Description,
Parameters = new Dictionary<string, ParameterDefinition>
{
["location"] = new ParameterDefinition
{
Type = ParameterType.String,
Description = "City or location name"
},
["days"] = new ParameterDefinition
{
Type = ParameterType.Integer,
Description = "Number of forecast days",
Default = 3
}
},
Required = new[] { "location" }
};
}
public async Task<ToolResponse> ExecuteAsync(IDictionary<string, object> parameters)
{
var location = parameters["location"].ToString();
var days = parameters.ContainsKey("days")
? Convert.ToInt32(parameters["days"])
: 3;
var forecast = await _weatherService.GetForecastAsync(location, days);
return new ToolResponse
{
Content = new List<ContentItem>
{
new TextContent(JsonSerializer.Serialize(forecast))
}
};
}
}Tekeleza usimamizi imara wa makosa ukitumia ujumbe wa makosa wenye taarifa na mbinu zinazofaa za kupona.
# Mfano wa Python wenye uchunguzi wa makosa kwa kina
class DataQueryTool:
def get_name(self):
return "dataQuery"
def get_description(self):
return "Queries data from specified database tables"
async def execute(self, parameters):
try:
# Uthibitishaji wa vigezo
if "query" not in parameters:
raise ToolParameterError("Missing required parameter: query")
query = parameters["query"]
# Uthibitishaji wa usalama
if self._contains_unsafe_sql(query):
raise ToolSecurityError("Query contains potentially unsafe SQL")
try:
# Operesheni ya database na muda wa kusubiri
async with timeout(10): # Muda wa kusubiri wa sekunde 10
result = await self._database.execute_query(query)
return ToolResponse(
content=[TextContent(json.dumps(result))]
)
except asyncio.TimeoutError:
raise ToolExecutionError("Database query timed out after 10 seconds")
except DatabaseConnectionError as e:
# Makosa ya muunganisho yanaweza kuwa ya muda mfupi
self._log_error("Database connection error", e)
raise ToolExecutionError(f"Database connection error: {str(e)}")
except DatabaseQueryError as e:
# Makosa ya maswali yana uwezekano wa kuwa makosa ya mteja
self._log_error("Database query error", e)
raise ToolExecutionError(f"Invalid query: {str(e)}")
except ToolError:
# Ruhusu makosa maalum ya zana kupitishwa
raise
except Exception as e:
# Kamili kwa makosa yasiyotarajiwa
self._log_error("Unexpected error in DataQueryTool", e)
raise ToolExecutionError(f"An unexpected error occurred: {str(e)}")
def _contains_unsafe_sql(self, query):
# Utekelezaji wa ugundaji wa sindano ya SQL
pass
def _log_error(self, message, error):
# Utekelezaji wa kurekodi makosa
passDaima hakiki vigezo vyote kwa kina ili kuzuia pembejeo zisizotakikana au hatari.
// Mfano wa JavaScript/TypeScript pamoja na uhakiki wa kina wa vigezo
class FileOperationTool {
getName() {
return "fileOperation";
}
getDescription() {
return "Performs file operations like read, write, and delete";
}
getDefinition() {
return {
name: this.getName(),
description: this.getDescription(),
parameters: {
operation: {
type: "string",
description: "Operation to perform",
enum: ["read", "write", "delete"]
},
path: {
type: "string",
description: "File path (must be within allowed directories)"
},
content: {
type: "string",
description: "Content to write (only for write operation)",
optional: true
}
},
required: ["operation", "path"]
};
}
async execute(parameters) {
// 1. Thibitisha uwepo wa kigezo
if (!parameters.operation) {
throw new ToolError("Missing required parameter: operation");
}
if (!parameters.path) {
throw new ToolError("Missing required parameter: path");
}
// 2. Thibitisha aina za vigezo
if (typeof parameters.operation !== "string") {
throw new ToolError("Parameter 'operation' must be a string");
}
if (typeof parameters.path !== "string") {
throw new ToolError("Parameter 'path' must be a string");
}
// 3. Thibitisha thamani za vigezo
const validOperations = ["read", "write", "delete"];
if (!validOperations.includes(parameters.operation)) {
throw new ToolError(`Invalid operation. Must be one of: ${validOperations.join(", ")}`);
}
// 4. Thibitisha uwepo wa maudhui kwa operesheni ya kuandika
if (parameters.operation === "write" && !parameters.content) {
throw new ToolError("Content parameter is required for write operation");
}
// 5. Uhakiki wa usalama wa njia
if (!this.isPathWithinAllowedDirectories(parameters.path)) {
throw new ToolError("Access denied: path is outside of allowed directories");
}
// Utekelezaji unaotegemea vigezo vilivyothibitishwa
// ...
}
isPathWithinAllowedDirectories(path) {
// Utekelezaji wa ukaguzi wa usalama wa njia
// ...
}
}// Mfano wa Java na uthibitishaji na idhini
public class SecureDataAccessTool implements Tool {
private final AuthenticationService authService;
private final AuthorizationService authzService;
private final DataService dataService;
// Injection ya utegemezi
public SecureDataAccessTool(
AuthenticationService authService,
AuthorizationService authzService,
DataService dataService) {
this.authService = authService;
this.authzService = authzService;
this.dataService = dataService;
}
@Override
public String getName() {
return "secureDataAccess";
}
@Override
public ToolResponse execute(ToolRequest request) {
// 1. Toa muktadha wa uthibitishaji
String authToken = request.getContext().getAuthToken();
// 2. Thibitisha mtumiaji
UserIdentity user;
try {
user = authService.validateToken(authToken);
} catch (AuthenticationException e) {
return ToolResponse.error("Authentication failed: " + e.getMessage());
}
// 3. Angalia idhini kwa ajili ya operesheni maalum
String dataId = request.getParameters().get("dataId").getAsString();
String operation = request.getParameters().get("operation").getAsString();
boolean isAuthorized = authzService.isAuthorized(user, "data:" + dataId, operation);
if (!isAuthorized) {
return ToolResponse.error("Access denied: Insufficient permissions for this operation");
}
// 4. Endelea na operesheni iliyoruhusiwa
try {
switch (operation) {
case "read":
Object data = dataService.getData(dataId, user.getId());
return ToolResponse.success(data);
case "update":
JsonNode newData = request.getParameters().get("newData");
dataService.updateData(dataId, newData, user.getId());
return ToolResponse.success("Data updated successfully");
default:
return ToolResponse.error("Unsupported operation: " + operation);
}
} catch (Exception e) {
return ToolResponse.error("Operation failed: " + e.getMessage());
}
}
}// C# rate limiting implementation
public class RateLimitingMiddleware
{
private readonly RequestDelegate _next;
private readonly IMemoryCache _cache;
private readonly ILogger<RateLimitingMiddleware> _logger;
// Configuration options
private readonly int _maxRequestsPerMinute;
public RateLimitingMiddleware(
RequestDelegate next,
IMemoryCache cache,
ILogger<RateLimitingMiddleware> logger,
IConfiguration config)
{
_next = next;
_cache = cache;
_logger = logger;
_maxRequestsPerMinute = config.GetValue<int>("RateLimit:MaxRequestsPerMinute", 60);
}
public async Task InvokeAsync(HttpContext context)
{
// 1. Get client identifier (API key or user ID)
string clientId = GetClientIdentifier(context);
// 2. Get rate limiting key for this minute
string cacheKey = $"rate_limit:{clientId}:{DateTime.UtcNow:yyyyMMddHHmm}";
// 3. Check current request count
if (!_cache.TryGetValue(cacheKey, out int requestCount))
{
requestCount = 0;
}
// 4. Enforce rate limit
if (requestCount >= _maxRequestsPerMinute)
{
_logger.LogWarning("Rate limit exceeded for client {ClientId}", clientId);
context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
context.Response.Headers.Add("Retry-After", "60");
await context.Response.WriteAsJsonAsync(new
{
error = "Rate limit exceeded",
message = "Too many requests. Please try again later.",
retryAfterSeconds = 60
});
return;
}
// 5. Increment request count
_cache.Set(cacheKey, requestCount + 1, TimeSpan.FromMinutes(2));
// 6. Add rate limit headers
context.Response.Headers.Add("X-RateLimit-Limit", _maxRequestsPerMinute.ToString());
context.Response.Headers.Add("X-RateLimit-Remaining", (_maxRequestsPerMinute - requestCount - 1).ToString());
// 7. Continue with the request
await _next(context);
}
private string GetClientIdentifier(HttpContext context)
{
// Implementation to extract API key or user ID
// ...
}
}Daima jaribu zana zako peke yake ukitumia maigizo ya utegemezi wa nje:
// Mfano wa TypeScript wa jaribio la kitengo cha zana
describe('WeatherForecastTool', () => {
let tool: WeatherForecastTool;
let mockWeatherService: jest.Mocked<IWeatherService>;
beforeEach(() => {
// Unda huduma ya hali ya hewa ya uigaji
mockWeatherService = {
getForecasts: jest.fn()
} as any;
// Unda zana na utegemezi wa uigaji
tool = new WeatherForecastTool(mockWeatherService);
});
it('should return weather forecast for a location', async () => {
// Panga
const mockForecast = {
location: 'Seattle',
forecasts: [
{ date: '2025-07-16', temperature: 72, conditions: 'Sunny' },
{ date: '2025-07-17', temperature: 68, conditions: 'Partly Cloudy' },
{ date: '2025-07-18', temperature: 65, conditions: 'Rain' }
]
};
mockWeatherService.getForecasts.mockResolvedValue(mockForecast);
// Fanya
const response = await tool.execute({
location: 'Seattle',
days: 3
});
// Thibitisha
expect(mockWeatherService.getForecasts).toHaveBeenCalledWith('Seattle', 3);
expect(response.content[0].text).toContain('Seattle');
expect(response.content[0].text).toContain('Sunny');
});
it('should handle errors from the weather service', async () => {
// Panga
mockWeatherService.getForecasts.mockRejectedValue(new Error('Service unavailable'));
// Fanya & Thibitisha
await expect(tool.execute({
location: 'Seattle',
days: 3
})).rejects.toThrow('Weather service error: Service unavailable');
});
});Jaribu mtiririko kamili kutoka maombi ya mteja hadi majibu ya seva:
# Mfano wa jaribio la muunganisho wa Python
@pytest.mark.asyncio
async def test_mcp_server_integration():
# Anzisha seva ya jaribio
server = McpServer()
server.register_tool(WeatherForecastTool(MockWeatherService()))
await server.start(port=5000)
try:
# Unda mteja
client = McpClient("http://localhost:5000")
# Jaribu ugunduzi wa zana
tools = await client.discover_tools()
assert "weatherForecast" in [t.name for t in tools]
# Jaribu utekelezaji wa zana
response = await client.execute_tool("weatherForecast", {
"location": "Seattle",
"days": 3
})
# Thibitisha majibu
assert response.status_code == 200
assert "Seattle" in response.content[0].text
assert len(json.loads(response.content[0].text)["forecasts"]) == 3
finally:
# Safisha mazingira
await server.stop()Tekeleza uhifadhi mzuri ili kupunguza ucheleweshaji na matumizi ya rasilimali:
// C# example with caching
public class CachedWeatherTool : ITool
{
private readonly IWeatherService _weatherService;
private readonly IDistributedCache _cache;
private readonly ILogger<CachedWeatherTool> _logger;
public CachedWeatherTool(
IWeatherService weatherService,
IDistributedCache cache,
ILogger<CachedWeatherTool> logger)
{
_weatherService = weatherService;
_cache = cache;
_logger = logger;
}
public string Name => "weatherForecast";
public async Task<ToolResponse> ExecuteAsync(IDictionary<string, object> parameters)
{
var location = parameters["location"].ToString();
var days = Convert.ToInt32(parameters.GetValueOrDefault("days", 3));
// Create cache key
string cacheKey = $"weather:{location}:{days}";
// Try to get from cache
string cachedForecast = await _cache.GetStringAsync(cacheKey);
if (!string.IsNullOrEmpty(cachedForecast))
{
_logger.LogInformation("Cache hit for weather forecast: {Location}", location);
return new ToolResponse
{
Content = new List<ContentItem>
{
new TextContent(cachedForecast)
}
};
}
// Cache miss - get from service
_logger.LogInformation("Cache miss for weather forecast: {Location}", location);
var forecast = await _weatherService.GetForecastAsync(location, days);
string forecastJson = JsonSerializer.Serialize(forecast);
// Store in cache (weather forecasts valid for 1 hour)
await _cache.SetStringAsync(
cacheKey,
forecastJson,
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
return new ToolResponse
{
Content = new List<ContentItem>
{
new TextContent(forecastJson)
}
};
}
}Buni zana kupokea utegemezi wake kupitia uingizaji wa konstrukta, zikifanya ziweze kupimika na kubadilishwa:
// Mfano wa Java na sindano ya utegemezi
public class CurrencyConversionTool implements Tool {
private final ExchangeRateService exchangeService;
private final CacheService cacheService;
private final Logger logger;
// Vitegemezi vilivyowekwa kupitia kimojawapo
public CurrencyConversionTool(
ExchangeRateService exchangeService,
CacheService cacheService,
Logger logger) {
this.exchangeService = exchangeService;
this.cacheService = cacheService;
this.logger = logger;
}
// Utekelezaji wa chombo
// ...
}Buni zana ambazo zinaweza kuunganishwa pamoja kuunda mitiririko ya kazi tata zaidi:
# Mfano wa Python unaoonyesha zana zinazoweza kuunganishwa
class DataFetchTool(Tool):
def get_name(self):
return "dataFetch"
# Utekelezaji...
class DataAnalysisTool(Tool):
def get_name(self):
return "dataAnalysis"
# Zana hii inaweza kutumia matokeo kutoka kwa zana ya dataFetch
async def execute_async(self, request):
# Utekelezaji...
pass
class DataVisualizationTool(Tool):
def get_name(self):
return "dataVisualize"
# Zana hii inaweza kutumia matokeo kutoka kwa zana ya dataAnalysis
async def execute_async(self, request):
# Utekelezaji...
pass
# Zana hizi zinaweza kutumika kwa kujitegemea au kama sehemu ya mchakato wa kaziMpangilio ni mkataba kati ya modeli na zana yako. Mipangilio iliyobuniwa vizuri hutoa urahisi zaidi wa matumizi ya zana.
Daima jumuisha taarifa za maelezo kwa kila kigezo:
public object GetSchema()
{
return new {
type = "object",
properties = new {
query = new {
type = "string",
description = "Search query text. Use precise keywords for better results."
},
filters = new {
type = "object",
description = "Optional filters to narrow down search results",
properties = new {
dateRange = new {
type = "string",
description = "Date range in format YYYY-MM-DD:YYYY-MM-DD"
},
category = new {
type = "string",
description = "Category name to filter by"
}
}
},
limit = new {
type = "integer",
description = "Maximum number of results to return (1-50)",
default = 10
}
},
required = new[] { "query" }
};
}Jumuisha vizuizi vya uhakiki ili kuzuia pembejeo zisizofaa:
Map<String, Object> getSchema() {
Map<String, Object> schema = new HashMap<>();
schema.put("type", "object");
Map<String, Object> properties = new HashMap<>();
// Mali ya barua pepe yenye uthibitisho wa muundo
Map<String, Object> email = new HashMap<>();
email.put("type", "string");
email.put("format", "email");
email.put("description", "User email address");
// Mali ya umri yenye vizingiti vya nambari
Map<String, Object> age = new HashMap<>();
age.put("type", "integer");
age.put("minimum", 13);
age.put("maximum", 120);
age.put("description", "User age in years");
// Mali ya orodha iliyoorodheshwa
Map<String, Object> subscription = new HashMap<>();
subscription.put("type", "string");
subscription.put("enum", Arrays.asList("free", "basic", "premium"));
subscription.put("default", "free");
subscription.put("description", "Subscription tier");
properties.put("email", email);
properties.put("age", age);
properties.put("subscription", subscription);
schema.put("properties", properties);
schema.put("required", Arrays.asList("email"));
return schema;
}Dumisha muundo thabiti wa majibu yako ili kurahisisha modeli kutafsiri matokeo:
async def execute_async(self, request):
try:
# Shughulikia ombi
results = await self._search_database(request.parameters["query"])
# Daima rudisha muundo thabiti
return ToolResponse(
result={
"matches": [self._format_item(item) for item in results],
"totalCount": len(results),
"queryTime": calculation_time_ms,
"status": "success"
}
)
except Exception as e:
return ToolResponse(
result={
"matches": [],
"totalCount": 0,
"queryTime": 0,
"status": "error",
"error": str(e)
}
)
def _format_item(self, item):
"""Ensures each item has a consistent structure"""
return {
"id": item.id,
"title": item.title,
"summary": item.summary[:100] + "..." if len(item.summary) > 100 else item.summary,
"url": item.url,
"relevance": item.score
}Usimamizi imara wa makosa ni muhimu kwa zana za MCP kudumisha kuaminika.
Shughulikia makosa ngazi zinazofaa na toa ujumbe wenye taarifa:
public async Task<ToolResponse> ExecuteAsync(ToolRequest request)
{
try
{
string fileId = request.Parameters.GetProperty("fileId").GetString();
try
{
var fileData = await _fileService.GetFileAsync(fileId);
return new ToolResponse {
Result = JsonSerializer.SerializeToElement(fileData)
};
}
catch (FileNotFoundException)
{
throw new ToolExecutionException($"File not found: {fileId}");
}
catch (UnauthorizedAccessException)
{
throw new ToolExecutionException("You don't have permission to access this file");
}
catch (Exception ex) when (ex is IOException || ex is TimeoutException)
{
_logger.LogError(ex, "Error accessing file {FileId}", fileId);
throw new ToolExecutionException("Error accessing file: The service is temporarily unavailable");
}
}
catch (JsonException)
{
throw new ToolExecutionException("Invalid file ID format");
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error in FileAccessTool");
throw new ToolExecutionException("An unexpected error occurred");
}
}Rudisha taarifa za makosa zilizo na muundo pale inapowezekana:
@Override
public ToolResponse execute(ToolRequest request) {
try {
// Utekelezaji
} catch (Exception ex) {
Map<String, Object> errorResult = new HashMap<>();
errorResult.put("success", false);
if (ex instanceof ValidationException) {
ValidationException validationEx = (ValidationException) ex;
errorResult.put("errorType", "validation");
errorResult.put("errorMessage", validationEx.getMessage());
errorResult.put("validationErrors", validationEx.getErrors());
return new ToolResponse.Builder()
.setResult(errorResult)
.build();
}
// Rudi kosa lingine kama ToolExecutionException
throw new ToolExecutionException("Tool execution failed: " + ex.getMessage(), ex);
}
}Tekeleza mchakato unaofaa wa jaribu tena kwa kushindwa za muda mfupi:
async def execute_async(self, request):
max_retries = 3
retry_count = 0
base_delay = 1 # sekunde
while retry_count < max_retries:
try:
# Piga API ya nje
return await self._call_api(request.parameters)
except TransientError as e:
retry_count += 1
if retry_count >= max_retries:
raise ToolExecutionException(f"Operation failed after {max_retries} attempts: {str(e)}")
# Kurudi nyuma kwa mwelekeo wa eksponential
delay = base_delay * (2 ** (retry_count - 1))
logging.warning(f"Transient error, retrying in {delay}s: {str(e)}")
await asyncio.sleep(delay)
except Exception as e:
# Hitilafu isiyo ya muda, usijaribu tena
raise ToolExecutionException(f"Operation failed: {str(e)}")Tekeleza uhifadhi kwa ajili ya operesheni ghali:
public class CachedDataTool : IMcpTool
{
private readonly IDatabase _database;
private readonly IMemoryCache _cache;
public CachedDataTool(IDatabase database, IMemoryCache cache)
{
_database = database;
_cache = cache;
}
public async Task<ToolResponse> ExecuteAsync(ToolRequest request)
{
var query = request.Parameters.GetProperty("query").GetString();
// Create cache key based on parameters
var cacheKey = $"data_query_{ComputeHash(query)}";
// Try to get from cache first
if (_cache.TryGetValue(cacheKey, out var cachedResult))
{
return new ToolResponse { Result = cachedResult };
}
// Cache miss - perform actual query
var result = await _database.QueryAsync(query);
// Store in cache with expiration
var cacheOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(15));
_cache.Set(cacheKey, JsonSerializer.SerializeToElement(result), cacheOptions);
return new ToolResponse { Result = JsonSerializer.SerializeToElement(result) };
}
private string ComputeHash(string input)
{
// Implementation to generate stable hash for cache key
}
}Tumia mifumo ya programu isiyo na mfuatano kwa operesheni za I/O:
public class AsyncDocumentProcessingTool implements Tool {
private final DocumentService documentService;
private final ExecutorService executorService;
@Override
public ToolResponse execute(ToolRequest request) {
String documentId = request.getParameters().get("documentId").asText();
// Kwa shughuli zinazochukua muda mrefu, rudisha kitambulisho cha usindikaji mara moja
String processId = UUID.randomUUID().toString();
// Anzisha usindikaji usioambatishwa
CompletableFuture.runAsync(() -> {
try {
// Fanya shughuli inayochukua muda mrefu
documentService.processDocument(documentId);
// Sasisha hali (kawaida itahifadhiwa katika hifadhidata)
processStatusRepository.updateStatus(processId, "completed");
} catch (Exception ex) {
processStatusRepository.updateStatus(processId, "failed", ex.getMessage());
}
}, executorService);
// Rejesha jibu la papo hapo lenye kitambulisho cha mchakato
Map<String, Object> result = new HashMap<>();
result.put("processId", processId);
result.put("status", "processing");
result.put("estimatedCompletionTime", ZonedDateTime.now().plusMinutes(5));
return new ToolResponse.Builder().setResult(result).build();
}
// Zana ya ukaguzi wa hali mwenzake
public class ProcessStatusTool implements Tool {
@Override
public ToolResponse execute(ToolRequest request) {
String processId = request.getParameters().get("processId").asText();
ProcessStatus status = processStatusRepository.getStatus(processId);
return new ToolResponse.Builder().setResult(status).build();
}
}
}Tekeleza kuzuia kwa kutumia rasilimali ili kuzuia mzigo kupita kiasi:
class ThrottledApiTool(Tool):
def __init__(self):
self.rate_limiter = TokenBucketRateLimiter(
tokens_per_second=5, # Ruhusu maombi 5 kwa sekunde
bucket_size=10 # Ruhusu mlipuko hadi maombi 10
)
async def execute_async(self, request):
# Angalia ikiwa tunaweza kuendelea au tunahitaji kusubiri
delay = self.rate_limiter.get_delay_time()
if delay > 0:
if delay > 2.0: # Ikiwa kusubiri ni kwa muda mrefu sana
raise ToolExecutionException(
f"Rate limit exceeded. Please try again in {delay:.1f} seconds."
)
else:
# Subiri kwa muda unaofaa wa kuchelewa
await asyncio.sleep(delay)
# Tumia tokeni moja na endelea na ombi
self.rate_limiter.consume()
# Piga API
result = await self._call_api(request.parameters)
return ToolResponse(result=result)
class TokenBucketRateLimiter:
def __init__(self, tokens_per_second, bucket_size):
self.tokens_per_second = tokens_per_second
self.bucket_size = bucket_size
self.tokens = bucket_size
self.last_refill = time.time()
self.lock = asyncio.Lock()
async def get_delay_time(self):
async with self.lock:
self._refill()
if self.tokens >= 1:
return 0
# Hesabu muda mpaka tokeni inayofuata itapatikana
return (1 - self.tokens) / self.tokens_per_second
async def consume(self):
async with self.lock:
self._refill()
self.tokens -= 1
def _refill(self):
now = time.time()
elapsed = now - self.last_refill
# Ongeza tokeni mpya kulingana na muda uliopita
new_tokens = elapsed * self.tokens_per_second
self.tokens = min(self.bucket_size, self.tokens + new_tokens)
self.last_refill = nowDaima hakiki vigezo vya ingizo kwa kina:
public async Task<ToolResponse> ExecuteAsync(ToolRequest request)
{
// Validate parameters exist
if (!request.Parameters.TryGetProperty("query", out var queryProp))
{
throw new ToolExecutionException("Missing required parameter: query");
}
// Validate correct type
if (queryProp.ValueKind != JsonValueKind.String)
{
throw new ToolExecutionException("Query parameter must be a string");
}
var query = queryProp.GetString();
// Validate string content
if (string.IsNullOrWhiteSpace(query))
{
throw new ToolExecutionException("Query parameter cannot be empty");
}
if (query.Length > 500)
{
throw new ToolExecutionException("Query parameter exceeds maximum length of 500 characters");
}
// Check for SQL injection attacks if applicable
if (ContainsSqlInjection(query))
{
throw new ToolExecutionException("Invalid query: contains potentially unsafe SQL");
}
// Proceed with execution
// ...
}Tekeleza ukaguzi sahihi wa idhini:
@Override
public ToolResponse execute(ToolRequest request) {
// Pata muktadha wa mtumiaji kutoka kwa ombi
UserContext user = request.getContext().getUserContext();
// Angalia kama mtumiaji ana ruhusa zinazohitajika
if (!authorizationService.hasPermission(user, "documents:read")) {
throw new ToolExecutionException("User does not have permission to access documents");
}
// Kwa rasilimali maalum, angalia ufikiaji wa rasilimali hiyo
String documentId = request.getParameters().get("documentId").asText();
if (!documentService.canUserAccess(user.getId(), documentId)) {
throw new ToolExecutionException("Access denied to the requested document");
}
// Endelea na utekelezaji wa chombo
// ...
}Shughulikia data nyeti kwa tahadhari:
class SecureDataTool(Tool):
def get_schema(self):
return {
"type": "object",
"properties": {
"userId": {"type": "string"},
"includeSensitiveData": {"type": "boolean", "default": False}
},
"required": ["userId"]
}
async def execute_async(self, request):
user_id = request.parameters["userId"]
include_sensitive = request.parameters.get("includeSensitiveData", False)
# Pata data ya mtumiaji
user_data = await self.user_service.get_user_data(user_id)
# Chuja sehemu nyeti isipokuwa ziombwe wazi NA ruhusiwa
if not include_sensitive or not self._is_authorized_for_sensitive_data(request):
user_data = self._redact_sensitive_fields(user_data)
return ToolResponse(result=user_data)
def _is_authorized_for_sensitive_data(self, request):
# Angalia kiwango cha idhini katika muktadha wa ombi
auth_level = request.context.get("authorizationLevel")
return auth_level == "admin"
def _redact_sensitive_fields(self, user_data):
# Tengeneza nakala ili kuepuka kubadilisha asili
redacted = user_data.copy()
# Ficha sehemu maalum nyeti
sensitive_fields = ["ssn", "creditCardNumber", "password"]
for field in sensitive_fields:
if field in redacted:
redacted[field] = "REDACTED"
# Ficha data nyeti zilizoko ndani
if "financialInfo" in redacted:
redacted["financialInfo"] = {"available": True, "accessRestricted": True}
return redactedUpimaji kamili huhakikisha zana za MCP zinafanya kazi kwa usahihi, kushughulikia matukio ya pembezoni, na kuunganishwa vyema na mfumo mzima.
Unda majaribio maalum kwa kazi ya kila zana:
[Fact]
public async Task WeatherTool_ValidLocation_ReturnsCorrectForecast()
{
// Arrange
var mockWeatherService = new Mock<IWeatherService>();
mockWeatherService
.Setup(s => s.GetForecastAsync("Seattle", 3))
.ReturnsAsync(new WeatherForecast(/* test data */));
var tool = new WeatherForecastTool(mockWeatherService.Object);
var request = new ToolRequest(
toolName: "weatherForecast",
parameters: JsonSerializer.SerializeToElement(new {
location = "Seattle",
days = 3
})
);
// Act
var response = await tool.ExecuteAsync(request);
// Assert
Assert.NotNull(response);
var result = JsonSerializer.Deserialize<WeatherForecast>(response.Result);
Assert.Equal("Seattle", result.Location);
Assert.Equal(3, result.DailyForecasts.Count);
}
[Fact]
public async Task WeatherTool_InvalidLocation_ThrowsToolExecutionException()
{
// Arrange
var mockWeatherService = new Mock<IWeatherService>();
mockWeatherService
.Setup(s => s.GetForecastAsync("InvalidLocation", It.IsAny<int>()))
.ThrowsAsync(new LocationNotFoundException("Location not found"));
var tool = new WeatherForecastTool(mockWeatherService.Object);
var request = new ToolRequest(
toolName: "weatherForecast",
parameters: JsonSerializer.SerializeToElement(new {
location = "InvalidLocation",
days = 3
})
);
// Act & Assert
var exception = await Assert.ThrowsAsync<ToolExecutionException>(
() => tool.ExecuteAsync(request)
);
Assert.Contains("Location not found", exception.Message);
}Jaribu kwamba mipangilio ni halali na inatekeleza vizuizi ipasavyo:
@Test
public void testSchemaValidation() {
// Tengeneza mfano wa chombo
SearchTool searchTool = new SearchTool();
// Pata skimu
Object schema = searchTool.getSchema();
// Badilisha skimu kuwa JSON kwa ajili ya uthibitishaji
String schemaJson = objectMapper.writeValueAsString(schema);
// Thibitisha skimu ni JSONSchema halali
JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonSchema jsonSchema = factory.getJsonSchema(schemaJson);
// Jaribu vigezo halali
JsonNode validParams = objectMapper.createObjectNode()
.put("query", "test query")
.put("limit", 5);
ProcessingReport validReport = jsonSchema.validate(validParams);
assertTrue(validReport.isSuccess());
// Jaribu kigezo kilichokosekana kinachohitajika
JsonNode missingRequired = objectMapper.createObjectNode()
.put("limit", 5);
ProcessingReport missingReport = jsonSchema.validate(missingRequired);
assertFalse(missingReport.isSuccess());
// Jaribu aina ya kigezo isiyo halali
JsonNode invalidType = objectMapper.createObjectNode()
.put("query", "test")
.put("limit", "not-a-number");
ProcessingReport invalidReport = jsonSchema.validate(invalidType);
assertFalse(invalidReport.isSuccess());
}Tengeneza majaribio maalum ya hali za makosa:
@pytest.mark.asyncio
async def test_api_tool_handles_timeout():
# Panga
tool = ApiTool(timeout=0.1) # Muda mfupi sana wa kusubiri
# Fanya mfano wa ombi litakaloisha muda
with aioresponses() as mocked:
mocked.get(
"https://api.example.com/data",
callback=lambda *args, **kwargs: asyncio.sleep(0.5) # Ndefu zaidi ya muda wa kusubiri
)
request = ToolRequest(
tool_name="apiTool",
parameters={"url": "https://api.example.com/data"}
)
# Tenda & Thibitisha
with pytest.raises(ToolExecutionException) as exc_info:
await tool.execute_async(request)
# Hakiki ujumbe wa makosa
assert "timed out" in str(exc_info.value).lower()
@pytest.mark.asyncio
async def test_api_tool_handles_rate_limiting():
# Panga
tool = ApiTool()
# Fanya mfano wa jibu lililozuiliwa kwa kiwango cha kiwango
with aioresponses() as mocked:
mocked.get(
"https://api.example.com/data",
status=429,
headers={"Retry-After": "2"},
body=json.dumps({"error": "Rate limit exceeded"})
)
request = ToolRequest(
tool_name="apiTool",
parameters={"url": "https://api.example.com/data"}
)
# Tenda & Thibitisha
with pytest.raises(ToolExecutionException) as exc_info:
await tool.execute_async(request)
# Hakiki makosa yanayoonyesha taarifa za kiwango cha kiwango
error_msg = str(exc_info.value).lower()
assert "rate limit" in error_msg
assert "try again" in error_msgJaribu zana zikifanya kazi pamoja katika mchanganyiko unaotarajiwa:
[Fact]
public async Task DataProcessingWorkflow_CompletesSuccessfully()
{
// Arrange
var dataFetchTool = new DataFetchTool(mockDataService.Object);
var analysisTools = new DataAnalysisTool(mockAnalysisService.Object);
var visualizationTool = new DataVisualizationTool(mockVisualizationService.Object);
var toolRegistry = new ToolRegistry();
toolRegistry.RegisterTool(dataFetchTool);
toolRegistry.RegisterTool(analysisTools);
toolRegistry.RegisterTool(visualizationTool);
var workflowExecutor = new WorkflowExecutor(toolRegistry);
// Act
var result = await workflowExecutor.ExecuteWorkflowAsync(new[] {
new ToolCall("dataFetch", new { source = "sales2023" }),
new ToolCall("dataAnalysis", ctx => new {
data = ctx.GetResult("dataFetch"),
analysis = "trend"
}),
new ToolCall("dataVisualize", ctx => new {
analysisResult = ctx.GetResult("dataAnalysis"),
type = "line-chart"
})
});
// Assert
Assert.NotNull(result);
Assert.True(result.Success);
Assert.NotNull(result.GetResult("dataVisualize"));
Assert.Contains("chartUrl", result.GetResult("dataVisualize").ToString());
}Jaribu seva ya MCP kwa usajili na utekelezaji kamili wa zana:
@SpringBootTest
@AutoConfigureMockMvc
public class McpServerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Test
public void testToolDiscovery() throws Exception {
// Jaribu kiunganishi cha ugunduzi
mockMvc.perform(get("/mcp/tools"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.tools").isArray())
.andExpect(jsonPath("$.tools[*].name").value(hasItems(
"weatherForecast", "calculator", "documentSearch"
)));
}
@Test
public void testToolExecution() throws Exception {
// Tengeneza ombi la chombo
Map<String, Object> request = new HashMap<>();
request.put("toolName", "calculator");
Map<String, Object> parameters = new HashMap<>();
parameters.put("operation", "add");
parameters.put("a", 5);
parameters.put("b", 7);
request.put("parameters", parameters);
// Tuma ombi na hakiki jibu
mockMvc.perform(post("/mcp/execute")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.result.value").value(12));
}
@Test
public void testToolValidation() throws Exception {
// Tengeneza ombi batili la chombo
Map<String, Object> request = new HashMap<>();
request.put("toolName", "calculator");
Map<String, Object> parameters = new HashMap<>();
parameters.put("operation", "divide");
parameters.put("a", 10);
// Kipengele kinachokosekana "b"
request.put("parameters", parameters);
// Tuma ombi na hakiki jibu la kosa
mockMvc.perform(post("/mcp/execute")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.error").exists());
}
}Jaribu mitiririko kamili kutoka kiamsha cha modeli hadi utekelezaji wa zana:
@pytest.mark.asyncio
async def test_model_interaction_with_tool():
# Panga - Tengeneza mteja wa MCP na mfano wa kuigiza
mcp_client = McpClient(server_url="http://localhost:5000")
# Jibu la mfano wa kuigiza
mock_model = MockLanguageModel([
MockResponse(
"What's the weather in Seattle?",
tool_calls=[{
"tool_name": "weatherForecast",
"parameters": {"location": "Seattle", "days": 3}
}]
),
MockResponse(
"Here's the weather forecast for Seattle:\n- Today: 65°F, Partly Cloudy\n- Tomorrow: 68°F, Sunny\n- Day after: 62°F, Rain",
tool_calls=[]
)
])
# Jibu la chombo cha hali ya hewa cha kuigiza
with aioresponses() as mocked:
mocked.post(
"http://localhost:5000/mcp/execute",
payload={
"result": {
"location": "Seattle",
"forecast": [
{"date": "2023-06-01", "temperature": 65, "conditions": "Partly Cloudy"},
{"date": "2023-06-02", "temperature": 68, "conditions": "Sunny"},
{"date": "2023-06-03", "temperature": 62, "conditions": "Rain"}
]
}
}
)
# Fanya
response = await mcp_client.send_prompt(
"What's the weather in Seattle?",
model=mock_model,
allowed_tools=["weatherForecast"]
)
# Thibitisha
assert "Seattle" in response.generated_text
assert "65" in response.generated_text
assert "Sunny" in response.generated_text
assert "Rain" in response.generated_text
assert len(response.tool_calls) == 1
assert response.tool_calls[0].tool_name == "weatherForecast"Jaribu ni maombi mangapi sawa seva yako ya MCP inaweza kushughulikia:
[Fact]
public async Task McpServer_HandlesHighConcurrency()
{
// Arrange
var server = new McpServer(
name: "TestServer",
version: "1.0",
maxConcurrentRequests: 100
);
server.RegisterTool(new FastExecutingTool());
await server.StartAsync();
var client = new McpClient("http://localhost:5000");
// Act
var tasks = new List<Task<McpResponse>>();
for (int i = 0; i < 1000; i++)
{
tasks.Add(client.ExecuteToolAsync("fastTool", new { iteration = i }));
}
var results = await Task.WhenAll(tasks);
// Assert
Assert.Equal(1000, results.Length);
Assert.All(results, r => Assert.NotNull(r));
}Jaribu mfumo chini ya mzigo wa hali ya juu sana:
@Test
public void testServerUnderStress() {
int maxUsers = 1000;
int rampUpTimeSeconds = 60;
int testDurationSeconds = 300;
// Tengeneza JMeter kwa jaribio la msongo
StandardJMeterEngine jmeter = new StandardJMeterEngine();
// Sanidi mpango wa jaribio la JMeter
HashTree testPlanTree = new HashTree();
// Unda mpango wa jaribio, kikundi cha nyuzi, sampuli, n.k.
TestPlan testPlan = new TestPlan("MCP Server Stress Test");
testPlanTree.add(testPlan);
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setNumThreads(maxUsers);
threadGroup.setRampUp(rampUpTimeSeconds);
threadGroup.setScheduler(true);
threadGroup.setDuration(testDurationSeconds);
testPlanTree.add(threadGroup);
// Ongeza sampuli ya HTTP kwa ajili ya utekelezaji wa zana
HTTPSampler toolExecutionSampler = new HTTPSampler();
toolExecutionSampler.setDomain("localhost");
toolExecutionSampler.setPort(5000);
toolExecutionSampler.setPath("/mcp/execute");
toolExecutionSampler.setMethod("POST");
toolExecutionSampler.addArgument("toolName", "calculator");
toolExecutionSampler.addArgument("parameters", "{\"operation\":\"add\",\"a\":5,\"b\":7}");
threadGroup.add(toolExecutionSampler);
// Ongeza wasikilizaji
SummaryReport summaryReport = new SummaryReport();
threadGroup.add(summaryReport);
// Endesha jaribio
jmeter.configure(testPlanTree);
jmeter.run();
// Hakiki matokeo
assertEquals(0, summaryReport.getErrorCount());
assertTrue(summaryReport.getAverage() < 200); // Wakati wa majibu wastani < 200ms
assertTrue(summaryReport.getPercentile(90.0) < 500); // Asilimia ya 90 < 500ms
}Weka ufuatiliaji kwa ajili ya uchambuzi wa utendaji wa muda mrefu:
# Sanidi ufuatiliaji kwa seva ya MCP
def configure_monitoring(server):
# Weka vipimo vya Prometheus
prometheus_metrics = {
"request_count": Counter("mcp_requests_total", "Total MCP requests"),
"request_latency": Histogram(
"mcp_request_duration_seconds",
"Request duration in seconds",
buckets=[0.01, 0.05, 0.1, 0.5, 1.0, 2.5, 5.0, 10.0]
),
"tool_execution_count": Counter(
"mcp_tool_executions_total",
"Tool execution count",
labelnames=["tool_name"]
),
"tool_execution_latency": Histogram(
"mcp_tool_duration_seconds",
"Tool execution duration in seconds",
labelnames=["tool_name"],
buckets=[0.01, 0.05, 0.1, 0.5, 1.0, 2.5, 5.0, 10.0]
),
"tool_errors": Counter(
"mcp_tool_errors_total",
"Tool execution errors",
labelnames=["tool_name", "error_type"]
)
}
# Ongeza tabaka kati kwa upimaji na kurekodi vipimo
server.add_middleware(PrometheusMiddleware(prometheus_metrics))
# Fungua sehemu ya vipimo
@server.router.get("/metrics")
async def metrics():
return generate_latest()
return serverMitiririko ya kazi ya MCP imetengenezwa vizuri huongeza ufanisi, kuaminika, na urahisi wa matengenezo. Hapa kuna mifumo muhimu ya kufuata:
Unganisha zana nyingi mfululizo ambapo pato la kila zana linakuwa pembejeo kwa inayofuata:
# Utekelezaji wa Mnyororo wa Zana za Python
class ChainWorkflow:
def __init__(self, tools_chain):
self.tools_chain = tools_chain # Orodha ya majina ya zana za kutekeleza kwa mfululizo
async def execute(self, mcp_client, initial_input):
current_result = initial_input
all_results = {"input": initial_input}
for tool_name in self.tools_chain:
# Tekeleza kila zana katika mnyororo, ukipitisha matokeo ya awali
response = await mcp_client.execute_tool(tool_name, current_result)
# Hifadhi matokeo na utumie kama pembejeo kwa zana inayofuata
all_results[tool_name] = response.result
current_result = response.result
return {
"final_result": current_result,
"all_results": all_results
}
# Mfano wa matumizi
data_processing_chain = ChainWorkflow([
"dataFetch",
"dataCleaner",
"dataAnalyzer",
"dataVisualizer"
])
result = await data_processing_chain.execute(
mcp_client,
{"source": "sales_database", "table": "transactions"}
)Tumia zana kuu inayosambaza kwenda kwa zana maalum kulingana na pembejeo:
public class ContentDispatcherTool : IMcpTool
{
private readonly IMcpClient _mcpClient;
public ContentDispatcherTool(IMcpClient mcpClient)
{
_mcpClient = mcpClient;
}
public string Name => "contentProcessor";
public string Description => "Processes content of various types";
public object GetSchema()
{
return new {
type = "object",
properties = new {
content = new { type = "string" },
contentType = new {
type = "string",
enum = new[] { "text", "html", "markdown", "csv", "code" }
},
operation = new {
type = "string",
enum = new[] { "summarize", "analyze", "extract", "convert" }
}
},
required = new[] { "content", "contentType", "operation" }
};
}
public async Task<ToolResponse> ExecuteAsync(ToolRequest request)
{
var content = request.Parameters.GetProperty("content").GetString();
var contentType = request.Parameters.GetProperty("contentType").GetString();
var operation = request.Parameters.GetProperty("operation").GetString();
// Determine which specialized tool to use
string targetTool = DetermineTargetTool(contentType, operation);
// Forward to the specialized tool
var specializedResponse = await _mcpClient.ExecuteToolAsync(
targetTool,
new { content, options = GetOptionsForTool(targetTool, operation) }
);
return new ToolResponse { Result = specializedResponse.Result };
}
private string DetermineTargetTool(string contentType, string operation)
{
return (contentType, operation) switch
{
("text", "summarize") => "textSummarizer",
("text", "analyze") => "textAnalyzer",
("html", _) => "htmlProcessor",
("markdown", _) => "markdownProcessor",
("csv", _) => "csvProcessor",
("code", _) => "codeAnalyzer",
_ => throw new ToolExecutionException($"No tool available for {contentType}/{operation}")
};
}
private object GetOptionsForTool(string toolName, string operation)
{
// Return appropriate options for each specialized tool
return toolName switch
{
"textSummarizer" => new { length = "medium" },
"htmlProcessor" => new { cleanUp = true, operation },
// Options for other tools...
_ => new { }
};
}
}Tekeleza zana nyingi kwa wakati mmoja kwa ufanisi:
public class ParallelDataProcessingWorkflow {
private final McpClient mcpClient;
public ParallelDataProcessingWorkflow(McpClient mcpClient) {
this.mcpClient = mcpClient;
}
public WorkflowResult execute(String datasetId) {
// Hatua 1: Pata metadata ya dataseti (kwa mstari)
ToolResponse metadataResponse = mcpClient.executeTool("datasetMetadata",
Map.of("datasetId", datasetId));
// Hatua 2: Anzisha uchambuzi mwingi kwa wakati mmoja
CompletableFuture<ToolResponse> statisticalAnalysis = CompletableFuture.supplyAsync(() ->
mcpClient.executeTool("statisticalAnalysis", Map.of(
"datasetId", datasetId,
"type", "comprehensive"
))
);
CompletableFuture<ToolResponse> correlationAnalysis = CompletableFuture.supplyAsync(() ->
mcpClient.executeTool("correlationAnalysis", Map.of(
"datasetId", datasetId,
"method", "pearson"
))
);
CompletableFuture<ToolResponse> outlierDetection = CompletableFuture.supplyAsync(() ->
mcpClient.executeTool("outlierDetection", Map.of(
"datasetId", datasetId,
"sensitivity", "medium"
))
);
// Subiri kazi zote zinazofanywa kwa pamoja kukamilika
CompletableFuture<Void> allAnalyses = CompletableFuture.allOf(
statisticalAnalysis, correlationAnalysis, outlierDetection
);
allAnalyses.join(); // Subiri kumalizika
// Hatua 3: Changanya matokeo
Map<String, Object> combinedResults = new HashMap<>();
combinedResults.put("metadata", metadataResponse.getResult());
combinedResults.put("statistics", statisticalAnalysis.join().getResult());
combinedResults.put("correlations", correlationAnalysis.join().getResult());
combinedResults.put("outliers", outlierDetection.join().getResult());
// Hatua 4: Tengeneza ripoti ya muhtasari
ToolResponse summaryResponse = mcpClient.executeTool("reportGenerator",
Map.of("analysisResults", combinedResults));
// Rudisha matokeo ya mchakato kamili
WorkflowResult result = new WorkflowResult();
result.setDatasetId(datasetId);
result.setAnalysisResults(combinedResults);
result.setSummaryReport(summaryResponse.getResult());
return result;
}
}Tekeleza mbinu za kupunguzia kwa upole kushindwa kwa zana:
class ResilientWorkflow:
def __init__(self, mcp_client):
self.client = mcp_client
async def execute_with_fallback(self, primary_tool, fallback_tool, parameters):
try:
# Jaribu chombo cha msingi kwanza
response = await self.client.execute_tool(primary_tool, parameters)
return {
"result": response.result,
"source": "primary",
"tool": primary_tool
}
except ToolExecutionException as e:
# Rekodi kushindwa
logging.warning(f"Primary tool '{primary_tool}' failed: {str(e)}")
# Rudia tena kwa chombo cha sekondari
try:
# Inaweza kuhitaji kubadilisha vigezo kwa chombo cha akiba
fallback_params = self._adapt_parameters(parameters, primary_tool, fallback_tool)
response = await self.client.execute_tool(fallback_tool, fallback_params)
return {
"result": response.result,
"source": "fallback",
"tool": fallback_tool,
"primaryError": str(e)
}
except ToolExecutionException as fallback_error:
# Vyombo vyote vilianguka
logging.error(f"Both primary and fallback tools failed. Fallback error: {str(fallback_error)}")
raise WorkflowExecutionException(
f"Workflow failed: primary error: {str(e)}; fallback error: {str(fallback_error)}"
)
def _adapt_parameters(self, params, from_tool, to_tool):
"""Adapt parameters between different tools if needed"""
# Utekelezaji huu utategemea vyombo maalum
# Kwa mfano huu, tutarudisha tu vigezo vya awali
return params
# Matumizi ya mfano
async def get_weather(workflow, location):
return await workflow.execute_with_fallback(
"premiumWeatherService", # API ya hali ya hewa ya msingi (ililipwa)
"basicWeatherService", # API ya hali ya hewa ya akiba (bure)
{"location": location}
)Jenga mitiririko tata kwa kuunganisha mitiririko rahisi:
public class CompositeWorkflow : IWorkflow
{
private readonly List<IWorkflow> _workflows;
public CompositeWorkflow(IEnumerable<IWorkflow> workflows)
{
_workflows = new List<IWorkflow>(workflows);
}
public async Task<WorkflowResult> ExecuteAsync(WorkflowContext context)
{
var results = new Dictionary<string, object>();
foreach (var workflow in _workflows)
{
var workflowResult = await workflow.ExecuteAsync(context);
// Store each workflow's result
results[workflow.Name] = workflowResult;
// Update context with the result for the next workflow
context = context.WithResult(workflow.Name, workflowResult);
}
return new WorkflowResult(results);
}
public string Name => "CompositeWorkflow";
public string Description => "Executes multiple workflows in sequence";
}
// Example usage
var documentWorkflow = new CompositeWorkflow(new IWorkflow[] {
new DocumentFetchWorkflow(),
new DocumentProcessingWorkflow(),
new InsightGenerationWorkflow(),
new ReportGenerationWorkflow()
});
var result = await documentWorkflow.ExecuteAsync(new WorkflowContext {
Parameters = new { documentId = "12345" }
});Upimaji ni kipengele muhimu katika kuendeleza seva za MCP zenye kuaminika na ubora wa hali ya juu. Mwongozo huu unatoa mazoea bora na vidokezo vya upimaji seva zako za MCP katika mzunguko wote wa maendeleo, kutoka majaribio ya msingi hadi majaribio ya uunganishaji na uthibitishaji wa mwisho-mwisho.
Seva za MCP hutumikia kama programu za kati muhimu kati ya modeli za AI na programu za wateja. Upimaji kamili huhakikisha:
- Kuaminika katika mazingira ya uzalishaji
- Kushughulikia kwa usahihi maombi na majibu
- Utekelezaji sahihi wa vipimo vya MCP
- Ustahimilivu dhidi ya kushindwa na matukio ya pembezoni
- Utendaji thabiti chini ya mizunguko mbalimbali ya mzigo
Majaribio ya kiwango kidogo yanathibitisha vipengele binafsi vya seva yako ya MCP kwa kujitenga.
- Watendaji wa Rasilimali: Jaribu mantiki ya kila mtendaji wa rasilimali kwa kujitegemea
- Utekelezaji wa Zana: Hakiki tabia ya zana kwa pembejeo mbalimbali
- Mitindo ya Kiamsha: Hakikisha mitindo ya viamsha inatolewa vizuri
- Uhakiki wa Mpangilio: Jaribu mantiki ya uhakiki wa vigezo
- Usimamizi wa Makosa: Hakiki majibu ya makosa kwa pembejeo batili
// Example unit test for a calculator tool in C#
[Fact]
public async Task CalculatorTool_Add_ReturnsCorrectSum()
{
// Arrange
var calculator = new CalculatorTool();
var parameters = new Dictionary<string, object>
{
["operation"] = "add",
["a"] = 5,
["b"] = 7
};
// Act
var response = await calculator.ExecuteAsync(parameters);
var result = JsonSerializer.Deserialize<CalculationResult>(response.Content[0].ToString());
// Assert
Assert.Equal(12, result.Value);
}# Mfano wa jaribio la kitengo kwa chombo cha kalkuleta katika Python
def test_calculator_tool_add():
# Panga
calculator = CalculatorTool()
parameters = {
"operation": "add",
"a": 5,
"b": 7
}
# Fanya
response = calculator.execute(parameters)
result = json.loads(response.content[0].text)
# Thibitisha
assert result["value"] == 12Majaribio ya uunganishaji yanathibitisha mwingiliano kati ya vipengele vya seva yako ya MCP.
- Kuanza Seva: Jaribu huduma ya seva na usanidi tofauti
- Usajili wa Njia: Hakiki kwamba vituo vyote vinaandikishwa ipasavyo
- Usindikaji wa Maombi: Jaribu mzunguko kamili wa maombi-majibu
- Uenezaji wa Makosa: Hakikisha makosa yanashughulikiwa ipasavyo kati ya vipengele
- Utambulisho na Idhini: Jaribu mifumo ya usalama
// Example integration test for MCP server in C#
[Fact]
public async Task Server_ProcessToolRequest_ReturnsValidResponse()
{
// Arrange
var server = new McpServer();
server.RegisterTool(new CalculatorTool());
await server.StartAsync();
var request = new McpRequest
{
Tool = "calculator",
Parameters = new Dictionary<string, object>
{
["operation"] = "multiply",
["a"] = 6,
["b"] = 7
}
};
// Act
var response = await server.ProcessRequestAsync(request);
// Assert
Assert.NotNull(response);
Assert.Equal(McpStatusCodes.Success, response.StatusCode);
// Additional assertions for response content
// Cleanup
await server.StopAsync();
}Majaribio ya mwisho-mwisho yanathibitisha tabia kamili ya mfumo kutoka kwa mteja hadi seva.
- Mawasiliano ya Mteja-Seva: Jaribu mizunguko kamili ya maombi-majibu
- SDK za Mteja Halisi: Jaribu kwa utekelezaji halisi wa wateja
- Utendaji Chini ya Mzigo: Hakiki tabia kwa maombi mengi sambamba
- Kupona Makosa: Jaribu kupona kwa mfumo kutoka kwa kushindwa
- Shughuli Zenye Mzunguko Mrefu: Hakiki usimamizi wa mtiririko na shughuli ndefu
// Mfano wa jaribio la E2E na mteja katika TypeScript
describe('MCP Server E2E Tests', () => {
let client: McpClient;
beforeAll(async () => {
// Anzisha seva katika mazingira ya mtihani
await startTestServer();
client = new McpClient('http://localhost:5000');
});
afterAll(async () => {
await stopTestServer();
});
test('Client can invoke calculator tool and get correct result', async () => {
// Tenda
const response = await client.invokeToolAsync('calculator', {
operation: 'divide',
a: 20,
b: 4
});
// Thibitisha
expect(response.statusCode).toBe(200);
expect(response.content[0].text).toContain('5');
});
});Kuiga ni muhimu ili kutenganisha vipengele wakati wa upimaji.
- Mifano ya AI ya Nje: Kuiga majibu ya modeli kwa upimaji wa utabiri
- Huduma za Nje: Kuiga utegemezi wa API (hifadhidata, huduma za tatu)
- Huduma za Utambulisho: Kuiga watoaji wa utambulisho
- Watoa Rasilimali: Kuiga watendaji wa rasilimali ghali
// C# example with Moq
var mockModel = new Mock<ILanguageModel>();
mockModel
.Setup(m => m.GenerateResponseAsync(
It.IsAny<string>(),
It.IsAny<McpRequestContext>()))
.ReturnsAsync(new ModelResponse {
Text = "Mocked model response",
FinishReason = FinishReason.Completed
});
var server = new McpServer(modelClient: mockModel.Object);# Mfano wa Python na unittest.mock
@patch('mcp_server.models.OpenAIModel')
def test_with_mock_model(mock_model):
# Sanidi mock
mock_model.return_value.generate_response.return_value = {
"text": "Mocked model response",
"finish_reason": "completed"
}
# Tumia mock katika jaribio
server = McpServer(model_client=mock_model)
# Endelea na jaribioUpimaji wa utendaji ni muhimu kwa seva za MCP za uzalishaji.
- Ucheleweshaji: Muda wa majibu kwa maombi
- Uwezo wa Kushughulikia Maombi: Idadi ya maombi yanayoshughulikiwa kwa sekunde
- Matumizi ya Rasilimali: Matumizi ya CPU, kumbukumbu, mtandao
- Usimamizi wa Mizunguko Sambamba: Tabia chini ya maombi ya sambamba
- Sifa za Kupanua: Utendaji unavyobadilika kwa kuongezeka kwa mzigo
- k6: Zana ya upimaji mzigo ya chanzo huria
- JMeter: Upimaji wa utendaji kamili
- Locust: Upimaji mzigo unaotumia Python
- Azure Load Testing: Upimaji wa utendaji wa wingu
// skripti ya k6 kwa upimaji mzigo wa seva ya MCP
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10, // watumiaji wa mtandao 10
duration: '30s',
};
export default function () {
const payload = JSON.stringify({
tool: 'calculator',
parameters: {
operation: 'add',
a: Math.floor(Math.random() * 100),
b: Math.floor(Math.random() * 100)
}
});
const params = {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer test-token'
},
};
const res = http.post('http://localhost:5000/api/tools/invoke', payload, params);
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}Kuendesha majaribio yako kwa njia ya kiotomatiki huhakikisha ubora thabiti na mizunguko ya majibu ya haraka.
- Endesha Vipimo vya Unit kwenye Maombi ya Kuvuta: Hakikisha mabadiliko ya msimbo hayatavunja utendakazi uliopo
- Vipimo vya Muunganisho katika Mazingira ya Kujaribu: Endesha vipimo vya muunganisho katika mazingira ya kabla ya uzalishaji
- Misingi ya Utendaji: Dumisha viwango vya utendaji ili kugundua nyuma
- Skani za Usalama: Tengeneza mtihani wa usalama kama sehemu ya mchakato
name: MCP Server Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Runtime
uses: actions/setup-dotnet@v1
with:
dotnet-version: '8.0.x'
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Unit Tests
run: dotnet test --no-build --filter Category=Unit
- name: Integration Tests
run: dotnet test --no-build --filter Category=Integration
- name: Performance Tests
run: dotnet run --project tests/PerformanceTests/PerformanceTests.csprojThibitisha server yako inatekeleza maelezo ya MCP kwa usahihi.
- Vituo vya API: Jaribu vituo vinavyohitajika (/resources, /tools, n.k.)
- Muundo wa Maombi/Jawabu: Thibitisha ufuataji wa skema
- Nambari za Makosa: Hakikisha nambari sahihi za hali kwa matukio mbalimbali
- Aina za Yaliyomo: Jaribu kushughulikia aina tofauti za yaliyomo
- Mtiririko wa Uthibitishaji: Thibitisha michakato ya uthibitishaji inayolingana na maelezo
[Fact]
public async Task Server_ResourceEndpoint_ReturnsCorrectSchema()
{
// Arrange
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer test-token");
// Act
var response = await client.GetAsync("http://localhost:5000/api/resources");
var content = await response.Content.ReadAsStringAsync();
var resources = JsonSerializer.Deserialize<ResourceList>(content);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(resources);
Assert.All(resources.Resources, resource =>
{
Assert.NotNull(resource.Id);
Assert.NotNull(resource.Type);
// Additional schema validation
});
}- Jaribu Maelezo ya Zana Kando: Thibitisha maelezo ya skema peke yake mbali na mantiki ya zana
- Tumia Vipimo Vilivyopangwa: Jaribu zana kwa aina mbalimbali za ingizo, ikijumuisha hali za kipekee
- Angalia Majibu ya Makosa: Hakikisha usimamizi sahihi wa makosa kwa hali zote za makosa zinazowezekana
- Jaribu Mantiki ya Idhini: Hakikisha udhibiti sahihi wa upatikanaji kwa majukumu tofauti ya watumiaji
- Fuatilia Ueneaji wa Vipimo: Lenga kufikia ueneaji mkubwa wa msimbo wa njia muhimu
- Jaribu Majibu ya Mtiririko: Hakikisha kushughulikia kwa usahihi yaliyomo yanayorushwa mtiririko
- Sanifu Matatizo ya Mtandao: Jaribu tabia chini ya hali mbaya za mtandao
- Jaribu Vizingiti vya Rasilimali: Thibitisha tabia wakati mipaka au viwango vya kasi vinafikiwa
- Jalibisha Vipimo vya Kuangusha Mabadiliko: Tengeneza mkusanyiko unaoendeshwa kila unapobadilisha msimbo
- Andika Hali za Vipimo: Dumisha nyaraka wazi za matukio ya vipimo
- Kutegemea Kupita Kiasi Vipimo vya Njia Rahisi: Hakikisha kupima hali za makosa kwa kina
- Kusahau Upimaji wa Utendaji: Tambua vizuizi kabla havijaathiri uzalishaji
- Kupima Pekee Kwa Kutengwa: Changanya vipimo vya unit, muunganisho, na mwisho-mwisho
- Ueneaji Usio Kamili wa API: Hakikisha vituo vyote na vipengele vinapimwa
- Mazingaombwe ya Mazingira ya Vipimo Yasiyo Linganifu: Tumia kontena ili kuhakikisha mazingira ya vipimo yanalingana
Mikakati kamili ya kupima ni muhimu kwa kuendeleza server za MCP zenye kuaminika na ubora wa juu. Kwa kutekeleza mbinu bora na vidokezo vilivyoainishwa katika mwongozo huu, unaweza kuhakikisha utekelezaji wako wa MCP unakutana na viwango vikubwa vya ubora, kuaminika, na utendaji.
- Ubunifu wa Zana: Fuata kanuni ya jukumu moja, tumia sindano ya utegemezi, na ngaiza ubunifu wa muungano
- Ubunifu wa Skema: Tengeneza skema zilizo wazi na zilizotangazwa vyema na vizuizi vya uthibitishaji sahihi
- Usimamizi wa Makosa: Tekeleza usimamizi mzuri wa makosa, majibu ya makosa yaliyopangwa, na mantiki ya jaribio tena
- Utendaji: Tumia uhifadhi wa muda, usindikaji usio sambamba, na kuzuia matumizi ya rasilimali
- Usalama: Tekeleza uthibitishaji mzuri wa ingizo, ukaguzi wa idhini, na usimamizi wa data nyeti
- Vipimo: Tengeneza vipimo kamilifu vya unit, muunganisho, na mwisho-mwisho
- Mifumo ya Mtiririko wa Kazi: Tumia mifumo iliyojulikana kama mnyororo, wasambazaji, na usindikaji sambamba
Sanifu zana ya MCP na mtiririko wa kazi kwa mfumo wa usindikaji wa nyaraka unaofanya:
- Kupokea nyaraka katika fomati mbalimbali (PDF, DOCX, TXT)
- Kuchuja maandishi na taarifa muhimu kutoka kwenye nyaraka
- Kugawanya nyaraka kwa aina na yaliyomo
- Kutengeneza muhtasari wa kila nyaraka
Tekeleza skema za zana, usimamizi wa makosa, na mtiririko wa kazi unaofaa zaidi kwa hali hii. Fikiria jinsi utakavyopima utekelezaji huu.
- Jiunge na jamii ya MCP kwenye Azure AI Foundry Discord Community ili uwe na taarifa mpya za maendeleo
- Changia kwenye miradi ya chanzo wazi ya MCP projects
- Tumia kanuni za MCP katika miradi ya AI ya shirika lako
- Chunguza utekelezaji wa MCP maalum kwa sekta yako.
- Fikiria kuhudhuria kozi za juu juu ya mada maalum za MCP, kama vile muunganisho wa njia nyingi au muunganisho wa programu za biashara.
- Jaribu kujijengea zana na mitiririko yako ya MCP kwa kutumia kanuni ulizojifunza kupitia Hands on Lab
Kinachofuata: Case Studies
Kipinga Hukumu: Hati hii imetafsiriwa kwa kutumia huduma ya tafsiri ya AI Co-op Translator. Ingawa tunajitahidi kwa usahihi, tafadhali fahamu kwamba tafsiri za kiotomatiki zinaweza kuwa na makosa au upotovu wa maana. Hati asili katika lugha yake ya asili inapaswa kuzingatiwa kama chanzo cha mamlaka. Kwa habari muhimu, tafsiri ya mtaalamu wa binadamu inapendekezwa. Hatuwajibiki kwa kutoelewana au tafsiri isiyo sahihi inayotokana na matumizi ya tafsiri hii.
