← Back to Build Log
mcpauthorizationsecuritygatewaysep-protocol

Securing MCP Servers: Why Tool-Level Authorization Is Non-Negotiable

Research published in early 2026 found that 32% of MCP servers have critical vulnerabilities. That number is high, but the more important finding is the root cause: the Model Context Protocol has no built-in authorization layer. The protocol defines how to discover tools and call them. It says nothing about who is allowed to call which tools, under what conditions, with what arguments, or how to produce a verifiable record of what happened.

This is not a criticism of MCP. It is a reasonable design choice to keep the protocol lean. But it means that authorization is the responsibility of everyone who deploys an MCP server, and most teams are not doing it.

What "No Authorization" Actually Means

When you run an MCP server without an authorization layer, any MCP client that can reach it can call any tool it exposes. There are no roles. There are no policies. There are no rate limits enforced at the authorization boundary. There is no audit log you could produce to demonstrate what happened.

If you have an MCP tool server with a delete_file tool and a read_config tool, a client calling delete_file with arbitrary arguments will succeed as long as the underlying file system operation succeeds. There is nothing at the MCP layer that asks whether this client is allowed to call delete_file, whether the path argument is in scope, or whether a human should approve it first.

This is the vulnerability surface. It is not a flaw in any specific server. It is an absence in the protocol that every deployer has to fill.

Why Per-Server Authorization Does Not Scale

The obvious fix is to add authorization to each tool server individually. Add middleware that checks API keys. Add logic that validates arguments against an allowlist. Add a logging statement for each call.

This works for one server. It does not work for ten. You now have ten separate authorization implementations. They may use different key formats, different policy models, different log schemas. When you need to change a policy — say, adding a new rate limit for all destructive tools across all servers — you are making ten separate changes. When you want to audit what happened across a workflow that touched four different servers, you are reconciling four different log formats.

The correctness of your security posture depends on all ten implementations being right simultaneously. One misconfigured server and you have a gap.

The Gateway Model

What you actually need is a single enforcement point. A gateway that sits between every MCP client and every tool server, evaluating every call against a unified policy before deciding whether to forward it.

The Authensor MCP Gateway implements this model. You point your MCP client at the gateway instead of directly at tool servers. You point the gateway at your downstream servers. You define one policy. Every call that flows through the gateway is evaluated against that policy, regardless of which tool server the call is destined for.

The tool servers do not need to change. They do not implement any authorization logic. They receive only the calls that the gateway has already cleared.

The SEP Authorization Protocol

The gateway implements the SEP (Structured Evaluation Protocol) authorization flow. Three message types handle the full lifecycle.

authorization/propose — The client sends the intent before anything executes. The message includes the tool name, the arguments, and the identity of the agent making the call. The gateway receives this and does nothing else until it has a decision.

authorization/decide — The gateway evaluates the intent against the active policy. The policy engine checks action rules, resource constraints, time windows, rate limits, and content safety via Aegis. The output is one of three decisions: ALLOW, DENY, or REVIEW. ALLOW means forward the call. DENY means block it and return a structured error. REVIEW means hold the intent and route it to a human approver.

authorization/receipt — After the decision, the gateway writes an immutable receipt. The receipt contains the full intent, the policy version that evaluated it, the matched rules, the decision, the principal, and a hash-chain link to the previous receipt. This is the audit trail.

Only after an ALLOW decision does the gateway forward the tool call to the downstream server. A denied call never reaches the tool server. A tool server that receives a call from the gateway can assume the call has been authorized.

Backward Compatibility

Not all MCP clients support SEP messages. If your client does not, the gateway falls back to inline evaluation automatically. The tool call arrives at the gateway as a standard MCP request. The gateway evaluates it internally, applies the policy, and either forwards it or blocks it. The client does not need to be updated. You get policy enforcement and audit logging without changing any existing integration.

Setting Up the Gateway

Install and scaffold:

npx create-authensor

This creates a project with the gateway configured, a starter policy, and receipt storage. Then define your policy. Here is a complete example covering a typical MCP tool server with read and write tools:

version: "1"
default: deny

rules:
  # Read tools are open to all agents
  - action: "read_*"
    principal: "agent:*"
    effect: allow

  # Write tools require explicit allowlisting
  - action: write_file
    principal: "agent:content-editor"
    effect: allow
    conditions:
      - field: "args.path"
        operator: matches
        value: "^/workspace/drafts/"

  # Destructive tools require human approval
  - action: delete_file
    principal: "agent:content-editor"
    effect: review
    reason: "File deletion requires human approval"
    approvalTimeout: "15m"

  # Destructive tools are denied for all other principals
  - action: delete_file
    principal: "*"
    effect: deny

  # Admin tools are completely locked down
  - action: "admin_*"
    principal: "*"
    effect: deny

Point your MCP client at the gateway:

import { MCPClient } from "@modelcontextprotocol/sdk/client";

// Before: pointing directly at the tool server
// const transport = new StdioTransport({ command: "my-tool-server" });

// After: pointing at the Authensor gateway
const transport = new SSETransport({
  url: "http://localhost:4002/mcp",
  headers: {
    "X-Agent-Principal": "agent:content-editor",
    Authorization: `Bearer ${process.env.AUTHENSOR_API_KEY}`,
  },
});

const client = new MCPClient({ name: "my-agent", version: "1.0" });
await client.connect(transport);

// Tool calls work exactly the same way
const result = await client.callTool({ name: "write_file", arguments: { path: "/workspace/drafts/post.md", content: "..." } });

The client code does not change. The tool servers do not change. The gateway handles policy evaluation, approval routing, and receipt creation transparently.

What Unified Policy Enforcement Covers

With a single policy governing all tool servers, you can express rules that span the entire MCP surface:

Agent identity binding — Only agents with specific principal identifiers can call specific tools. A read_database tool is available to agent:analyst but not agent:onboarding.

Cross-server rate limits — A rate limit on generate_image applies regardless of which image server the agent is calling through.

Time-of-day windows — Deployment tools can be restricted to business hours across all servers simultaneously.

Content scanning — Aegis scans the arguments of every tool call for prompt injection, PII, and credential patterns before the call is forwarded. One scanner covers every tool server.

Approval workflows — Any action matching a REVIEW rule is held for human approval. The approval queue is unified across all servers. Reviewers see everything in one place.

Try It

The gateway, the policy engine, the SEP protocol implementation, and the receipt system are all open source. Run npx create-authensor to get a working gateway with an example policy. Read the MCP integration docs at authensor.com/docs. If you are running MCP servers in production without an authorization layer, this is the fastest path to one. Star the repo on GitHub if it is useful.