Skip to content

RFC: Tool call middleware hook for authorization and cross-cutting concerns #2870

@aimable100

Description

@aimable100

Is this related to an existing feature request or issue?

No response

Summary

Add a standard middleware interface that intercepts tool calls before handler execution, enabling authorization, audit logging, and argument validation to be implemented once and applied across all AWS MCP servers without modifying tool handlers or forking the repo.

Use case

Teams deploying AWS MCP servers in multi-tenant or regulated environments need to enforce per-tool authorization policies, log tool invocations for compliance, and validate arguments against external constraints. Today there is no hook to do this without either modifying each tool handler individually or maintaining a fork. - Both approaches break on upstream updates and produce non-interoperable implementations — every team reimplements the same interception logic independently.
Concrete examples:

  • Enforcing that an agent can only call s3_get_object on a specific bucket prefix before the handler executes
  • Logging every tool invocation with caller identity and arguments to a compliance audit trail
  • Rejecting tool calls whose arguments fail an external policy check

Proposal

A single middleware interface registered at server startup, applied to every tool call before the handler runs:

type ToolMiddleware interface {
    BeforeToolCall(
        ctx context.Context,
        toolName string,
        arguments map[string]any,
        meta map[string]any,
    ) (map[string]any, error) // return modified args, or non-nil error to deny
}

Registered at server startup:

server.Use(myAuthMiddleware, myAuditMiddleware)

Middleware runs in registration order. A non-nil error short-circuits the chain and returns an MCP error response without invoking the tool handler. The meta parameter exposes params._meta so middleware can read authorization context (tokens, signatures) passed by the client without those fields reaching the tool handler.

Out of scope

  • Built-in authorization implementations — the interface is the primitive; implementations are external
  • Changes to the MCP wire protocol
  • Modifications to individual tool handler signatures or behavior

Potential challenges

Middleware ordering matters when multiple middlewares modify arguments. The proposed return signature (map[string]any, error) passes modified arguments to the next middleware in the chain, which requires each middleware to be aware it may receive arguments already transformed by a predecessor. This is the same pattern mcp-go uses and is well understood.
Panic recovery in middleware should be handled consistently with how the server handles panics in tool handlers today.

Dependencies and Integrations

The GitHub MCP server merged equivalent middleware support in github/github-mcp-server#2026. The official Go MCP SDK ships AddReceivingMiddleware with the same semantics. mcp-go supports WithToolHandlerMiddleware. This proposal aligns awslabs/mcp with the pattern already established across the ecosystem.
No external dependencies required. The interface is pure Go with no new imports.

Alternative solutions

- Fork per team: teams maintain their own patched version of each AWS MCP server. 
- Breaks on upstream updates, no interoperability.
- Tool handler modification: authorization logic added to each individual tool handler. Duplicates logic across tools, tightly couples security policy to application code.
- Proxy server: a separate process sits in front of the MCP server and intercepts calls. Adds deployment complexity and a network hop.

A standard middleware hook eliminates all three workarounds.

Happy to submit a draft PR for discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    RFC-proposalA Request for Comments to announce intentions and get early feedback (mainly for new MCP servers)needs-triageThis needs to be handled, it is the first automatically assigned label to issues.

    Type

    No type

    Projects

    Status

    To triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions