Skip to content

Commit 543134e

Browse files
committed
Add 1.1 update
1 parent 539efc4 commit 543134e

File tree

13 files changed

+386
-3
lines changed

13 files changed

+386
-3
lines changed

packages/cli/src/cli_call_template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export interface CliCallTemplate extends CallTemplate {
162162
env_vars?: Record<string, string> | null;
163163
working_dir?: string | null;
164164
auth?: undefined;
165+
allowed_communication_protocols?: string[];
165166
}
166167

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

179181
/**
@@ -200,6 +202,7 @@ export class CliCallTemplateSerializer extends Serializer<CliCallTemplate> {
200202
env_vars: obj.env_vars,
201203
working_dir: obj.working_dir,
202204
auth: obj.auth,
205+
allowed_communication_protocols: obj.allowed_communication_protocols,
203206
};
204207
}
205208

packages/cli/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,8 @@ export function register(override: boolean = false): void {
1313
CommunicationProtocol.communicationProtocols['cli'] = new CliCommunicationProtocol();
1414
}
1515

16+
// Automatically register CLI plugins on import
17+
register();
18+
1619
export * from './cli_call_template';
1720
export * from './cli_communication_protocol';

packages/core/src/client/utcp_client.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,26 @@ export class UtcpClient implements IUtcpClient {
138138
const result = await protocol.registerManual(this, processedCallTemplate);
139139

140140
if (result.success) {
141+
// Determine allowed protocols: use explicit list if provided, otherwise default to manual's own protocol
142+
const allowedProtocols = (processedCallTemplate.allowed_communication_protocols?.length)
143+
? processedCallTemplate.allowed_communication_protocols
144+
: [processedCallTemplate.call_template_type];
145+
146+
// Filter tools based on allowed protocols and prefix names
147+
const filteredTools = [];
141148
for (const tool of result.manual.tools) {
149+
const toolProtocol = tool.tool_call_template.call_template_type;
150+
if (!allowedProtocols.includes(toolProtocol)) {
151+
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.`);
152+
continue;
153+
}
142154
if (!tool.name.startsWith(`${processedCallTemplate.name}.`)) {
143155
tool.name = `${processedCallTemplate.name}.${tool.name}`;
144156
}
157+
filteredTools.push(tool);
145158
}
159+
result.manual.tools = filteredTools;
160+
146161
await this.config.tool_repository.saveManual(processedCallTemplate, result.manual);
147162
console.log(`Successfully registered manual '${manualCallTemplate.name}' with ${result.manual.tools.length} tools.`);
148163
} else {
@@ -224,6 +239,16 @@ export class UtcpClient implements IUtcpClient {
224239
throw new Error(`Could not find manual call template for manual '${manualName}'.`);
225240
}
226241

242+
// Validate protocol is allowed
243+
const toolProtocol = tool.tool_call_template.call_template_type;
244+
const allowedProtocols = (manualCallTemplate.allowed_communication_protocols?.length)
245+
? manualCallTemplate.allowed_communication_protocols
246+
: [manualCallTemplate.call_template_type];
247+
248+
if (!allowedProtocols.includes(toolProtocol)) {
249+
throw new Error(`Tool '${toolName}' uses communication protocol '${toolProtocol}' which is not allowed by manual '${manualName}'. Allowed protocols: [${allowedProtocols.map(p => `'${p}'`).join(', ')}]`);
250+
}
251+
227252
const processedToolCallTemplate = await this.substituteCallTemplateVariables(tool.tool_call_template, manualName);
228253

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

291+
// Validate protocol is allowed
292+
const toolProtocol = tool.tool_call_template.call_template_type;
293+
const allowedProtocols = (manualCallTemplate.allowed_communication_protocols?.length)
294+
? manualCallTemplate.allowed_communication_protocols
295+
: [manualCallTemplate.call_template_type];
296+
297+
if (!allowedProtocols.includes(toolProtocol)) {
298+
throw new Error(`Tool '${toolName}' uses communication protocol '${toolProtocol}' which is not allowed by manual '${manualName}'. Allowed protocols: [${allowedProtocols.map(p => `'${p}'`).join(', ')}]`);
299+
}
300+
266301
const processedToolCallTemplate = await this.substituteCallTemplateVariables(tool.tool_call_template, manualName);
267302

268303
const protocol = this._registeredCommProtocols.get(processedToolCallTemplate.call_template_type);

packages/core/src/data/call_template.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ export interface CallTemplate {
2323
*/
2424
auth?: Auth;
2525

26+
/**
27+
* Optional list of allowed communication protocol types for tools within this manual.
28+
*
29+
* Behavior:
30+
* - If undefined, null, or empty array → defaults to only allowing the manual's own call_template_type
31+
* - If set to a non-empty array → only those protocol types are allowed
32+
*
33+
* This provides secure-by-default behavior where a manual can only register/call tools
34+
* that use its own protocol unless explicitly configured otherwise.
35+
*/
36+
allowed_communication_protocols?: string[];
37+
2638
[key: string]: any;
2739
}
2840

