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}