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.server.mcp.v20260728; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.util.*; 022 023/** 024 * Thrown by a handler's ordinary {@code call}/{@code get}/{@code read} body to signal that it needs more input 025 * before it can complete (MCP {@code 2026-07-28} SEP-2322 Multi-Round-Trip Requests). 026 * 027 * <p> 028 * Caught (and turned into an {@code input_required} result) <b>only</b> on the three MRTR-wired in-scope paths: 029 * {@link McpRevision}'s {@code callTool}/{@code getPrompt}/{@code readResource}-exact-resource branches. Any other 030 * handler path is <b>not</b> MRTR-wired — the resource-<i>template</i> handler, a {@code completion/complete} 031 * completer, and the list/discover/ping paths all run outside those try/catch blocks. A signal thrown from one of 032 * them is not caught here; it propagates to {@link McpRevision#dispatch}'s generic error branch and surfaces as the 033 * {@code -32603} internal-error fail-safe (a misuse outcome, not an {@code input_required} result). This is the 034 * spec's Open item #4: MRTR engages by construction only for the three scoped seams, so an out-of-scope pause is a 035 * handler bug the fail-safe contains rather than a supported flow. 036 * 037 * <p> 038 * Deliberately <b>not</b> an {@link org.apache.juneau.bean.jsonrpc.McpException}: it is not itself a JSON-RPC 039 * error, it is an internal dispatch-control signal that gets turned into a successful {@code input_required} 040 * result. 041 */ 042public class McpInputRequiredSignal extends RuntimeException { 043 044 private static final long serialVersionUID = 1L; 045 046 private final transient Map<String,Object> inputRequests; 047 private final transient Object continuation; 048 049 /** 050 * Constructor. 051 * 052 * @param inputRequests Server-assigned-id-keyed map of requested inputs. Must not be <jk>null</jk> or empty. 053 * Each value must be a sub-request object ({@code Map}, per the pinned schema); it is carried to the wire 054 * byte-for-byte (a non-map value is a handler bug the dispatcher's {@code -32603} fail-safe contains). 055 * @param continuation Handler-opaque continuation value. Can be <jk>null</jk> if the handler needs no 056 * state carried between rounds beyond the original request itself. 057 * @throws IllegalArgumentException If {@code inputRequests} is <jk>null</jk> or empty. 058 */ 059 public McpInputRequiredSignal(Map<String,Object> inputRequests, Object continuation) { 060 super("Handler requested more input"); 061 if (ie(inputRequests)) 062 throw iaex("inputRequests must not be null or empty"); 063 this.inputRequests = inputRequests; 064 this.continuation = continuation; 065 } 066 067 /** 068 * The requested inputs. 069 * 070 * @return The map. Never <jk>null</jk> or empty. 071 */ 072 public Map<String,Object> getInputRequests() { 073 return inputRequests; 074 } 075 076 /** 077 * The handler-opaque continuation. 078 * 079 * @return The continuation, or <jk>null</jk> if the handler supplied none. 080 */ 081 public Object getContinuation() { 082 return continuation; 083 } 084}