Skip to content

feat(server): add tool name validation per SEP-986#695

Merged
devcrocod merged 3 commits intomainfrom
devcrocod/tool-name-guidance
Apr 14, 2026
Merged

feat(server): add tool name validation per SEP-986#695
devcrocod merged 3 commits intomainfrom
devcrocod/tool-name-guidance

Conversation

@devcrocod
Copy link
Copy Markdown
Contributor

Add warn-only validation for tool names at registration time, following the MCP tool naming standard (SEP-986)

closes #417

How Has This Been Tested?

unit tests

Breaking Changes

none

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds warn-only validation when registering tools on the server, intended to align tool names with the SEP-986 naming guidance while preserving backward compatibility.

Changes:

  • Introduces validateToolName() / warnIfInvalidToolName() utility to emit warnings for non-conforming tool names.
  • Hooks validation into Server.addTool(...) and Server.addTools(...) registration paths.
  • Adds an integration test ensuring non-conpliant tool names are still accepted/registrable.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/utils/ToolNameValidation.kt New warn-only tool-name validation and logging utility.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt Calls validation during tool registration.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerToolsTest.kt Ensures registration/removal still works for non-conforming names.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings April 14, 2026 11:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +7 to +23
private const val MAX_TOOL_NAME_LENGTH = 128

private const val SEP_986_URL = "https://github.com/modelcontextprotocol/modelcontextprotocol/issues/986"

/**
* Validates a tool name against the MCP tool naming standard (SEP-986).
* Returns a list of warnings. An empty list means the name is valid.
*/
internal fun validateToolName(name: String): List<String> {
if (name.isEmpty()) return listOf("Tool name cannot be empty")

val invalidChars = name.toSet().filterNot { it.isAsciiAllowed() }
val remainingInvalidChars = invalidChars - setOf(' ', ',')

return listOfNotNull(
"Tool name exceeds maximum length of $MAX_TOOL_NAME_LENGTH characters (current: ${name.length})"
.takeIf { name.length > MAX_TOOL_NAME_LENGTH },
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SEP-986 specifies tool names must be 1–64 characters, but this validation uses MAX_TOOL_NAME_LENGTH = 128. This will incorrectly treat names of length 65–128 as conforming. Update the max length constant (and related messages) to 64 to match the spec.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +60
"Tool name contains invalid characters: ${remainingInvalidChars.joinToString(", ") { "\"$it\"" }}"
.takeIf { remainingInvalidChars.isNotEmpty() },
"Allowed characters are: A-Z, a-z, 0-9, underscore (_), dash (-), and dot (.)"
.takeIf { invalidChars.isNotEmpty() },
"Tool name starts or ends with a dash, which may cause parsing issues in some contexts"
.takeIf { name.startsWith('-') || name.endsWith('-') },
"Tool name starts or ends with a dot, which may cause parsing issues in some contexts"
.takeIf { name.startsWith('.') || name.endsWith('.') },
)
}

/**
* Validates the tool [name] and logs a warning if it does not conform to SEP-986.
* Does not block registration — tools with non-conforming names are still accepted.
*/
internal fun warnIfInvalidToolName(name: String) {
val warnings = validateToolName(name)
if (warnings.isEmpty()) return

val warningLines = warnings.joinToString("\n") { " - $it" }
logger.warn {
"""
|Tool name validation warning for "$name":
|$warningLines
|Tool registration will proceed, but this may cause compatibility issues.
|Consider updating the tool name to conform to the MCP tool naming standard.
|See SEP-986: $SEP_986_URL
""".trimMargin()
}
}

private fun Char.isAsciiAllowed(): Boolean =
this in 'a'..'z' || this in 'A'..'Z' || this in '0'..'9' || this == '_' || this == '-' || this == '.'
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SEP-986 allows forward slashes (/) and dots (.), but isAsciiAllowed() currently excludes '/'. This causes valid names like "user/profile/update" to be flagged as invalid and also makes the "Allowed characters are..." warning inaccurate. Include '/' in the allowed character set and update the allowed-characters message accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +35
@Test
fun `should return no warnings for max length name`() {
validateToolName("a".repeat(128)).shouldBeEmpty()
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test contradicts SEP-986: max tool name length should be 64, but the test treats 128 as the maximum valid length. Update the test cases to assert 64 is valid and 65 triggers a warning (matching the spec and the validator).

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +70
@ParameterizedTest
@ValueSource(strings = ["user/profile/update", "a/b"])
fun `should warn for names with forward slashes`(name: String) {
val warnings = validateToolName(name)
warnings.any { "invalid characters" in it }.shouldBeTrue()
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SEP-986 explicitly allows forward slashes (/), but this test expects names containing '/' to produce an "invalid characters" warning. Once '/' is allowed in the validator, this test should instead assert no warnings for slash-separated tool names (and optionally add a slash example to the "valid tool names" parameter set).

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +78
@ParameterizedTest
@ValueSource(strings = ["user@domain.com", "tool#1", "tool\$name"])
fun `should warn for names with special characters`(name: String) {
val warnings = validateToolName(name)
warnings.any { "invalid characters" in it }.shouldBeTrue()
warnings shouldContain "Allowed characters are: A-Z, a-z, 0-9, underscore (_), dash (-), and dot (.)"
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected "Allowed characters are..." message omits forward slash (/), but SEP-986 allows it. If you update the validator to allow '/', update this assertion to include '/' in the allowed-character list (or adjust the test to match the final wording).

Copilot uses AI. Check for mistakes.
@devcrocod devcrocod merged commit e74ef2d into main Apr 14, 2026
24 checks passed
@devcrocod devcrocod deleted the devcrocod/tool-name-guidance branch April 14, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-986: Tool Name Guidance

3 participants