Skip to content
Merged

v1.1 #14

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/cli",
"version": "1.0.12",
"version": "1.1.0",
"description": "CLI utilities for UTCP",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down Expand Up @@ -43,7 +43,7 @@
}
},
"dependencies": {
"@utcp/sdk": "^1.0.15"
"@utcp/sdk": "^1.1.0"
},
"devDependencies": {
"bun-types": "latest",
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/cli_call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export interface CliCallTemplate extends CallTemplate {
env_vars?: Record<string, string> | null;
working_dir?: string | null;
auth?: undefined;
allowed_communication_protocols?: string[];
}

/**
Expand All @@ -174,6 +175,7 @@ export const CliCallTemplateSchema: z.ZodType<CliCallTemplate> = z.object({
env_vars: z.record(z.string(), z.string()).nullable().optional().describe('Environment variables to set when executing the commands'),
working_dir: z.string().nullable().optional().describe('Working directory for command execution'),
auth: z.undefined().optional(),
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
}).strict() as z.ZodType<CliCallTemplate>;

/**
Expand All @@ -200,6 +202,7 @@ export class CliCallTemplateSerializer extends Serializer<CliCallTemplate> {
env_vars: obj.env_vars,
working_dir: obj.working_dir,
auth: obj.auth,
allowed_communication_protocols: obj.allowed_communication_protocols,
};
}

Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ export function register(override: boolean = false): void {
CommunicationProtocol.communicationProtocols['cli'] = new CliCommunicationProtocol();
}

// Automatically register CLI plugins on import
register();

export * from './cli_call_template';
export * from './cli_communication_protocol';
4 changes: 2 additions & 2 deletions packages/code-mode/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/code-mode",
"version": "1.0.5",
"version": "1.1.0",
"description": "Code execution mode for UTCP - enables executing TypeScript code chains with tool access",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down Expand Up @@ -40,7 +40,7 @@
}
},
"dependencies": {
"@utcp/sdk": "^1.0.17"
"@utcp/sdk": "^1.1.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/sdk",
"version": "1.0.17",
"version": "1.1.0",
"description": "Universal Tool Calling Protocol SDK",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down
35 changes: 35 additions & 0 deletions packages/core/src/client/utcp_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,26 @@ export class UtcpClient implements IUtcpClient {
const result = await protocol.registerManual(this, processedCallTemplate);

if (result.success) {
// Determine allowed protocols: use explicit list if provided, otherwise default to manual's own protocol
const allowedProtocols = (processedCallTemplate.allowed_communication_protocols?.length)
? processedCallTemplate.allowed_communication_protocols
: [processedCallTemplate.call_template_type];

// Filter tools based on allowed protocols and prefix names
const filteredTools = [];
for (const tool of result.manual.tools) {
const toolProtocol = tool.tool_call_template.call_template_type;
if (!allowedProtocols.includes(toolProtocol)) {
console.warn(`Tool '${tool.name}' uses communication protocol '${toolProtocol}' which is not in allowed protocols [${allowedProtocols.map(p => `'${p}'`).join(', ')}] for manual '${manualCallTemplate.name}'. Tool will not be registered.`);
continue;
}
if (!tool.name.startsWith(`${processedCallTemplate.name}.`)) {
tool.name = `${processedCallTemplate.name}.${tool.name}`;
}
filteredTools.push(tool);
}
result.manual.tools = filteredTools;

await this.config.tool_repository.saveManual(processedCallTemplate, result.manual);
console.log(`Successfully registered manual '${manualCallTemplate.name}' with ${result.manual.tools.length} tools.`);
} else {
Expand Down Expand Up @@ -224,6 +239,16 @@ export class UtcpClient implements IUtcpClient {
throw new Error(`Could not find manual call template for manual '${manualName}'.`);
}

// Validate protocol is allowed
const toolProtocol = tool.tool_call_template.call_template_type;
const allowedProtocols = (manualCallTemplate.allowed_communication_protocols?.length)
? manualCallTemplate.allowed_communication_protocols
: [manualCallTemplate.call_template_type];

if (!allowedProtocols.includes(toolProtocol)) {
throw new Error(`Tool '${toolName}' uses communication protocol '${toolProtocol}' which is not allowed by manual '${manualName}'. Allowed protocols: [${allowedProtocols.map(p => `'${p}'`).join(', ')}]`);
}

const processedToolCallTemplate = await this.substituteCallTemplateVariables(tool.tool_call_template, manualName);

const protocol = this._registeredCommProtocols.get(processedToolCallTemplate.call_template_type);
Expand Down Expand Up @@ -263,6 +288,16 @@ export class UtcpClient implements IUtcpClient {
throw new Error(`Could not find manual call template for manual '${manualName}'.`);
}

// Validate protocol is allowed
const toolProtocol = tool.tool_call_template.call_template_type;
const allowedProtocols = (manualCallTemplate.allowed_communication_protocols?.length)
? manualCallTemplate.allowed_communication_protocols
: [manualCallTemplate.call_template_type];

if (!allowedProtocols.includes(toolProtocol)) {
throw new Error(`Tool '${toolName}' uses communication protocol '${toolProtocol}' which is not allowed by manual '${manualName}'. Allowed protocols: [${allowedProtocols.map(p => `'${p}'`).join(', ')}]`);
}

const processedToolCallTemplate = await this.substituteCallTemplateVariables(tool.tool_call_template, manualName);

const protocol = this._registeredCommProtocols.get(processedToolCallTemplate.call_template_type);
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/data/call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ export interface CallTemplate {
*/
auth?: Auth;

/**
* Optional list of allowed communication protocol types for tools within this manual.
*
* Behavior:
* - If undefined, null, or empty array → defaults to only allowing the manual's own call_template_type
* - If set to a non-empty array → only those protocol types are allowed
*
* This provides secure-by-default behavior where a manual can only register/call tools
* that use its own protocol unless explicitly configured otherwise.
*/
allowed_communication_protocols?: string[];

[key: string]: any;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/direct-call/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/direct-call",
"version": "1.0.12",
"version": "1.1.0",
"description": "Direct callable functions plugin for UTCP",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down Expand Up @@ -44,7 +44,7 @@
}
},
"dependencies": {
"@utcp/sdk": "^1.0.15"
"@utcp/sdk": "^1.1.0"
},
"devDependencies": {
"bun-types": "latest",
Expand Down
3 changes: 3 additions & 0 deletions packages/direct-call/src/direct_call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface DirectCallTemplate extends CallTemplate {
call_template_type: 'direct-call';
callable_name: string;
auth?: undefined;
allowed_communication_protocols?: string[];
}

/**
Expand All @@ -27,6 +28,7 @@ export const DirectCallTemplateSchema: z.ZodType<DirectCallTemplate> = z.object(
call_template_type: z.literal('direct-call'),
callable_name: z.string().describe('The name of the callable function to invoke.'),
auth: z.undefined().optional(),
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
}).strict() as z.ZodType<DirectCallTemplate>;

/**
Expand All @@ -42,6 +44,7 @@ export class DirectCallTemplateSerializer extends Serializer<DirectCallTemplate>
call_template_type: obj.call_template_type,
callable_name: obj.callable_name,
auth: obj.auth,
allowed_communication_protocols: obj.allowed_communication_protocols,
};
}

Expand Down
4 changes: 2 additions & 2 deletions packages/dotenv-loader/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/dotenv-loader",
"version": "1.0.1",
"version": "1.1.0",
"description": "DotEnv Variable Loader plugin for UTCP",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down Expand Up @@ -44,7 +44,7 @@
"zod": "^3.23.8"
},
"peerDependencies": {
"@utcp/sdk": "^1.0.15"
"@utcp/sdk": "^1.1.0"
},
"devDependencies": {
"bun-types": "latest",
Expand Down
6 changes: 3 additions & 3 deletions packages/file/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/file",
"version": "1.0.1",
"version": "1.1.0",
"description": "File system protocol for UTCP - reads UTCP manuals from local files (Node.js only)",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down Expand Up @@ -43,8 +43,8 @@
}
},
"dependencies": {
"@utcp/sdk": "^1.0.15",
"@utcp/http": "^1.0.13",
"@utcp/sdk": "^1.1.0",
"@utcp/http": "^1.1.0",
"js-yaml": "^4.1.0"
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions packages/file/src/file_call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface FileCallTemplate extends CallTemplate {
file_path: string;
auth?: undefined;
auth_tools?: Auth | null;
allowed_communication_protocols?: string[];
}

/**
Expand All @@ -40,6 +41,7 @@ export const FileCallTemplateSchema: z.ZodType<FileCallTemplate> = z.object({
}
return val as Auth;
}).describe('Authentication to apply to generated tools from OpenAPI specs.'),
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
}).strict() as z.ZodType<FileCallTemplate>;

/**
Expand All @@ -58,6 +60,7 @@ export class FileCallTemplateSerializer extends Serializer<FileCallTemplate> {
file_path: obj.file_path,
auth: obj.auth,
auth_tools: obj.auth_tools ? new AuthSerializer().toDict(obj.auth_tools) : null,
allowed_communication_protocols: obj.allowed_communication_protocols,
};
}

Expand Down
4 changes: 2 additions & 2 deletions packages/http/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/http",
"version": "1.0.13",
"version": "1.1.0",
"description": "HTTP utilities for UTCP",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down Expand Up @@ -43,7 +43,7 @@
}
},
"dependencies": {
"@utcp/sdk": "^1.0.15",
"@utcp/sdk": "^1.1.0",
"axios": "^1.11.0",
"js-yaml": "^4.1.0"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/http/src/http_call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface HttpCallTemplate extends CallTemplate {
body_field?: string;
header_fields?: string[];
auth_tools?: Auth | null;
allowed_communication_protocols?: string[];
}

/**
Expand All @@ -45,6 +46,7 @@ export const HttpCallTemplateSchema: z.ZodType<HttpCallTemplate> = z.object({
}
return val as Auth;
}).describe('Authentication configuration for generated tools'),
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
}) as z.ZodType<HttpCallTemplate>;

/**
Expand All @@ -64,6 +66,7 @@ export class HttpCallTemplateSerializer extends Serializer<HttpCallTemplate> {
headers: obj.headers,
body_field: obj.body_field,
header_fields: obj.header_fields,
allowed_communication_protocols: obj.allowed_communication_protocols,
};
}

Expand Down
3 changes: 3 additions & 0 deletions packages/http/src/sse_call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface SseCallTemplate extends CallTemplate {
headers?: Record<string, string>;
body_field?: string | null;
header_fields?: string[] | null;
allowed_communication_protocols?: string[];
}

/**
Expand All @@ -49,6 +50,7 @@ export const SseCallTemplateSchema: z.ZodType<SseCallTemplate> = z.object({
headers: z.record(z.string(), z.string()).optional().describe('Optional static headers for the initial connection.'),
body_field: z.string().nullable().optional().describe('The name of the single input field to be sent as the request body.'),
header_fields: z.array(z.string()).nullable().optional().describe('List of input fields to be sent as request headers for the initial connection.'),
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
}) as z.ZodType<SseCallTemplate>;

/**
Expand All @@ -72,6 +74,7 @@ export class SseCallTemplateSerializer extends Serializer<SseCallTemplate> {
headers: obj.headers,
body_field: obj.body_field,
header_fields: obj.header_fields,
allowed_communication_protocols: obj.allowed_communication_protocols,
};
}

Expand Down
3 changes: 3 additions & 0 deletions packages/http/src/streamable_http_call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface StreamableHttpCallTemplate extends CallTemplate {
headers?: Record<string, string>;
body_field?: string | null;
header_fields?: string[] | null;
allowed_communication_protocols?: string[];
}

/**
Expand All @@ -52,6 +53,7 @@ export const StreamableHttpCallTemplateSchema: z.ZodType<StreamableHttpCallTempl
headers: z.record(z.string(), z.string()).optional().describe('Optional static headers to include in requests.'),
body_field: z.string().nullable().optional().describe('The name of the single input field to be sent as the request body.'),
header_fields: z.array(z.string()).nullable().optional().describe('List of input fields to be sent as request headers.'),
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
}) as z.ZodType<StreamableHttpCallTemplate>;

/**
Expand All @@ -76,6 +78,7 @@ export class StreamableHttpCallTemplateSerializer extends Serializer<StreamableH
headers: obj.headers,
body_field: obj.body_field,
header_fields: obj.header_fields,
allowed_communication_protocols: obj.allowed_communication_protocols,
};
}

Expand Down
4 changes: 2 additions & 2 deletions packages/mcp/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@utcp/mcp",
"version": "1.0.17",
"version": "1.1.0",
"description": "Model Context Protocol integration for UTCP",
"main": "dist/index.cjs",
"module": "dist/index.js",
Expand Down Expand Up @@ -46,7 +46,7 @@
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^15.1.2",
"@modelcontextprotocol/sdk": "^1.17.4",
"@utcp/sdk": "^1.0.15",
"@utcp/sdk": "^1.1.0",
"axios": "^1.11.0"
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions packages/mcp/src/mcp_call_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export interface McpCallTemplate extends CallTemplate {
config: McpConfig;
auth?: OAuth2Auth;
register_resources_as_tools?: boolean;
allowed_communication_protocols?: string[];
}

/**
Expand All @@ -135,6 +136,7 @@ export const McpCallTemplateSchema: z.ZodType<McpCallTemplate> = z.object({
config: McpConfigSchema.describe('Configuration object containing MCP server definitions. Follows the same format as the official MCP server configuration.'),
auth: AuthSchema.nullable().optional().describe('Optional OAuth2 authentication for HTTP-based MCP servers.'),
register_resources_as_tools: z.boolean().default(false).describe('Whether to register MCP resources as callable tools. When True, server resources are exposed as tools that can be called.'),
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
}) as z.ZodType<McpCallTemplate>;

/**
Expand All @@ -153,6 +155,7 @@ export class McpCallTemplateSerializer extends Serializer<McpCallTemplate> {
config: obj.config,
auth: obj.auth,
register_resources_as_tools: obj.register_resources_as_tools,
allowed_communication_protocols: obj.allowed_communication_protocols,
};
}

Expand Down
Loading