What an MCP server can access: three layers on one open-source platform
An MCP server can access the systems behind its tools. What your agent can reach through it is narrower. Three layers decide that reach: the exposed tools, the agent's grant, and the account each call runs as. Kortix is the open-source AI Operating System. Your agents, skills, company memory, and connectors live in one git repo you own.
What the protocol assigns to each side
Tools in MCP are designed to be model-controlled, meaning that the language model can discover and invoke tools automatically based on its contextual understanding and the user's prompts. Servers MUST: Validate all tool inputs Implement proper access controls Rate limit tool invocations Sanitize tool outputs Clients SHOULD: Prompt for user confirmation on sensitive operations Show tool inputs to the user before calling the server Log tool usage for audit purposes
Source: modelcontextprotocol.io/specification/2025-06-18/server/tools
Three layers, three edits
One grant, one account, one rule, each in a place a person can review before a call runs.
Grant
agents:
release-bot:
connectors: [docs-search]Account
kortix connectors connect docs-search --owner me # private, only you kortix connectors connect docs-search --owner project # shared, everyone in the project kortix connectors accounts docs-search # accounts you may use, default first
Policy
connectors:
- slug: docs-search
provider: mcp
url: https://mcp.example.com/mcp
sensitive: true
policies:
- match: "get_*"
action: always_runA tool list is one layer of three
Every tool on an MCP server's list is a door into the system behind it. A call reaches the server under the credential the server holds or accepts. What an agent reaches through the server is narrower. Three layers cut it down: the tools the server publishes, the grant the agent holds in kortix.yaml, and the account the call runs as.
A connector is the client-side entry that carries the policy and the account for one server. In Kortix it is a manifest entry, so the grant and the policy are files a person can read before an agent runs (what an MCP connector is). The account inventory is a screen, and each layer hides a fact the other two would show.
The tool list and the grant can be read before anything runs, while the account is settled at the moment a call asks for one. Read all three and the review takes minutes. Read the tool list alone and the two layers that decide the call stay unread.
Layer one: the tools a server publishes
An MCP client discovers tools by sending tools/list, and invokes one by sending tools/call. Each entry in the reply carries a name, a description and an input schema, so a reviewer can see the arguments a call takes. That reply is the server's own account of what it can do.
The protocol hands the choice of tool to the model. "Tools in MCP are designed to be model-controlled, meaning that the language model can discover and invoke tools automatically based on its contextual understanding and the user's prompts." A model that can see forty tools chooses among them, and two servers fronting the same product can publish different lists.
The list is also where the server states part of its own limit. The specification requires servers to implement proper access controls, so a read-only token on the server side turns a write tool into a refused call. Nothing in a tool description tells you the scope of that token. You learn it from the account, which is the third layer.
Layer two: the grant an agent holds
A grant is the layer teams skip, because a connected connector looks available. An agent reaches a connector only when agents.<name>.connectors in kortix.yaml lists its slug or is all, and an omitted value means none. A connector that is connected, authorized and working stays unreachable by an agent whose block does not name it (Kortix docs).
The grant is a line in a file, which makes it the easiest layer to review. A change to it arrives as a diff, and a reviewer can watch a new slug appear beside the agent that gains it. The value to argue about is all, because it covers every connector in the project, including the ones someone adds next month. A slug list costs more lines and answers a narrower question.
Layer three: the account a call runs as
Every connector holds one or more accounts, and an account is the identity a call runs as. An owner type decides who may use it. A shared account has owner_type: project. It covers everyone in the project and every agent whose connectors grant lists the connector, triggers included. A private account (owner_type: member) belongs to one person and runs only in that person's private sessions. An unattended run, a trigger or code holding a service-account key kortix_sa_…, never uses a private account (Kortix docs).
A call that names no account, or names me or project, uses one only when the choice is certain: exactly one account is reachable, or exactly one is pinned as the default. Anything else is denied with account_required and the list of available_accounts. Kortix never substitutes another account. That refusal is the failure a tool-list review cannot predict. The connector is connected, the grant names it, the agent calls a tool, and the call stops because two accounts are reachable and nobody said which.
Connector credentials are brokered server-side and never enter the machine. The account also decides what the agent can leak by accident. A call runs with a credential the agent never holds. Whose permissions an MCP connector uses covers the choice between a personal grant and one shared identity.
Where the three layers meet on every call
Policy runs on every call, once the connector is in the agent's reach and before the provider sees anything. Kortix evaluates each call against four levels, and the first match wins: project-wide policies:, then the connector's own policies:, then sensitive: true, then policy.default_mode. Allow (always_run) runs the call, Ask (require_approval) holds it, Block (block) refuses it. "Approval holds the call; the agent's turn pauses and resumes."
Two switches narrow reach without a rule per tool. sensitive: true on a connector sends every action no rule matched to approval, reads included. policy.default_mode: risk runs reads and holds writes and destructive actions for approval. Set neither and the default is allow_all, which runs every remaining action. "Approval gates you set. Off until you set them."
Policy is the layer that can still catch a wrong account. A held write shows the account, the action and the arguments before anything leaves. A shared identity with broad scope still needs a person. Pick the gate from the tool: an action that changes state earns a rule whether the credential behind it is wide or narrow.
One connector read three ways
Take a docs-search connector publishing twelve actions against Acme's documentation, connected with a Northwind read-only key. The tool list shows twelve actions, several of which create or replace pages. The grant names docs-search for release-bot, so the agent may call all twelve. The account can read, so the writes will fail at the provider.
Each layer hides a different fact. The tool list hides the credential's scope, because no description says whether the token behind a tool may write. The grant hides the identity, since connectors: [docs-search] says the agent may call the connector and nothing about whose login pays for it. The account hides the policy, because a read-only credential makes a missing approval rule invisible until the key is widened. A review that stops at the list sees twelve working actions. The same connector seen from the account has writes that cannot run and a policy gap nobody has looked at.
What to ask before you accept that an agent has access
When someone says an agent has access to a system, ask for five things. Each one has a file or a screen behind it, so a vague answer is itself information.
- The tool list, with names and input schemas, and every action that changes state marked.
- The grant line. Read
agents.<name>.connectorsinkortix.yaml, and treatallas every connector in the project, including future ones. - The account. Ask which one resolves for the call, who owns it, and who else can use it. An unattended run needs a shared account.
- The rule that covers writes. Ask for the policy entry matching the write tool, and for the default mode when nothing matches.
- The record. "Every action is recorded. Reading, exporting and streaming the audit log depend on the plan." Ask who can read it and for how long it is kept.
A sixth question matters once those answers span more than one server, because every server adds a tool list to read and the same log then has to answer for all of them. What changes when you connect several MCP servers is the next page in that review.
Questions about what an agent can reach
Reach, limits and the account behind a call, taken one layer at a time.
What can an MCP server access?
An MCP server reaches the systems behind the tools it publishes, and each call runs under a credential the server holds or accepts. Its tool list shows those tools, and its own access controls decide how much of the backend a single call can touch.
How do I limit which MCP tools an agent can call?
Name the connector's slug in that agent's connectors list, then set a rule for the actions that change state. In Kortix the grant in kortix.yaml decides reach first: a slug list, or all, while an omitted value gives the agent none. sensitive: true then holds every remaining action, reads included, and policy.default_mode: risk holds the writes and destructive actions, so neither needs a rule per tool.
Can an agent use my permissions?
Only through a private account you own, and only in your own private sessions. An unattended run, such as a trigger or a service-account key, never uses a private account, so a scheduled job needs a shared account with its own identity.
Does MCP have permissions?
No. Merge puts the gap plainly: "Tool access control is handled at the MCP server level, since MCP doesn't offer a built-in permissions system" (Merge). The grant, the account and the policy rule all sit in the layer above the server.
Write the grant, name the account, set the rule.
Connectors, policies and grants in one repo you own, so the next access review reads a diff.