Grant access to MCP tools

Last validated:
Aperture by Tailscale is currently in beta.

Aperture connectors are in public alpha. The connectors grant syntax and the connectors configuration section may change. The mcp_tools, mcp_resources, and mcp_templates grant fields are deprecated. Use the connectors field instead.

When you configure connectors with Aperture, users can access MCP tools, resources, templates, and HTTP connector endpoints through the Aperture proxy. Like model access, connector access is deny-by-default. You need to configure grants that specify which connector capabilities each user or group can use.

This topic assumes you have already configured model access grants. Connector grants use the same structure, with the connectors field for connector capabilities.

Prerequisites

Before you begin, make sure you have the following:

Configure connector access grants

Add the connectors field to your grants to control which connector capabilities users can access. The connectors field accepts an array of fully qualified name (FQN) glob patterns in "connectorID/category/resource" format.

Open the Settings page of the Aperture dashboard and add connectors entries to the tailscale.com/cap/aperture capability array.

The following example grants users in group:ai-users access to all capabilities from the built-in Aperture connector, all capabilities from a GitHub connector, and all tools from local, an example MCP connector you define in your connectors.servers configuration:

{
  "grants": [
    {
      "src": ["group:ai-users"],
      "app": {
        "tailscale.com/cap/aperture": [
          { "role": "user" },
          { "models": "anthropic/**" },
          { "connectors": ["aperture/**", "github/**", "local/tools/*"] }
        ]
      }
    }
  ]
}

Matching group: sources, like group:ai-users in the example above, requires visible groups enabled for the Aperture device.

The grant examples on this page use Aperture configuration syntax, where the dst field is not required because the destination is the Aperture device itself. If you define grants in the tailnet policy file instead, you must include a dst key specifying the Aperture device (for example, "dst": ["tag:aperture"]). Omitting dst in a tailnet policy file grant causes the grant to silently have no effect. For a full comparison and conversion steps, refer to Aperture grants vs. tailnet policy file grants.

Connector capability fields

Each capability entry under tailscale.com/cap/aperture can include the connectors field:

FieldFormatDescription
connectorsArray of FQN globsGrant access to connector capabilities by "connectorID/category/resource" pattern.

The following grant categories are available:

CategoryApplies toDescriptionExample
toolsMCP connectorsMCP tools"local/tools/search"
resourcesMCP connectorsMCP resources"local/resources/*"
templatesMCP connectorsMCP resource templates"local/templates/*"
proxyHTTP connectorsProxy access to /v1/connectors/<id>/"github/proxy"

A proxy grant authorizes the connector's entire /v1/connectors/<id>/ path. It has no per-path granularity.

Patterns use the same glob syntax as model grants: * matches a single path segment and also matches any characters within a segment (for example, get_* matches tool names that start with get_), and ** matches zero or more segments.

A malformed pattern, such as one with more than two slashes or with an unrecognized category segment, is silently dropped rather than reported as an error. A typo in a grant pattern grants nothing, so confirm each pattern matches an existing connector capability.

The deprecated mcp_tools, mcp_resources, and mcp_templates grant fields continue to work. New configurations should use the connectors field instead.

Pattern examples

The following examples show how to use FQN patterns to grant access to specific connector capabilities:

PatternMatches
"local/tools/*"All MCP tools from local connector
"local/**"All capabilities from local
"github/proxy"Proxy access to github HTTP connector
"github/**"All access to github connector
"aperture/**"Built-in Aperture system connector, by ID
"*/tools/search"The search tool from any connector
"**"All capabilities from all connectors
"label:system"Every connector labeled system, which is every built-in connector

An FQN pattern always includes at least the connector ID. To grant access to everything a connector exposes, use "connectorID/**".

Grant access by label

Alongside FQN patterns, the connectors field accepts label:<name> patterns. Labels are flat strings you set on a connector, so one pattern can cover a group of connectors that changes over time without a policy edit:

{ "connectors": ["label:sales"] }

A label pattern behaves differently from an FQN pattern in two ways. Matching is exact rather than glob-based, the same as tag: and group: elsewhere in Tailscale grants, so label:team.* matches nothing. And a matching label grants the entire connector at every category and resource, including proxy, so labels cannot express tool-level access. Keep FQN patterns for a single tool or a read-only slice, and use labels for connector-level policy.

Because grants are additive, a label only ever adds access. Labeling a connector restricted does not gate it, and a user holding "**" still reaches it. For the label grammar, the reserved system label, and the full task, refer to Grant connector access by label.

What denial looks like

When a user lacks a matching grant, Aperture hides the capability rather than exposing it. Tools and resources the user cannot access do not appear in the tool or resource list, and a direct call to an unauthorized tool returns an "unknown tool" error (or "unknown resource" for a resource). A request to an unauthorized HTTP connector proxy path returns 403 access denied.

If a capability is missing or a request is denied unexpectedly, check for a missing or misspelled grant pattern.

Built-in connectors

Aperture includes a built-in aperture system connector. It exposes a list_connectors tool (surfaced to models as aperture_list_connectors) for discovering the HTTP API connectors available through Aperture. This tool is registered only when at least one HTTP connector is configured.

New instances already grant this connector. The default configuration includes the following grant, which matches the system label that every built-in connector carries automatically:

{ "connectors": ["label:system"] }

Built-in connectors are not special-cased in the authorization path, so removing that grant makes their tools unreachable. You can also target the connector by ID, which is the only way to reach a single built-in tool:

{ "connectors": ["aperture/**"] }
{ "connectors": ["aperture/tools/list_connectors"] }

The aperture connector ID is reserved and cannot be used for custom connectors, and so is the system label.

Connector access follows a three-layer authorization model:

  1. Configuration: The connector must be declared in your connectors.servers configuration.
  2. Grants: The user needs a matching connectors grant pattern. Grants define the ceiling of what a user can access.
  3. Credentials: For connectors using per-user OAuth, the user must complete the OAuth authorization flow before accessing the connector.

Next steps