# Connecting Remote MCP Servers to Flue Agents with Authentication

> Easily connect remote MCP servers to Flue agents using the connectMcpServer helper. Secure your connections with bearer tokens and inject tools into your agent harness.

- Repository: [Astro/flue](https://github.com/withastro/flue)
- Tags: how-to-guide
- Published: 2026-05-11

---

**Use the `connectMcpServer` helper from `@flue/sdk/client` to establish authenticated connections to remote Model Context Protocol (MCP) servers, passing bearer tokens via the `headers` option and injecting discovered tools into your agent harness through `init({ tools })`.**

Flue agents extend their capabilities by consuming tools hosted on remote MCP servers. According to the withastro/flue source code, the SDK provides a dedicated connection helper that handles transport negotiation, header injection, and tool discovery, enabling secure authenticated integrations with external tool providers.

## How the Flue SDK Handles MCP Authentication

The authentication flow centers on the `McpServerOptions` interface defined in [`packages/sdk/src/mcp.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/mcp.ts) (lines 8‑14). This configuration object accepts a `headers` field that allows you to inject any HTTP headers—including `Authorization` bearer tokens—into every request sent to the remote MCP server.

### Header Injection and Merging

When you provide custom headers, the SDK merges them with any existing `requestInit` configuration using the internal `mergeRequestInit` utility (lines 13‑22 in [`packages/sdk/src/mcp.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/mcp.ts)). This ensures your authentication tokens take precedence while preserving additional fetch options you might specify.

```typescript
// From mcp.ts - merges headers ensuring auth tokens are preserved
const mergedInit = mergeRequestInit(
  { headers: { Authorization: `Bearer ${env.TOKEN}` } },
  userProvidedInit
);

```

The `connectMcpServer` function (lines 25‑55) then uses these merged options to build the transport layer, negotiate the connection, and return a `McpServerConnection` object containing the discovered tools.

## Step-by-Step Implementation

### 1. Configure the Connection with Environment Variables

Never hardcode secrets. Instead, access tokens through the `env` object available in your Flue agent function. Call `connectMcpServer` with a descriptive name and the remote URL:

```typescript
// .flue/agents/github-assist.ts
import { connectMcpServer } from '@flue/sdk/client';

const github = await connectMcpServer('github', {
  url: 'https://mcp.github.com/mcp',
  headers: {
    Authorization: `Bearer ${env.GITHUB_TOKEN}`, // Securely injected
  },
});

```

### 2. Initialize the Harness with Remote Tools

The connection object exposes a `tools` array containing the remote MCP tools formatted for Flue's harness system. Pass these to the `init` function alongside your model configuration:

```typescript
const harness = await init({
  model: 'anthropic/claude-sonnet-4-6',
  tools: github.tools, // Remote tools become available to the LLM
});

```

### 3. Cleanup Resources After Execution

Remote connections hold active HTTP sessions and SSE streams. Always close the connection in a `finally` block to prevent resource leaks:

```typescript
try {
  const session = await harness.session();
  return await session.prompt(payload.prompt);
} finally {
  await github.close(); // Releases underlying client resources
}

```

## Transport Protocol Options

### Streamable HTTP (Default)

The modern **streamable‑http** transport is the default in Flue. It uses standard HTTP requests with streaming response bodies for efficient bidirectional communication. This mode works automatically when you omit the `transport` option or set it explicitly to `'streamable-http'`.

### Legacy SSE Mode

For older MCP servers that require Server-Sent Events, force the transport by setting `transport: 'sse'` in your options:

```typescript
const legacy = await connectMcpServer('legacy-server', {
  url: 'https://old-mcp.example.com/sse',
  transport: 'sse',
  headers: { Authorization: `Bearer ${env.TOKEN}` },
});

```

## Advanced Configuration

Pass additional fetch parameters through the `requestInit` option. These are merged with your authentication headers via the internal `mergeRequestInit` logic:

```typescript
const github = await connectMcpServer('github', {
  url: 'https://mcp.github.com/mcp',
  headers: { Authorization: `Bearer ${env.GITHUB_TOKEN}` },
  requestInit: { 
    mode: 'cors',
    cache: 'no-store' 
  },
});

```

## Complete Working Example

Here is the canonical implementation from the withastro/flue repository demonstrating secure authentication and proper resource management:

```typescript
// .flue/agents/github-assist.ts
import { connectMcpServer, type FlueContext } from '@flue/sdk/client';

export const triggers = { webhook: true };

export default async function ({ init, payload, env }: FlueContext) {
  // Establish authenticated connection
  const github = await connectMcpServer('github', {
    url: 'https://mcp.github.com/mcp',
    headers: {
      Authorization: `Bearer ${env.GITHUB_TOKEN}`,
    },
  });

  try {
    // Initialize harness with remote tools
    const harness = await init({
      model: 'anthropic/claude-sonnet-4-6',
      tools: github.tools,
    });

    // Execute agent logic
    const session = await harness.session();
    return await session.prompt(payload.prompt);
  } finally {
    // Critical: Release connection resources
    await github.close();
  }
}

```

## Key Source Files

- **[`packages/sdk/src/mcp.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/mcp.ts)** – Core implementation of `connectMcpServer`, transport selection, and the `mergeRequestInit` utility (lines 8‑55).
- **[`packages/sdk/src/client.ts`](https://github.com/withastro/flue/blob/main/packages/sdk/src/client.ts)** – Public API surface that re‑exports `connectMcpServer` for convenient importing (lines 59‑62).
- **[`README.md`](https://github.com/withastro/flue/blob/main/README.md)** – Canonical usage examples in the "Remote MCP Tools" section (lines 93‑124).

## Summary

- **`connectMcpServer`** handles transport negotiation, authentication header injection, and tool discovery in a single async call.
- **Authentication tokens** pass securely through the `headers` field of `McpServerOptions`, merged via `mergeRequestInit` to preserve precedence.
- **Remote tools** integrate seamlessly into the Flue harness by passing the `tools` array from the connection to `init({ tools })`.
- **Resource management** requires explicit `close()` calls to terminate underlying HTTP clients and SSE connections.
- **Environment variables** (`env`) provide the secure mechanism for accessing secrets without exposing them in code.

## Frequently Asked Questions

### How do I securely store authentication tokens for MCP servers?

Store sensitive tokens as environment variables in your Flue project configuration. The `env` object injected into every agent function provides secure runtime access to these values. Never commit credentials to your repository or hardcode them in agent files.

### What transport protocols does Flue support for MCP connections?

Flue supports **streamable-http** (modern default) and **sse** (legacy Server-Sent Events). The SDK automatically negotiates the appropriate transport unless you explicitly override it via the `transport` option in `McpServerOptions`.

### Can I combine remote MCP tools with local custom tools?

Yes. The `tools` array accepted by `init()` accepts any combination of remote tools (from `connectMcpServer`) and local tool definitions. You can merge multiple remote connections and local implementations into a single tools array passed to the harness.

### How do I handle connection errors and retries?

Wrap `connectMcpServer` calls in try-catch blocks to handle network failures. The underlying MCP client throws descriptive errors for connection timeouts, authentication failures (401/403), and transport negotiation issues. Implement retry logic around the initial connection call if your use case requires high availability.