001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.client.mcp.v20260728; 018 019import java.io.*; 020import java.util.*; 021 022import org.apache.juneau.bean.mcp.v20260728.*; 023 024/** 025 * Caller-supplied callback that answers one round of server→client MCP {@code 2026-07-28} SEP-2322 026 * elicitation requests during a client-side Multi-Round-Trip-Request (MRTR) auto-resume loop. 027 * 028 * <p> 029 * Passed to {@link McpClient#callToolWithElicitation}, {@link McpClient#getPromptWithElicitation}, and 030 * {@link McpClient#readResourceWithElicitation}: each time the server pauses a call with an {@code input_required} 031 * result, the client decodes that round's pending requests (there may be more than one) and invokes 032 * {@link #elicit(Map)} to obtain the matching answers, which it then echoes back on the resume call. This turns 033 * the otherwise hand-driven {@link McpClient#callRaw}/{@link ElicitationRequests}/{@link ElicitationResponses} 034 * loop into a single call plus one handler. 035 * 036 * <p> 037 * A handler answers by returning, keyed by the same server-assigned ids it was given, an {@link ElicitResult} 038 * per request it wishes to answer — an {@link ElicitAction#ACCEPT} with content, or an 039 * {@link ElicitAction#DECLINE}/{@link ElicitAction#CANCEL} to refuse. Decline/cancel answers are still sent back 040 * to the server (which decides the terminal outcome of a refused elicitation); the client does not short-circuit 041 * them locally. 042 * 043 * @since 10.0.0 044 */ 045@FunctionalInterface 046public interface McpElicitationHandler { 047 048 /** 049 * Answers one round of elicitation requests. 050 * 051 * <p> 052 * The returned map may legitimately omit ids the handler chooses not to answer (the server may then 053 * re-pause, bounded by the auto-resume loop's max-rounds guard); returning <jk>null</jk> outright is illegal 054 * and causes the auto-resume loop to throw {@link IllegalArgumentException}; and any extra/unknown ids 055 * present in the returned map are echoed back to the server unvalidated. 056 * 057 * @param requests The pending requests for this round, keyed by server-assigned id (decoded via 058 * {@link ElicitationRequests#requests(Map)}). Never <jk>null</jk>; may contain more than one entry, and an 059 * individual value may be <jk>null</jk> if the corresponding raw entry was absent/<jk>null</jk>. 060 * @return The answers keyed by the same server-assigned ids. Must not be <jk>null</jk>. An 061 * {@link ElicitResult} value must not be <jk>null</jk>. Use a {@link LinkedHashMap} for deterministic 062 * ordering of the echoed {@code inputResponses}. May legitimately omit ids the handler chooses not to 063 * answer (the server may then re-pause, bounded by the loop's max-rounds guard). 064 * @throws IOException If the handler performs its own I/O (e.g. prompting a remote user) and it fails; the 065 * auto-resume loop propagates it to the caller unchanged. 066 */ 067 Map<String,ElicitResult> elicit(Map<String,ElicitRequest> requests) throws IOException; 068}