manage mcp access.md

Manage MCP Access

Onboard an MCP server, connect it tenant-wide, register an AI Agent, and govern access with a policy — all in Terraform

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.

New server

# 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
}

Existing server (data source)

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

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 source

An 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"

actions = ["tools/call:search", "tools/call:get_document"]
      roles   = ["*"]
    },
  ]
}

Reference: barndoor_policy

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" } },
        ]
      }
    })
  },
]

Lifecycle notes

Complete example

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
}