fix: try and patch the PATCH/update issue with MCP server URL [LET-3933]

* fix: patch update path

* autogenerate

* update

* update

---------

Co-authored-by: Jin Peng <jinjpeng@Jins-MacBook-Pro.local>
Co-authored-by: Letta Bot <noreply@letta.com>
Co-authored-by: jnjpng <jin@letta.com>
This commit is contained in:
Charles Packer
2025-09-03 09:42:57 -07:00
committed by GitHub
parent 93ef177ab6
commit 507784f292
3 changed files with 66 additions and 7 deletions

View File

@@ -84,7 +84,6 @@ class MCPServer(BaseMCPServer):
class UpdateSSEMCPServer(LettaBase):
"""Update an SSE MCP server"""
server_name: Optional[str] = Field(None, description="The name of the server")
server_url: Optional[str] = Field(None, description="The URL of the server (MCP SSE client will connect to this URL)")
token: Optional[str] = Field(None, description="The access token or API key for the MCP server (used for SSE authentication)")
custom_headers: Optional[Dict[str, str]] = Field(None, description="Custom authentication headers as key-value pairs")
@@ -93,7 +92,6 @@ class UpdateSSEMCPServer(LettaBase):
class UpdateStdioMCPServer(LettaBase):
"""Update a Stdio MCP server"""
server_name: Optional[str] = Field(None, description="The name of the server")
stdio_config: Optional[StdioServerConfig] = Field(
None, description="The configuration for the server (MCP 'local' client will run this command)"
)
@@ -102,7 +100,6 @@ class UpdateStdioMCPServer(LettaBase):
class UpdateStreamableHTTPMCPServer(LettaBase):
"""Update a Streamable HTTP MCP server"""
server_name: Optional[str] = Field(None, description="The name of the server")
server_url: Optional[str] = Field(None, description="The URL path for the streamable HTTP server (e.g., 'example/mcp')")
auth_header: Optional[str] = Field(None, description="The name of the authentication header (e.g., 'Authorization')")
auth_token: Optional[str] = Field(None, description="The authentication token or API key value")

View File

@@ -26,10 +26,7 @@
"dev": {
"executor": "@nxlv/python:run-commands",
"options": {
"commands": [
"./otel/start-otel-collector.sh",
"uv run letta server"
],
"commands": ["./otel/start-otel-collector.sh", "uv run letta server"],
"parallel": true,
"cwd": "apps/core"
}

View File

@@ -375,3 +375,68 @@ async def test_streamable_http_mcp_server_update_schema_no_docstring_required(cl
finally:
client.tools.delete_mcp_server(mcp_server_name=mcp_server_name)
assert mcp_server_name not in client.tools.list_mcp_servers()
@pytest.mark.asyncio
async def test_mcp_server_patch_updates_url(client, server_url):
"""
Test that PATCHing an MCP server actually updates the server URL.
"""
# Create a unique server name
mcp_server_name = f"test_patch_{uuid.uuid4().hex[:6]}"
original_url = "https://mcp.deepwiki.com/sse"
updated_url = "https://mcp2.deepwiki.com/sse" # Intentionally invalid URL
# Create the initial SSE MCP server
sse_config = SSEServerConfig(server_name=mcp_server_name, server_url=original_url)
try:
# Add the MCP server
client.tools.add_mcp_server(request=sse_config)
# Verify the server was created with correct URL
servers = client.tools.list_mcp_servers()
assert mcp_server_name in servers
assert servers[mcp_server_name].server_url == original_url
print(f"✓ Server created with URL: {original_url}")
# Import the update schema
from letta.schemas.mcp import UpdateSSEMCPServer
# Now PATCH the server to update ONLY the URL (partial update)
update_request = UpdateSSEMCPServer(server_url=updated_url)
# Note: We're only setting server_url, not server_name
print(f"Updating server with request: {update_request.model_dump(exclude_unset=True)}")
updated_server = client.tools.update_mcp_server(mcp_server_name=mcp_server_name, request=update_request)
# Verify the server URL was actually updated
print(f"Server after update: URL={updated_server.server_url}")
assert updated_server.server_url == updated_url, f"Server URL not updated. Expected {updated_url}, got {updated_server.server_url}"
# Also verify through the list endpoint
servers = client.tools.list_mcp_servers()
assert mcp_server_name in servers
assert servers[mcp_server_name].server_url == updated_url, (
f"Server URL not updated in list. Got: {servers[mcp_server_name].server_url}"
)
print(f"✓ Server URL successfully updated to: {updated_url}")
# Now try to list tools with the updated (invalid) URL
# This should fail or return empty list if the patch actually worked
try:
tools = client.tools.list_mcp_tools_by_server(mcp_server_name=mcp_server_name)
# If we get here, either the tools listing succeeded (shouldn't with invalid URL)
# or it returned an empty list
assert len(tools) == 0, f"Expected no tools from invalid URL {updated_url}, but got {len(tools)} tools"
print("✓ Invalid URL correctly returns no tools")
except Exception:
# This is expected - the invalid URL should cause an error
# which confirms the PATCH actually updated the URL
print("✓ Invalid URL correctly causes error when listing tools")
finally:
try:
client.tools.delete_mcp_server(mcp_server_name=mcp_server_name)
except Exception:
pass