Tool descriptions and schemas improve interoperability, but they are not a security boundary. Route every MCP tool invocation through one server-side path that validates arguments, verifies identity and scopes, enforces resource ownership, and sanitizes failures.
Last updated: November 3, 2026.
async function invokeTool(context, toolName, rawArguments) {
const definition = toolRegistry.get(toolName);
if (!definition) throw new PublicError('Unknown tool');
const input = definition.schema.parse(rawArguments);
requireScopes(context.auth, definition.scopes);
requireTenant(context.auth, input.tenantId);
return definition.handler({ input, actor: context.auth.subject });
}The dispatcher is the only route to a handler. Individual tools can add stricter business rules, but they cannot bypass the mandatory baseline checks.
Authenticate at the transport boundary
For an HTTP MCP server, validate bearer tokens before protected requests reach tool code. The official MCP TypeScript authorization guidance describes the server as an OAuth resource server: it verifies tokens issued by an authorization server and can enforce required scopes.
Check issuer, audience or resource, signature, expiration, and scopes. Never accept a token merely because it is structurally valid. Create an immutable request context containing the authenticated subject and tenant, then pass that context to the dispatcher. Do not accept an authoritative user or tenant ID from tool arguments.
Make secure behavior the default
Register every tool with a schema, required scopes, and a handler. Reject unknown properties where possible, apply length and range limits, and resolve referenced objects within the authenticated tenant. A valid UUID proves only format; it does not prove ownership.
Return stable public errors such as unauthorized, forbidden, invalid input, and not found. Log a correlation ID and detailed internal reason separately, without recording access tokens, secrets, or complete sensitive arguments.
Test the dispatcher as a policy matrix: missing token, wrong audience, missing scope, cross-tenant identifier, malformed input, unknown tool, and successful call. Add a registration test that fails if any tool lacks a schema or scope declaration. This prevents a newly added tool from silently choosing weaker defaults. Continue with multi-tenant roles and permissions, tenant isolation in SQL, and RLS tenant isolation.