refactor: use snake case instead of camel case in types (#1894)
This commit is contained in:
parent
7080fcf1e6
commit
e94b386a13
127 changed files with 1063 additions and 1057 deletions
40
README.md
40
README.md
|
|
@ -442,7 +442,7 @@ def validated_tool() -> Annotated[CallToolResult, ValidationModel]:
|
||||||
"""Return CallToolResult with structured output validation."""
|
"""Return CallToolResult with structured output validation."""
|
||||||
return CallToolResult(
|
return CallToolResult(
|
||||||
content=[TextContent(type="text", text="Validated response")],
|
content=[TextContent(type="text", text="Validated response")],
|
||||||
structuredContent={"status": "success", "data": {"result": 42}},
|
structured_content={"status": "success", "data": {"result": 42}},
|
||||||
_meta={"internal": "metadata"},
|
_meta={"internal": "metadata"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -757,8 +757,8 @@ async def run():
|
||||||
# List available resource templates
|
# List available resource templates
|
||||||
templates = await session.list_resource_templates()
|
templates = await session.list_resource_templates()
|
||||||
print("Available resource templates:")
|
print("Available resource templates:")
|
||||||
for template in templates.resourceTemplates:
|
for template in templates.resource_templates:
|
||||||
print(f" - {template.uriTemplate}")
|
print(f" - {template.uri_template}")
|
||||||
|
|
||||||
# List available prompts
|
# List available prompts
|
||||||
prompts = await session.list_prompts()
|
prompts = await session.list_prompts()
|
||||||
|
|
@ -767,20 +767,20 @@ async def run():
|
||||||
print(f" - {prompt.name}")
|
print(f" - {prompt.name}")
|
||||||
|
|
||||||
# Complete resource template arguments
|
# Complete resource template arguments
|
||||||
if templates.resourceTemplates:
|
if templates.resource_templates:
|
||||||
template = templates.resourceTemplates[0]
|
template = templates.resource_templates[0]
|
||||||
print(f"\nCompleting arguments for resource template: {template.uriTemplate}")
|
print(f"\nCompleting arguments for resource template: {template.uri_template}")
|
||||||
|
|
||||||
# Complete without context
|
# Complete without context
|
||||||
result = await session.complete(
|
result = await session.complete(
|
||||||
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
|
ref=ResourceTemplateReference(type="ref/resource", uri=template.uri_template),
|
||||||
argument={"name": "owner", "value": "model"},
|
argument={"name": "owner", "value": "model"},
|
||||||
)
|
)
|
||||||
print(f"Completions for 'owner' starting with 'model': {result.completion.values}")
|
print(f"Completions for 'owner' starting with 'model': {result.completion.values}")
|
||||||
|
|
||||||
# Complete with context - repo suggestions based on owner
|
# Complete with context - repo suggestions based on owner
|
||||||
result = await session.complete(
|
result = await session.complete(
|
||||||
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
|
ref=ResourceTemplateReference(type="ref/resource", uri=template.uri_template),
|
||||||
argument={"name": "repo", "value": ""},
|
argument={"name": "repo", "value": ""},
|
||||||
context_arguments={"owner": "modelcontextprotocol"},
|
context_arguments={"owner": "modelcontextprotocol"},
|
||||||
)
|
)
|
||||||
|
|
@ -910,7 +910,7 @@ async def connect_service(service_name: str, ctx: Context[ServerSession, None])
|
||||||
mode="url",
|
mode="url",
|
||||||
message=f"Authorization required to connect to {service_name}",
|
message=f"Authorization required to connect to {service_name}",
|
||||||
url=f"https://{service_name}.example.com/oauth/authorize?elicit={elicitation_id}",
|
url=f"https://{service_name}.example.com/oauth/authorize?elicit={elicitation_id}",
|
||||||
elicitationId=elicitation_id,
|
elicitation_id=elicitation_id,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
@ -1706,7 +1706,7 @@ async def handle_list_tools() -> list[types.Tool]:
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="query_db",
|
name="query_db",
|
||||||
description="Query the database",
|
description="Query the database",
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"query": {"type": "string", "description": "SQL query to execute"}},
|
"properties": {"query": {"type": "string", "description": "SQL query to execute"}},
|
||||||
"required": ["query"],
|
"required": ["query"],
|
||||||
|
|
@ -1867,12 +1867,12 @@ async def list_tools() -> list[types.Tool]:
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="get_weather",
|
name="get_weather",
|
||||||
description="Get current weather for a city",
|
description="Get current weather for a city",
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"city": {"type": "string", "description": "City name"}},
|
"properties": {"city": {"type": "string", "description": "City name"}},
|
||||||
"required": ["city"],
|
"required": ["city"],
|
||||||
},
|
},
|
||||||
outputSchema={
|
output_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"temperature": {"type": "number", "description": "Temperature in Celsius"},
|
"temperature": {"type": "number", "description": "Temperature in Celsius"},
|
||||||
|
|
@ -1970,7 +1970,7 @@ async def list_tools() -> list[types.Tool]:
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="advanced_tool",
|
name="advanced_tool",
|
||||||
description="Tool with full control including _meta field",
|
description="Tool with full control including _meta field",
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"message": {"type": "string"}},
|
"properties": {"message": {"type": "string"}},
|
||||||
"required": ["message"],
|
"required": ["message"],
|
||||||
|
|
@ -1986,7 +1986,7 @@ async def handle_call_tool(name: str, arguments: dict[str, Any]) -> types.CallTo
|
||||||
message = str(arguments.get("message", ""))
|
message = str(arguments.get("message", ""))
|
||||||
return types.CallToolResult(
|
return types.CallToolResult(
|
||||||
content=[types.TextContent(type="text", text=f"Processed: {message}")],
|
content=[types.TextContent(type="text", text=f"Processed: {message}")],
|
||||||
structuredContent={"result": "success", "message": message},
|
structured_content={"result": "success", "message": message},
|
||||||
_meta={"hidden": "data for client applications only"},
|
_meta={"hidden": "data for client applications only"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -2062,7 +2062,7 @@ async def list_resources_paginated(request: types.ListResourcesRequest) -> types
|
||||||
# Determine next cursor
|
# Determine next cursor
|
||||||
next_cursor = str(end) if end < len(ITEMS) else None
|
next_cursor = str(end) if end < len(ITEMS) else None
|
||||||
|
|
||||||
return types.ListResourcesResult(resources=page_items, nextCursor=next_cursor)
|
return types.ListResourcesResult(resources=page_items, next_cursor=next_cursor)
|
||||||
```
|
```
|
||||||
|
|
||||||
_Full example: [examples/snippets/servers/pagination_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/pagination_example.py)_
|
_Full example: [examples/snippets/servers/pagination_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/pagination_example.py)_
|
||||||
|
|
@ -2103,8 +2103,8 @@ async def list_all_resources() -> None:
|
||||||
print(f"Fetched {len(result.resources)} resources")
|
print(f"Fetched {len(result.resources)} resources")
|
||||||
|
|
||||||
# Check if there are more pages
|
# Check if there are more pages
|
||||||
if result.nextCursor:
|
if result.next_cursor:
|
||||||
cursor = result.nextCursor
|
cursor = result.next_cursor
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
@ -2167,7 +2167,7 @@ async def handle_sampling_message(
|
||||||
text="Hello, world! from model",
|
text="Hello, world! from model",
|
||||||
),
|
),
|
||||||
model="gpt-3.5-turbo",
|
model="gpt-3.5-turbo",
|
||||||
stopReason="endTurn",
|
stop_reason="endTurn",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2205,7 +2205,7 @@ async def run():
|
||||||
result_unstructured = result.content[0]
|
result_unstructured = result.content[0]
|
||||||
if isinstance(result_unstructured, types.TextContent):
|
if isinstance(result_unstructured, types.TextContent):
|
||||||
print(f"Tool result: {result_unstructured.text}")
|
print(f"Tool result: {result_unstructured.text}")
|
||||||
result_structured = result.structuredContent
|
result_structured = result.structured_content
|
||||||
print(f"Structured tool result: {result_structured}")
|
print(f"Structured tool result: {result_structured}")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2306,7 +2306,7 @@ async def display_resources(session: ClientSession):
|
||||||
print(f"Resource: {display_name} ({resource.uri})")
|
print(f"Resource: {display_name} ({resource.uri})")
|
||||||
|
|
||||||
templates_response = await session.list_resource_templates()
|
templates_response = await session.list_resource_templates()
|
||||||
for template in templates_response.resourceTemplates:
|
for template in templates_response.resource_templates:
|
||||||
display_name = get_display_name(template)
|
display_name = get_display_name(template)
|
||||||
print(f"Resource Template: {display_name}")
|
print(f"Resource Template: {display_name}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ class Server:
|
||||||
|
|
||||||
for item in tools_response:
|
for item in tools_response:
|
||||||
if item[0] == "tools":
|
if item[0] == "tools":
|
||||||
tools.extend(Tool(tool.name, tool.description, tool.inputSchema, tool.title) for tool in item[1])
|
tools.extend(Tool(tool.name, tool.description, tool.input_schema, tool.title) for tool in item[1])
|
||||||
|
|
||||||
return tools
|
return tools
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ async def run(url: str) -> None:
|
||||||
arguments={},
|
arguments={},
|
||||||
ttl=60000,
|
ttl=60000,
|
||||||
)
|
)
|
||||||
task_id = result.task.taskId
|
task_id = result.task.task_id
|
||||||
print(f"Task created: {task_id}")
|
print(f"Task created: {task_id}")
|
||||||
|
|
||||||
status = None
|
status = None
|
||||||
# Poll until done (respects server's pollInterval hint)
|
# Poll until done (respects server's pollInterval hint)
|
||||||
async for status in session.experimental.poll_task(task_id):
|
async for status in session.experimental.poll_task(task_id):
|
||||||
print(f" Status: {status.status} - {status.statusMessage or ''}")
|
print(f" Status: {status.status} - {status.status_message or ''}")
|
||||||
|
|
||||||
# Check final status
|
# Check final status
|
||||||
if status and status.status != "completed":
|
if status and status.status != "completed":
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ async def sampling_callback(context, params) -> CreateMessageResult:
|
||||||
```python
|
```python
|
||||||
# Call a tool as a task (returns immediately with task reference)
|
# Call a tool as a task (returns immediately with task reference)
|
||||||
result = await session.experimental.call_tool_as_task("tool_name", {"arg": "value"})
|
result = await session.experimental.call_tool_as_task("tool_name", {"arg": "value"})
|
||||||
task_id = result.task.taskId
|
task_id = result.task.task_id
|
||||||
|
|
||||||
# Get result - this delivers elicitation/sampling requests and blocks until complete
|
# Get result - this delivers elicitation/sampling requests and blocks until complete
|
||||||
final = await session.experimental.get_task_result(task_id, CallToolResult)
|
final = await session.experimental.get_task_result(task_id, CallToolResult)
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ async def run(url: str) -> None:
|
||||||
print("Calling confirm_delete tool...")
|
print("Calling confirm_delete tool...")
|
||||||
|
|
||||||
elicit_task = await session.experimental.call_tool_as_task("confirm_delete", {"filename": "important.txt"})
|
elicit_task = await session.experimental.call_tool_as_task("confirm_delete", {"filename": "important.txt"})
|
||||||
elicit_task_id = elicit_task.task.taskId
|
elicit_task_id = elicit_task.task.task_id
|
||||||
print(f"Task created: {elicit_task_id}")
|
print(f"Task created: {elicit_task_id}")
|
||||||
|
|
||||||
# Poll until terminal, calling tasks/result on input_required
|
# Poll until terminal, calling tasks/result on input_required
|
||||||
|
|
@ -112,7 +112,7 @@ async def run(url: str) -> None:
|
||||||
print("Calling write_haiku tool...")
|
print("Calling write_haiku tool...")
|
||||||
|
|
||||||
sampling_task = await session.experimental.call_tool_as_task("write_haiku", {"topic": "autumn leaves"})
|
sampling_task = await session.experimental.call_tool_as_task("write_haiku", {"topic": "autumn leaves"})
|
||||||
sampling_task_id = sampling_task.task.taskId
|
sampling_task_id = sampling_task.task.task_id
|
||||||
print(f"Task created: {sampling_task_id}")
|
print(f"Task created: {sampling_task_id}")
|
||||||
|
|
||||||
# Poll until terminal, calling tasks/result on input_required
|
# Poll until terminal, calling tasks/result on input_required
|
||||||
|
|
|
||||||
|
|
@ -20,5 +20,5 @@ class EchoResponse(BaseModel):
|
||||||
def echo(text: str) -> Annotated[CallToolResult, EchoResponse]:
|
def echo(text: str) -> Annotated[CallToolResult, EchoResponse]:
|
||||||
"""Echo the input text with structure and metadata"""
|
"""Echo the input text with structure and metadata"""
|
||||||
return CallToolResult(
|
return CallToolResult(
|
||||||
content=[TextContent(type="text", text=text)], structuredContent={"text": text}, _meta={"some": "metadata"}
|
content=[TextContent(type="text", text=text)], structured_content={"text": text}, _meta={"some": "metadata"}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ icon_path = Path(__file__).parent / "mcp.png"
|
||||||
icon_data = base64.standard_b64encode(icon_path.read_bytes()).decode()
|
icon_data = base64.standard_b64encode(icon_path.read_bytes()).decode()
|
||||||
icon_data_uri = f"data:image/png;base64,{icon_data}"
|
icon_data_uri = f"data:image/png;base64,{icon_data}"
|
||||||
|
|
||||||
icon_data = Icon(src=icon_data_uri, mimeType="image/png", sizes=["64x64"])
|
icon_data = Icon(src=icon_data_uri, mime_type="image/png", sizes=["64x64"])
|
||||||
|
|
||||||
# Create server with icons in implementation
|
# Create server with icons in implementation
|
||||||
mcp = FastMCP("Icons Demo Server", website_url="https://github.com/modelcontextprotocol/python-sdk", icons=[icon_data])
|
mcp = FastMCP("Icons Demo Server", website_url="https://github.com/modelcontextprotocol/python-sdk", icons=[icon_data])
|
||||||
|
|
@ -40,9 +40,9 @@ def prompt_with_icon(text: str) -> str:
|
||||||
|
|
||||||
@mcp.tool(
|
@mcp.tool(
|
||||||
icons=[
|
icons=[
|
||||||
Icon(src=icon_data_uri, mimeType="image/png", sizes=["16x16"]),
|
Icon(src=icon_data_uri, mime_type="image/png", sizes=["16x16"]),
|
||||||
Icon(src=icon_data_uri, mimeType="image/png", sizes=["32x32"]),
|
Icon(src=icon_data_uri, mime_type="image/png", sizes=["32x32"]),
|
||||||
Icon(src=icon_data_uri, mimeType="image/png", sizes=["64x64"]),
|
Icon(src=icon_data_uri, mime_type="image/png", sizes=["64x64"]),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def multi_icon_tool(action: str) -> str:
|
def multi_icon_tool(action: str) -> str:
|
||||||
|
|
|
||||||
|
|
@ -161,32 +161,32 @@ if __name__ == "__main__":
|
||||||
# Test get_weather
|
# Test get_weather
|
||||||
result = await client.call_tool("get_weather", {"city": "London"})
|
result = await client.call_tool("get_weather", {"city": "London"})
|
||||||
print("\nWeather in London:")
|
print("\nWeather in London:")
|
||||||
print(json.dumps(result.structuredContent, indent=2))
|
print(json.dumps(result.structured_content, indent=2))
|
||||||
|
|
||||||
# Test get_weather_summary
|
# Test get_weather_summary
|
||||||
result = await client.call_tool("get_weather_summary", {"city": "Paris"})
|
result = await client.call_tool("get_weather_summary", {"city": "Paris"})
|
||||||
print("\nWeather summary for Paris:")
|
print("\nWeather summary for Paris:")
|
||||||
print(json.dumps(result.structuredContent, indent=2))
|
print(json.dumps(result.structured_content, indent=2))
|
||||||
|
|
||||||
# Test get_weather_metrics
|
# Test get_weather_metrics
|
||||||
result = await client.call_tool("get_weather_metrics", {"cities": ["Tokyo", "Sydney", "Mumbai"]})
|
result = await client.call_tool("get_weather_metrics", {"cities": ["Tokyo", "Sydney", "Mumbai"]})
|
||||||
print("\nWeather metrics:")
|
print("\nWeather metrics:")
|
||||||
print(json.dumps(result.structuredContent, indent=2))
|
print(json.dumps(result.structured_content, indent=2))
|
||||||
|
|
||||||
# Test get_weather_alerts
|
# Test get_weather_alerts
|
||||||
result = await client.call_tool("get_weather_alerts", {"region": "California"})
|
result = await client.call_tool("get_weather_alerts", {"region": "California"})
|
||||||
print("\nWeather alerts for California:")
|
print("\nWeather alerts for California:")
|
||||||
print(json.dumps(result.structuredContent, indent=2))
|
print(json.dumps(result.structured_content, indent=2))
|
||||||
|
|
||||||
# Test get_temperature
|
# Test get_temperature
|
||||||
result = await client.call_tool("get_temperature", {"city": "Berlin", "unit": "fahrenheit"})
|
result = await client.call_tool("get_temperature", {"city": "Berlin", "unit": "fahrenheit"})
|
||||||
print("\nTemperature in Berlin:")
|
print("\nTemperature in Berlin:")
|
||||||
print(json.dumps(result.structuredContent, indent=2))
|
print(json.dumps(result.structured_content, indent=2))
|
||||||
|
|
||||||
# Test get_weather_stats
|
# Test get_weather_stats
|
||||||
result = await client.call_tool("get_weather_stats", {"city": "Seattle", "days": 30})
|
result = await client.call_tool("get_weather_stats", {"city": "Seattle", "days": 30})
|
||||||
print("\nWeather stats for Seattle (30 days):")
|
print("\nWeather stats for Seattle (30 days):")
|
||||||
print(json.dumps(result.structuredContent, indent=2))
|
print(json.dumps(result.structured_content, indent=2))
|
||||||
|
|
||||||
# Also show the text content for comparison
|
# Also show the text content for comparison
|
||||||
print("\nText content for last result:")
|
print("\nText content for last result:")
|
||||||
|
|
@ -204,11 +204,11 @@ if __name__ == "__main__":
|
||||||
print(f"\nTool: {tool.name}")
|
print(f"\nTool: {tool.name}")
|
||||||
print(f"Description: {tool.description}")
|
print(f"Description: {tool.description}")
|
||||||
print("Input Schema:")
|
print("Input Schema:")
|
||||||
print(json.dumps(tool.inputSchema, indent=2))
|
print(json.dumps(tool.input_schema, indent=2))
|
||||||
|
|
||||||
if tool.outputSchema:
|
if tool.output_schema:
|
||||||
print("Output Schema:")
|
print("Output Schema:")
|
||||||
print(json.dumps(tool.outputSchema, indent=2))
|
print(json.dumps(tool.output_schema, indent=2))
|
||||||
else:
|
else:
|
||||||
print("Output Schema: None (returns unstructured content)")
|
print("Output Schema: None (returns unstructured content)")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,13 +98,13 @@ def test_simple_text() -> str:
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def test_image_content() -> list[ImageContent]:
|
def test_image_content() -> list[ImageContent]:
|
||||||
"""Tests image content response"""
|
"""Tests image content response"""
|
||||||
return [ImageContent(type="image", data=TEST_IMAGE_BASE64, mimeType="image/png")]
|
return [ImageContent(type="image", data=TEST_IMAGE_BASE64, mime_type="image/png")]
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def test_audio_content() -> list[AudioContent]:
|
def test_audio_content() -> list[AudioContent]:
|
||||||
"""Tests audio content response"""
|
"""Tests audio content response"""
|
||||||
return [AudioContent(type="audio", data=TEST_AUDIO_BASE64, mimeType="audio/wav")]
|
return [AudioContent(type="audio", data=TEST_AUDIO_BASE64, mime_type="audio/wav")]
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
|
|
@ -115,7 +115,7 @@ def test_embedded_resource() -> list[EmbeddedResource]:
|
||||||
type="resource",
|
type="resource",
|
||||||
resource=TextResourceContents(
|
resource=TextResourceContents(
|
||||||
uri="test://embedded-resource",
|
uri="test://embedded-resource",
|
||||||
mimeType="text/plain",
|
mime_type="text/plain",
|
||||||
text="This is an embedded resource content.",
|
text="This is an embedded resource content.",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -127,12 +127,12 @@ def test_multiple_content_types() -> list[TextContent | ImageContent | EmbeddedR
|
||||||
"""Tests response with multiple content types (text, image, resource)"""
|
"""Tests response with multiple content types (text, image, resource)"""
|
||||||
return [
|
return [
|
||||||
TextContent(type="text", text="Multiple content types test:"),
|
TextContent(type="text", text="Multiple content types test:"),
|
||||||
ImageContent(type="image", data=TEST_IMAGE_BASE64, mimeType="image/png"),
|
ImageContent(type="image", data=TEST_IMAGE_BASE64, mime_type="image/png"),
|
||||||
EmbeddedResource(
|
EmbeddedResource(
|
||||||
type="resource",
|
type="resource",
|
||||||
resource=TextResourceContents(
|
resource=TextResourceContents(
|
||||||
uri="test://mixed-content-resource",
|
uri="test://mixed-content-resource",
|
||||||
mimeType="application/json",
|
mime_type="application/json",
|
||||||
text='{"test": "data", "value": 123}',
|
text='{"test": "data", "value": 123}',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -164,7 +164,7 @@ async def test_tool_with_progress(ctx: Context[ServerSession, None]) -> str:
|
||||||
await ctx.report_progress(progress=100, total=100, message="Completed step 100 of 100")
|
await ctx.report_progress(progress=100, total=100, message="Completed step 100 of 100")
|
||||||
|
|
||||||
# Return progress token as string
|
# Return progress token as string
|
||||||
progress_token = ctx.request_context.meta.progressToken if ctx.request_context and ctx.request_context.meta else 0
|
progress_token = ctx.request_context.meta.progress_token if ctx.request_context and ctx.request_context.meta else 0
|
||||||
return str(progress_token)
|
return str(progress_token)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -373,7 +373,7 @@ def test_prompt_with_embedded_resource(resourceUri: str) -> list[UserMessage]:
|
||||||
type="resource",
|
type="resource",
|
||||||
resource=TextResourceContents(
|
resource=TextResourceContents(
|
||||||
uri=resourceUri,
|
uri=resourceUri,
|
||||||
mimeType="text/plain",
|
mime_type="text/plain",
|
||||||
text="Embedded resource content for testing.",
|
text="Embedded resource content for testing.",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -386,7 +386,7 @@ def test_prompt_with_embedded_resource(resourceUri: str) -> list[UserMessage]:
|
||||||
def test_prompt_with_image() -> list[UserMessage]:
|
def test_prompt_with_image() -> list[UserMessage]:
|
||||||
"""A prompt that includes image content"""
|
"""A prompt that includes image content"""
|
||||||
return [
|
return [
|
||||||
UserMessage(role="user", content=ImageContent(type="image", data=TEST_IMAGE_BASE64, mimeType="image/png")),
|
UserMessage(role="user", content=ImageContent(type="image", data=TEST_IMAGE_BASE64, mime_type="image/png")),
|
||||||
UserMessage(role="user", content=TextContent(type="text", text="Please analyze the image above.")),
|
UserMessage(role="user", content=TextContent(type="text", text="Please analyze the image above.")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -427,7 +427,7 @@ async def _handle_completion(
|
||||||
"""Handle completion requests"""
|
"""Handle completion requests"""
|
||||||
# Basic completion support - returns empty array for conformance
|
# Basic completion support - returns empty array for conformance
|
||||||
# Real implementations would provide contextual suggestions
|
# Real implementations would provide contextual suggestions
|
||||||
return Completion(values=[], total=0, hasMore=False)
|
return Completion(values=[], total=0, has_more=False)
|
||||||
|
|
||||||
|
|
||||||
# CLI
|
# CLI
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ SAMPLE_TOOLS = [
|
||||||
name=f"tool_{i}",
|
name=f"tool_{i}",
|
||||||
title=f"Tool {i}",
|
title=f"Tool {i}",
|
||||||
description=f"This is sample tool number {i}",
|
description=f"This is sample tool number {i}",
|
||||||
inputSchema={"type": "object", "properties": {"input": {"type": "string"}}},
|
input_schema={"type": "object", "properties": {"input": {"type": "string"}}},
|
||||||
)
|
)
|
||||||
for i in range(1, 26) # 25 tools total
|
for i in range(1, 26) # 25 tools total
|
||||||
]
|
]
|
||||||
|
|
@ -71,7 +71,7 @@ def main(port: int, transport: str) -> int:
|
||||||
start_idx = int(cursor)
|
start_idx = int(cursor)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
# Invalid cursor, return empty
|
# Invalid cursor, return empty
|
||||||
return types.ListToolsResult(tools=[], nextCursor=None)
|
return types.ListToolsResult(tools=[], next_cursor=None)
|
||||||
|
|
||||||
# Get the page of tools
|
# Get the page of tools
|
||||||
page_tools = SAMPLE_TOOLS[start_idx : start_idx + page_size]
|
page_tools = SAMPLE_TOOLS[start_idx : start_idx + page_size]
|
||||||
|
|
@ -81,7 +81,7 @@ def main(port: int, transport: str) -> int:
|
||||||
if start_idx + page_size < len(SAMPLE_TOOLS):
|
if start_idx + page_size < len(SAMPLE_TOOLS):
|
||||||
next_cursor = str(start_idx + page_size)
|
next_cursor = str(start_idx + page_size)
|
||||||
|
|
||||||
return types.ListToolsResult(tools=page_tools, nextCursor=next_cursor)
|
return types.ListToolsResult(tools=page_tools, next_cursor=next_cursor)
|
||||||
|
|
||||||
# Paginated list_resources - returns 10 resources per page
|
# Paginated list_resources - returns 10 resources per page
|
||||||
@app.list_resources()
|
@app.list_resources()
|
||||||
|
|
@ -100,7 +100,7 @@ def main(port: int, transport: str) -> int:
|
||||||
start_idx = int(cursor)
|
start_idx = int(cursor)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
# Invalid cursor, return empty
|
# Invalid cursor, return empty
|
||||||
return types.ListResourcesResult(resources=[], nextCursor=None)
|
return types.ListResourcesResult(resources=[], next_cursor=None)
|
||||||
|
|
||||||
# Get the page of resources
|
# Get the page of resources
|
||||||
page_resources = SAMPLE_RESOURCES[start_idx : start_idx + page_size]
|
page_resources = SAMPLE_RESOURCES[start_idx : start_idx + page_size]
|
||||||
|
|
@ -110,7 +110,7 @@ def main(port: int, transport: str) -> int:
|
||||||
if start_idx + page_size < len(SAMPLE_RESOURCES):
|
if start_idx + page_size < len(SAMPLE_RESOURCES):
|
||||||
next_cursor = str(start_idx + page_size)
|
next_cursor = str(start_idx + page_size)
|
||||||
|
|
||||||
return types.ListResourcesResult(resources=page_resources, nextCursor=next_cursor)
|
return types.ListResourcesResult(resources=page_resources, next_cursor=next_cursor)
|
||||||
|
|
||||||
# Paginated list_prompts - returns 7 prompts per page
|
# Paginated list_prompts - returns 7 prompts per page
|
||||||
@app.list_prompts()
|
@app.list_prompts()
|
||||||
|
|
@ -129,7 +129,7 @@ def main(port: int, transport: str) -> int:
|
||||||
start_idx = int(cursor)
|
start_idx = int(cursor)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
# Invalid cursor, return empty
|
# Invalid cursor, return empty
|
||||||
return types.ListPromptsResult(prompts=[], nextCursor=None)
|
return types.ListPromptsResult(prompts=[], next_cursor=None)
|
||||||
|
|
||||||
# Get the page of prompts
|
# Get the page of prompts
|
||||||
page_prompts = SAMPLE_PROMPTS[start_idx : start_idx + page_size]
|
page_prompts = SAMPLE_PROMPTS[start_idx : start_idx + page_size]
|
||||||
|
|
@ -139,7 +139,7 @@ def main(port: int, transport: str) -> int:
|
||||||
if start_idx + page_size < len(SAMPLE_PROMPTS):
|
if start_idx + page_size < len(SAMPLE_PROMPTS):
|
||||||
next_cursor = str(start_idx + page_size)
|
next_cursor = str(start_idx + page_size)
|
||||||
|
|
||||||
return types.ListPromptsResult(prompts=page_prompts, nextCursor=next_cursor)
|
return types.ListPromptsResult(prompts=page_prompts, next_cursor=next_cursor)
|
||||||
|
|
||||||
# Implement call_tool handler
|
# Implement call_tool handler
|
||||||
@app.call_tool()
|
@app.call_tool()
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ def main(port: int, transport: str) -> int:
|
||||||
name=name,
|
name=name,
|
||||||
title=SAMPLE_RESOURCES[name]["title"],
|
title=SAMPLE_RESOURCES[name]["title"],
|
||||||
description=f"A sample text resource named {name}",
|
description=f"A sample text resource named {name}",
|
||||||
mimeType="text/plain",
|
mime_type="text/plain",
|
||||||
)
|
)
|
||||||
for name in SAMPLE_RESOURCES.keys()
|
for name in SAMPLE_RESOURCES.keys()
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ def main(
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="start-notification-stream",
|
name="start-notification-stream",
|
||||||
description=("Sends a stream of notifications with configurable count and interval"),
|
description=("Sends a stream of notifications with configurable count and interval"),
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["interval", "count", "caller"],
|
"required": ["interval", "count", "caller"],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ def main(
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="start-notification-stream",
|
name="start-notification-stream",
|
||||||
description=("Sends a stream of notifications with configurable count and interval"),
|
description=("Sends a stream of notifications with configurable count and interval"),
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["interval", "count", "caller"],
|
"required": ["interval", "count", "caller"],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
||||||
|
|
@ -31,17 +31,17 @@ async def list_tools() -> list[types.Tool]:
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="confirm_delete",
|
name="confirm_delete",
|
||||||
description="Asks for confirmation before deleting (demonstrates elicitation)",
|
description="Asks for confirmation before deleting (demonstrates elicitation)",
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"filename": {"type": "string"}},
|
"properties": {"filename": {"type": "string"}},
|
||||||
},
|
},
|
||||||
execution=types.ToolExecution(taskSupport=types.TASK_REQUIRED),
|
execution=types.ToolExecution(task_support=types.TASK_REQUIRED),
|
||||||
),
|
),
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="write_haiku",
|
name="write_haiku",
|
||||||
description="Asks LLM to write a haiku (demonstrates sampling)",
|
description="Asks LLM to write a haiku (demonstrates sampling)",
|
||||||
inputSchema={"type": "object", "properties": {"topic": {"type": "string"}}},
|
input_schema={"type": "object", "properties": {"topic": {"type": "string"}}},
|
||||||
execution=types.ToolExecution(taskSupport=types.TASK_REQUIRED),
|
execution=types.ToolExecution(task_support=types.TASK_REQUIRED),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@ async def handle_confirm_delete(arguments: dict[str, Any]) -> types.CreateTaskRe
|
||||||
|
|
||||||
result = await task.elicit(
|
result = await task.elicit(
|
||||||
message=f"Are you sure you want to delete '{filename}'?",
|
message=f"Are you sure you want to delete '{filename}'?",
|
||||||
requestedSchema={
|
requested_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"confirm": {"type": "boolean"}},
|
"properties": {"confirm": {"type": "boolean"}},
|
||||||
"required": ["confirm"],
|
"required": ["confirm"],
|
||||||
|
|
@ -121,7 +121,7 @@ async def handle_call_tool(name: str, arguments: dict[str, Any]) -> types.CallTo
|
||||||
else:
|
else:
|
||||||
return types.CallToolResult(
|
return types.CallToolResult(
|
||||||
content=[types.TextContent(type="text", text=f"Unknown tool: {name}")],
|
content=[types.TextContent(type="text", text=f"Unknown tool: {name}")],
|
||||||
isError=True,
|
is_error=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ async def list_tools() -> list[types.Tool]:
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="long_running_task",
|
name="long_running_task",
|
||||||
description="A task that takes a few seconds to complete with status updates",
|
description="A task that takes a few seconds to complete with status updates",
|
||||||
inputSchema={"type": "object", "properties": {}},
|
input_schema={"type": "object", "properties": {}},
|
||||||
execution=types.ToolExecution(taskSupport=types.TASK_REQUIRED),
|
execution=types.ToolExecution(task_support=types.TASK_REQUIRED),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ async def handle_call_tool(name: str, arguments: dict[str, Any]) -> types.CallTo
|
||||||
else:
|
else:
|
||||||
return types.CallToolResult(
|
return types.CallToolResult(
|
||||||
content=[types.TextContent(type="text", text=f"Unknown tool: {name}")],
|
content=[types.TextContent(type="text", text=f"Unknown tool: {name}")],
|
||||||
isError=True,
|
is_error=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ def main(port: int, transport: str) -> int:
|
||||||
name="fetch",
|
name="fetch",
|
||||||
title="Website Fetcher",
|
title="Website Fetcher",
|
||||||
description="Fetches a website and returns its content",
|
description="Fetches a website and returns its content",
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["url"],
|
"required": ["url"],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ def main(port: int, log_level: str, retry_interval: int) -> int:
|
||||||
"Process a batch of items with periodic checkpoints. "
|
"Process a batch of items with periodic checkpoints. "
|
||||||
"Demonstrates SSE polling where server closes stream periodically."
|
"Demonstrates SSE polling where server closes stream periodically."
|
||||||
),
|
),
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"items": {
|
"items": {
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@ async def list_tools() -> list[types.Tool]:
|
||||||
types.Tool(
|
types.Tool(
|
||||||
name="get_weather",
|
name="get_weather",
|
||||||
description="Get weather information (simulated)",
|
description="Get weather information (simulated)",
|
||||||
inputSchema={
|
input_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"city": {"type": "string", "description": "City name"}},
|
"properties": {"city": {"type": "string", "description": "City name"}},
|
||||||
"required": ["city"],
|
"required": ["city"],
|
||||||
},
|
},
|
||||||
outputSchema={
|
output_schema={
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"temperature": {"type": "number"},
|
"temperature": {"type": "number"},
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ async def run():
|
||||||
# List available resource templates
|
# List available resource templates
|
||||||
templates = await session.list_resource_templates()
|
templates = await session.list_resource_templates()
|
||||||
print("Available resource templates:")
|
print("Available resource templates:")
|
||||||
for template in templates.resourceTemplates:
|
for template in templates.resource_templates:
|
||||||
print(f" - {template.uriTemplate}")
|
print(f" - {template.uri_template}")
|
||||||
|
|
||||||
# List available prompts
|
# List available prompts
|
||||||
prompts = await session.list_prompts()
|
prompts = await session.list_prompts()
|
||||||
|
|
@ -38,20 +38,20 @@ async def run():
|
||||||
print(f" - {prompt.name}")
|
print(f" - {prompt.name}")
|
||||||
|
|
||||||
# Complete resource template arguments
|
# Complete resource template arguments
|
||||||
if templates.resourceTemplates:
|
if templates.resource_templates:
|
||||||
template = templates.resourceTemplates[0]
|
template = templates.resource_templates[0]
|
||||||
print(f"\nCompleting arguments for resource template: {template.uriTemplate}")
|
print(f"\nCompleting arguments for resource template: {template.uri_template}")
|
||||||
|
|
||||||
# Complete without context
|
# Complete without context
|
||||||
result = await session.complete(
|
result = await session.complete(
|
||||||
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
|
ref=ResourceTemplateReference(type="ref/resource", uri=template.uri_template),
|
||||||
argument={"name": "owner", "value": "model"},
|
argument={"name": "owner", "value": "model"},
|
||||||
)
|
)
|
||||||
print(f"Completions for 'owner' starting with 'model': {result.completion.values}")
|
print(f"Completions for 'owner' starting with 'model': {result.completion.values}")
|
||||||
|
|
||||||
# Complete with context - repo suggestions based on owner
|
# Complete with context - repo suggestions based on owner
|
||||||
result = await session.complete(
|
result = await session.complete(
|
||||||
ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate),
|
ref=ResourceTemplateReference(type="ref/resource", uri=template.uri_template),
|
||||||
argument={"name": "repo", "value": ""},
|
argument={"name": "repo", "value": ""},
|
||||||
context_arguments={"owner": "modelcontextprotocol"},
|
context_arguments={"owner": "modelcontextprotocol"},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ async def display_resources(session: ClientSession):
|
||||||
print(f"Resource: {display_name} ({resource.uri})")
|
print(f"Resource: {display_name} ({resource.uri})")
|
||||||
|
|
||||||
templates_response = await session.list_resource_templates()
|
templates_response = await session.list_resource_templates()
|
||||||
for template in templates_response.resourceTemplates:
|
for template in templates_response.resource_templates:
|
||||||
display_name = get_display_name(template)
|
display_name = get_display_name(template)
|
||||||
print(f"Resource Template: {display_name}")
|
print(f"Resource Template: {display_name}")
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue