Skip to main content
This tutorial starts from a generated Fentaris project and turns it into a proxy for two upstream MCP servers. The app code keeps runtime endpoint settings in fentaris.json and declares upstream servers with app.mcp(...).

Quick Start

Use the optional agent skills when you want an agent to ask setup questions, choose upstream MCP servers, and validate the project after edits:
Then restart or reload your agent and ask it to use the setup skill:
If you prefer to build the tutorial manually, create a project with the CLI:

Step 1: Configure the Runtime Endpoint

fentaris init writes fentaris.json. Keep endpoint settings there instead of hardcoding them in src/index.ts:
When app.start() runs without explicit options, @fentaris/core searches upward from the current working directory and reads the nearest fentaris.json. With the config above, the local endpoint is http://localhost:4000/mcp.
Change port or path in fentaris.json when the local endpoint needs to move. Keep src/index.ts focused on proxy behavior.

Step 2: Create the App Boundary

Open src/index.ts and start with an empty Fentaris app:
fentaris() creates the proxy application boundary. Project discovery, host, port, and path come from fentaris.json, while upstream MCP servers are attached with app.mcp(...). Policy.allowAll() keeps this local tutorial focused on routing; replace it with an allow-list policy before sharing the endpoint.

Step 3: Attach the Filesystem Server

Create a local directory that the filesystem MCP server can expose:
Then register the upstream MCP server:
app.mcp("filesystem", ...) gives the upstream server a stable Fentaris name. Fentaris uses that name when routing tool calls, applying middleware, logging events, and exposing proxied tool names such as filesystem__read_file.

Step 4: Attach a Remote Server

Add the public MCP specification server as a second upstream:
The specification server requires network access. The filesystem server remains local, so you can still start the proxy and test local routing if the remote server is unavailable.

Step 5: Add Global Middleware

Middleware runs after Fentaris builds request context and before the matching upstream MCP server receives the call:
Use middleware for runtime checks that depend on request data, tool arguments, tenant state, or an approval workflow. For static allow-list access, use policy rules.

Step 6: Add a Server Hook

Server-scoped handles keep observability close to the upstream MCP server they describe:
This hook only observes successful tool calls for the specification upstream MCP server. It does not affect filesystem calls and does not replace middleware or policy decisions.

Step 7: Start the Proxy

Finish src/index.ts with app.start():
The complete entrypoint should look like this:
Run the proxy:

Step 8: Connect a Client

Point your MCP client to the endpoint from fentaris.json:
Fentaris exposes one MCP endpoint and routes each request to the matching upstream MCP server. The client talks to Fentaris; Fentaris starts or connects to upstream MCP servers, applies policy and middleware, forwards allowed calls, and records hooks and logs.

Validate the Project

Run static project checks before sharing the endpoint:
When the proxy is running, verify the runtime endpoint:
The tutorial is suitable for local development. Add authentication and allow-list policies before exposing a Fentaris endpoint outside your machine.

What You Built

You now have:
  • one Fentaris endpoint configured by fentaris.json
  • two upstream MCP servers declared with app.mcp(...)
  • global middleware for logging and request-time denial
  • a server-scoped hook for remote upstream observability