MCP Servers

Posit Assistant can connect to external tool servers using the Model Context Protocol (MCP). This lets you extend the assistant with custom tools — database access, API integrations, internal services, and more.

Besides configuring servers yourself as described below, MCP servers can also come from a plugin you install from a marketplace. Plugin-provided servers are disabled until you approve them; see Plugins & Marketplaces for how that consent works.

Configuration

Add MCP servers to your settings file under the mcpServers key. Each server has a name and a configuration object.

You can configure MCP servers in both the global settings file (~/.posit/assistant/settings.json) and a project settings file (.posit/assistant/settings.json). The two are merged by server name — project entries override global entries with the same name, while global servers not mentioned in the project config remain available. To disable a global server for a specific project, add it to the project config with "enabled": false.

In older versions, these files were at ~/.positai/settings.json and .positai/settings.json.

Local Servers

Local servers run as subprocesses, communicating over stdio. Use these for MCP servers installed as npm packages, Python packages, or standalone executables.

{
	"mcpServers": {
		"filesystem": {
			"type": "local",
			"command": ["npx", "@anthropic-ai/mcp-server-filesystem", "/path/to/dir"]
		}
	}
}

Options

KeyTypeDescription
commandstring[]Command and arguments to start the server. Required.
environmentobjectEnvironment variables passed to the subprocess.
enabledbooleanWhether this server is active. Default: true.
timeoutnumberConnection timeout in milliseconds. Default: 10000.

Environment Variables

Pass secrets to local servers via the environment field:

{
	"mcpServers": {
		"database": {
			"type": "local",
			"command": ["npx", "mcp-server-postgres"],
			"environment": {
				"DATABASE_URL": "{env:DATABASE_URL}"
			}
		}
	}
}

The {env:VAR_NAME} syntax expands to the value of the environment variable at runtime. This works in command, environment, url, and headers fields.

Remote Servers

Remote servers communicate over HTTP or SSE (Server-Sent Events).

{
	"mcpServers": {
		"my-api": {
			"type": "remote",
			"url": "https://mcp.example.com",
			"headers": {
				"Authorization": "Bearer {env:MCP_API_KEY}"
			}
		}
	}
}

Options

KeyTypeDescription
urlstringServer URL. Required.
headersobjectHTTP headers for MCP transport and SDK-managed OAuth requests.
transportstringProtocol: "http" (default) or "sse" (legacy).
authobjectOAuth configuration (see below).
enabledbooleanWhether this server is active. Default: true.
timeoutnumberConnection timeout in milliseconds. Default: 10000.

Authentication

Remote servers support three authentication approaches:

Configured headers other than User-Agent are sent to URLs on the MCP server’s origin. This includes OAuth endpoints when the authorization server shares that origin, as Posit Connect commonly does. They are not added to direct requests to a different-origin authorization server. A configured User-Agent replaces the assistant’s default on MCP transport requests and SDK-managed OAuth requests such as discovery, client registration, and token exchange, including when those requests use a different-origin authorization server. The interactive authorization page is opened in your browser and uses the browser’s own User-Agent. Because HTTP redirects are followed by the runtime, a redirecting endpoint may forward configured headers to its destination; configure the final MCP URL whenever possible to avoid that exposure.

Bearer Token

Pass a static token via headers:

{
	"headers": {
		"Authorization": "Bearer {env:API_TOKEN}"
	}
}

OAuth (Dynamic Registration)

Use "oauth" for servers that support RFC 7591 dynamic client registration:

{
	"auth": "oauth"
}

The assistant handles the browser-based authorization flow automatically.

OAuth (Pre-Registered Client)

For servers that require a specific client ID:

{
	"auth": {
		"clientId": "my-app",
		"clientSecret": "{env:CLIENT_SECRET}"
	}
}

Hosted on Posit Connect

