Skip to content

Swapnil/mcp server trigger #339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 17 commits into
base: v4.x
Choose a base branch
from
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@azure/functions",
"version": "4.7.0",
"version": "4.8.0-experimental.0",
"description": "Microsoft Azure Functions NodeJS Framework",
"keywords": [
"azure",
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
152 changes: 152 additions & 0 deletions src/converters/toMcpToolTriggerOptionsToRpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.

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

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.

/**
* 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 objects.');
}
}

// 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,
};
});

console.log('result', {
...baseResult,
toolProperties: JSON.stringify(result),
});

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 &&
'propertyValue' in property &&
'description' in property &&
typeof (property as McpToolProperty).propertyName === 'string' &&
typeof (property as McpToolProperty).propertyValue === 'string' &&
typeof (property as McpToolProperty).description === 'string'
);
}
19 changes: 18 additions & 1 deletion src/trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import {
GenericTriggerOptions,
HttpTrigger,
HttpTriggerOptions,
McpToolTrigger,
McpToolTriggerOptions,
MySqlTrigger,
MySqlTriggerOptions,
MySqlTriggerOptions,
ServiceBusQueueTrigger,
ServiceBusQueueTriggerOptions,
ServiceBusTopicTrigger,
Expand All @@ -32,6 +34,7 @@ import {
WebPubSubTriggerOptions,
} from '@azure/functions';
import { addBindingName } from './addBindingName';
import { converToMcpToolTriggerOptionsToRpc } from './converters/toMcpToolTriggerOptionsToRpc';

export function http(options: HttpTriggerOptions): HttpTrigger {
return addTriggerBindingName({
Expand Down Expand Up @@ -126,6 +129,20 @@ export function webPubSub(options: WebPubSubTriggerOptions): WebPubSubTrigger {
});
}

/**
* Creates an MCP Tool trigger configuration.
* This function is used to define an MCP Tool trigger for an Azure Function.
*
* @param options - The configuration options for the MCP Tool trigger, including tool-specific metadata.
* @returns An MCP Tool trigger object with the specified configuration.
*/
export function mcpTool(options: McpToolTriggerOptions): McpToolTrigger {
return addTriggerBindingName({
...converToMcpToolTriggerOptionsToRpc(options),
type: 'mcpToolTrigger',
});
}

export function generic(options: GenericTriggerOptions): FunctionTrigger {
return addTriggerBindingName(options);
}
Expand Down
3 changes: 3 additions & 0 deletions types/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { EventGridFunctionOptions } from './eventGrid';
import { EventHubFunctionOptions } from './eventHub';
import { GenericFunctionOptions } from './generic';
import { HttpFunctionOptions, HttpHandler, HttpMethodFunctionOptions } from './http';
import { McpToolFunctionOptions } from './mcpTool';
import { MySqlFunctionOptions } from './mySql';
import { ServiceBusQueueFunctionOptions, ServiceBusTopicFunctionOptions } from './serviceBus';
import { SetupOptions } from './setup';
Expand Down Expand Up @@ -196,4 +197,6 @@ export function generic(name: string, options: GenericFunctionOptions): void;
*/
export function webPubSub(name: string, options: WebPubSubFunctionOptions): void;

export function mcpTool(name: string, options: McpToolFunctionOptions): void;

export * as hook from './hooks/registerHook';
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export * from './hooks/logHooks';
export * from './http';
export * as input from './input';
export * from './InvocationContext';
export * from './mcpTool';
export * from './mySql';
export * as output from './output';
export * from './serviceBus';
Expand Down
102 changes: 102 additions & 0 deletions types/mcpTool.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.

import { FunctionOptions, FunctionResult, FunctionTrigger } from './index';
import { InvocationContext } from './InvocationContext';

/**
* A handler function for MCP Tool triggers.
*
* @param messages - The messages or data received by the trigger.
* @param context - The invocation context for the function.
* @returns A result that can be a promise or a synchronous value.
*/
export type McpToolTriggerHandler = (messages: unknown, context: InvocationContext) => FunctionResult;

/**
* Configuration options for an MCP Tool function.
* This includes trigger-specific options and general function options.
*/
export interface McpToolFunctionOptions extends McpToolTriggerOptions, Partial<FunctionOptions> {
/**
* The handler function to execute when the trigger is invoked.
*/
handler: McpToolTriggerHandler;

/**
* The trigger configuration for the MCP Tool.
*/
trigger?: McpToolTrigger;
}

/**
* Configuration options for an MCP Tool trigger.
* These options define the behavior and metadata for the trigger.
*/
export interface McpToolTriggerOptions {
/**
* The name of the tool associated with the trigger.
* This is typically an app setting or environment variable.
*/
toolName: string;

/**
* A description of the tool or trigger.
* This provides additional context about the trigger's purpose.
*/
description: string;

/**
* Additional properties or metadata for the tool.
* This is a dictionary of key-value pairs that can be used to configure the trigger.
*/
toolProperties?: any | McpToolProperty[];
}

/**
* Configuration options for an MCP Tool trigger.
* These options define the behavior and metadata for the trigger.
*/
export interface McpToolTriggerOptionsToRpc {
/**
* The name of the tool associated with the trigger.
* This is typically an app setting or environment variable.
*/
toolName: string;

/**
* A description of the tool or trigger.
* This provides additional context about the trigger's purpose.
*/
description: string;

/**
* Additional properties or metadata for the tool.
* This is a dictionary of key-value pairs that can be used to configure the trigger.
*/
toolProperties?: string;
}

/**
* Represents an MCP Tool trigger, combining base function trigger options
* with MCP Tool-specific trigger options.
*/
export type McpToolTrigger = FunctionTrigger & McpToolTriggerOptionsToRpc;

export interface McpToolProperty {
/**
* The name of the property.
*/
propertyName: string;

/**
* The value of the property.
*/
propertyValue: string;

/**
* A description of the property.
* This provides additional context about the purpose or usage of the property.
*/
description: string;
}
6 changes: 6 additions & 0 deletions types/trigger.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { EventHubTrigger, EventHubTriggerOptions } from './eventHub';
import { GenericTriggerOptions } from './generic';
import { HttpTrigger, HttpTriggerOptions } from './http';
import { FunctionTrigger } from './index';
import { McpToolFunctionOptions, McpToolTrigger } from './mcpTool';
import { MySqlTrigger, MySqlTriggerOptions } from './mySql';
import {
ServiceBusQueueTrigger,
Expand Down Expand Up @@ -90,6 +91,11 @@ export function mySql(options: MySqlTriggerOptions): MySqlTrigger;
*/
export function webPubSub(options: WebPubSubTriggerOptions): WebPubSubTrigger;

/**
* [Link to docs and examples](//TODO Add link to docs and examples)
*/
export function mcpTool(options: McpToolFunctionOptions): McpToolTrigger;

/**
* A generic option that can be used for any trigger type
* Use this method if your desired trigger type does not already have its own method
Expand Down
Loading