Install
$ agentstack add mcp-universal-tool-calling-protocol-typescript-utcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Universal Tool Calling Protocol (UTCP) for TypeScript
[](https://github.com/universal-tool-calling-protocol) [](https://www.npmjs.com/package/@utcp/sdk) [](https://github.com/universal-tool-calling-protocol/typescript-utcp/blob/main/LICENSE) [](https://cdtm.com/)
The Universal Tool Calling Protocol (UTCP) is a secure and scalable standard for defining and interacting with tools across a wide variety of communication protocols. This repository contains the official TypeScript implementation, structured as a monorepo with a lean core and pluggable communication protocols.
UTCP offers a unified framework for integrating disparate tools and services, making them accessible through a consistent and well-defined interface. This TypeScript SDK provides a comprehensive toolkit for developers to leverage the full power of the UTCP standard in their applications.
Key Features
- Automatic Plugin Registration: The official plugins are automatically discovered and registered when you import the core client—no manual setup required. For other plugins, you will need to register them manually.
- Scalability: Designed to handle a large number of tools and providers without compromising performance.
- Extensibility: A pluggable architecture allows developers to easily add new communication protocols, tool storage mechanisms, and search strategies without modifying the core library.
- Interoperability: With a growing ecosystem of protocol plugins—including HTTP, MCP, Text, File, and CLI—UTCP can integrate with almost any existing service or infrastructure.
- Code Execution Mode: Execute TypeScript code with hierarchical access to tools, complete console output capture, and runtime interface introspection for powerful AI agent workflows.
- Type Safety: Built on well-defined TypeScript interfaces and runtime validation powered by Zod, making it robust and developer-friendly.
- Secure Variable Management: Namespace-isolated variables prevent leakage between manuals, with support for environment variables and .env files.
Getting Started
Installation
Install UTCP packages from npm:
# Install core SDK and desired protocol plugins
npm install @utcp/sdk @utcp/http @utcp/mcp @utcp/text @utcp/file
# Optional: Add dotenv variable loader for Node.js
npm install @utcp/dotenv-loader
# Or using bun
bun add @utcp/sdk @utcp/http @utcp/mcp @utcp/text @utcp/file
For Development
To set up the monorepo for development:
# Clone the repository
git clone https://github.com/universal-tool-calling-protocol/typescript-utcp.git
cd typescript-utcp
# Install dependencies (requires bun)
bun install
# Build all packages
bun run build
Quick Start
Basic Usage
Plugins are automatically registered when you import the UtcpClient—no manual registration needed!
import { UtcpClient } from '@utcp/sdk';
import { HttpCallTemplateSerializer } from '@utcp/http';
async function main() {
// Create client - plugins auto-register
const serializer = new HttpCallTemplateSerializer();
const githubTemplate = serializer.validateDict({
name: 'github_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.github.com/users/${username}',
});
const client = await UtcpClient.create(process.cwd(), {
manual_call_templates: [githubTemplate],
variables: {
// Namespace format: manual_name_VARIABLE
github__api_username: 'octocat'
}
});
// Search for tools
const tools = await client.searchTools('github user');
console.log('Found tools:', tools.map(t => t.name));
// Call a tool
const result = await client.callTool('github_api.get_user', {});
console.log('Result:', result);
await client.close();
}
main().catch(console.error);
Working with Multiple Protocols
import { UtcpClient } from '@utcp/sdk';
import { HttpCallTemplateSerializer } from '@utcp/http';
import { McpCallTemplateSerializer } from '@utcp/mcp';
import { FileCallTemplateSerializer } from '@utcp/file';
async function main() {
// Create serializers for each protocol
const httpSerializer = new HttpCallTemplateSerializer();
const mcpSerializer = new McpCallTemplateSerializer();
const fileSerializer = new FileCallTemplateSerializer();
// Validate and create call templates
const httpTemplate = httpSerializer.validateDict({
name: 'api_manual',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.example.com/data',
headers: {
'Authorization': 'Bearer ${API_KEY}'
}
});
const mcpTemplate = mcpSerializer.validateDict({
name: 'mcp_tools',
call_template_type: 'mcp',
config: {
mcpServers: {
my_mcp_server: {
transport: 'stdio',
command: 'node',
args: ['./mcp-server.js'],
cwd: './servers'
}
}
}
});
const fileTemplate = fileSerializer.validateDict({
name: 'local_tools',
call_template_type: 'file',
file_path: './config/tools.json'
});
const client = await UtcpClient.create(process.cwd(), {
variables: {
// Namespaced variables for security
api__manual_API_KEY: process.env.API_KEY || 'default-key',
},
load_variables_from: [
{
variable_loader_type: 'dotenv',
env_file_path: './.env'
}
],
manual_call_templates: [
httpTemplate, // HTTP API
mcpTemplate, // MCP Server
fileTemplate // Local file-based tools
]
});
// Tools are namespaced: manual_name.tool_name
// For MCP: manual_name.server_name.tool_name
const allTools = await client.getTools();
console.log('Registered tools:', allTools.map(t => t.name));
// Examples:
// - 'api_manual.get_data'
// - 'mcp_tools.my_mcp_server.echo'
// - 'local_tools.my_function'
await client.close();
}
API Reference
UtcpClient.create()
static async create(
root_dir: string,
config: Partial
): Promise
Parameters:
root_dir: Base directory for resolving relative paths (usuallyprocess.cwd())config: Client configuration object
Configuration Options:
interface UtcpClientConfig {
// Direct variable definitions (highest priority)
variables?: Record;
// External variable loaders (e.g., .env files)
load_variables_from?: Array;
// Manual call templates to register at startup
manual_call_templates?: CallTemplate[];
// Tool repository configuration (defaults to in-memory)
tool_repository?: ConcurrentToolRepository;
// Search strategy configuration (defaults to tag_and_description_word_match)
tool_search_strategy?: ToolSearchStrategy;
// Post-processing configurations
post_processing?: ToolPostProcessor[];
}
Core Methods
Search Tools
async searchTools(
query: string,
limit?: number,
anyOfTagsRequired?: string[]
): Promise
Searches for tools matching the query. The search considers:
- Tool names (highest priority)
- Tool tags
- Tool descriptions
Call Tool
async callTool(
toolName: string,
args: Record
): Promise
Executes a tool with the given arguments. Tool names follow these formats:
- HTTP/Text/CLI:
manual_name.tool_name - MCP:
manual_name.server_name.tool_name
Get Tools
async getTools(): Promise
async getTool(toolName: string): Promise
Retrieve all registered tools or get a specific tool by name.
Register/Deregister Manuals
async registerManual(callTemplate: CallTemplate): Promise
async deregisterManual(manualName: string): Promise
Dynamically add or remove tool manuals at runtime.
Variable Management
Variable Namespacing (Security Feature)
Variables are namespace-isolated by manual name to prevent variable leakage between manuals:
// For a manual named "github_api", variables are accessed as:
// ${VARIABLE} -> resolved from "github__api_VARIABLE"
import { HttpCallTemplateSerializer } from '@utcp/http';
const serializer = new HttpCallTemplateSerializer();
const githubTemplate = serializer.validateDict({
name: 'github_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.github.com/users',
headers: {
// Resolves to 'github__api_TOKEN' only
'Authorization': 'Bearer ${TOKEN}'
}
});
const client = await UtcpClient.create(process.cwd(), {
variables: {
'github__api_TOKEN': 'github-token-123',
'slack__api_TOKEN': 'slack-token-456',
},
manual_call_templates: [githubTemplate]
});
Namespace transformation: Manual name underscores become double underscores:
github_api→github__api_my-service→my_service_(hyphens to underscores)
Variable Resolution Order
- Client config variables (highest priority)
- Variable loaders (e.g., .env files, in order)
- Environment variables (lowest priority)
All lookups use the namespaced key: {namespace}_VARIABLE_NAME.
Loading from .env Files
const client = await UtcpClient.create(process.cwd(), {
load_variables_from: [
{
variable_loader_type: 'dotenv',
env_file_path: './.env'
}
]
});
Communication Protocols
HTTP Protocol
Supports RESTful APIs with automatic OpenAPI specification conversion:
import { HttpCallTemplateSerializer } from '@utcp/http';
const serializer = new HttpCallTemplateSerializer();
const weatherTemplate = serializer.validateDict({
name: 'weather_api',
call_template_type: 'http',
http_method: 'GET',
url: 'https://api.weather.com/v1/forecast',
headers: {
'X-API-Key': '${API_KEY}'
},
// Optional: Basic, API Key, or OAuth2 authentication
auth: {
auth_type: 'api_key',
var_name: 'X-API-Key',
api_key_value: '${API_KEY}',
in: 'header'
}
});
Features:
- Path parameter substitution
- Header and body templates
- Multiple authentication methods
- Automatic OpenAPI to UTCP conversion
MCP Protocol
Connect to Model Context Protocol servers:
import { McpCallTemplateSerializer } from '@utcp/mcp';
const serializer = new McpCallTemplateSerializer();
const mcpTemplate = serializer.validateDict({
name: 'mcp_manual',
call_template_type: 'mcp',
config: {
mcpServers: {
server_name: {
transport: 'stdio', // or 'http'
command: 'bun',
args: ['run', './mcp-server.ts'],
cwd: './servers',
env: { DEBUG: 'true' }
}
}
}
});
Tool Naming: manual_name.server_name.tool_name
Features:
- Stdio and HTTP transports
- Persistent session management
- Automatic retry on connection errors
- Multiple servers per manual
Text Protocol
Handle direct text/string content (browser-compatible):
import { TextCallTemplateSerializer } from '@utcp/text';
const serializer = new TextCallTemplateSerializer();
const textTemplate = serializer.validateDict({
name: 'inline_tools',
call_template_type: 'text',
content: JSON.stringify({
tools: [
// UTCP manual or OpenAPI spec as string
]
})
});
File Protocol
Load tools from local JSON/YAML files or OpenAPI specs (Node.js only):
import { FileCallTemplateSerializer } from '@utcp/file';
const serializer = new FileCallTemplateSerializer();
const fileTemplate = serializer.validateDict({
name: 'local_tools',
call_template_type: 'file',
file_path: './config/tools.json'
// Supports: .json, .yaml, .yml, OpenAPI specs
});
CLI Protocol
Execute command-line tools:
import { CliCallTemplateSerializer } from '@utcp/cli';
const serializer = new CliCallTemplateSerializer();
const cliTemplate = serializer.validateDict({
name: 'system_commands',
call_template_type: 'cli',
commands: [
{
command: 'git status'
}
],
working_dir: './my-repo'
});
Code Execution Mode
Implementation moved to https://github.com/universal-tool-calling-protocol/code-mode/tree/main/typescript-library
The @utcp/code-mode package provides a powerful extension that allows executing TypeScript code with direct access to registered tools, perfect for AI agents and complex workflows:
import { CodeModeUtcpClient } from '@utcp/code-mode';
async function main() {
const client = await CodeModeUtcpClient.create();
// Register your tools (same as regular UTCP)
await client.registerManual({
name: 'math_tools',
call_template_type: 'text',
content: '...' // Your tool definitions
});
// Execute TypeScript code with hierarchical tool access
const { result, logs } = await client.callToolChain(`
console.log('Starting calculation...');
// Tools are organized by namespace: manual.tool
const sum = await math_tools.add({ a: 10, b: 20 });
console.log('Sum result:', sum.result);
// Access TypeScript interfaces at runtime for introspection
const addInterface = __getToolInterface('math_tools.add');
console.log('Tool interface:', addInterface);
// Chain multiple tool calls
const result = await math_tools.multiply({
a: sum.result,
b: 2
});
return result;
`);
console.log('Execution result:', result);
console.log('Console output:', logs);
// logs: ['Starting calculation...', 'Sum result: 30', 'Tool interface: ...']
await client.close();
}
Code Mode Features
- Hierarchical Tool Access: Tools organized by manual namespace (
manual.tool()) preventing naming conflicts - Console Output Capture: All console output automatically captured and returned
- Runtime Interface Introspection: Access TypeScript interface definitions during execution
- Type Safety: Generated TypeScript interfaces for all tools with hierarchical namespaces
- Secure Execution: VM-based sandboxed execution with timeout protection
- AI Agent Ready: Built-in prompt template to guide AI agents on proper usage
Perfect for AI Agents
The CodeModeUtcpClient.AGENT_PROMPT_TEMPLATE provides comprehensive guidance for AI agents:
// Add to your AI system prompt
const systemPrompt = `
${CodeModeUtcpClient.AGENT_PROMPT_TEMPLATE}
Your additional instructions...
`;
The template includes:
- Tool discovery workflow
- Interface introspection patterns
- Best practices for hierarchical tool access
- Error handling guidelines
- Runtime context documentation
Monorepo Structure
typescript-utcp/
├── packages/
│ ├── core/ # Core SDK with UtcpClient and interfaces
│ ├── http/ # HTTP protocol plugin
│ ├── mcp/ # MCP protocol plugin
│ ├── text/ # Text/string content protocol plugin (browser-compatible)
│ ├── file/ # File system protocol plugin (Node.js only)
│ ├── dotenv-loader/ # DotEnv variable loader plugin (Node.js only)
│ ├── direct-call/ # Direct call protocol plugin
│ └── cli/ # CLI protocol plugin
├── tests/ # End-to-end integration tests
└── README.md
Each package is independently published to npm:
@utcp/sdk- Core SDK library (required)@utcp/http- HTTP protocol support@utcp/mcp- MCP protocol support@utcp/text- Direct text/string content (browser-compatible)@utcp/file- File system operations (Node.js only)@utcp/dotenv-loader- DotEnv variable loader (Node.js only)@utcp/direct-call- Direct function call protocol@utcp/cli- Command-line tools
Development & Testing
Build
# Build all packages
bun run build
# Clean and rebuild
bun run rebuild
Testing
# Run all tests
bun test
# Run specific test file
bun test tests/utcp_client.test.ts
Publishing
# Publish all packages
bun run publish:all
# Or publish individually
bun run publish:core
bun run publish:http
bun run publish:mcp
Advanced Features
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: universal-tool-calling-protocol
- Source: universal-tool-calling-protocol/typescript-utcp
- License: MPL-2.0
- Homepage: https://www.utcp.io
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.