Skip to content

Commit 6d951cd

Browse files
M A E R Y Odevcrocod
authored andcommitted
fix: correct _meta key validation according to MCP spec
1 parent b25f03d commit 6d951cd

File tree

1 file changed

+13
-23
lines changed
  • kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client

1 file changed

+13
-23
lines changed

kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/Client.kt

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -596,17 +596,13 @@ public open class Client(private val clientInfo: Implementation, options: Client
596596
*
597597
* Key format: [prefix/]name
598598
* - Prefix (optional): dot-separated labels + slash
599-
* - Labels: start with letter, end with letter/digit, contain letters/digits/hyphens
600-
* - Reserved prefixes: those starting with "mcp" or "modelcontextprotocol"
601-
* - Name: alphanumeric start/end, may contain hyphens, underscores, dots, alphanumerics
599+
* - Reserved prefixes contain "modelcontextprotocol" or "mcp" as complete labels
600+
* - Name: alphanumeric start/end, may contain hyphens, underscores, dots (empty allowed)
602601
*/
603602
private fun validateMetaKeys(keys: Set<String>) {
604603
for (key in keys) {
605604
if (!isValidMetaKey(key)) {
606-
throw Error(
607-
"Invalid _meta key '$key'. Keys must follow MCP specification format: " +
608-
"[prefix/]name where prefix is dot-separated labels and name is alphanumeric with allowed separators."
609-
)
605+
throw Error("Invalid _meta key '$key'. Must follow format [prefix/]name with valid labels.")
610606
}
611607
}
612608
}
@@ -629,24 +625,16 @@ public open class Client(private val clientInfo: Implementation, options: Client
629625

630626
private fun isValidMetaPrefix(prefix: String): Boolean {
631627
if (prefix.isEmpty()) return false
632-
633-
// Check for reserved prefixes
634628
val labels = prefix.split('.')
635-
if (labels.isNotEmpty()) {
636-
val firstLabel = labels[0].lowercase()
637-
if (firstLabel == "mcp" || firstLabel == "modelcontextprotocol") {
638-
return false
639-
}
640629

641-
// Check for reserved patterns like "*.mcp.*" or "*.modelcontextprotocol.*"
642-
for (label in labels) {
643-
val lowerLabel = label.lowercase()
644-
if (lowerLabel == "mcp" || lowerLabel == "modelcontextprotocol") {
645-
return false
646-
}
647-
}
630+
if (!labels.all { isValidLabel(it) }) {
631+
return false
632+
}
633+
634+
return !labels.any { label ->
635+
label.equals("modelcontextprotocol", ignoreCase = true) ||
636+
label.equals("mcp", ignoreCase = true)
648637
}
649-
return labels.all { isValidLabel(it) }
650638
}
651639

652640
private fun isValidLabel(label: String): Boolean {
@@ -658,7 +646,9 @@ public open class Client(private val clientInfo: Implementation, options: Client
658646
}
659647

660648
private fun isValidMetaName(name: String): Boolean {
661-
if (name.isEmpty()) return false
649+
// Empty names are allowed per MCP specification
650+
if (name.isEmpty()) return true
651+
662652
if (!name.first().isLetterOrDigit() || !name.last().isLetterOrDigit()) {
663653
return false
664654
}

0 commit comments

Comments
 (0)