packages/direct-call/src/direct_call_template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface DirectCallTemplate extends CallTemplate {
1717
call_template_type: 'direct-call';
1818
callable_name: string;
1919
auth?: undefined;
20+
allowed_communication_protocols?: string[];
2021
}
2122

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

3234
/**
@@ -42,6 +44,7 @@ export class DirectCallTemplateSerializer extends Serializer<DirectCallTemplate>
4244
call_template_type: obj.call_template_type,
4345
callable_name: obj.callable_name,
4446
auth: obj.auth,
47+
allowed_communication_protocols: obj.allowed_communication_protocols,
4548
};
4649
}
4750

packages/file/src/file_call_template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export interface FileCallTemplate extends CallTemplate {
2323
file_path: string;
2424
auth?: undefined;
2525
auth_tools?: Auth | null;
26+
allowed_communication_protocols?: string[];
2627
}
2728

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

4547
/**
@@ -58,6 +60,7 @@ export class FileCallTemplateSerializer extends Serializer<FileCallTemplate> {
5860
file_path: obj.file_path,
5961
auth: obj.auth,
6062
auth_tools: obj.auth_tools ? new AuthSerializer().toDict(obj.auth_tools) : null,
63+
allowed_communication_protocols: obj.allowed_communication_protocols,
6164
};
6265
}
6366

packages/http/src/http_call_template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface HttpCallTemplate extends CallTemplate {
2222
body_field?: string;
2323
header_fields?: string[];
2424
auth_tools?: Auth | null;
25+
allowed_communication_protocols?: string[];
2526
}
2627

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

5052
/**
@@ -64,6 +66,7 @@ export class HttpCallTemplateSerializer extends Serializer<HttpCallTemplate> {
6466
headers: obj.headers,
6567
body_field: obj.body_field,
6668
header_fields: obj.header_fields,
69+
allowed_communication_protocols: obj.allowed_communication_protocols,
6770
};
6871
}
6972

packages/http/src/sse_call_template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface SseCallTemplate extends CallTemplate {
3333
headers?: Record<string, string>;
3434
body_field?: string | null;
3535
header_fields?: string[] | null;
36+
allowed_communication_protocols?: string[];
3637
}
3738

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

5456
/**
@@ -72,6 +74,7 @@ export class SseCallTemplateSerializer extends Serializer<SseCallTemplate> {
7274
headers: obj.headers,
7375
body_field: obj.body_field,
7476
header_fields: obj.header_fields,
77+
allowed_communication_protocols: obj.allowed_communication_protocols,
7578
};
7679
}
7780

packages/http/src/streamable_http_call_template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export interface StreamableHttpCallTemplate extends CallTemplate {
3535
headers?: Record<string, string>;
3636
body_field?: string | null;
3737
header_fields?: string[] | null;
38+
allowed_communication_protocols?: string[];
3839
}
3940

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

5759
/**
@@ -76,6 +78,7 @@ export class StreamableHttpCallTemplateSerializer extends Serializer<StreamableH
7678
headers: obj.headers,
7779
body_field: obj.body_field,
7880
header_fields: obj.header_fields,
81+
allowed_communication_protocols: obj.allowed_communication_protocols,
7982
};
8083
}
8184

packages/mcp/src/mcp_call_template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export interface McpCallTemplate extends CallTemplate {
123123
config: McpConfig;
124124
auth?: OAuth2Auth;
125125
register_resources_as_tools?: boolean;
126+
allowed_communication_protocols?: string[];
126127
}
127128

128129
/**
@@ -135,6 +136,7 @@ export const McpCallTemplateSchema: z.ZodType<McpCallTemplate> = z.object({
135136
config: McpConfigSchema.describe('Configuration object containing MCP server definitions. Follows the same format as the official MCP server configuration.'),
136137
auth: AuthSchema.nullable().optional().describe('Optional OAuth2 authentication for HTTP-based MCP servers.'),
137138
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.'),
139+
allowed_communication_protocols: z.array(z.string()).optional().describe('Optional list of allowed communication protocol types for tools within this manual.'),
138140
}) as z.ZodType<McpCallTemplate>;
139141

140142
/**
@@ -153,6 +155,7 @@ export class McpCallTemplateSerializer extends Serializer<McpCallTemplate> {
153155
config: obj.config,
154156
auth: obj.auth,
155157
register_resources_as_tools: obj.register_resources_as_tools,
158+
allowed_communication_protocols: obj.allowed_communication_protocols,
156159
};
157160
}
158161

0 commit comments

Comments
 (0)