Class McpToolUtils

java.lang.Object
io.meeds.mcp.server.util.McpToolUtils

public class McpToolUtils extends Object
  • Field Details

  • Method Details

    • parseToolDefinitions

      public static List<SimpleToolDefinition> parseToolDefinitions(URL url)
      Parses one ai-tool-definitions.json resource.
      Parameters:
      url - the resource to read
      Returns:
      the tool definitions it declares, empty when it cannot be read
    • fromJsonString

      public static final ToolDefinitionMethods fromJsonString(String value)
      Parameters:
      value - the tool definitions as a JSON string
      Returns:
      the parsed definitions, or null when the string is blank
    • fromJsonStringBase64

      public static ToolDefinitionMethods fromJsonStringBase64(String value)
      Same as fromJsonString(String) for the persisted form, whose input schemas are base64 encoded.
      Parameters:
      value - the persisted tool definitions
      Returns:
      the parsed definitions with decoded schemas, or null when blank
    • toJsonStringBase64

      public static String toJsonStringBase64(ToolDefinitionMethods toolDefinitions)
      Serializes tool definitions to their persisted form, base64 encoding each input schema.
      Parameters:
      toolDefinitions - the definitions to serialize
      Returns:
      the JSON string to persist
    • toSnakeCase

      public static String toSnakeCase(String name)
      Parameters:
      name - a Java method name
      Returns:
      its snake-case form, which is the MCP tool name
    • toCamelCase

      public static String toCamelCase(String name)
      Parameters:
      name - a snake-case name
      Returns:
      its camel-case form
    • getMethodToolFieldValue

      public static Object getMethodToolFieldValue(org.springframework.ai.tool.method.MethodToolCallback toolCallback, String fieldName) throws NoSuchFieldException, IllegalAccessException
      Reads a private field of a Spring AI MethodToolCallback, which exposes no accessor for the tool object and method it wraps.
      Parameters:
      toolCallback - the callback to introspect
      fieldName - the field to read
      Returns:
      the field value
      Throws:
      NoSuchFieldException - when the field does not exist
      IllegalAccessException - when it cannot be read
    • getCurrentUserName

      public static String getCurrentUserName()
      Resolves the user on behalf of whom the current Tool is executed: the kernel ConversationState identity when set, else, for the internal client-credentials call only, the TOOL_CONTEXT_USER_NAME_PARAM request header, else the authenticated principal. The header is trusted under the gate of getInternalToolCallRequest() and nowhere else; the internal call is recognized by the OAuth client that owns the token (isInternalClientAuthentication(Authentication)), never by the token subject, so a user whose login happens to be the internal client id is just that user.
      Returns:
      the user name, or null when no user can be resolved
    • getCurrentConversationId

      public static String getCurrentConversationId()
      Resolves the AI chat conversation in which the current Tool is executed. The id travels in the TOOL_CONTEXT_CONVERSATION_ID_PARAM request header set by the internal MCP client and is trusted under exactly the same gate as the user name (getInternalToolCallRequest()): any other caller, an external OAuth MCP client for instance, gets null whatever it sends, so it can never choose the conversation its Tool executions are recorded in.
      Returns:
      the conversation id, or null when the call isn't the internal client's or carries no conversation
    • isInternalClientAuthentication

      public static boolean isInternalClientAuthentication(org.springframework.security.core.Authentication authentication)
      Tells whether the authentication is the internal client-credentials call: a bearer token whose introspection attributes name MCP_OAUTH2_CLIENT_CREDENTIALS_REGISTRATION_ID as the owning OAuth client (OAuth2TokenIntrospectionClaimNames.CLIENT_ID, set by the authorization server from the registered client the token was issued to). The token subject is deliberately not consulted: it is the client id for a client-credentials grant but the user login for a user grant, so a user whose login is the internal client id would otherwise enter the internal path with an ordinary user token.
      Parameters:
      authentication - the current Authentication, may be null
      Returns:
      true when the token belongs to the internal client, else false
    • isInternalClientPrincipal

      public static boolean isInternalClientPrincipal(Map<String,Object> tokenAttributes)
      Same question as isInternalClientAuthentication(Authentication), asked one step earlier: at token introspection time there is no Authentication yet, only the introspected principal. Both enforcement points of the MCP access gate must recognize the internal client the same way or the exemption means two different things, so both go through isInternalClientId(Object) and neither consults the token subject.
      Parameters:
      tokenAttributes - the introspected token attributes, may be null
      Returns:
      true when the token belongs to the internal client, else false
    • markdownToHtml

      public static String markdownToHtml(String markdown)
      Renders Markdown a tool produced into the HTML the platform's content fields expect, and leaves it untouched when it already carries HTML — a tool's output is not always Markdown, and rendering HTML twice mangles it.
      Parameters:
      markdown - the tool output, may be null or blank
      Returns:
      the rendered HTML, or the input unchanged when it is blank, when it already looks like HTML, or when rendering failed
    • toDate

      public static Date toDate(String date)
      Parameters:
      date - an ISO-8601 date as a tool argument carries it, may be null or blank
      Returns:
      the parsed date, or null when nothing was given
    • formatDate

      public static String formatDate(Long time)
      Parameters:
      time - an epoch timestamp in milliseconds, may be null or non-positive
      Returns:
      the ISO-8601 representation in the current user's time zone, or null when no usable timestamp was given
    • formatDate

      public static String formatDate(Date date)
      Parameters:
      date - the date to render, may be null
      Returns:
      the ISO-8601 representation in the current user's time zone, or null when no date was given
    • getUserTimeZone

      public static TimeZone getUserTimeZone()
      Reads the acting user's time zone from their platform profile, so that a date a tool returns reads the same as the one the web UI shows them.
      Returns:
      the user's time zone, or null when the profile carries none — the caller then falls back to the server's default