
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@utcp/http
Advanced tools
HTTP-Based Communication Protocols for UTCP
The @utcp/http package provides comprehensive HTTP-based protocol support for the Universal Tool Calling Protocol (UTCP). It includes three distinct protocols:
All protocols support multiple authentication methods, URL path parameters, custom headers, and automatic OpenAPI specification conversion.
Standard HTTP requests for RESTful APIs:
interface HttpCallTemplate {
name: string;
call_template_type: 'http';
http_method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
url: string;
headers?: Record<string, string>;
body_field?: string;
content_type?: string;
timeout?: number;
auth?: ApiKeyAuth | BasicAuth | OAuth2Auth;
}
HTTP streaming with chunked transfer encoding for large responses:
interface StreamableHttpCallTemplate {
name: string;
call_template_type: 'streamable_http';
url: string;
http_method: 'GET' | 'POST';
content_type?: string;
chunk_size?: number; // Default: 4096 bytes
timeout?: number; // Default: 60000ms
headers?: Record<string, string>;
body_field?: string;
header_fields?: string[];
auth?: ApiKeyAuth | BasicAuth | OAuth2Auth;
}
Server-Sent Events for real-time streaming:
interface SseCallTemplate {
name: string;
call_template_type: 'sse';
url: string;
event_type?: string; // Filter specific event types
reconnect?: boolean; // Auto-reconnect on disconnect
retry_timeout?: number; // Reconnection timeout (ms)
headers?: Record<string, string>;
body_field?: string;
header_fields?: string[];
auth?: ApiKeyAuth | BasicAuth | OAuth2Auth;
}
Tool Discovery: Automatically registers tools from:
Tool Execution:
${param_name} or {param_name}body_fieldAuthentication Support:
Security:
Automatically converts OpenAPI specifications to UTCP tools:
| Protocol | Use Case | Response Type | Best For |
|---|---|---|---|
| HTTP | Standard RESTful APIs | Complete response | Most APIs, CRUD operations, single requests |
| Streamable HTTP | Large data downloads | Chunked streaming | Large files, datasets, progressive data |
| SSE | Real-time updates | Event stream | Live updates, notifications, real-time feeds |
HTTP
Streamable HTTP
SSE
npm install @utcp/http @utcp/sdk
# Or with bun
bun add @utcp/http @utcp/sdk
Dependencies:
@utcp/sdk - Core UTCP SDK (peer dependency)axios - HTTP clientjs-yaml - YAML parsing for OpenAPI specsAll three HTTP-based protocols (http, streamable_http, sse) are automatically registered when you import the UtcpClient. No manual setup required!
import { UtcpClient } from '@utcp/sdk';
import { HttpCallTemplateSerializer } from '@utcp/http';
async function main() {
const serializer = new HttpCallTemplateSerializer();
const weatherTemplate = serializer.validateDict({
name: 'weather_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.weatherapi.com/v1/current.json',
headers: {
'X-API-Key': '${API_KEY}'
}
});
const client = await UtcpClient.create(process.cwd(), {
variables: {
// Namespaced variables for security
'weather__api_API_KEY': process.env.WEATHER_API_KEY || ''
},
manual_call_templates: [weatherTemplate]
});
// Call the API
const weather = await client.callTool('weather_api.get_current', {
q: 'London'
});
console.log('Weather:', weather);
await client.close();
}
Automatically discover tools from an OpenAPI spec:
import { UtcpClient } from '@utcp/sdk';
import { HttpCallTemplateSerializer } from '@utcp/http';
const serializer = new HttpCallTemplateSerializer();
const petstoreTemplate = serializer.validateDict({
name: 'petstore_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://petstore.swagger.io/v2/swagger.json',
// Tools will be auto-discovered from the OpenAPI spec
});
const client = await UtcpClient.create(process.cwd(), {
manual_call_templates: [petstoreTemplate]
});
// Search for discovered tools
const tools = await client.searchTools('pet');
console.log('Available tools:', tools.map(t => t.name));
// Call a discovered tool
const pets = await client.callTool('petstore_api.findPetsByStatus', {
status: 'available'
});
Stream large responses using chunked transfer encoding:
import { UtcpClient } from '@utcp/sdk';
import { StreamableHttpCallTemplateSerializer } from '@utcp/http';
const serializer = new StreamableHttpCallTemplateSerializer();
const streamTemplate = serializer.validateDict({
name: 'large_data_api',
call_template_type: 'streamable_http',
http_method: 'GET',
url: 'https://api.example.com/large-dataset',
chunk_size: 8192, // 8KB chunks
timeout: 120000, // 2 minutes
headers: {
'Accept': 'application/octet-stream'
}
});
const client = await UtcpClient.create(process.cwd(), {
manual_call_templates: [streamTemplate]
});
// Stream the response
const stream = await client.callToolStreaming('large_data_api.get_dataset', {
filter: 'recent'
});
for await (const chunk of stream) {
console.log('Received chunk:', chunk.length, 'bytes');
// Process chunk...
}
Real-time event streaming from servers:
import { UtcpClient } from '@utcp/sdk';
import { SseCallTemplateSerializer } from '@utcp/http';
const serializer = new SseCallTemplateSerializer();
const sseTemplate = serializer.validateDict({
name: 'events_api',
call_template_type: 'sse',
url: 'https://api.example.com/events',
event_type: 'notification', // Filter to specific event type
reconnect: true, // Auto-reconnect on disconnect
retry_timeout: 5000, // Retry after 5 seconds
headers: {
'Authorization': 'Bearer ${API_KEY}'
}
});
const client = await UtcpClient.create(process.cwd(), {
variables: {
'events__api_API_KEY': process.env.SSE_API_KEY || ''
},
manual_call_templates: [sseTemplate]
});
// Stream real-time events
const eventStream = await client.callToolStreaming('events_api.stream_events', {
channel: 'updates'
});
for await (const event of eventStream) {
console.log('Event received:', event);
// Handle event...
}
import { HttpCallTemplateSerializer } from '@utcp/http';
const serializer = new HttpCallTemplateSerializer();
const callTemplate = serializer.validateDict({
name: 'api_with_key',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.example.com/data',
auth: {
auth_type: 'api_key',
var_name: 'X-API-Key',
api_key_value: '${API_KEY}',
in: 'header' // or 'query' or 'cookie'
}
});
const serializer = new HttpCallTemplateSerializer();
const callTemplate = serializer.validateDict({
name: 'api_with_basic',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.example.com/data',
auth: {
auth_type: 'basic',
username: '${USERNAME}',
password: '${PASSWORD}'
}
});
const serializer = new HttpCallTemplateSerializer();
const callTemplate = serializer.validateDict({
name: 'api_with_oauth',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.example.com/data',
auth: {
auth_type: 'oauth2',
token_url: 'https://auth.example.com/oauth/token',
client_id: '${CLIENT_ID}',
client_secret: '${CLIENT_SECRET}',
scope: 'read write'
}
});
Use ${param} or {param} syntax for path parameters:
const serializer = new HttpCallTemplateSerializer();
const callTemplate = serializer.validateDict({
name: 'github_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.github.com/users/${username}',
});
// Call with arguments
await client.callTool('github_api.get_user', {
username: 'octocat'
});
// Resolves to: https://api.github.com/users/octocat
For POST/PUT/PATCH requests, use body_field:
const serializer = new HttpCallTemplateSerializer();
const callTemplate = serializer.validateDict({
name: 'create_resource',
call_template_type: 'http',
http_method: 'POST',
url: 'https://api.example.com/resources',
body_field: 'data',
content_type: 'application/json',
headers: {
'Content-Type': 'application/json'
}
});
// Call with body
await client.callTool('create_resource.post', {
data: {
name: 'My Resource',
value: 42
}
});
const serializer = new HttpCallTemplateSerializer();
const githubTemplate = serializer.validateDict({
name: 'github_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.github.com/repos/${owner}/${repo}/issues',
headers: { 'Authorization': 'Bearer ${TOKEN}' }
});
const client = await UtcpClient.create(process.cwd(), {
variables: { 'github__api_TOKEN': process.env.GITHUB_TOKEN || '' },
manual_call_templates: [githubTemplate]
});
const issues = await client.callTool('github_api.get_issues', {
owner: 'utcp', repo: 'typescript-utcp'
});
const serializer = new StreamableHttpCallTemplateSerializer();
const cdnTemplate = serializer.validateDict({
name: 'cdn',
call_template_type: 'streamable_http',
http_method: 'GET',
url: 'https://cdn.example.com/large-file.zip',
chunk_size: 16384
});
const client = await UtcpClient.create(process.cwd(), {
manual_call_templates: [cdnTemplate]
});
const stream = await client.callToolStreaming('cdn.download', {});
for await (const chunk of stream) {
// Write chunk to file or process incrementally
fs.appendFileSync('output.zip', chunk);
}
const serializer = new SseCallTemplateSerializer();
const stockTemplate = serializer.validateDict({
name: 'stock_api',
call_template_type: 'sse',
url: 'https://api.stocks.com/stream',
event_type: 'price_update',
reconnect: true
});
const client = await UtcpClient.create(process.cwd(), {
manual_call_templates: [stockTemplate]
});
const priceStream = await client.callToolStreaming('stock_api.watch', {
symbol: 'AAPL'
});
for await (const update of priceStream) {
console.log('Price update:', update.price, 'at', update.timestamp);
}
const serializer = new HttpCallTemplateSerializer();
const callTemplate = serializer.validateDict({
name: 'custom_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.example.com/data',
headers: {
'Authorization': 'Bearer ${TOKEN}',
'X-Request-ID': '${REQUEST_ID}',
'User-Agent': 'UTCP-Client/1.0'
}
});
const serializer = new HttpCallTemplateSerializer();
const callTemplate = serializer.validateDict({
name: 'slow_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.example.com/slow-endpoint',
timeout: 60000 // 60 seconds
});
All variables are automatically namespaced by manual name for security:
const client = await UtcpClient.create(process.cwd(), {
variables: {
// For manual "github_api", variables must be prefixed
'github__api_TOKEN': 'github-token-123',
'gitlab__api_TOKEN': 'gitlab-token-456'
},
manual_call_templates: [
{
name: 'github_api',
// ...
headers: {
// Resolves to "github__api_TOKEN"
'Authorization': 'Bearer ${TOKEN}'
}
}
]
});
The OpenApiConverter automatically:
import { OpenApiConverter } from '@utcp/http';
const converter = new OpenApiConverter('https://api.example.com/openapi.json');
const manual = await converter.convert();
console.log('Discovered tools:', manual.tools.length);
The HTTP protocol enforces HTTPS or localhost connections by default to prevent MITM attacks:
// ✅ Allowed
'https://api.example.com'
'http://localhost:8080'
'http://127.0.0.1:3000'
// ❌ Rejected
'http://api.example.com' // Non-localhost HTTP
OAuth2 tokens are automatically cached by client_id to minimize token requests:
try {
const result = await client.callTool('api_manual.endpoint', args);
} catch (error) {
if (error.message.includes('401')) {
console.error('Authentication failed');
} else if (error.message.includes('404')) {
console.error('Endpoint not found');
} else {
console.error('Request failed:', error);
}
}
Full TypeScript support with exported types for all three protocols:
import {
// HTTP Protocol
HttpCallTemplate,
HttpCommunicationProtocol,
// Streamable HTTP Protocol
StreamableHttpCallTemplate,
StreamableHttpCommunicationProtocol,
// SSE Protocol
SseCallTemplate,
SseCommunicationProtocol,
// OpenAPI Converter
OpenApiConverter,
// Authentication Types
ApiKeyAuth,
BasicAuth,
OAuth2Auth
} from '@utcp/http';
# Run HTTP protocol tests
bun test packages/http/tests/
@utcp/sdk - Core UTCP SDK@utcp/mcp - MCP protocol support@utcp/text - File-based tools@utcp/cli - Command-line toolsSee the root repository for contribution guidelines.
Mozilla Public License Version 2.0
FAQs
HTTP utilities for UTCP
We found that @utcp/http demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.