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