mcpParamHeaders function

({List<McpParamHeader> headers, String? problem}) mcpParamHeaders(
  1. Object? inputSchema
)

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);
}