このバージョンはまだ開発中であり、まだ安定しているとは考えられていません。最新のスナップショットバージョンについては、Spring AI 1.1.2 を使用してください。 |
MCP アノテーションの特殊パラメーター
MCP アノテーションは、アノテーションされたメソッドに追加のコンテキストと機能を提供するいくつかの特殊なパラメーター型をサポートしています。これらのパラメーターはフレームワークによって自動的に挿入され、JSON スキーマ生成からは除外されます。
特殊なパラメーター型
McpMeta
McpMeta クラスは、MCP リクエスト、通知、結果からのメタデータへのアクセスを提供します。
概要
メソッドパラメーターとして使用された場合、自動的に挿入されます
パラメーター数の制限と JSON スキーマ生成から除外
get(String key)メソッドを通じてメタデータへの便利なアクセスを提供しますリクエストにメタデータが存在しない場合は、空の
McpMetaオブジェクトが挿入されます。
ツールでの使用
@McpTool(name = "contextual-tool", description = "Tool with metadata access")
public String processWithContext(
@McpToolParam(description = "Input data", required = true) String data,
McpMeta meta) {
// Access metadata from the request
String userId = (String) meta.get("userId");
String sessionId = (String) meta.get("sessionId");
String userRole = (String) meta.get("userRole");
// Use metadata to customize behavior
if ("admin".equals(userRole)) {
return processAsAdmin(data, userId);
} else {
return processAsUser(data, userId);
}
}リソースでの使用
@McpResource(uri = "secure-data://{id}", name = "Secure Data")
public ReadResourceResult getSecureData(String id, McpMeta meta) {
String requestingUser = (String) meta.get("requestingUser");
String accessLevel = (String) meta.get("accessLevel");
// Check access permissions using metadata
if (!"admin".equals(accessLevel)) {
return new ReadResourceResult(List.of(
new TextResourceContents("secure-data://" + id,
"text/plain", "Access denied")
));
}
String data = loadSecureData(id);
return new ReadResourceResult(List.of(
new TextResourceContents("secure-data://" + id,
"text/plain", data)
));
}プロンプトでの使用
@McpPrompt(name = "localized-prompt", description = "Localized prompt generation")
public GetPromptResult localizedPrompt(
@McpArg(name = "topic", required = true) String topic,
McpMeta meta) {
String language = (String) meta.get("language");
String region = (String) meta.get("region");
// Generate localized content based on metadata
String message = generateLocalizedMessage(topic, language, region);
return new GetPromptResult("Localized Prompt",
List.of(new PromptMessage(Role.ASSISTANT, new TextContent(message)))
);
}@McpProgressToken
@McpProgressToken アノテーションは、MCP リクエストから進行状況トークンを受信するためのパラメーターをマークします。
概要
パラメーター型は
Stringである必要がありますリクエストから進行トークンの値を自動的に受信します
生成された JSON スキーマから除外
進捗トークンが存在しない場合は、
nullが注入される長時間実行される操作を追跡するために使用されます
ツールでの使用
@McpTool(name = "long-operation", description = "Long-running operation with progress")
public String performLongOperation(
@McpProgressToken String progressToken,
@McpToolParam(description = "Operation name", required = true) String operation,
@McpToolParam(description = "Duration in seconds", required = true) int duration,
McpSyncServerExchange exchange) {
if (progressToken != null) {
// Send initial progress
exchange.progressNotification(new ProgressNotification(
progressToken, 0.0, 1.0, "Starting " + operation));
// Simulate work with progress updates
for (int i = 1; i <= duration; i++) {
Thread.sleep(1000);
double progress = (double) i / duration;
exchange.progressNotification(new ProgressNotification(
progressToken, progress, 1.0,
String.format("Processing... %d%%", (int)(progress * 100))));
}
}
return "Operation " + operation + " completed";
}リソースでの使用
@McpResource(uri = "large-file://{path}", name = "Large File Resource")
public ReadResourceResult getLargeFile(
@McpProgressToken String progressToken,
String path,
McpSyncServerExchange exchange) {
File file = new File(path);
long fileSize = file.length();
if (progressToken != null) {
// Track file reading progress
exchange.progressNotification(new ProgressNotification(
progressToken, 0.0, fileSize, "Reading file"));
}
String content = readFileWithProgress(file, progressToken, exchange);
if (progressToken != null) {
exchange.progressNotification(new ProgressNotification(
progressToken, fileSize, fileSize, "File read complete"));
}
return new ReadResourceResult(List.of(
new TextResourceContents("large-file://" + path, "text/plain", content)
));
}McpSyncRequestContext/McpAsyncRequestContext
リクエストコンテキストオブジェクトは、MCP リクエスト情報とサーバー側操作への統合されたアクセスを提供します。
概要
ステートフル操作とステートレス操作の両方に統一されたインターフェースを提供します
パラメーターとして使用すると自動的に挿入されます
JSON スキーマ生成から除外
ログ記録、進捗通知、サンプリング、抽出などの高度な機能を有効にします
ステートフル(サーバー交換)モードとステートレス(トランスポートコンテキスト)モードの両方で動作します
McpSyncRequestContext の機能
public record UserInfo(String name, String email, int age) {}
@McpTool(name = "advanced-tool", description = "Tool with full server capabilities")
public String advancedTool(
McpSyncRequestContext context,
@McpToolParam(description = "Input", required = true) String input) {
// Send logging notification
context.info("Processing: " + input);
// Ping the client
context.ping();
// Send progress updates
context.progress(50); // 50% complete
// Check if elicitation is supported before using it
if (context.elicitEnabled()) {
// Request additional information from user
StructuredElicitResult<UserInfo> elicitResult = context.elicit(
e -> e.message("Need additional information"),
UserInfo.class
);
if (elicitResult.action() == ElicitResult.Action.ACCEPT) {
UserInfo userInfo = elicitResult.structuredContent();
// Use the user information
}
}
// Check if sampling is supported before using it
if (context.sampleEnabled()) {
// Request LLM sampling
CreateMessageResult samplingResult = context.sample(
s -> s.message("Process: " + input)
.modelPreferences(pref -> pref.modelHints("gpt-4"))
);
}
return "Processed with advanced features";
}McpAsyncRequestContext の機能
public record UserInfo(String name, String email, int age) {}
@McpTool(name = "async-advanced-tool", description = "Async tool with server capabilities")
public Mono<String> asyncAdvancedTool(
McpAsyncRequestContext context,
@McpToolParam(description = "Input", required = true) String input) {
return context.info("Async processing: " + input)
.then(context.progress(25))
.then(context.ping())
.flatMap(v -> {
// Perform elicitation if supported
if (context.elicitEnabled()) {
return context.elicitation(UserInfo.class)
.map(userInfo -> "Processing for user: " + userInfo.name());
}
return Mono.just("Processing...");
})
.flatMap(msg -> {
// Perform sampling if supported
if (context.sampleEnabled()) {
return context.sampling("Process: " + input)
.map(result -> "Completed: " + result);
}
return Mono.just("Completed: " + msg);
});
}McpTransportContext
ステートレス操作のための軽量コンテキスト。
使用例
@McpTool(name = "stateless-tool", description = "Stateless tool with context")
public String statelessTool(
McpTransportContext context,
@McpToolParam(description = "Input", required = true) String input) {
// Limited context access
// Useful for transport-level operations
return "Processed in stateless mode: " + input;
}
@McpResource(uri = "stateless://{id}", name = "Stateless Resource")
public ReadResourceResult statelessResource(
McpTransportContext context,
String id) {
// Access transport context if needed
String data = loadData(id);
return new ReadResourceResult(List.of(
new TextResourceContents("stateless://" + id, "text/plain", data)
));
}CallToolRequest
動的スキーマを使用して完全なリクエストにアクセスする必要があるツールの特別なパラメーター。
使用例
@McpTool(name = "dynamic-tool", description = "Tool with dynamic schema support")
public CallToolResult processDynamicSchema(CallToolRequest request) {
Map<String, Object> args = request.arguments();
// Process based on whatever schema was provided at runtime
StringBuilder result = new StringBuilder("Processed:\n");
for (Map.Entry<String, Object> entry : args.entrySet()) {
result.append(" ").append(entry.getKey())
.append(": ").append(entry.getValue()).append("\n");
}
return CallToolResult.builder()
.addTextContent(result.toString())
.build();
}混合パラメーター
@McpTool(name = "hybrid-tool", description = "Tool with typed and dynamic parameters")
public String processHybrid(
@McpToolParam(description = "Operation", required = true) String operation,
@McpToolParam(description = "Priority", required = false) Integer priority,
CallToolRequest request) {
// Use typed parameters for known fields
String result = "Operation: " + operation;
if (priority != null) {
result += " (Priority: " + priority + ")";
}
// Access additional dynamic arguments
Map<String, Object> allArgs = request.arguments();
// Remove known parameters to get only additional ones
Map<String, Object> additionalArgs = new HashMap<>(allArgs);
additionalArgs.remove("operation");
additionalArgs.remove("priority");
if (!additionalArgs.isEmpty()) {
result += " with " + additionalArgs.size() + " additional parameters";
}
return result;
}進捗トークンを使用する場合
@McpTool(name = "flexible-with-progress", description = "Flexible tool with progress")
public CallToolResult flexibleWithProgress(
@McpProgressToken String progressToken,
CallToolRequest request,
McpSyncServerExchange exchange) {
Map<String, Object> args = request.arguments();
if (progressToken != null) {
exchange.progressNotification(new ProgressNotification(
progressToken, 0.0, 1.0, "Processing dynamic request"));
}
// Process dynamic arguments
String result = processDynamicArgs(args);
if (progressToken != null) {
exchange.progressNotification(new ProgressNotification(
progressToken, 1.0, 1.0, "Complete"));
}
return CallToolResult.builder()
.addTextContent(result)
.build();
}パラメーター注入ルール
ベストプラクティス
コンテキストには McpMeta を使用する
@McpTool(name = "context-aware", description = "Context-aware tool")
public String contextAware(
@McpToolParam(description = "Data", required = true) String data,
McpMeta meta) {
// Always check for null values in metadata
String userId = (String) meta.get("userId");
if (userId == null) {
userId = "anonymous";
}
return processForUser(data, userId);
}プログレストークンの Null チェック
@McpTool(name = "safe-progress", description = "Safe progress handling")
public String safeProgress(
@McpProgressToken String progressToken,
@McpToolParam(description = "Task", required = true) String task,
McpSyncServerExchange exchange) {
// Always check if progress token is available
if (progressToken != null) {
exchange.progressNotification(new ProgressNotification(
progressToken, 0.0, 1.0, "Starting"));
}
// Perform work...
if (progressToken != null) {
exchange.progressNotification(new ProgressNotification(
progressToken, 1.0, 1.0, "Complete"));
}
return "Task completed";
}適切なコンテキストを選択する
リクエストコンテキストへの統一されたアクセスのために
McpSyncRequestContext/McpAsyncRequestContextを使用し、便利なヘルパーメソッドでステートフル操作とステートレス操作の両方をサポートします。トランスポートレベルのコンテキストのみが必要な場合は、単純なステートレス操作に
McpTransportContextを使用します。最も単純なケースではコンテキストパラメーターを完全に省略する
機能確認
クライアント機能を使用する前に、必ず機能のサポートを確認してください。
@McpTool(name = "capability-aware", description = "Tool that checks capabilities")
public String capabilityAware(
McpSyncRequestContext context,
@McpToolParam(description = "Data", required = true) String data) {
// Check if elicitation is supported before using it
if (context.elicitEnabled()) {
// Safe to use elicitation
var result = context.elicit(UserInfo.class);
// Process result...
}
// Check if sampling is supported before using it
if (context.sampleEnabled()) {
// Safe to use sampling
var samplingResult = context.sample("Process: " + data);
// Process result...
}
// Note: Stateless servers do not support bidirectional operations
// (roots, elicitation, sampling) and will return false for these checks
return "Processed with capability awareness";
}