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;
018
019
020import java.util.*;
021import java.util.function.*;
022
023import org.apache.juneau.commons.inject.*;
024import static org.apache.juneau.commons.utils.Shorts.*;
025
026/**
027 * Handler for a single MCP prompt.
028 *
029 * <p>
030 * Implementations declare a {@link #descriptor() descriptor} (the {@link McpPromptSpec} returned by
031 * {@code prompts/list}) and a {@link #get(Map, BeanStore) get} body invoked when the matching
032 * {@code prompts/get} method runs.
033 *
034 * <p>
035 * This is a genuine two-method contract, not a single-method one: both {@link #descriptor()} and
036 * {@link #get(Map, BeanStore)} are abstract, so it is deliberately <b>not</b> annotated
037 * {@code @FunctionalInterface} and a bare lambda cannot implement it. Routing calls {@link #descriptor()}
038 * on every registered handler for both {@code prompts/list} and {@code prompts/get}, so a handler with no
039 * usable descriptor is not a valid handler; making {@link #descriptor()} abstract catches that at compile
040 * time instead of the first request to reach it at runtime. Use {@link #of(McpPromptSpec, BiFunction)} for
041 * the common case of wiring both in a single expression.
042 */
043public interface McpPromptHandler {
044
045   /**
046    * Builds a handler from a fixed descriptor and a {@code get} lambda.
047    *
048    * <p>
049    * The sanctioned one-expression path for registering a prompt: unlike a bare lambda (which cannot
050    * satisfy this two-method interface at all), this factory wires both {@link #descriptor()} and
051    * {@link #get(Map, BeanStore)} from a single call.
052    *
053    * @param descriptor The static descriptor returned from every {@link #descriptor()} call. Must not be
054    *    <jk>null</jk> and must carry a non-blank {@link McpPromptSpec#getName() name} (routing matches
055    *    incoming {@code prompts/get} requests on name, so a nameless prompt would be silently unreachable).
056    * @param get The get body, invoked with the incoming arguments and the per-request bean store. Must not be <jk>null</jk>.
057    * @return A new handler wiring both. Never <jk>null</jk>.
058    */
059   static McpPromptHandler of(McpPromptSpec descriptor, BiFunction<Map<String,Object>,BeanStore,McpPromptOutcome> get) {
060      reqnn("descriptor", descriptor);
061      reqnb("descriptor.getName()", descriptor.getName());
062      reqnn("get", get);
063      return new McpPromptHandler() {
064         @Override public McpPromptSpec descriptor() {
065            return descriptor;
066         }
067
068         @Override public McpPromptOutcome get(Map<String,Object> arguments, BeanStore ctx) {
069            return get.apply(arguments, ctx);
070         }
071      };
072   }
073
074   /**
075    * Returns the static descriptor for this prompt.
076    *
077    * <p>
078    * The {@link McpPromptSpec#getName() name} value is used by the bound {@link McpRevision} to route
079    * incoming {@code prompts/get} requests, so each handler in an {@link McpServerConfig} must use a
080    * unique name.
081    *
082    * @return The prompt descriptor. Never {@code null}.
083    */
084   McpPromptSpec descriptor();
085
086   /**
087    * Renders the prompt.
088    *
089    * @param arguments The arguments object passed in the JSON-RPC params (never {@code null}; empty map when omitted).
090    * @param ctx Per-request bean store. Never {@code null}.
091    * @return The rendered prompt. Never {@code null}.
092    */
093   McpPromptOutcome get(Map<String,Object> arguments, BeanStore ctx);
094}