MCP Proxy Configuration
An organization that already runs its own MCP proxy — a policy engine, a DLP gateway, a vendor proxy — can put it in front of any MCP in the AlienGiraffe Connector catalog. The proxy is configured per catalog MCP, as part of the normal “add an MCP to the catalog” flow: the admin writes the catalog entry so that the proxy is the entrypoint to that MCP. There is no separate, org-wide proxy feature and no proxy switch to turn on.
Lander then enforces it. On the device, the AI client only ever talks to Lander; Lander only ever talks to the entrypoint the catalog entry declares; and the entry declares the proxy. The hop after Lander is the one the admin chose:
AI client → Lander → your MCP proxy → upstream MCP serverFour things follow from this model, and the rest of the page explains each:
- Configuration is per catalog MCP. The proxy run configuration (command and args, or URL and headers) lives on the MCP’s catalog entry. Different MCPs can use different proxies, or none.
- Lander enforces it. Tool calls to a catalog MCP are always carried through the configured entrypoint. There is no fallback to a direct connection or to Lander’s native routing; if the entrypoint cannot be reached the call fails closed.
- Catalog purview. Lander can keep a device to the catalog: in
enforcemode it removes MCPs the Connector has blocked or no longer declares, and it reports any MCP added by hand as an unmanaged change. - Authentication and authorization are inherited. Whatever authN, authZ, RBAC, or permissioning the proxy (and the MCP server behind it) applies is respected as-is. Lander does not replace, add to, or bypass it.
Lander treats your proxy as a regular MCP
Section titled “Lander treats your proxy as a regular MCP”Lander has no concept of a “proxy MCP” as a separate kind of thing. A catalog entry is a catalog entry: it declares an entrypoint (a command to spawn or a URL to connect to), and Lander installs, mirrors, audits, and governs it the same way whether that entrypoint is the vendor’s MCP server or your gateway in front of it. The proxy is simply the MCP, as far as the device is concerned; the upstream server behind it is your proxy’s business.
flowchart LR
subgraph direct["Catalog entry without a proxy"]
direction LR
A1["AI client"] --> L1["Lander<br/>(mirror · audit · tool policy)"] --> M1["MCP server"]
end
subgraph proxied["Catalog entry whose install spec names your proxy"]
direction LR
A2["AI client"] --> L2["Lander<br/>(mirror · audit · tool policy)"] --> P2["Your MCP proxy<br/>(treated as the MCP)"] -.->|"opened by your proxy"| M2["Upstream MCP server"]
end
Everything on the Lander side of the entrypoint is identical in both rows, which is why the proxy gets the full observability surface for free:
| Lander behavior | With your proxy as the entrypoint |
|---|---|
| Identity | The MCP is known by the catalog entry’s slug. Events, logs, and dashboards carry that name, so you can tell which entry (and therefore which proxy configuration) produced a call. |
| Install | The agent’s config is rewritten to point at Lander (lander serve-stdio --proxy <slug> or /stream/proxy/<slug>), with the original entrypoint stored as the upstream. Removing the entry restores the agent’s original config. See lossless restore. |
| Mirroring and audit | Lander records the message it hands to the entrypoint and the message it gets back — the same access.log / query.log records and mcp.tool_call events as any other MCP. |
| Tool policy | allowed_tools / disallowed_tools are applied by Lander before the call is forwarded, and disabled tools are filtered out of tools/list responses. |
| Lifecycle | Approval, auto-install, block, and group access come from the same catalog flags as for any MCP. |
Because observability happens around the entrypoint rather than inside it, you get a complete record of what your proxy was asked and what it answered without the proxy having to emit anything. What happens beyond the proxy — its connection to the upstream server — is outside what Lander can observe (see Security considerations).
Architecture
Section titled “Architecture”Lander proxies in two transports — a per-session stdio subprocess (lander serve-stdio --proxy <name>) and the daemon’s HTTP-stream reverse proxy (/stream/proxy/<name>), as described in MCP mirroring. For a Connector-managed MCP, the thing Lander forwards to is whatever the catalog entry’s install spec says: a command to spawn or a url to connect to. When that spec points at your proxy, the proxy is what Lander spawns or connects to, and the proxy opens the connection to the real MCP server. Lander records the message it hands to the proxy and the message it gets back.
sequenceDiagram participant Client as AI client participant Lander participant Proxy as Your MCP proxy<br/>(catalog entry command / url) participant MCP as Upstream MCP server participant Connector Client->>Lander: JSON-RPC tools/call (stdin or /stream/proxy/<name>) Note over Lander: attribute (LANDER_AGENT_ID / X-Lander-Agent)<br/>check allowed_tools / disallowed_tools<br/>audit: message sent Lander->>Proxy: tools/call Note over Proxy: proxy's own authN / authZ / policy Proxy->>MCP: tools/call MCP-->>Proxy: result Proxy-->>Lander: result Note over Lander: audit: message received<br/>emit event Lander-->>Client: JSON-RPC result Lander->>Connector: POST /v1/devices/events (mcp.tool_call)
The failure path is short. If the step Lander->>Proxy cannot complete — the command does not start, the URL does not answer, or the proxy rejects the session — Lander returns a JSON-RPC error to the client, logs the failure, and reports an event with result = error. It does not open a direct connection to the upstream MCP server, because it has no configuration for one: the only entrypoint it knows is the proxy. See Failure modes.
Configuring the proxy on a catalog entry
Section titled “Configuring the proxy on a catalog entry”Every catalog entry that can be installed on devices carries an install spec. It is the same handful of fields whether the entry points straight at an MCP server or at a proxy in front of one; routing through a proxy is a matter of what you put in them. The fields fall into four groups.
1. Entrypoint: where Lander connects
Section titled “1. Entrypoint: where Lander connects”| Field | Type | Description |
|---|---|---|
install_transport |
stdio | http | sse |
How Lander reaches the entrypoint. Empty means a display-only entry with no install spec. |
install_command |
string | stdio only, required. Executable Lander spawns per MCP session — your proxy binary. Resolved on the device’s PATH or given as an absolute path. |
install_args |
string[] | stdio only. Arguments for the command. For a proxy, this is where you tell it which upstream to launch or route to. |
install_url |
string | http / sse only, required. The URL Lander connects to — your proxy’s endpoint for this MCP. |
The Connector validates the pairing on save: stdio requires install_command; http and sse require install_url; install_headers is rejected on stdio because a stdio process has no HTTP layer; and install fields without a transport are rejected.
2. Credentials: what Lander presents to the entrypoint
Section titled “2. Credentials: what Lander presents to the entrypoint”| Field | Type | Description |
|---|---|---|
install_env |
list | Environment for the spawned process (stdio). Each item is a name plus either a plain value or a secret. |
install_headers |
list | Static HTTP headers sent on every request (http / sse). Each item is a name plus a plain value or a secret, with an optional value_prefix such as Bearer that is prepended to the resolved value. |
A value and a secret reference are mutually exclusive on one item. value_prefix keeps the stored secret a pure credential: rotating a token cannot silently drop the Bearer prefix and leave the proxy returning an opaque 401. Secret handling is covered in Secrets, and what these credentials mean for authentication in Authentication and authorization are inherited.
3. Lander-side governance: what Lander enforces before the call
Section titled “3. Lander-side governance: what Lander enforces before the call”| Field | Type | Description |
|---|---|---|
proxied |
boolean | Whether Lander installs the entry routed through its own mirror on the device, so the agent talks to Lander (lander serve-stdio --proxy <slug> or /stream/proxy/<slug>). Set it for every entry you want observed and governed. The three fields below are delivered to devices only when it is set. |
allowed_tools / disallowed_tools |
string[] | Tool allow/deny policy Lander applies before a call is forwarded. Independent of, and in addition to, any policy your proxy applies; it can only narrow what the proxy would permit. |
capture_payloads |
boolean | Whether the redacted, truncated arguments and result are attached to events. Set it to false to keep payloads out of the Connector. |
4. Lifecycle: who gets it and how
Section titled “4. Lifecycle: who gets it and how”| Field | Type | Description |
|---|---|---|
requires_approval |
boolean | Users must request the MCP and an admin approves it before it installs. |
auto_install |
boolean | Installed on every eligible device without a request. |
blocked |
boolean | Disallowed: hidden from the catalog, never auto-installed, removed from devices in enforce mode. See Catalog purview. |
access_groups |
string[] | Groups whose members may see and request the entry. |
available |
boolean | Hide an entry from users without deleting it. |
The install spec is the same for every device and every user who installs that entry. If you need different proxies, or a proxy for some MCPs and not others, express it in the catalog: one entry per routing. Per-tenant or per-user routing inside your proxy is the proxy’s business; Lander passes the calling agent’s identity (LANDER_AGENT_ID for stdio, X-Lander-Agent for HTTP-stream) so the proxy can make that decision if it wants to.
Where catalog entries are authored
Section titled “Where catalog entries are authored”Entries reach the Connector’s catalog from two sources, and both produce the same install spec in the same desired-state document:
- The admin catalog (database). Created and edited under Admin → MCP Catalog. Editable in the dashboard and through the admin API; this is the source for
install_env, including secret values. - A catalog config file (
mcp.toml). Loaded at Connector start from./mcp.toml, or the path given byA10E_MCP_CONFIG_PATHor the--mcp-configflag. Entries from the file appear read-only (“from mcp.toml”) in the admin catalog. Each[[mcp_server]]must have an[mcp_server.install]block or the Connector refuses to start, and[[mcp_server.install.headers]]is howinstall_headersare declared, withsecret_refpointing at a secrets backend. If a database entry has the sameslugoralias, the database entry wins and the file entry is reported as shadowed.
A file-sourced entry that routes through your proxy looks like this:
[[mcp_server]]slug = "atlassian"name = "Atlassian"transport = "http"auth_type = "none" # the proxy, not the vendor, authenticates the deviceproxied = truedisallowed_tools = ["deleteJiraIssue"]
[mcp_server.install]transport = "http"url = "https://mcp-proxy.corp.example.com/mcp/atlassian"
[[mcp_server.install.headers]]name = "X-Tenant"value = "acme"
[[mcp_server.install.headers]]name = "Authorization"value_prefix = "Bearer "secret_ref = { backend = "file", reference = "/etc/connector/secrets/proxy.json", key = "token" }Example: stdio proxy in front of a stdio MCP
Section titled “Example: stdio proxy in front of a stdio MCP”The admin adds github to the catalog, but instead of naming the GitHub MCP server as the command, names the organization’s gateway binary and tells it to launch GitHub as its upstream. Lander spawns the gateway per session; the gateway spawns and governs the real server.
{ "slug": "github", "name": "GitHub", "install_transport": "stdio", "install_command": "/usr/local/bin/mcp-gateway", "install_args": [ "--policy", "default", "--upstream-name", "github", "--", "npx", "-y", "@modelcontextprotocol/server-github" ], "install_env": [ { "name": "GATEWAY_TENANT", "value": "acme" }, { "name": "GATEWAY_API_KEY", "value": "…", "secret": true }, { "name": "GITHUB_PERSONAL_ACCESS_TOKEN", "value": "…", "secret": true } ], "proxied": true, "disallowed_tools": ["delete_repo", "transfer_repo"], "requires_approval": true}Example: URL proxy in front of a remote MCP
Section titled “Example: URL proxy in front of a remote MCP”The admin adds a remote MCP, but the URL is the organization’s DLP proxy endpoint for it rather than the vendor’s. Lander connects to the proxy; the proxy connects onward. The effective install spec, as delivered to devices, is:
{ "slug": "atlassian", "install_transport": "http", "install_url": "https://mcp-proxy.corp.example.com/mcp/atlassian", "install_headers": [ { "name": "X-Tenant", "value": "acme" }, { "name": "Authorization", "value_prefix": "Bearer ", "secret": true } ], "proxied": true, "auto_install": true}The mcp.toml form above declares the same entry from a file.
Admin flow
Section titled “Admin flow”Adding a proxied MCP is the ordinary catalog flow; the only difference is what goes in the install spec.
- In the Connector dashboard, open Admin → MCP Catalog (
/admin/mcp-catalog) and choose Add entry (or edit an existing one). Writing the catalog requires the org super admin role. - Fill in the display fields (
slug,name, description, category) as for any entry. - Set the install spec so the proxy is the entrypoint: for
stdio,install_commandis your proxy andinstall_argsname the upstream; forhttp/sse,install_urlis your proxy’s endpoint for this MCP. Addinstall_envas the proxy needs and mark credentials Secret. Forhttp/sseentrypoints that need headers, declareinstall_headersin the entry’smcp.tomlsource. - Turn Proxied on so Lander installs the entry routed through its proxy and observes it.
- Set the tool policy (
allowed_tools/disallowed_tools) and lifecycle flags (requires_approval,auto_install). - Save. The Connector validates the spec (for example,
install_headersrequires anhttporssetransport), stores it, writes an administrative audit entry, and bumps the desired-state generation so devices pick up the change on their next poll.
From there, users request and admins approve it exactly as in Install an approved MCP. Changing the proxy for an MCP later is an edit to the same entry; devices converge to the new spec on their next poll.
Secrets
Section titled “Secrets”Credentials for the proxy follow the Connector’s write-only secret handling:
- On write through the admin catalog, an
install_envvalue is submitted as{ "name", "value", "secret": true }. The value goes to the Connector’s secrets registry (the preferred writable backend) and only a reference is stored on the catalog row. Submitting a secret with an empty value keeps the existing reference, which is how an entry is edited without re-entering its credentials. - In an
mcp.tomlentry, a secret is asecret_ref—backend,reference, andkey— pointing at a value in a secrets backend. Do not inline real credentials withvalue. - On read — the admin API and the dashboard — a secret comes back as
{ "name", "has_secret": true }. The value is never echoed back. To rotate it, re-enter it. - At delivery, the Connector resolves secrets server-side when it builds the device’s desired-state document (prepending any
value_prefix), so Lander receives runtime values, never a reference. - On the device, Lander holds the resolved values for the proxy process or request headers; they are not reported in inventory and not included in events.
- Client-specific exposure. Agents with native HTTP MCP support (Claude Code, Gemini CLI, Codex) receive header values in their config file. Claude Desktop reaches HTTP MCPs through
mcp-remote, which receives the value as a command-line argument and so makes it visible topson that device. Prefer a proxy credential that is scoped, short-lived, and revocable.
What Lander enforces on the device
Section titled “What Lander enforces on the device”How Lander receives the configuration
Section titled “How Lander receives the configuration”Lander learns about catalog MCPs through the desired-state call it already makes — GET /v1/devices/desired-state. The document lists, per agent on the device, the MCP entries that should be installed, each with the install spec resolved from its catalog entry. Lander polls it in the lander serve convergence loop; the response is versioned by generation with ETag / 304 Not Modified, and Lander keeps a last-known-good copy. Saving a catalog entry bumps the generation.
{ "generation": 42, "issued_at": "2026-10-06T14:00:00Z", "modes": { "mcp": "enforce", "skill": "enforce" }, "blocked": { "mcp": ["legacy-filesystem"], "skills": [] }, "agents": { "claude-code": { "mcp": [ { "name": "github", "transport": "stdio", "command": "/usr/local/bin/mcp-gateway", "args": ["--policy", "default", "--upstream-name", "github", "--", "npx", "-y", "@modelcontextprotocol/server-github"], "env": { "GATEWAY_TENANT": "acme", "GATEWAY_API_KEY": "<resolved at delivery>", "GITHUB_PERSONAL_ACCESS_TOKEN": "<resolved at delivery>" }, "proxied": true, "disallowed_tools": ["delete_repo", "transfer_repo"], "source": "user" } ], "skills": [] } }}The request is authenticated like every other /v1/devices/* call: TLS to the Connector plus the device certificate and a signature in X-Device-Certificate, X-Device-Timestamp, and X-Device-Signature. The Connector verifies the device before it resolves secrets into the response. See Security & audit.
The device cannot override the configuration locally. There is no flag, environment variable, managed preference, or ~/.lander.json field that re-points a catalog MCP at a different entrypoint. The only source is the catalog entry in the Connector.
Installing and routing
Section titled “Installing and routing”For each desired entry with proxied: true, Lander:
- Writes the agent’s config so the agent talks to Lander, not to the entrypoint —
lander serve-stdio --proxy <name>for stdio, or/stream/proxy/<name>for HTTP-stream — exactly as for any other mirrored MCP. - Stores the entry’s
command/args/envorurl/headersas the upstream Lander itself forwards to. When the catalog entry names your proxy, this is your proxy. - Applies the entry’s
allowed_tools/disallowed_toolsbefore forwarding each call. - Reports the outcome in its converge report (
POST /v1/devices/converge-report) as a result withkind: "mcp",action: "install", andstatusokorfailedwith anerrorstring.
Because the agent only knows about Lander, and Lander only knows about the entrypoint the catalog declares, every tool call to a catalog MCP goes through the configured proxy. There is nothing on the device that could route around it.
Configuration change
Section titled “Configuration change”When a poll returns a new generation whose entry for an MCP differs from what is installed, Lander converges: it reinstalls the entry with the new spec and reports the result. New MCP sessions use the new entrypoint immediately; a stdio proxy process already serving a session runs until that session ends.
If the Connector is unreachable and Lander is working from its last-known-good document, it keeps the last-known-good configuration and does not remove or re-point anything. Losing contact with the Connector never turns a proxied MCP into a direct one.
Failure modes
Section titled “Failure modes”Lander fails closed. Whenever the configured entrypoint cannot carry a call, the call does not go through — not to the proxy and not directly to the upstream MCP server. There is no native or direct fallback, because none is configured.
| Situation | What Lander does |
|---|---|
http / sse entrypoint does not answer, refuses the connection, or times out |
Returns a JSON-RPC error to the client; emits an event with result = error and the transport error in error_message. |
stdio command is missing, not executable, or exits before accepting the first message |
Same: JSON-RPC error to the client, result = error event with the spawn error. |
| The proxy rejects the session or call (its own authN / authZ) | Lander forwards the proxy’s JSON-RPC error to the client unchanged and records the exchange; the proxy’s decision stands. |
What the AI client sees. A JSON-RPC error for the request it made, which the agent surfaces the way it surfaces any failed tool call. The MCP’s tool list may still be visible; every call on it fails until the entrypoint is healthy.
What the user sees. A line in the daemon log (~/.lander/logs/service.err) and in the per-MCP access.log naming the MCP and the error.
What the Connector sees. One observability event per failed call, in the existing event shape, with result = error and error_message carrying the transport or spawn error:
{ "event_time": "2026-10-06T14:02:11Z", "agent_type": "claude-code", "mcp_name": "github", "tool": "list_issues", "event_type": "mcp.tool_call", "result": "error", "error_message": "dial tcp 10.0.4.12:443: connection refused"}The Error tile and the result filter in Observability → Events (/admin/observability/events) show how much traffic an outage blocked, on which devices, for which MCPs.
Catalog purview: keeping devices to the catalog
Section titled “Catalog purview: keeping devices to the catalog”Two settings decide how far Lander goes in keeping a device to the catalog. Both are set in the Connector and delivered in the desired-state document.
- Convergence mode (
modes.mcp, set fleet-wide in the Connector at/v1/admin/fleet/converge-modewith a per-device override at/v1/admin/devices/{id}/converge-mode). Inreport-only, Lander computes the actions needed to match the catalog and reports them withstatus: "planned"but does not execute them. Inenforce, Lander executes them: it installs declared entries, removes any MCP the Connector lists underblocked, and removes Lander-managed MCPs the Connector no longer declares. A user-initiated install or removal that already passed the Connector’s authorization converges in either mode. - Blocked entries (
blockedon the catalog entry). A blocked MCP is hidden from the user catalog, never auto-installed, and removed from devices that have it. Blocking is how an admin forbids a specific MCP outright.
An MCP that someone adds by hand, outside the catalog — editing ~/.claude.json, say — is not something Lander installed and not something the catalog declares. Lander detects the edit through file-watching and reports it as an unmanaged change to the audit log, and the device’s compliance view (/v1/admin/devices/{id}/compliance) lists it under unmanaged until it is removed or brought into the catalog. If the hand-added MCP matches a blocked entry, enforce mode removes it. Together these let an organization require that every MCP on a device be a catalog MCP — and therefore one whose routing, including any proxy, the admin chose. See Audit & compliance.
Authentication and authorization are inherited
Section titled “Authentication and authorization are inherited”Lander adds no authentication or authorization layer of its own between the agent and the MCP. Routing through Lander does not replace the proxy’s login, re-issue its tokens, or widen what a caller may do. The guarantee has four parts:
- Credentials pass through untouched. What the admin put in
install_envorinstall_headersis handed to the proxy process or sent on each request, and Lander does nothing else with it. On the HTTP-stream path Lander is a reverse proxy: request headers reach the entrypoint as sent, and the entrypoint’s response — status, headers, and body — comes back to the client as sent. - The proxy’s decision stands. A call the proxy rejects is rejected: Lander returns the proxy’s error to the client and records it. It does not retry around the proxy, re-authenticate on the agent’s behalf, or re-route to the upstream.
- Lander can only narrow. A call the proxy allows is allowed as far as the proxy is concerned. Lander’s only independent gate is the catalog entry’s
allowed_tools/disallowed_toolspolicy, which runs before the call reaches the proxy and can only narrow, never widen, what the proxy would permit. - Identity is offered, not imposed. The calling agent’s identity is available to the proxy (
LANDER_AGENT_IDorX-Lander-Agent) if its authorization wants it, but Lander does not require the proxy to use it.
Credential layers
Section titled “Credential layers”Three separate credentials can be involved on a proxied call. Lander touches only the first, and only to deliver it.
| Layer | Who holds it | What Lander does |
|---|---|---|
| Device → proxy | The credential the proxy requires from this device or tenant: a bearer token, API key, or tenant header, set in install_env / install_headers. |
Resolved by the Connector at delivery, held by Lander, and presented to the proxy on every session or request. |
| User → proxy | A per-user credential the proxy demands, such as an OAuth login the proxy runs itself. | Nothing. The proxy’s challenge and the client’s answer travel through Lander as ordinary traffic; Lander does not terminate, mint, or cache the user’s token. |
| Proxy → upstream | Whatever the proxy uses to reach the real MCP server. | Nothing. This hop belongs entirely to the proxy; Lander neither sees nor holds that credential. |
Flow: static credential from the catalog
Section titled “Flow: static credential from the catalog”The common case. The proxy needs a credential that identifies the organization or device, so the admin puts it in the catalog entry and the Connector delivers it. Lander never sees the secret in a reference form and the agent never needs it.
sequenceDiagram
participant Admin as Admin (Connector dashboard)
participant Connector
participant Secrets as Secrets backend
participant Lander
participant Client as AI client
participant Proxy as Your MCP proxy
participant MCP as Upstream MCP server
Admin->>Connector: Save catalog entry (install spec + secret credential)
Connector->>Secrets: Store credential, keep only a reference
Lander->>Connector: GET /v1/devices/desired-state (device-signed)
Connector->>Secrets: Resolve reference (+ value_prefix)
Connector-->>Lander: Entry with runtime credential
Client->>Lander: tools/call (no proxy credential needed)
Lander->>Proxy: tools/call + credential (env or Authorization header)
Note over Proxy: authenticates the device / tenant<br/>applies its own authZ and policy
alt proxy accepts
Proxy->>MCP: tools/call (proxy's own upstream credential)
MCP-->>Proxy: result
Proxy-->>Lander: result
Lander-->>Client: result
else proxy rejects
Proxy-->>Lander: JSON-RPC / HTTP error
Lander-->>Client: error, unchanged
end
Flow: the proxy authenticates the user itself
Section titled “Flow: the proxy authenticates the user itself”When the proxy runs its own interactive login (for example an OAuth authorization the user completes), Lander is a transparent hop. The challenge reaches the client exactly as the proxy issued it, the user completes the proxy’s flow, and the client then presents what it obtained on later calls. Lander adds nothing to the exchange and does not hold the user’s token.
sequenceDiagram participant User participant Client as AI client participant Lander participant Proxy as Your MCP proxy participant IdP as Proxy's identity provider participant MCP as Upstream MCP server Client->>Lander: tools/call Lander->>Proxy: tools/call (as sent) Proxy-->>Lander: 401 + authorization challenge Lander-->>Client: 401 + challenge (relayed unchanged) Note over Lander: records the exchange; no retry,<br/>no fallback to the upstream Client->>User: Open proxy's sign-in User->>IdP: Authenticate and consent IdP-->>Client: Token for the proxy Client->>Lander: tools/call + token Lander->>Proxy: tools/call + token (as sent) Proxy->>MCP: tools/call (proxy's upstream credential) MCP-->>Proxy: result Proxy-->>Lander: result Lander-->>Client: result
How the client completes a challenge depends on the agent and on whether it reaches the MCP through its native HTTP support or through mcp-remote; that is client behavior, not something Lander changes. Test the sign-in once from each agent you support before rolling an OAuth-protected proxy out to a fleet.
Flow: authorization denied by the proxy
Section titled “Flow: authorization denied by the proxy”The proxy’s RBAC says this user may not call this tool. Lander applied its own tool policy first, forwarded the call, and returns the proxy’s refusal as the answer. Both sides are recorded, so the denial is visible in the Connector without the proxy having to report it.
sequenceDiagram participant Client as AI client participant Lander participant Proxy as Your MCP proxy participant Connector Client->>Lander: tools/call delete_project Note over Lander: allowed_tools / disallowed_tools: pass<br/>audit: message sent to proxy Lander->>Proxy: tools/call delete_project Note over Proxy: RBAC: caller may not call this tool Proxy-->>Lander: JSON-RPC error (forbidden) Note over Lander: audit: message received (the proxy's error) Lander-->>Client: JSON-RPC error, unchanged Lander->>Connector: POST /v1/devices/events (mcp.tool_call, result = error)
A call that Lander’s own policy denies never reaches the proxy; it is rejected locally with a denied result, and the proxy sees nothing.
What does not change
Section titled “What does not change”| Concern | Without Lander in the path | With Lander in the path |
|---|---|---|
| Who authenticates the caller | The proxy | The proxy |
| Token and credential format the proxy accepts | Whatever the proxy defines | The same; value_prefix and headers are how the admin supplies it |
| Who decides which tools a caller may use | The proxy’s RBAC | The proxy’s RBAC, optionally narrowed by disallowed_tools |
| What the upstream sees | What the proxy sends | The same; Lander is not on that hop |
| Where authentication failures surface | To the client | To the client, unchanged, and as an event in the Connector |
Observability
Section titled “Observability”Because Lander treats the proxy as a regular MCP, nothing about the event model changes. Every event Lander reports carries mcp_name, the agent, the device, and the tool, exactly as for an MCP without a proxy, so the catalog entry — and with it the proxy configuration in effect — is identifiable from the MCP name. The dashboards under Observability and MCP Servers aggregate proxied and unproxied MCPs alike.
Payload capture is unchanged: unless the catalog entry opts out with capture_payloads: false, metadata.arguments and metadata.result hold the redacted, truncated payloads Lander sent to and received from the proxy. The local query.log carries the same two sides in full, subject to the redaction controls.
Security considerations and trust boundary
Section titled “Security considerations and trust boundary”Putting a proxy in the path moves part of the trust boundary. Be explicit about what changes:
- The proxy sees and can alter MCP traffic. Everything Lander forwards — tool names, arguments, results, and any upstream credentials carried in
install_envorinstall_headers— is visible to the proxy, and the proxy can modify, delay, or drop it before it reaches the upstream server or on the way back. - Lander audits both sides. For every call it records the message it sent to the proxy and the message it received back. For
stdio, that is what Lander wrote to the proxy’s stdin and read from its stdout; forhttp/sse, the request body it sent and the response body it received. Those two records are what Alien Giraffe can vouch for. - What Alien Giraffe vouches for: that the configuration in effect is the catalog entry the organization’s super admin wrote (it comes only from the Connector over the device-authenticated channel, and every change is in the administrative audit log); that the events and logs reflect what Lander observed on both sides of the proxy; and that no device-local setting can re-point a catalog MCP.
- What Alien Giraffe cannot vouch for: what the proxy does on its connection to the upstream server; the proxy’s own logging, retention, or onward disclosure of the traffic it sees; or that the response the upstream server produced reached Lander unmodified. Those are properties of the proxy and are the proxy operator’s responsibility.
- Secrets. Credentials in
install_env/install_headersare write-only in the Connector and resolved only into the device’s desired-state response. Upstream credentials now transit the proxy; treat the proxy as a secret-handling system in your threat model. - Fail closed is a security property. An outage of the proxy blocks that MCP’s traffic rather than bypassing the control the organization chose. If a bypass is ever acceptable, the admin expresses it by editing the catalog entry to point at the upstream directly — a change that is itself audited and that reaches devices on the next poll.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | What to check / fix |
|---|---|---|
| Every call to one MCP fails with a connection error and the Error tile climbs across many devices | The install_url proxy is down or unreachable from endpoints |
Reach the URL from an affected device; check the proxy’s health and firewall rules for the endpoint network. Filter events on result = error and the MCP name to list affected devices. |
| Spawn errors on a subset of devices | install_command is not installed, not executable, or at a different path on those devices |
Ship the proxy binary with your MDM to the configured path, or use a PATH-resolvable name. The converge report for the device shows the install error. |
| Authentication errors right after rotating a credential | Devices still hold the old resolved value, or the proxy rejects the new one | Confirm the proxy accepts the new credential directly. Saving the entry bumps the generation, so devices refresh on their next poll. |
| Calls to an MCP produce no events | The catalog entry has proxied off, so the agent talks to the entrypoint directly |
Turn Proxied on for the entry; Lander reinstalls it routed through its proxy on the next poll. |
| A hand-added MCP keeps working outside the proxy | It is not a catalog MCP, so no catalog routing applies | It appears as an unmanaged change in the audit log and under unmanaged in the device’s compliance view. Add a blocked entry for it and run the fleet in enforce mode, or bring it into the catalog with the right install spec. |
Dashboard shows has_secret but you need to see the value |
Secrets are write-only by design | Re-enter the value; the Connector never returns it. |
| A device seems to have reverted to direct routing after a Connector outage | It did not — a last-known-good document keeps the installed configuration | If events are missing, the device may never have completed a poll with the current generation. Check registration and connectivity. |
Endpoint reference
Section titled “Endpoint reference”Admin endpoints are organization-scoped and live under /v1/admin/... (the dashboard calls them as /api/admin/...). Reading requires an org admin; writing requires the org super admin role.
| Method | Path | Result |
|---|---|---|
GET |
/v1/admin/mcp-catalog |
The organization’s catalog entries including each install spec. Secret values in install_env / install_headers are returned as { "name", "has_secret": true }. |
POST / PATCH |
/v1/admin/mcp-catalog (create) and /v1/admin/mcp-catalog/{id} (update) |
Create or update an entry, including install_transport, install_command, install_args, install_url, install_env, proxied, tool policy, and lifecycle flags. install_headers entries are declared in the mcp.toml catalog source. Secret values are submitted as { "name", "value", "secret": true }. On success bumps the desired-state generation and writes an administrative audit entry. Org super admin only. |
GET |
/v1/devices/desired-state |
Device-authenticated. Per-agent MCP entries with the install spec resolved from the catalog, proxied, tool policy, and source; plus modes and blocked. ETag is the generation; If-None-Match yields 304. |
POST |
/v1/devices/converge-report |
Device-authenticated. Lander reports one result per action with kind: "mcp", action install or remove, status ok, failed, or planned, and error when the install failed. |
GET |
/v1/admin/devices/{id}/compliance |
Desired versus observed MCPs for a device, including the unmanaged list of MCPs present on the device that no catalog entry declares. |
POST |
/v1/devices/events |
Device-authenticated. Unchanged route; a failed hop to the proxy is reported with result = error and error_message. |
Related reading: MCP mirroring for the on-device proxy, Install an approved MCP for the request and approval flow, Observability events for the event model, and Security & audit for device identity and redaction.