Package io.meeds.mcp.server.util
Class McpToolUtils
java.lang.Object
io.meeds.mcp.server.util.McpToolUtils
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringEvent parameter: the agent the call is made for, when known.static final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final StringEvent parameter: the argument limit kind the card may offer.static final StringEvent parameter: the argument limit value the card may offer.static final StringEvent parameter: when the created standing approval expires (epoch ms).static final StringEvent parameter: the standing approval a call ran under, or created.static final StringEvent parameter: the longest validity, in days, the card may offer.static final StringEvent parameter: the owner type of the standing approval.static final StringEvent parameter: whether the approval card may offer "Always allow".static final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final StringName of theExoFeatureServicefeature carrying the MCP server's global on/off flag.static final StringHeader naming the agent on whose behalf the internal client calls a tool, trusted under the same gate asTOOL_CONTEXT_USER_NAME_PARAM.static final Stringstatic final Stringstatic final Stringstatic final StringHeader carried by the internal client when the call belongs to a retried answer, trusted under the same gate asTOOL_CONTEXT_USER_NAME_PARAM.static final Stringstatic final Stringstatic final Stringstatic final String -
Method Summary
Modifier and TypeMethodDescriptionstatic StringformatDate(Long time) static StringformatDate(Date date) static final ToolDefinitionMethodsfromJsonString(String value) static ToolDefinitionMethodsfromJsonStringBase64(String value) Same asfromJsonString(String)for the persisted form, whose input schemas are base64 encoded.static StringgetClientId(org.springframework.security.core.Authentication authentication) Reads the OAuth client that owns the bearer token of a call.static StringResolves the agent on whose behalf the current Tool is executed, from theTOOL_CONTEXT_AGENT_NAME_ID_PARAMheader of the internal client only (getInternalToolCallRequest()): any other caller gets null, so an external client can never claim the agent a standing approval names.static StringResolves the AI chat conversation in which the current Tool is executed.static StringResolves the user on behalf of whom the current Tool is executed: the kernelConversationStateidentity when set, else, for the internal client-credentials call only, theTOOL_CONTEXT_USER_NAME_PARAMrequest header, else the authenticated principal.static ObjectgetMethodToolFieldValue(org.springframework.ai.tool.method.MethodToolCallback toolCallback, String fieldName) Reads a private field of a Spring AIMethodToolCallback, which exposes no accessor for the tool object and method it wraps.static TimeZoneReads 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.static booleanTells whether the current Tool call belongs to a retried answer, from theTOOL_CONTEXT_RETRY_MESSAGE_ID_PARAMheader of the internal client only.static booleanisInternalClientAuthentication(org.springframework.security.core.Authentication authentication) Tells whether the authentication is the internal client-credentials call: a bearer token whose introspection attributes nameMCP_OAUTH2_CLIENT_CREDENTIALS_REGISTRATION_IDas the owning OAuth client (OAuth2TokenIntrospectionClaimNames.CLIENT_ID, set by the authorization server from the registered client the token was issued to).static booleanisInternalClientPrincipal(Map<String, Object> tokenAttributes) Same question asisInternalClientAuthentication(Authentication), asked one step earlier: at token introspection time there is noAuthenticationyet, only the introspected principal.static StringmarkdownToHtml(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.static List<SimpleToolDefinition> parseToolDefinitions(URL url) Parses oneai-tool-definitions.jsonresource.static List<SimpleToolDefinition> parseToolDefinitions(URL url, Collection<String> leftOutToolNames) Same asparseToolDefinitions(URL), and adds the name of each tool left out for a key this server does not know to the given collection.static StringtoCamelCase(String name) static Datestatic StringtoJsonStringBase64(ToolDefinitionMethods toolDefinitions) Serializes tool definitions to their persisted form, base64 encoding each input schema.static StringtoSnakeCase(String name)
-
Field Details
-
AI_AGENT_TOOL_EXECUTION_EVENT
- See Also:
-
MCP_OAUTH2_CLIENT_CREDENTIALS_REGISTRATION_ID
- See Also:
-
MCP_SERVER_FEATURE
Name of theExoFeatureServicefeature carrying the MCP server's global on/off flag. The per-user audience is not a feature plugin: it is resolved byMcpServerAudienceServicealone.- See Also:
-
EVENT_MCP_SERVER_AUDIENCE_UPDATED
- See Also:
-
TOOL_CONTEXT_USER_NAME_PARAM
- See Also:
-
TOOL_CONTEXT_ID_PARAM
- See Also:
-
TOOL_CONTEXT_CONVERSATION_ID_PARAM
- See Also:
-
TOOL_CONTEXT_AGENT_NAME_ID_PARAM
Header naming the agent on whose behalf the internal client calls a tool, trusted under the same gate asTOOL_CONTEXT_USER_NAME_PARAM.- See Also:
-
TOOL_CONTEXT_RETRY_MESSAGE_ID_PARAM
Header carried by the internal client when the call belongs to a retried answer, trusted under the same gate asTOOL_CONTEXT_USER_NAME_PARAM.- See Also:
-
TOOL_CONTEXT_ID
-
TOOL_READ_SCOPE
- See Also:
-
TOOL_WRITE_SCOPE
- See Also:
-
TOOL_WRITE_APPROVE_SCOPE
- See Also:
-
EVENT_TOOL_UPDATED
- See Also:
-
AI_AGENT_TOOL_APPROVED_PARAM
- See Also:
-
AI_AGENT_TOOL_USERNAME_PARAM
- See Also:
-
AI_AGENT_TOOL_CONVERSATION_ID_PARAM
- See Also:
-
AI_AGENT_TOOL_INPUT_PARAM
- See Also:
-
AI_AGENT_TOOL_OUTPUT_PARAM
- See Also:
-
AI_AGENT_TOOL_TYPE_PARAM
- See Also:
-
AI_AGENT_TOOL_DURATION_PARAM
- See Also:
-
AI_AGENT_TOOL_START_TIME_PARAM
- See Also:
-
AI_AGENT_TOOL_ID_PARAM
- See Also:
-
AI_AGENT_TOOL_NAME_PARAM
- See Also:
-
AI_AGENT_TOOL_EXEC_COMPLETED_PARAM
- See Also:
-
AI_AGENT_TOOL_GRANT_ID_PARAM
Event parameter: the standing approval a call ran under, or created.- See Also:
-
AI_AGENT_TOOL_GRANT_OWNER_TYPE_PARAM
Event parameter: the owner type of the standing approval.- See Also:
-
AI_AGENT_TOOL_GRANT_EXPIRES_AT_PARAM
Event parameter: when the created standing approval expires (epoch ms).- See Also:
-
AI_AGENT_TOOL_GRANTABLE_PARAM
Event parameter: whether the approval card may offer "Always allow".- See Also:
-
AI_AGENT_TOOL_GRANT_MAX_DAYS_PARAM
Event parameter: the longest validity, in days, the card may offer.- See Also:
-
AI_AGENT_TOOL_AGENT_NAME_ID_PARAM
Event parameter: the agent the call is made for, when known.- See Also:
-
AI_AGENT_TOOL_GRANT_CONSTRAINT_KIND_PARAM
Event parameter: the argument limit kind the card may offer.- See Also:
-
AI_AGENT_TOOL_GRANT_CONSTRAINT_VALUE_PARAM
Event parameter: the argument limit value the card may offer.- See Also:
-
-
Method Details
-
parseToolDefinitions
Parses oneai-tool-definitions.jsonresource. A tool that declares no icon takes the file's default icon, when the file declares one. A key the file declares at its root and this server does not know is ignored. A tool entry carrying a key this server does not know is left out, with a WARN, and the file's other tools load: loaded, the tool would run with the default of whatever field the key misspells, a misspelledrequire_approvalorannotationskey included. The keys insideannotationsare read by the MCP SDK'sToolAnnotations, which ignores the ones it does not know.- Parameters:
url- the resource to read- Returns:
- the tool definitions it declares, empty when it cannot be read
-
parseToolDefinitions
public static List<SimpleToolDefinition> parseToolDefinitions(URL url, Collection<String> leftOutToolNames) Same asparseToolDefinitions(URL), and adds the name of each tool left out for a key this server does not know to the given collection.- Parameters:
url- the resource to readleftOutToolNames- receives the names of the tools left out- Returns:
- the tool definitions it declares, empty when it cannot be read
-
fromJsonString
- Parameters:
value- the tool definitions as a JSON string- Returns:
- the parsed definitions, or null when the string is blank
-
fromJsonStringBase64
Same asfromJsonString(String)for the persisted form, whose input schemas are base64 encoded. A saved tool carrying a key this server does not know is kept, with a WARN: the persisted form is written bytoJsonStringBase64(ToolDefinitionMethods)alone, so such a key comes from a newer server, not from a misspelling, and dropping the tool would replace the administrator'srequire_approvalanddisabledwith the shipped values.- Parameters:
value- the persisted tool definitions- Returns:
- the parsed definitions with decoded schemas, or null when blank
-
toJsonStringBase64
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
- Parameters:
name- a Java method name- Returns:
- its snake-case form, which is the MCP tool name
-
toCamelCase
- 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 AIMethodToolCallback, which exposes no accessor for the tool object and method it wraps.- Parameters:
toolCallback- the callback to introspectfieldName- the field to read- Returns:
- the field value
- Throws:
NoSuchFieldException- when the field does not existIllegalAccessException- when it cannot be read
-
getCurrentUserName
Resolves the user on behalf of whom the current Tool is executed: the kernelConversationStateidentity when set, else, for the internal client-credentials call only, theTOOL_CONTEXT_USER_NAME_PARAMrequest header, else the authenticated principal. The header is trusted under the gate ofgetInternalToolCallRequest()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
Resolves the AI chat conversation in which the current Tool is executed. The id travels in theTOOL_CONTEXT_CONVERSATION_ID_PARAMrequest 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
-
getCurrentAgentNameId
Resolves the agent on whose behalf the current Tool is executed, from theTOOL_CONTEXT_AGENT_NAME_ID_PARAMheader of the internal client only (getInternalToolCallRequest()): any other caller gets null, so an external client can never claim the agent a standing approval names.- Returns:
- the agent name id, or null when unknown
-
isCurrentCallRetry
public static boolean isCurrentCallRetry()Tells whether the current Tool call belongs to a retried answer, from theTOOL_CONTEXT_RETRY_MESSAGE_ID_PARAMheader of the internal client only. The answer can only make the approval gate stricter (no standing approval applies to a retried answer), so no caller gains anything by sending it, and an external client's header is ignored like the others.- Returns:
- true when the internal client marked the call as a retry
-
getClientId
Reads the OAuth client that owns the bearer token of a call.- Parameters:
authentication- the currentAuthentication, may be null- Returns:
- the client id, or null when the call isn't a bearer-token call
-
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 nameMCP_OAUTH2_CLIENT_CREDENTIALS_REGISTRATION_IDas 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 currentAuthentication, may be null- Returns:
- true when the token belongs to the internal client, else false
-
isInternalClientPrincipal
Same question asisInternalClientAuthentication(Authentication), asked one step earlier: at token introspection time there is noAuthenticationyet, 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 throughisInternalClientId(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
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
- 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
- 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
- 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
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
-