|
4 | 4 |
|
5 | 5 | import pytest |
6 | 6 | from mcp.types import ElicitRequestParams |
7 | | -from pydantic import BaseModel |
| 7 | +from pydantic import BaseModel, Field |
8 | 8 | from typing_extensions import TypedDict |
9 | 9 |
|
10 | 10 | from fastmcp import Context, FastMCP |
@@ -729,3 +729,134 @@ class TaskUpdate: |
729 | 729 | "Completed", |
730 | 730 | "On Hold", |
731 | 731 | ] |
| 732 | + |
| 733 | + |
| 734 | +class TestElicitationDefaults: |
| 735 | + """Test suite for default values in elicitation schemas.""" |
| 736 | + |
| 737 | + def test_string_default_preserved(self): |
| 738 | + """Test that string defaults are preserved in the schema.""" |
| 739 | + |
| 740 | + class Model(BaseModel): |
| 741 | + email: str = Field(default="[email protected]") |
| 742 | + |
| 743 | + schema = get_elicitation_schema(Model) |
| 744 | + props = schema.get("properties", {}) |
| 745 | + |
| 746 | + assert "email" in props |
| 747 | + assert "default" in props["email"] |
| 748 | + assert props["email"]["default"] == "[email protected]" |
| 749 | + assert props["email"]["type"] == "string" |
| 750 | + |
| 751 | + def test_integer_default_preserved(self): |
| 752 | + """Test that integer defaults are preserved in the schema.""" |
| 753 | + |
| 754 | + class Model(BaseModel): |
| 755 | + count: int = Field(default=50) |
| 756 | + |
| 757 | + schema = get_elicitation_schema(Model) |
| 758 | + props = schema.get("properties", {}) |
| 759 | + |
| 760 | + assert "count" in props |
| 761 | + assert "default" in props["count"] |
| 762 | + assert props["count"]["default"] == 50 |
| 763 | + assert props["count"]["type"] == "integer" |
| 764 | + |
| 765 | + def test_number_default_preserved(self): |
| 766 | + """Test that number defaults are preserved in the schema.""" |
| 767 | + |
| 768 | + class Model(BaseModel): |
| 769 | + price: float = Field(default=3.14) |
| 770 | + |
| 771 | + schema = get_elicitation_schema(Model) |
| 772 | + props = schema.get("properties", {}) |
| 773 | + |
| 774 | + assert "price" in props |
| 775 | + assert "default" in props["price"] |
| 776 | + assert props["price"]["default"] == 3.14 |
| 777 | + assert props["price"]["type"] == "number" |
| 778 | + |
| 779 | + def test_boolean_default_preserved(self): |
| 780 | + """Test that boolean defaults are preserved in the schema.""" |
| 781 | + |
| 782 | + class Model(BaseModel): |
| 783 | + enabled: bool = Field(default=False) |
| 784 | + |
| 785 | + schema = get_elicitation_schema(Model) |
| 786 | + props = schema.get("properties", {}) |
| 787 | + |
| 788 | + assert "enabled" in props |
| 789 | + assert "default" in props["enabled"] |
| 790 | + assert props["enabled"]["default"] is False |
| 791 | + assert props["enabled"]["type"] == "boolean" |
| 792 | + |
| 793 | + def test_enum_default_preserved(self): |
| 794 | + """Test that enum defaults are preserved in the schema.""" |
| 795 | + |
| 796 | + class Priority(Enum): |
| 797 | + LOW = "low" |
| 798 | + MEDIUM = "medium" |
| 799 | + HIGH = "high" |
| 800 | + |
| 801 | + class Model(BaseModel): |
| 802 | + choice: Priority = Field(default=Priority.MEDIUM) |
| 803 | + |
| 804 | + schema = get_elicitation_schema(Model) |
| 805 | + props = schema.get("properties", {}) |
| 806 | + |
| 807 | + assert "choice" in props |
| 808 | + assert "default" in props["choice"] |
| 809 | + assert props["choice"]["default"] == "medium" |
| 810 | + assert "enum" in props["choice"] |
| 811 | + assert props["choice"]["type"] == "string" |
| 812 | + |
| 813 | + def test_all_defaults_preserved_together(self): |
| 814 | + """Test that all default types are preserved when used together.""" |
| 815 | + |
| 816 | + class Priority(Enum): |
| 817 | + A = "A" |
| 818 | + B = "B" |
| 819 | + |
| 820 | + class Model(BaseModel): |
| 821 | + string_field: str = Field(default="[email protected]") |
| 822 | + integer_field: int = Field(default=50) |
| 823 | + number_field: float = Field(default=3.14) |
| 824 | + boolean_field: bool = Field(default=False) |
| 825 | + enum_field: Priority = Field(default=Priority.A) |
| 826 | + |
| 827 | + schema = get_elicitation_schema(Model) |
| 828 | + props = schema.get("properties", {}) |
| 829 | + |
| 830 | + assert props["string_field"]["default"] == "[email protected]" |
| 831 | + assert props["integer_field"]["default"] == 50 |
| 832 | + assert props["number_field"]["default"] == 3.14 |
| 833 | + assert props["boolean_field"]["default"] is False |
| 834 | + assert props["enum_field"]["default"] == "A" |
| 835 | + |
| 836 | + def test_mixed_defaults_and_required(self): |
| 837 | + """Test that fields with defaults are not in required list.""" |
| 838 | + |
| 839 | + class Model(BaseModel): |
| 840 | + required_field: str = Field(description="Required field") |
| 841 | + optional_with_default: int = Field(default=42) |
| 842 | + |
| 843 | + schema = get_elicitation_schema(Model) |
| 844 | + props = schema.get("properties", {}) |
| 845 | + required = schema.get("required", []) |
| 846 | + |
| 847 | + assert "required_field" in required |
| 848 | + assert "optional_with_default" not in required |
| 849 | + assert props["optional_with_default"]["default"] == 42 |
| 850 | + |
| 851 | + def test_compress_schema_preserves_defaults(self): |
| 852 | + """Test that compress_schema() doesn't strip default values.""" |
| 853 | + |
| 854 | + class Model(BaseModel): |
| 855 | + string_field: str = Field(default="test") |
| 856 | + integer_field: int = Field(default=42) |
| 857 | + |
| 858 | + schema = get_elicitation_schema(Model) |
| 859 | + props = schema.get("properties", {}) |
| 860 | + |
| 861 | + assert "default" in props["string_field"] |
| 862 | + assert "default" in props["integer_field"] |
0 commit comments