Manage MCP Access - Barndoor Documentation
Documentation Index
Fetch the complete documentation index at: /llms.txt
Use this file to discover all available pages before exploring further.
This guide builds the core Barndoor workflow as code: an MCP server your organization can reach, a credential connection for it, a registered AI Agent, and an access policy that governs what that agent may do.
Estimated time: 20–30 minutes. Complete Getting Started first — this guide assumes a working provider configuration.
Before You Begin
- A configured
provider "barndoor"block (see Getting Started) - An API key for the service your MCP server fronts (this guide uses a non-OAuth server)
- The catalog slug or name of the MCP server you want to onboard and the name of the agent you want to register — directory entries are looked up by data source, so no IDs need to be copied from the app.
Step 1: Onboard the MCP server
If the server is new to your organization, create it from its directory entry. If it was already onboarded in the portal, look it up with a data source instead — don’t manage the same server from both places.
New server
Existing server (data source)
# Look up the catalog entry by its connector slug (or name, or id).
data "barndoor_mcp_server_directory" "search" {
slug = "search"
}
resource "barndoor_mcp_server" "search" {
name = "Search"
mcp_server_directory_id = data.barndoor_mcp_server_directory.search.id
}
data "barndoor_mcp_server" "search" {
# Look up by name, slug, or id. Name matching is case- and
# whitespace-insensitive; an ambiguous name fails with candidates.
name = "Search"
}
References: barndoor_mcp_server resource, data source, barndoor_mcp_server_directory data source
Server names are unique within an organization (case- and whitespace-insensitively), and destroying a barndoor_mcp_server soft-deletes it: its connections and stored credentials are torn down, and the name is freed for reuse.
Step 2: Connect it tenant-wide
A barndoor_connection stores a service-account-owned credential for the server, so every authorized agent can use it without each user connecting individually:
resource "barndoor_connection" "search" {
server_id = barndoor_mcp_server.search.id
# Write-only: stored in Barndoor's secret store, never returned by the API.
api_key = var.search_api_key
}
variable "search_api_key" {
type = string
sensitive = true
}
Reference: barndoor_connection
OAuth servers can’t be connected by Terraform — the interactive browser consent can’t happen inside a declarative apply. Terraform supports the non-OAuth credential providers (api_key, bearer_token, basic_auth, generic); connect OAuth servers in the Barndoor app. Also note: an organization can have at most one tenant-wide connection per server, and changing any credential attribute replaces the connection.
Step 3: Register the AI Agent
Registration attaches the agent’s directory entry to your organization and creates the service account that policies bind to:
data "barndoor_agent_directory" "assistant" {
name = "Assistant"
}
resource "barndoor_agent" "assistant" {
application_directory_id = data.barndoor_agent_directory.assistant.id
llm_gateway_enabled = true
}
References: barndoor_agent, barndoor_agent_directory data sourceAn agent directory entry can have one live registration per organization. To reference an agent registered outside Terraform, use the barndoor_agent data source.
Step 4: Govern access with a policy
The policy is where the three pieces meet: it binds the agent (application_ids) to the server (mcp_server_id) and defines what’s allowed:
resource "barndoor_policy" "search_read_only" {
name = "Search read-only for the assistant"
mcp_server_id = barndoor_mcp_server.search.id
description = "The assistant may run searches; everything else is blocked."
support_contact = "platform@example.com"
status = "ACTIVE" # DRAFT (default), ACTIVE, or INACTIVE
application_ids = [barndoor_agent.assistant.id]
tags = ["search", "terraform-managed"]
rules = [\
{\
name = "allow searches"\
effect = "ALLOW"\\n\
actions = ["tools/call:search", "tools/call:get_document"]\
roles = ["*"]\
},\
]
}
Reference: barndoor_policy
Always set actions and roles explicitly on every rule. If you omit either list, the platform API defaults it to ["]*" — everything. An “allow” rule you meant to scope narrowly becomes an allow-all. Write ["]*" only when you mean it.
Conditional rules
Rules accept an optional condition tree, passed as JSON. Each node has exactly one of expr or a combinator (all / any / none) with of = [...]:
rules = [\
{\
name = "allow small reads"\
effect = "ALLOW"\
actions = ["tools/call:search"]\
roles = ["role:analyst"]\
\
condition = jsonencode({\
all = {\
of = [\
{ expr = { expr = "request.size < 100" } },\
]\
}\
})\
},\
]
Start new policies in DRAFT (the default), review the result in the Barndoor app under MCP Gateway → Policies, then flip status to ACTIVE in a follow-up apply — the same draft-then-activate flow the portal uses.
Lifecycle notes
- Destroy archives, it doesn’t delete. Destroying a
barndoor_policymoves it toARCHIVED— the platform’s terminal lifecycle state, kept for audit history. The name is freed for non-archived reuse. mcp_server_idis immutable on a policy; changing it forces a replacement (a new policy is created and the old one archived).- Importing existing objects: all four resources support
terraform import. Policies, servers, and agents import by ID; connections import by their server ID (or slug). See Best Practices → Importing.
Complete example
Show Full configuration from this guide
data "barndoor_mcp_server_directory" "search" {
slug = "search"
}
resource "barndoor_mcp_server" "search" {
name = "Search"
mcp_server_directory_id = data.barndoor_mcp_server_directory.search.id
}
resource "barndoor_connection" "search" {
server_id = barndoor_mcp_server.search.id
api_key = var.search_api_key
}
data "barndoor_agent_directory" "assistant" {
name = "Assistant"
}
resource "barndoor_agent" "assistant" {
application_directory_id = data.barndoor_agent_directory.assistant.id
llm_gateway_enabled = true
}
resource "barndoor_policy" "search_read_only" {
name = "Search read-only for the assistant"
mcp_server_id = barndoor_mcp_server.search.id
description = "The assistant may run searches; everything else is blocked."
support_contact = "platform@example.com"
status = "ACTIVE"
application_ids = [barndoor_agent.assistant.id]
tags = ["search", "terraform-managed"]
rules = [\
{\
name = "allow searches"\
effect = "ALLOW"\
actions = ["tools/call:search", "tools/call:get_document"]\
roles = ["*"]\
},\
]
}
variable "search_api_key" {
type = string
sensitive = true
}