Skip to content
Closed
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
28 changes: 3 additions & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@azure/functions",
"version": "4.7.2",
"version": "4.8.0",
"description": "Microsoft Azure Functions NodeJS Framework",
"keywords": [
"azure",
Expand Down Expand Up @@ -42,8 +42,7 @@
},
"dependencies": {
"cookie": "^0.7.0",
"long": "^4.0.0",
"undici": "^5.29.0"
"long": "^4.0.0"
},
"devDependencies": {
"@types/chai": "^4.2.22",
Expand Down
12 changes: 12 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
HttpHandler,
HttpMethod,
HttpMethodFunctionOptions,
McpToolFunctionOptions,
MySqlFunctionOptions,
ServiceBusQueueFunctionOptions,
ServiceBusTopicFunctionOptions,
Expand Down Expand Up @@ -145,6 +146,17 @@ export function webPubSub(name: string, options: WebPubSubFunctionOptions): void
generic(name, convertToGenericOptions(options, trigger.webPubSub));
}

/**
* Registers an MCP Tool function in your app.
* This function is triggered by MCP Tool events and allows you to define the behavior of the function.
*
* @param name - The name of the function. This must be unique within your app and is primarily used for tracking purposes.
* @param options - Configuration options for the MCP Tool function, including the handler and trigger-specific settings.
*/
export function mcpTool(name: string, options: McpToolFunctionOptions): void {
generic(name, convertToGenericOptions(options, trigger.mcpTool));
}

export function generic(name: string, options: GenericFunctionOptions): void {
if (!hasSetModel) {
setProgrammingModel();
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.

export const version = '4.7.2';
export const version = '4.8.0';

export const returnBindingKey = '$return';
146 changes: 146 additions & 0 deletions src/converters/toMcpToolTriggerOptionsToRpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.

import { McpToolProperty, McpToolTriggerOptions, McpToolTriggerOptionsToRpc } from '../../types';

/**
* Converts an McpToolTriggerOptions object to an McpToolTriggerOptionsToRpc object.
*
* @param mcpToolTriggerOptions - The input options to be converted.
* @returns The converted McpToolTriggerOptionsToRpc object.
*/
export function converToMcpToolTriggerOptionsToRpc(
mcpToolTriggerOptions: McpToolTriggerOptions
): McpToolTriggerOptionsToRpc {
// Base object for the return value
const baseResult = {
toolName: mcpToolTriggerOptions.toolName,
description: mcpToolTriggerOptions.description,
};

// Check for null or undefined toolProperties
if (!mcpToolTriggerOptions?.toolProperties) {
return {
...baseResult,
toolProperties: JSON.stringify([]), // Default to an empty array
};
}

// Check if toolProperties is an array of McpToolProperty objects
if (Array.isArray(mcpToolTriggerOptions.toolProperties)) {
const isValid = mcpToolTriggerOptions.toolProperties.every(isMcpToolProperty);
if (isValid) {
return {
...baseResult,
toolProperties: JSON.stringify(mcpToolTriggerOptions.toolProperties),
};
} else {
throw new Error(
'Invalid toolProperties: Array contains invalid McpToolProperty, please validate the parameters.'
);
}
}

// Handle cases where toolProperties is an object (e.g., Zod schema)
if (typeof mcpToolTriggerOptions.toolProperties === 'object') {
// Define the type of the ZodObject shape and ZodPropertyDef
type ZodPropertyDef = {
description?: string;
typeName: string;
};
type ZodObjectShape = Record<string, { _def: ZodPropertyDef }>;

// Define the type of the toolProperties object
type ToolProperties =
| {
_def?: {
typeName?: string;
};
shape?: ZodObjectShape;
}
| Record<string, unknown>;

let isZodObject = false;

const toolProperties = mcpToolTriggerOptions.toolProperties as ToolProperties;

// Check if the object is a ZodObject
if ((toolProperties?._def as { typeName?: string })?.typeName === 'ZodObject') {
isZodObject = true;
}

// Check if shape is a valid ZodObject shape
const shape: ZodObjectShape | Record<string, unknown> = isZodObject
? (toolProperties as { shape: ZodObjectShape }).shape
: toolProperties;

// Extract properties from the ZodObject shape
const result = Object.keys(shape).map((propertyName) => {
const property = shape[propertyName] as { _def: ZodPropertyDef };
const description = property?._def?.description || '';
const propertyType = getPropertyType(property?._def?.typeName?.toLowerCase() || 'unknown'); // Extract type name or default to "unknown"

return {
propertyName,
propertyType,
description,
};
});

return {
...baseResult,
toolProperties: JSON.stringify(result),
};
}
// Handle cases where toolProperties is not an array
throw new Error('Invalid toolProperties: Expected an array of McpToolProperty objects or zod objects.');
}

// Helper function to infer property type from zod schema
function getPropertyType(zodType: string): string {
switch (zodType) {
case 'zodnumber':
return 'number';
case 'zodstring':
return 'string';
case 'zodboolean':
return 'boolean';
case 'zodarray':
return 'array';
case 'zodobject':
return 'object';
case 'zodbigint':
return 'long';
case 'zoddate':
return 'DateTime';
case 'zodtuple':
return 'Tuple';
default:
console.warn(`Unknown zod type: ${zodType}`);
return 'unknown';
}
}

/**
* Type guard to check if a given object is of type McpToolProperty.
*
* @param property - The object to check.
* @returns True if the object is of type McpToolProperty, otherwise false.
*
* This function ensures that the object:
* - Is not null and is of type 'object'.
* - Contains the required properties: 'propertyName', 'propertyValue', and 'description'.
* - Each of these properties is of the correct type (string).
*/
function isMcpToolProperty(property: unknown): property is McpToolProperty {
return (
typeof property === 'object' &&
property !== null &&
'propertyName' in property &&
'propertyType' in property &&
'description' in property &&
typeof (property as McpToolProperty).propertyName === 'string' &&
typeof (property as McpToolProperty).propertyType === 'string' &&
typeof (property as McpToolProperty).description === 'string'
);
}
Loading
Loading