Implementation Guide
This guide will walk you through the process of implementing UTCP in your applications, whether you're creating a tool provider or developing a client that consumes tools.
Overview
Implementing UTCP typically involves one or both of the following:
- Creating a Tool Provider: Exposing your tools through a UTCP-compliant discovery endpoint
- Building a UTCP Client: Consuming tools from UTCP providers
Creating a Tool Provider
A UTCP tool provider exposes one or more tools through a standardized discovery endpoint. Here's how to implement one:
Step 1: Define Your Tools
First, define the tools you want to expose using the UTCP Tool
model:
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a location",
"inputs": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"description": "The unit of temperature (celsius or fahrenheit)",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"],
"description": "Weather query parameters"
},
"outputs": {
"type": "object",
"properties": {
"temperature": {
"type": "number",
"description": "The current temperature"
},
"conditions": {
"type": "string",
"description": "The weather conditions (e.g., sunny, cloudy)"
}
},
"required": ["temperature", "conditions"],
"description": "Weather information"
},
"tags": ["weather", "api"],
"tool_provider": {
"provider_type": "http",
"url": "https://api.example.com/weather",
"http_method": "GET"
}
}
]
Step 2: Create a Discovery Endpoint
Create an endpoint that returns a UTCPManual
containing your tool definitions:
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
app = FastAPI()
class UTCPManual(BaseModel):
version: str
tools: List[dict]
@app.get("/utcp")
def utcp_discovery():
return UTCPManual(
version="1.0",
tools=tools
)
Step 3: Implement Tool Functionality
Implement the actual functionality of each tool according to its provider specification. For example, for an HTTP provider:
@app.get("/weather")
def get_weather(location: str, unit: str = "celsius"):
# Implement your weather logic here
return {
"temperature": 22.5,
"conditions": "Sunny"
}
Using a UTCP Client
Here's how you might use a UTCP client:
import asyncio
from utcp.client import UtcpClient
from utcp.shared.provider import HttpProvider
async def main():
# Create a client
client = await UtcpClient.create()
# Define the manual provider for the discovery endpoint
manual_provider = HttpProvider(
name="weather_api",
provider_type="http",
url="https://api.example.com/utcp",
http_method="GET"
)
# Register tools from the manual provider
await client.register_manual_provider(manual_provider)
# Call a tool
result = await client.call_tool(
"weather_api.get_weather",
arguments={"location": "San Francisco"}
)
print(f"The temperature is {result['temperature']}°C and it's {result['conditions']}")
# Run the example
if __name__ == "__main__":
asyncio.run(main())
Best Practices
When implementing UTCP:
- Cache tool discoveries to reduce load and handle temporary outages
- Validate inputs against the tool's input schema before sending
- Handle errors gracefully, especially for network-related issues
- Implement timeouts to prevent hanging on unresponsive tools
- Log tool usage for debugging and monitoring