001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2025-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.ai.mcp; 019 020import dev.enola.common.io.object.WithSchema; 021 022import io.modelcontextprotocol.spec.McpSchema; 023 024import org.jspecify.annotations.Nullable; 025 026import java.net.URI; 027import java.time.Duration; 028import java.util.ArrayList; 029import java.util.HashMap; 030import java.util.List; 031import java.util.Map; 032 033/** 034 * Configuration how to connect to an MCP Server. 035 * 036 * <p>This is inspired by e.g. Claude's or VSC's mcp.json etc. 037 * 038 * @see McpServerMetadata 039 */ 040public class McpServerConnectionsConfig extends WithSchema { 041 // implements Identifiable ? String id() { return origin.toString(); } 042 043 /** Origin of configuration; e.g. file:/.../mcp.yaml, or something like that. */ 044 // TODO extends WithOrigin implements HasOrigin; and set it in ObjectReader 045 public URI origin; 046 047 public Map<String, ServerConnection> servers = new HashMap<>(); 048 049 // public final Map<String, Input> inputs = new HashMap<>(); 050 051 public static class ServerConnection { 052 053 public ServerConnection() {} 054 055 public ServerConnection(ServerConnection other) { 056 this.origin = other.origin; 057 this.docs = other.docs; 058 this.type = other.type; 059 this.command = other.command; 060 this.args = other.args; 061 this.env = other.env; 062 this.url = other.url; 063 this.headers = other.headers; 064 this.timeout = other.timeout; 065 this.roots = other.roots; 066 this.log = other.log; 067 } 068 069 /** 070 * Origin of configuration; e.g. file:/.../mcp.yaml#github, or something like that. This is 071 * automatically set by the {@link McpLoader}. (This originally used to be confused with 072 * {@link #docs}.) 073 */ 074 // TODO extends WithOrigin implements HasOrigin; and set it in ObjectReader 075 public @Nullable URI origin; 076 077 /** 078 * Server's homepage or GitHub repo, or whatever uniquely identifies it. 079 * 080 * <p>There could be (external) sameAs equivalencies defined for disambiguation. 081 * 082 * <p>This is NOT its "package", so don't put a NPM or Container Image etc. 'PURL' here. 083 */ 084 // TODO Use another name than 'origin' here, to avoid confusion with the outer origin above? 085 public String docs; 086 087 public enum Type { 088 stdio, 089 http, 090 sse 091 } 092 093 public Type type = Type.stdio; 094 095 // STDIO; like io.modelcontextprotocol.client.transport.ServerParameters 096 public String command; 097 public List<String> args = new ArrayList<>(); 098 public Map<String, String> env = new HashMap<>(); 099 100 // HTTP; like com.google.adk.tools.mcp.SseServerParameters 101 public String url; 102 public Map<String, String> headers = new HashMap<>(); 103 public Duration timeout = Duration.ofSeconds(7); 104 105 public boolean roots = false; 106 107 public McpSchema.LoggingLevel log = McpSchema.LoggingLevel.WARNING; 108 } 109 110 /* 111 public static class Input { 112 public enum Type { 113 http 114 } 115 116 public Type type; 117 public String id; 118 public String description; 119 public boolean password; 120 } 121 */ 122 // TODO public Optional<String> validate() {} 123}