mcpParamHeaders function
The x-mcp-header annotations of inputSchema (2026-07-28 Streamable
HTTP, custom headers from tool parameters), or the reason the tool
definition is invalid: an empty or non-token name, a name repeated
(case-insensitively), a parameter that is not integer / string /
boolean, or one not reachable through properties alone.
Implementation
({List<McpParamHeader> headers, String? problem}) mcpParamHeaders(Object? inputSchema) {
final headers = <McpParamHeader>[];
String? problem;
void visit(Object? node, List<String> path, bool reachable) {
if (problem != null) return;
if (node is List) {
for (final n in node) {
visit(n, path, false);
}
return;
}
if (node is! Map) return;
if (node.containsKey('x-mcp-header')) {
final name = node['x-mcp-header'];
final type = node['type'];
if (name is! String || name.isEmpty || !_tchar.hasMatch(name)) {
problem = 'x-mcp-header "$name" is not an HTTP token';
} else if (!reachable || path.isEmpty) {
problem = 'x-mcp-header "$name" is not reachable through properties alone';
} else if (type != 'string' && type != 'integer' && type != 'boolean') {
problem = 'x-mcp-header "$name" is on a $type parameter (integer, string or boolean only)';
} else if (headers.any((h) => h.name.toLowerCase() == name.toLowerCase())) {
problem = 'x-mcp-header "$name" is used twice';
} else {
headers.add((name: name, path: path, type: type as String));
}
}
for (final e in node.entries) {
final key = '${e.key}';
if (key == 'properties' && e.value is Map) {
for (final p in (e.value as Map).entries) {
visit(p.value, [...path, '${p.key}'], reachable);
}
} else if (key != 'x-mcp-header' && (e.value is Map || e.value is List)) {
// Anything else (items, oneOf, $defs, if/then/else, …) leaves the
// statically reachable part of the schema.
visit(e.value, path, false);
}
}
}
visit(inputSchema, const [], true);
return (headers: problem == null ? headers : const [], problem: problem);
}