Posit Connect can host MCP servers as published content. A Connect-hosted MCP server is a remote server whose URL is the content’s endpoint — MCP endpoints are conventionally mounted under a /mcp path (for example, https://connect.example.com/content/abc123/mcp).

Connect includes a built-in OAuth authorization server, so the recommended setup uses "auth": "oauth" — the assistant discovers Connect’s OAuth server and prompts you to authorize the connection in your browser:

{
	"mcpServers": {
		"connect-tools": {
			"type": "remote",
			"url": "https://connect.example.com/content/abc123/mcp",
			"auth": "oauth"
		}
	}
}

The OAuth authorization server requires Posit Connect 2026.02.0 or later. On older versions — or if your Connect administrator has disabled OAuth — authenticate with a Connect API key instead, passed as an Authorization: Key ... header:

{
	"mcpServers": {
		"connect-tools": {
			"type": "remote",
			"url": "https://connect.example.com/content/abc123/mcp",
			"headers": {
				"Authorization": "Key {env:CONNECT_API_KEY}"
			}
		}
	}
}

For more details, see the Posit Connect MCP servers documentation.

Signing in

A server configured with OAuth stays disconnected until you authorize it, and its authorization eventually expires. Rather than waiting for the next tool call to fail, you can sign in on demand from the session panel:

  • In the web, desktop, RStudio, and Positron apps, run /mcp (or /context, or click the token counter) to open the Session panel. Its MCP Servers section lists every configured server with its status, and a Sign in button on each one that needs authorizing.
  • In the terminal (TUI), run /mcp to open the Session window and go to its Activity tab. Servers needing sign-in are marked; move to one with the arrow keys and press Enter to start the browser flow.

Either way, the browser-based authorization flow opens, and the server connects and registers its tools once you approve it. This works the same for a server you configured yourself and one contributed by a plugin.

Enabling and Disabling

Set enabled: false to temporarily disable a server without removing its configuration:

{
	"mcpServers": {
		"staging-api": {
			"type": "remote",
			"url": "https://staging.example.com",
			"enabled": false
		}
	}
}

Admission Policy

The mcp key (a sibling of mcpServers) controls which configured servers may run at all. It exists primarily for managed deployments — administrators set it through POSIT_ASSISTANT_SETTINGS_ENFORCED / POSIT_ASSISTANT_SETTINGS_DEFAULT (see Administrator-managed settings) — but it works in any settings file.

{
	"mcpServers": {
		/* server definitions, unchanged */
	},
	"mcp": {
		"access": "allowlist", // "all" | "allowlist" | "plugins" | "none"
		"allow": [{ "serverName": "corp-tools" }, { "serverUrl": "https://mcp.corp.com/*" }],
		"deny": [{ "serverCommand": ["/usr/local/bin/legacy-mcp", "--stdio"] }, { "serverType": "local" }]
	}
}

The access rungs:

accessServers from mcpServersPlugin-contributed servers
"all" (default)Allowed unless matched by denyConsent + marketplace rules, unless deny-matched
"allowlist"Only if matched by allow, and not by denyConsent + marketplace rules, unless deny-matched
"plugins"BlockedConsent + marketplace rules, unless deny-matched
"none"BlockedBlocked

deny applies to every server in every mode — user-declared or plugin-contributed — and always wins over allow, plugin consent, and marketplace rules. Use it to block one exfil endpoint or one legacy binary without distrusting everything else. allow only gates servers from mcpServers; plugin servers are already gated by marketplace rules, so they never need allow entries.

"allowlist" fails closed: if no tier defines allow at all, every server from mcpServers is blocked — an omitted list is not more permissive than an explicit "allow": [].

“Only MCP servers from our plugin registry” is "access": "plugins" plus a marketplace lockdown (plugins.strictKnownMarketplaces) — see Plugins & Marketplaces.

Matchers

Each allow/deny entry is an object with exactly one of these keys:

KeyMatchesExample
serverNameExact server name{ "serverName": "corp-tools" }
serverUrlRemote URL; * is a glob wildcard{ "serverUrl": "https://mcp.corp.com/*" }
serverCommandLocal command — exact command and arguments{ "serverCommand": ["npx", "-y", "@corp/server"] }
serverType"local" or "remote"{ "serverType": "local" }

Matchers see the server’s effective configuration: {env:...} references are expanded before matching, so writing a command as "command": ["npx", "-y", "{env:PACKAGE}"] is not a way around a serverCommand rule — and an allowlisted command only admits what it actually expands to. (For the same reason, the logs never print a blocked server’s arguments: they may contain secrets. A block is logged with the server’s name, the command’s name and argument count, and the matcher that matched.)

serverCommand matching is deliberately exact, element by element — that is what makes it unspoofable, and it makes no attempt to guess equivalences:

  • ["npx", "-y", "@corp/x"] does not match ["npx", "--yes", "@corp/x"] — no flag-alias normalization.
  • ["npx", ...] does not match ["/usr/local/bin/npx", ...] — no PATH resolution.
  • ["npx", "-y", "@corp/x"] does not match ["npx", "-y", "@corp/x@1.2.0"] — no version tolerance.
  • The value is an array, not a shell string; no word-splitting or quoting is applied.

Because matchers see the expanded command, supply the value it expands to, not the {env:...} template. Where the goal is “no local servers at all” rather than “these specific local servers”, prefer { "serverType": "local" } in deny — it cannot be missed by an argv variation.

A serverType of "remote" covers every remote protocol (Streamable HTTP, SSE, and anything added later); there is deliberately no per-protocol matcher.

How tiers combine

When several settings sources set mcp, they compose rather than override:

  • deny lists union — every source’s denies apply.
  • allow lists intersect — a server must be admitted by every source that sets allow at all. An explicit "allow": [] admits nothing; leaving allow unset imposes no constraint.
  • access narrows — a project file can only make the value more restrictive than your global settings, and an administrator’s enforced value is a ceiling that can only restrict, never re-enable something you turned off. A value in POSIT_ASSISTANT_SETTINGS_DEFAULT is just the starting point and can be changed in either direction.

A malformed mcp value in an administrator payload fails closed (that tier reads as "access": "none") with an error naming the key, rather than silently dropping the restriction.

Workspace trust

Servers and policy from a project’s .posit/assistant/settings.json apply only in a trusted workspace. While a workspace is untrusted, project-declared servers are dropped entirely — including a project entry that tries to disable a global server — and the project’s mcp policy is ignored. Trusting the workspace (or the host granting trust) reloads them.

Blocked servers stay visible

A blocked server is listed in the MCP Servers section of the Session panel (/mcp) as Blocked by policy, with the reason — so a server that “just isn’t there” has an explanation. The first time a session hits a policy-blocked server, a one-time notification says so and names where the rule came from. When the policy comes from an administrator, the section says “Managed by your administrator”.

Mapping from VS Code policy

If you already administer VS Code’s MCP settings, the vocabulary carries over:

VS CodePosit Assistant
chat.mcp.access: "all" / "registry" / "none"mcp.access: "all" / "plugins" (plus plugins.strictKnownMarketplaces) / "none" — plus a fourth rung, "allowlist"
allowedMcpServersmcp.allow (same {serverName} / {serverUrl} / {serverCommand} shapes)
deniedMcpServersmcp.deny (takes precedence over allow, same as VS Code)
allowManagedMcpServersOnlymcp.access: "plugins"
McpGalleryServiceUrlPlugin marketplace lockdown (plugins.strictKnownMarketplaces)

How It Works

When Posit Assistant starts, it connects to all enabled MCP servers and registers their tools. These tools appear alongside the built-in tools and can be used by the assistant in the same way — you don’t need to reference them explicitly.

Tools from MCP servers are namespaced: mcp__<server-name>__<tool-name>.