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.*; 021 022import org.apache.juneau.commons.inject.*; 023import static org.apache.juneau.commons.utils.Shorts.*; 024 025/** 026 * Handler for a single MCP resource template. 027 * 028 * <p> 029 * Implementations declare a {@link #descriptor() descriptor} (the {@link McpResourceTemplateSpec} returned by 030 * {@code resources/templates/list}), a {@link #read(String, Map, BeanStore) read} body invoked when this 031 * template is selected for a matching {@code resources/read} request, and an optional 032 * {@link #completer(String) completer} for one of the template's declared variables. 033 * 034 * <p> 035 * A registration whose {@link #descriptor() descriptor}.{@code uriTemplate} is not one of 036 * {@link McpUriTemplateMatcher}'s reverse-matchable forms remains listable and completable but is never 037 * selected for a template-backed read. Use {@link McpServerConfig#addResourceTemplate(McpResourceTemplateSpec...)} 038 * to register a listing-only template without implementing this interface. 039 * 040 * <p> 041 * Use {@link #of(McpResourceTemplateSpec, ReadFunction)} for the common case of wiring both 042 * {@link #descriptor()} and {@link #read(String, Map, BeanStore)} in a single expression. 043 */ 044public interface McpResourceTemplateHandler { 045 046 /** 047 * A three-argument function from ({@code uri}, {@code variables}, {@code ctx}) to a 048 * {@link McpResourceOutcome}, matching {@link #read(String, Map, BeanStore)}'s signature. 049 * 050 * <p> 051 * A dedicated functional interface rather than {@link java.util.function.BiFunction} because 052 * {@code read(...)} takes three parameters, not two. 053 */ 054 @FunctionalInterface 055 interface ReadFunction { 056 /** 057 * Reads the resource body for a concrete URI matched against the template. 058 * 059 * @param uri The original concrete URI from the {@code resources/read} request. 060 * @param variables An immutable, insertion-ordered map of the template's declared variables to their 061 * decoded values, captured from {@code uri}. 062 * @param ctx Per-request bean store. Never {@code null}. 063 * @return The resource contents, or {@code null} if this template does not serve {@code uri}. 064 */ 065 McpResourceOutcome read(String uri, Map<String,String> variables, BeanStore ctx); 066 } 067 068 /** 069 * Builds a handler from a fixed descriptor and a {@code read} lambda. 070 * 071 * <p> 072 * The sanctioned one-expression path for registering a resource template: wires both 073 * {@link #descriptor()} and {@link #read(String, Map, BeanStore)} from a single call. 074 * 075 * @param descriptor The static descriptor returned from every {@link #descriptor()} call. Must not be 076 * <jk>null</jk> and must carry a non-blank {@link McpResourceTemplateSpec#getUriTemplate() uriTemplate} 077 * (routing and {@code completion/complete} both match on it, so a templateless registration would be 078 * silently unreachable). Must not be <jk>null</jk>. 079 * @param read The read body, invoked with the concrete URI, its captured template variables, and the 080 * per-request bean store. Must not be <jk>null</jk>. 081 * @return A new handler wiring both. Never <jk>null</jk>. 082 */ 083 static McpResourceTemplateHandler of(McpResourceTemplateSpec descriptor, ReadFunction read) { 084 reqnn("descriptor", descriptor); 085 reqnb("descriptor.getUriTemplate()", descriptor.getUriTemplate()); 086 reqnn("read", read); 087 return new McpResourceTemplateHandler() { 088 @Override public McpResourceTemplateSpec descriptor() { 089 return descriptor; 090 } 091 092 @Override public McpResourceOutcome read(String uri, Map<String,String> variables, BeanStore ctx) { 093 return read.read(uri, variables, ctx); 094 } 095 }; 096 } 097 098 /** 099 * Returns the static descriptor for this resource template. 100 * 101 * <p> 102 * The {@link McpResourceTemplateSpec#getUriTemplate() uriTemplate} value is used by the bound 103 * {@link McpRevision} to route incoming {@code resources/read} requests and by {@code completion/complete} 104 * to identify this template, so each handler in an {@link McpServerConfig} must use a unique template 105 * string. 106 * 107 * @return The resource-template descriptor. Never {@code null}. 108 */ 109 McpResourceTemplateSpec descriptor(); 110 111 /** 112 * Reads the resource body for a concrete URI matched against this template. 113 * 114 * @param uri The original concrete URI from the {@code resources/read} request. 115 * @param variables An immutable, insertion-ordered map of this template's declared variables to their 116 * decoded values, captured from {@code uri}. 117 * @param ctx Per-request bean store. Never {@code null}. 118 * @return The resource contents, or {@code null} if this template does not serve {@code uri}, which is 119 * reported as resource-not-found. A {@code null} result never falls through to a less-specific template. 120 */ 121 McpResourceOutcome read(String uri, Map<String,String> variables, BeanStore ctx); 122 123 /** 124 * Returns the completer for one of this template's declared variables. 125 * 126 * @param variableName The variable name from a {@code completion/complete} request. 127 * @return The completer for that variable, or {@code null} if none is registered. Callers must treat an 128 * undeclared variable name as having no completer regardless of what this method returns. 129 */ 130 default McpCompleter completer(String variableName) { 131 return null; 132 } 133}