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

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.

# 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

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
}