Skip to content

Commit 8304ae8

Browse files
committed
Mcp Tool Trigger Support
1 parent 8aa8b08 commit 8304ae8

File tree

10 files changed

+300
-5
lines changed

10 files changed

+300
-5
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@azure/functions",
3-
"version": "4.7.2",
3+
"version": "4.8.0",
44
"description": "Microsoft Azure Functions NodeJS Framework",
55
"keywords": [
66
"azure",

src/app.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
HttpHandler,
1212
HttpMethod,
1313
HttpMethodFunctionOptions,
14+
McpToolFunctionOptions,
1415
MySqlFunctionOptions,
1516
ServiceBusQueueFunctionOptions,
1617
ServiceBusTopicFunctionOptions,
@@ -145,6 +146,17 @@ export function webPubSub(name: string, options: WebPubSubFunctionOptions): void
145146
generic(name, convertToGenericOptions(options, trigger.webPubSub));
146147
}
147148

149+
/**
150+
* Registers an MCP Tool function in your app.
151+
* This function is triggered by MCP Tool events and allows you to define the behavior of the function.
152+
*
153+
* @param name - The name of the function. This must be unique within your app and is primarily used for tracking purposes.
154+
* @param options - Configuration options for the MCP Tool function, including the handler and trigger-specific settings.
155+
*/
156+
export function mcpTool(name: string, options: McpToolFunctionOptions): void {
157+
generic(name, convertToGenericOptions(options, trigger.mcpTool));
158+
}
159+
148160
export function generic(name: string, options: GenericFunctionOptions): void {
149161
if (!hasSetModel) {
150162
setProgrammingModel();

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
export const version = '4.7.2';
4+
export const version = '4.8.0';
55

66
export const returnBindingKey = '$return';
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { McpToolProperty, McpToolTriggerOptions, McpToolTriggerOptionsToRpc } from '../../types';
5+
6+
// Copyright (c) .NET Foundation. All rights reserved.
7+
// Licensed under the MIT License.
8+
9+
/**
10+
* Converts an McpToolTriggerOptions object to an McpToolTriggerOptionsToRpc object.
11+
*
12+
* @param mcpToolTriggerOptions - The input options to be converted.
13+
* @returns The converted McpToolTriggerOptionsToRpc object.
14+
*/
15+
export function converToMcpToolTriggerOptionsToRpc(
16+
mcpToolTriggerOptions: McpToolTriggerOptions
17+
): McpToolTriggerOptionsToRpc {
18+
// Base object for the return value
19+
const baseResult = {
20+
toolName: mcpToolTriggerOptions.toolName,
21+
description: mcpToolTriggerOptions.description,
22+
};
23+
24+
// Check for null or undefined toolProperties
25+
if (!mcpToolTriggerOptions?.toolProperties) {
26+
return {
27+
...baseResult,
28+
toolProperties: JSON.stringify([]), // Default to an empty array
29+
};
30+
}
31+
32+
// Check if toolProperties is an array of McpToolProperty objects
33+
if (Array.isArray(mcpToolTriggerOptions.toolProperties)) {
34+
const isValid = mcpToolTriggerOptions.toolProperties.every(isMcpToolProperty);
35+
if (isValid) {
36+
return {
37+
...baseResult,
38+
toolProperties: JSON.stringify(mcpToolTriggerOptions.toolProperties),
39+
};
40+
} else {
41+
throw new Error(
42+
'Invalid toolProperties: Array contains invalid McpToolProperty, please validate the parameters.'
43+
);
44+
}
45+
}
46+
47+
// Handle cases where toolProperties is an object (e.g., Zod schema)
48+
if (typeof mcpToolTriggerOptions.toolProperties === 'object') {
49+
// Define the type of the ZodObject shape and ZodPropertyDef
50+
type ZodPropertyDef = {
51+
description?: string;
52+
typeName: string;
53+
};
54+
type ZodObjectShape = Record<string, { _def: ZodPropertyDef }>;
55+
56+
// Define the type of the toolProperties object
57+
type ToolProperties =
58+
| {
59+
_def?: {
60+
typeName?: string;
61+
};
62+
shape?: ZodObjectShape;
63+
}
64+
| Record<string, unknown>;
65+
66+
let isZodObject = false;
67+
68+
const toolProperties = mcpToolTriggerOptions.toolProperties as ToolProperties;
69+
70+
// Check if the object is a ZodObject
71+
if ((toolProperties?._def as { typeName?: string })?.typeName === 'ZodObject') {
72+
isZodObject = true;
73+
}
74+
75+
// Check if shape is a valid ZodObject shape
76+
const shape: ZodObjectShape | Record<string, unknown> = isZodObject
77+
? (toolProperties as { shape: ZodObjectShape }).shape
78+
: toolProperties;
79+
80+
// Extract properties from the ZodObject shape
81+
const result = Object.keys(shape).map((propertyName) => {
82+
const property = shape[propertyName] as { _def: ZodPropertyDef };
83+
const description = property?._def?.description || '';
84+
const propertyType = getPropertyType(property?._def?.typeName?.toLowerCase() || 'unknown'); // Extract type name or default to "unknown"
85+
86+
return {
87+
propertyName,
88+
propertyType,
89+
description,
90+
};
91+
});
92+
93+
return {
94+
...baseResult,
95+
toolProperties: JSON.stringify(result),
96+
};
97+
}
98+
// Handle cases where toolProperties is not an array
99+
throw new Error('Invalid toolProperties: Expected an array of McpToolProperty objects or zod objects.');
100+
}
101+
102+
// Helper function to infer property type from zod schema
103+
function getPropertyType(zodType: string): string {
104+
switch (zodType) {
105+
case 'zodnumber':
106+
return 'number';
107+
case 'zodstring':
108+
return 'string';
109+
case 'zodboolean':
110+
return 'boolean';
111+
case 'zodarray':
112+
return 'array';
113+
case 'zodobject':
114+
return 'object';
115+
case 'zodbigint':
116+
return 'long';
117+
case 'zoddate':
118+
return 'DateTime';
119+
case 'zodtuple':
120+
return 'Tuple';
121+
default:
122+
console.warn(`Unknown zod type: ${zodType}`);
123+
return 'unknown';
124+
}
125+
}
126+
127+
/**
128+
* Type guard to check if a given object is of type McpToolProperty.
129+
*
130+
* @param property - The object to check.
131+
* @returns True if the object is of type McpToolProperty, otherwise false.
132+
*
133+
* This function ensures that the object:
134+
* - Is not null and is of type 'object'.
135+
* - Contains the required properties: 'propertyName', 'propertyValue', and 'description'.
136+
* - Each of these properties is of the correct type (string).
137+
*/
138+
function isMcpToolProperty(property: unknown): property is McpToolProperty {
139+
return (
140+
typeof property === 'object' &&
141+
property !== null &&
142+
'propertyName' in property &&
143+
'propertyType' in property &&
144+
'description' in property &&
145+
typeof (property as McpToolProperty).propertyName === 'string' &&
146+
typeof (property as McpToolProperty).propertyType === 'string' &&
147+
typeof (property as McpToolProperty).description === 'string'
148+
);
149+
}

src/trigger.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
GenericTriggerOptions,
1313
HttpTrigger,
1414
HttpTriggerOptions,
15+
McpToolTrigger,
16+
McpToolTriggerOptions,
1517
MySqlTrigger,
16-
MySqlTriggerOptions,
18+
MySqlTriggerOptions,
1719
ServiceBusQueueTrigger,
1820
ServiceBusQueueTriggerOptions,
1921
ServiceBusTopicTrigger,
@@ -32,6 +34,7 @@ import {
3234
WebPubSubTriggerOptions,
3335
} from '@azure/functions';
3436
import { addBindingName } from './addBindingName';
37+
import { converToMcpToolTriggerOptionsToRpc } from './converters/toMcpToolTriggerOptionsToRpc';
3538

3639
export function http(options: HttpTriggerOptions): HttpTrigger {
3740
return addTriggerBindingName({
@@ -126,6 +129,20 @@ export function webPubSub(options: WebPubSubTriggerOptions): WebPubSubTrigger {
126129
});
127130
}
128131

132+
/**
133+
* Creates an MCP Tool trigger configuration.
134+
* This function is used to define an MCP Tool trigger for an Azure Function.
135+
*
136+
* @param options - The configuration options for the MCP Tool trigger, including tool-specific metadata.
137+
* @returns An MCP Tool trigger object with the specified configuration.
138+
*/
139+
export function mcpTool(options: McpToolTriggerOptions): McpToolTrigger {
140+
return addTriggerBindingName({
141+
...converToMcpToolTriggerOptionsToRpc(options),
142+
type: 'mcpToolTrigger',
143+
});
144+
}
145+
129146
export function generic(options: GenericTriggerOptions): FunctionTrigger {
130147
return addTriggerBindingName(options);
131148
}

types/app.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { EventGridFunctionOptions } from './eventGrid';
66
import { EventHubFunctionOptions } from './eventHub';
77
import { GenericFunctionOptions } from './generic';
88
import { HttpFunctionOptions, HttpHandler, HttpMethodFunctionOptions } from './http';
9+
import { McpToolFunctionOptions } from './mcpTool';
910
import { MySqlFunctionOptions } from './mySql';
1011
import { ServiceBusQueueFunctionOptions, ServiceBusTopicFunctionOptions } from './serviceBus';
1112
import { SetupOptions } from './setup';
@@ -196,4 +197,6 @@ export function generic(name: string, options: GenericFunctionOptions): void;
196197
*/
197198
export function webPubSub(name: string, options: WebPubSubFunctionOptions): void;
198199

200+
export function mcpTool(name: string, options: McpToolFunctionOptions): void;
201+
199202
export * as hook from './hooks/registerHook';

types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export * from './hooks/logHooks';
1717
export * from './http';
1818
export * as input from './input';
1919
export * from './InvocationContext';
20+
export * from './mcpTool';
2021
export * from './mySql';
2122
export * as output from './output';
2223
export * from './serviceBus';

types/mcpTool.d.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { FunctionOptions, FunctionResult, FunctionTrigger } from './index';
5+
import { InvocationContext } from './InvocationContext';
6+
7+
/**
8+
* A handler function for MCP Tool triggers.
9+
*
10+
* @param messages - The messages or data received by the trigger.
11+
* @param context - The invocation context for the function.
12+
* @returns A result that can be a promise or a synchronous value.
13+
*/
14+
export type McpToolTriggerHandler = (messages: unknown, context: InvocationContext) => FunctionResult;
15+
16+
/**
17+
* Configuration options for an MCP Tool function.
18+
* This includes trigger-specific options and general function options.
19+
*/
20+
export interface McpToolFunctionOptions extends McpToolTriggerOptions, Partial<FunctionOptions> {
21+
/**
22+
* The handler function to execute when the trigger is invoked.
23+
*/
24+
handler: McpToolTriggerHandler;
25+
26+
/**
27+
* The trigger configuration for the MCP Tool.
28+
*/
29+
trigger?: McpToolTrigger;
30+
}
31+
32+
/**
33+
* Configuration options for an MCP Tool trigger.
34+
* These options define the behavior and metadata for the trigger.
35+
*/
36+
export interface McpToolTriggerOptions {
37+
/**
38+
* The name of the tool associated with the trigger.
39+
* This is typically an app setting or environment variable.
40+
*/
41+
toolName: string;
42+
43+
/**
44+
* A description of the tool or trigger.
45+
* This provides additional context about the trigger's purpose.
46+
*/
47+
description: string;
48+
49+
/**
50+
* Additional properties or metadata for the tool.
51+
* This is a dictionary of key-value pairs that can be used to configure the trigger.
52+
*/
53+
toolProperties?: any | McpToolProperty[];
54+
}
55+
56+
/**
57+
* Configuration options for an MCP Tool trigger.
58+
* These options define the behavior and metadata for the trigger.
59+
*/
60+
export interface McpToolTriggerOptionsToRpc {
61+
/**
62+
* The name of the tool associated with the trigger.
63+
* This is typically an app setting or environment variable.
64+
*/
65+
toolName: string;
66+
67+
/**
68+
* A description of the tool or trigger.
69+
* This provides additional context about the trigger's purpose.
70+
*/
71+
description: string;
72+
73+
/**
74+
* Additional properties or metadata for the tool.
75+
* This is a dictionary of key-value pairs that can be used to configure the trigger.
76+
*/
77+
toolProperties?: string;
78+
}
79+
80+
/**
81+
* Represents an MCP Tool trigger, combining base function trigger options
82+
* with MCP Tool-specific trigger options.
83+
*/
84+
export type McpToolTrigger = FunctionTrigger & McpToolTriggerOptionsToRpc;
85+
86+
export interface McpToolProperty {
87+
/**
88+
* The name of the property.
89+
*/
90+
propertyName: string;
91+
92+
/**
93+
* The type of the property.
94+
*/
95+
propertyType: string;
96+
97+
/**
98+
* A description of the property.
99+
* This provides additional context about the purpose or usage of the property.
100+
*/
101+
description: string;
102+
103+
/**
104+
* Indicates whether the property is required.
105+
*/
106+
required?: boolean;
107+
}

types/trigger.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { EventHubTrigger, EventHubTriggerOptions } from './eventHub';
77
import { GenericTriggerOptions } from './generic';
88
import { HttpTrigger, HttpTriggerOptions } from './http';
99
import { FunctionTrigger } from './index';
10+
import { McpToolFunctionOptions, McpToolTrigger } from './mcpTool';
1011
import { MySqlTrigger, MySqlTriggerOptions } from './mySql';
1112
import {
1213
ServiceBusQueueTrigger,
@@ -90,6 +91,11 @@ export function mySql(options: MySqlTriggerOptions): MySqlTrigger;
9091
*/
9192
export function webPubSub(options: WebPubSubTriggerOptions): WebPubSubTrigger;
9293

94+
/**
95+
* [Link to docs and examples](//TODO Add link to docs and examples)
96+
*/
97+
export function mcpTool(options: McpToolFunctionOptions): McpToolTrigger;
98+
9399
/**
94100
* A generic option that can be used for any trigger type
95101
* Use this method if your desired trigger type does not already have its own method

0 commit comments

Comments
 (0)