> ## Documentation Index
> Fetch the complete documentation index at: https://fentaris.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-server routing

> Aggregate multiple MCP servers behind one proxy.

> Expose multiple upstream MCP servers through one Fentaris endpoint.

Use multi-server routing when teams ship separate MCP servers but clients should connect to a single proxy. Fentaris keeps tool names, policy, credentials, and observability centralized.

## Quick Start

Declare each upstream MCP server with `mcp(...)` and attach it to one `fentaris(...)` proxy.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { fentaris, mcp, stdio, streamableHttp } from "@fentaris/core";

const proxy = fentaris({
  port: 3000,
  path: "/mcp",
  servers: [
    mcp("filesystem", {
      transport: stdio({
        command: "npx",
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/srv/shared"],
      }),
    }),
    mcp("diagnostics", {
      transport: stdio({ command: "diagnostics-mcp-server" }),
    }),
    mcp("analytics", {
      transport: streamableHttp({ url: "https://analytics.internal/mcp" }),
    }),
  ],
});
```

Keep server names stable across environments. Tool names are derived from the server name, so clients may depend on prefixes such as `analytics__query`.

## List Tools Across Servers

Fentaris prefixes tool names with the upstream server name to avoid collisions.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const tools = await proxy.listTools();
```

This lets different teams expose similar tool names without sharing one server process. For example, `billing__create_invoice` and `support__create_ticket` can live behind the same public endpoint.

## Add Per-server Environment

Use `env` on `mcp(...)` to inject trusted values into a local stdio server.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const proxy = fentaris({
  servers: [
    mcp("analytics", {
      transport: stdio({ command: "analytics-mcp-server" }),
      env: (user) => ({
        TENANT_ID: user.tenantId ?? "unknown",
      }),
    }),
  ],
});
```

Use environment injection for tenant identifiers and deployment-owned secrets. Do not copy client-provided values into env without validation.

## Route By Group

Use `group(...)` to expose different upstream MCP servers to different callers.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { fentaris, group, mcp, policy, stdio, user } from "@fentaris/core";

const proxy = fentaris({
  groups: [
    group({
      id: "support",
      users: [user("alice")],
      servers: [
        mcp("support", {
          transport: stdio({ command: "support-mcp-server" }),
        }),
      ],
      policy: policy("support").mcp("support").allow("*"),
    }),
    group({
      id: "analysts",
      users: [user("bob")],
      servers: [
        mcp("analytics", {
          transport: stdio({ command: "analytics-mcp-server" }),
        }),
      ],
      policy: policy("analysts").mcp("analytics").allow("query"),
    }),
  ],
});
```

Group-scoped servers reduce accidental discovery. A caller only sees tools from servers available to their resolved subject.

## Add Server-specific Middleware

Use server handles when validation only applies to one upstream MCP server. Inside a group handle, `server(name)` scopes middleware to subjects in that group and that upstream server.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
proxy.group("analysts").server("analytics").use(async (ctx, next) => {
  if (!ctx.subject?.hasGroup("analysts")) {
    return ctx.deny("Analytics tools require the analysts group.");
  }

  ctx.log.info("analytics.allowed", {
    subject: ctx.subject.id,
  });

  return next();
});
```

Use `proxy.mcp("analytics")` for server-wide middleware, and prefer scoped handles over global middleware when the rule only applies to one domain.

## Separate Concerns By Server

Small upstream MCP servers make ownership and policy easier to reason about.

* `filesystem` for file operations.
* `analytics` for data access.
* `support` for tickets and workflows.
* `diagnostics` for health checks and runtime inspection.

Use `displayName` for human-friendly UI labels only. Keep the `name` stable for tool prefixes, policy, logs, and client expectations.

## Low-Level API

The class constructors remain available for compatibility and advanced embedding. Prefer declaration helpers for new applications.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { McpProxy, McpServer, StdioTransport } from "@fentaris/core";

const analytics = new McpServer({
  name: "analytics",
  transport: new StdioTransport({
    command: "analytics-mcp-server",
  }),
});

const proxy = new McpProxy({
  servers: [analytics],
});
```

## Related Documentation

* [Security](/guides/security)
* [Governance auth](/guides/governance-auth)
* [MCP server reference](/reference/mcp-server)
