Skip to content

How to create an inner decorator for tools? #1120

@BryanMakers

Description

@BryanMakers

Question

What I'm trying to achieve:

I'm creating a decorator that reuses elicitation logics. So I can reuse some code to write less code! 😄

What I have tried:

def simple_elicitation_acceptance(func):
    @wraps(func)
    async def wrapper(ctx: Context, *args, **kwargs):            
        if not ctx:
            raise ValueError("Context is required for elicitation acceptance.")
        
        result = await ctx.elicit(
            message=f"Confirm add a and b?", schema=SimpleConfirmation
        )
        
        match result:
            case AcceptedElicitation(data=data):
                if data.accepted:
                    return await func(*args, **kwargs)
                else:
                    return "Operation cancelled"
            case DeclinedElicitation():
                return "Operation declined"
            case CancelledElicitation():    
                return "Operation cancelled"
    return wrapper

then simply use it:

@mcp_app.tool(name="add")
@simple_elicitation_acceptance
async def add(a: int, b: int, ctx: Context) -> list:
    """
    add a and b
    """
    try:
        mcp_services: MCPServices = mcp_app.get_context().request_context.lifespan_context.some_fun_services
        res = some_fun_services.add(a, b)
        return res
    except Exception as e:
        raise Exception(f"Error adding: {e}")

My expected bahaviour:

I'm expecting my tool_call not to send a response until I've accepted the elicitation (via some input or event)

Actual behaviour:

Without me responding, the tool_call returns the following object and skips my input

meta=None content=[TextContent(type='text', text='Error executing tool add: Context is not available outside of a request', annotations=None, meta=None)] structuredContent=None isError=True

Additional Context

It actually works fine by just remove the decorator layer, but I really wanna make it a decorator so I can write less code!

Sorry if it was a noob question, or perhaps what I'm trying to achieve is not reasonable, or perhaps this sdk just doesn't yet support inner decorator for tools, but I've spent a lot of time on this so any answer is welcome haha!

Love the awesome work y'all are doing, thank you!

sorry made a couple edits to make my post reads a bit clearer

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Significant bug affecting many users, highly requested featureenhancementRequest for a new feature that's not currently supportedquestionFurther information is requestedready for workEnough information for someone to start working on

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions