Skip to content

[Bug]: mcp:test-tool crashes with “Array to string conversion” when JSON Schema type is an array (e.g., ["integer","null"]) #66

@jhariani

Description

@jhariani

What happened?

This library is fantastic, thank you for all the work on it. One minor thing I ran into while testing: when a tool’s JSON Schema uses a union type, running:

php artisan mcp:test-tool tool_name --input='{"param":"value"}'

throws:

ErrorException

Array to string conversion

at vendor/opgginc/laravel-mcp-server/src/Console/Commands/TestMcpToolCommand.php:167
    163▕                 $type = $propSchema['type'] ?? 'any';
    164▕                 $description = $propSchema['description'] ?? '';
    165▕                 $required = in_array($propName, $schema['required'] ?? []) ? '(required)' : '(optional)';
    166▕
  ➜ 167▕                 $this->line("{$indent}- {$propName}: {$type} {$required}");

This happens because $type can be an array (e.g., ["integer","null"]) and is interpolated directly into a string.

How to reproduce the bug

Sample failing schema snippet:

"results_size" => [
    "description" => "The number of results to return. Defaults to 25.",
    "type"        => ["integer", "null"],
    "minimum"     => 0,
    "maximum"     => 500,
],

Command:

php artisan mcp:test-tool tool_name --input='{"param":"value"}'

Expected behavior

  • The schema is printed without errors.
  • Union types print cleanly, e.g., integer | null.
  • Nested object/array properties are displayed even when type is a union such as ["object","null"] or ["array","null"].

Actual behavior

  • Command crashes with “Array to string conversion” at line 167 in TestMcpToolCommand::displaySchema.

Proposed fix

Normalize type for display and separately detect whether the property is (or may be) an object or array. Also handle items.type being an array.

protected function displaySchema(array $schema, string $indent = ''): void
{
    if (!isset($schema['properties']) || !is_array($schema['properties'])) {
        return;
    }

    foreach ($schema['properties'] as $propName => $propSchema) {
        $typeRaw     = $propSchema['type'] ?? 'any';
        $description = $propSchema['description'] ?? '';
        $required    = in_array($propName, $schema['required'] ?? [], true) ? '(required)' : '(optional)';

        // Normalize type for display (string) and detection (array)
        $typeList = is_array($typeRaw) ? $typeRaw : [$typeRaw];
        $typeList = array_values(array_filter($typeList)); // tidy
        $typeForDisplay = $typeList ? implode(' | ', $typeList) : 'any';

        $this->line("{$indent}- {$propName}: {$typeForDisplay} {$required}");
        if ($description) {
            $this->line("{$indent}  Description: {$description}");
        }

        // Determine if the schema includes object/array among union types
        $isObject = in_array('object', $typeList, true);
        $isArray  = in_array('array', $typeList, true);

        // If this is an object with nested properties
        if ($isObject && isset($propSchema['properties']) && is_array($propSchema['properties'])) {
            $this->line("{$indent}  Properties:");
            $this->displaySchema($propSchema, $indent . '    ');
        }

        // If this is an array with items
        if ($isArray && isset($propSchema['items']) && is_array($propSchema['items'])) {
            $itemsTypeRaw = $propSchema['items']['type'] ?? 'any';
            $itemsTypeList = is_array($itemsTypeRaw) ? $itemsTypeRaw : [$itemsTypeRaw];
            $itemsTypeForDisplay = $itemsTypeList ? implode(' | ', $itemsTypeList) : 'any';

            $this->line("{$indent}  Items: {$itemsTypeForDisplay}");

            // Array items might themselves be objects with properties
            if (isset($propSchema['items']['properties']) && is_array($propSchema['items']['properties'])) {
                $this->line("{$indent}  Item Properties:");
                $this->displaySchema($propSchema['items'], $indent . '    ');
            }
        }
    }
}

Package Version

1.4.2

PHP Version

8.4.11

Laravel Version

11.45.2

Which operating systems does this happen with?

Linux, macOS

Notes

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions