> ## 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.

# Extension API

> Public API tiers and supported extension contracts for @fentaris/core.

`@fentaris/core` has three supported API tiers:

* High-level application builders for most apps.
* Advanced low-level APIs for explicit proxy and transport wiring.
* Extension contracts for third-party integrations.

Use `@fentaris/core` as the primary import path. Use `@fentaris/core/extensions` when implementing custom extension contracts and you need names such as `Policy` without colliding with top-level declaration helpers.

Avoid deep imports from `@fentaris/core/dist/*` or source-layout paths. Those paths are package internals and can move during pre-alpha.

## Experimental plugin contracts

Plugin support is experimental and mostly placeholder-only in the current alpha surface. The package exposes the reserved contracts from `@fentaris/core/experimental/plugins`, but Fentaris does not yet provide a working plugin runtime.

What exists today:

* Manifest types.
* Registry contract.
* Loader contract.
* Lifecycle hook contract.
* Capability metadata placeholder.

What does not exist yet:

* Real plugin loading flow.
* Package discovery.
* Activation runtime.
* Permission negotiation.
* Plugin auth integration.
* CLI plugin management.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type {
  PluginCapabilities,
  PluginLifecycleHooks,
  PluginLoader,
  PluginManifest,
  PluginRegistry,
} from "@fentaris/core/experimental/plugins";

class CustomPluginLoader implements PluginLoader {
  async load(name: string): Promise<PluginManifest> {
    return { name, version: "0.0.0" };
  }
}

const capabilities: PluginCapabilities = {
  requiresAuth: true,
  requiredPermissions: ["tools:call"],
};

const lifecycle: PluginLifecycleHooks = {
  async onActivate() {},
};
```

Do not rely on these contracts for production plugin behavior yet. They are a reserved boundary for future work and may change during alpha.

## High-level app builders

Prefer `fentaris()` with declaration helpers for new applications:

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

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

This syntax is the recommended default for application authors because it keeps server, user, group, policy, and credential declarations together.

## Local capability declarations

Use `app.local(name)` for app-owned tools, resources, prompts, and completions. This is the preferred path when the behavior lives inside the Fentaris app and should still use policy, middleware, operation events, logging, and audit metadata.

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

const app = fentaris({
  policy: policy("workspace")
    .mcp("workspace")
    .allow("status")
    .mcp("workspace")
    .allowCapability({ operation: "prompt:get", target: "review_pr", targetKind: "prompt" }),
});

app.local("workspace")
  .tool("status", { inputSchema: { type: "object" } }, async (ctx) => ({
    content: [{ type: "text", text: ctx.auth.authenticated ? "ok" : "anonymous" }],
  }))
  .prompt("review_pr", { arguments: [{ name: "diff" }] }, async (_ctx, params) => ({
    messages: [{ role: "user", content: { type: "text", text: String(params.arguments?.diff ?? "") } }],
  }));
```

Local namespace names must be unique across upstream MCP server names. Policies address local namespaces with `.mcp(name)`.

## Advanced low-level APIs

Use `createProxy()`, `McpProxy`, `McpServer`, and explicit transports when you need direct construction or custom downstream exposure:

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

const proxy = createProxy({
  servers: [
    new McpServer({
      name: "crm",
      transport: new StreamableHttpMcpTransport({
        url: new URL("https://crm.example.com/mcp"),
      }),
    }),
  ],
});

const explicitProxy = new McpProxy({
  servers: [
    new McpServer({
      name: "crm",
      transport: new StreamableHttpMcpTransport({
        url: new URL("https://crm.example.com/mcp"),
      }),
    }),
  ],
});

await explicitProxy.listen(new HttpProxyExposureTransport({ port: 4000 }));
await proxy.start({ port: 3000 });
```

## Extension contracts

Extension authors can implement contracts from `@fentaris/core/extensions`.

### Upstream transport

Custom `FentarisTransport` implementations remain the advanced escape hatch for protocol adapters, external runtimes, or behavior that should be packaged as an MCP server-like transport. For app-owned capabilities, prefer `app.local(name)`.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { FentarisTransport } from "@fentaris/core/extensions";

class CustomTransport implements FentarisTransport {
  async listTools() {
    return { tools: [{ name: "search", inputSchema: { type: "object" as const } }] };
  }

  async callTool() {
    return { content: [{ type: "text" as const, text: "ok" }] };
  }

  async close() {}
}
```

### Downstream exposure transport

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { ProxyExposureHandle, ProxyExposureTransport, ProxyRuntime } from "@fentaris/core/extensions";

class CustomExposure implements ProxyExposureTransport<ProxyExposureHandle> {
  async listen(runtime: ProxyRuntime) {
    runtime.logger.info("custom exposure started");
    return { async close() {} };
  }
}
```

### Policy

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { Policy, PolicyDecision, ToolCallRequest } from "@fentaris/core/extensions";

class CustomPolicy implements Policy {
  readonly name = "custom";

  getPermissions() {
    return [{ tool: "*", effect: "allow" as const }];
  }

  evaluate(request: ToolCallRequest): PolicyDecision {
    return { allowed: request.toolName !== "dangerous" };
  }
}
```

### Registry

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { Registry } from "@fentaris/core/extensions";

class CustomRegistry implements Registry {
  async getUser(userId: string) {
    return { id: userId, plan: "team" };
  }

  async getSecrets() {
    return { token: "redacted" };
  }

  async getTokens() {
    return null;
  }
}
```

### Rate limiter

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { RateLimiter } from "@fentaris/core/extensions";

class CustomRateLimiter implements RateLimiter {
  async consume() {
    return true;
  }

  async checkLimit() {
    return true;
  }

  async recordCall() {}

  async getRemainingCalls() {
    return 99;
  }
}
```

`consume(key)` is the enforcement path used by middleware. Custom limiters and custom `RateLimitStore` implementations should perform the check and increment atomically for each limiter key, for example with a Redis Lua script, transaction, or native atomic counter operation. `checkLimit()` and `recordCall()` remain useful for diagnostics and compatibility, but they are not used for middleware enforcement.

### Logger driver

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { LoggerDriver, LogEntry } from "@fentaris/core/extensions";

class CustomLoggerDriver implements LoggerDriver {
  write(entry: LogEntry): void {
    console.log(entry.level, entry.message);
  }
}
```

### Middleware and events

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import type { Middleware, ProxyEventHandler } from "@fentaris/core/extensions";

const middleware: Middleware = async (ctx, next) => {
  ctx.log.info("operation", { operation: ctx.operation });
  return next();
};

const eventHandler: ProxyEventHandler = ({ ctx, durationMs }) => {
  ctx.log.info("completed", { operation: ctx.operation, durationMs });
};
```

## Import policy

| Tier                                | Import path                                           | Stability                   |
| ----------------------------------- | ----------------------------------------------------- | --------------------------- |
| High-level builders                 | `@fentaris/core`                                      | Public                      |
| Advanced runtime APIs               | `@fentaris/core`                                      | Public advanced             |
| Extension contracts                 | `@fentaris/core/extensions` or top-level type aliases | Public extension            |
| Plugin contracts                    | `@fentaris/core/experimental/plugins`                 | Experimental placeholder    |
| Source files and `dist/*` internals | Deep package paths                                    | Internal compatibility only |
