# Understanding the Relationship Between MetaMCP Endpoints and Namespaces

> Discover how MetaMCP endpoints use UUID references to bind to namespaces. Learn about the logic ensuring public endpoints stay within public namespaces and improve your understanding of metatool-ai/metamcp.

- Repository: [metatool-ai/metamcp](https://github.com/metatool-ai/metamcp)
- Tags: deep-dive
- Published: 2026-03-07

---

**MetaMCP endpoints are permanently bound to a single namespace through a UUID reference, with business logic enforcing that public endpoints can only reside in public namespaces.**

The metatool-ai/metamcp repository implements a strict hierarchical relationship between MetaMCP endpoints and namespaces. Every endpoint record stores a `namespaceUuid` field that permanently associates it with its parent namespace, enabling consistent routing, permission enforcement, and visibility control throughout the system.

## The Data Model: Storing Namespace References in Endpoints

### Schema Definition in endpoints.zod.ts

The foundation of the relationship is defined in [`packages/zod-types/src/endpoints.zod.ts`](https://github.com/metatool-ai/metamcp/blob/main/packages/zod-types/src/endpoints.zod.ts), where every endpoint schema includes a required `namespaceUuid` field. At line 12, the base schema defines `namespaceUuid: z.string().uuid()`, and this field propagates through all schema variations at lines 37, 61, and 134. This ensures that every endpoint creation, update, or retrieval operation must include a valid namespace UUID.

## Business Logic Enforcement

### Visibility Rules in endpoints.impl.ts

The implementation in [`apps/backend/src/trpc/endpoints.impl.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/trpc/endpoints.impl.ts) enforces strict visibility consistency between endpoints and their namespaces. At line 63, the code validates that "public endpoints can only use public namespaces," throwing an error if a user attempts to create a public endpoint in a private namespace. This same guard appears at line 321 during update operations, preventing existing public endpoints from being moved into private namespaces.

### Middleware Resolution in lookup-endpoint-middleware.ts

When processing incoming requests, [`apps/backend/src/middleware/lookup-endpoint-middleware.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/middleware/lookup-endpoint-middleware.ts) resolves the endpoint and injects its namespace UUID into the request context. At line 28, the middleware executes `authReq.namespaceUuid = endpoint.namespace_uuid;`, making the namespace identifier available to all downstream handlers for permission checks and routing decisions.

## Runtime Routing and Proxy Behavior

### Public MetaMCP Routes in streamable-http.ts

The public-facing proxy routes utilize the namespace relationship for session management. In [`apps/backend/src/routers/public-metamcp/streamable-http.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/streamable-http.ts), lines 117 and 128 extract the `namespaceUuid` from the authenticated endpoint and include it in session logs and context, ensuring that all traffic is properly attributed to its parent namespace.

### Namespace-Level MCP Proxy in metamcp.ts

The architecture routes all endpoint traffic through its parent namespace. The proxy endpoint at [`apps/backend/src/routers/mcp-proxy/metamcp.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/mcp-proxy/metamcp.ts) line 87 defines the route `/mcp-proxy/metamcp/:uuid`, where `:uuid` represents the namespace identifier. Endpoints are never accessed in isolation; they are always reached through their owning namespace's proxy endpoint.

## Practical Code Examples

### Creating an Endpoint with Namespace Binding

When creating an endpoint via the TRPC client, you must specify the `namespaceUuid`:

```typescript
import { createTRPCClient } from '@trpc/client';
import type { AppRouter } from '@metamcp/trpc';

const client = createTRPCClient<AppRouter>({
  url: '/trpc',
});

await client.mutation('endpoints.create', {
  name: 'weather-api',
  description: 'Expose weather data',
  // The namespace this endpoint belongs to
  namespaceUuid: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
});

```

The `namespaceUuid` field is validated by the Zod schema in [`packages/zod-types/src/endpoints.zod.ts`](https://github.com/metatool-ai/metamcp/blob/main/packages/zod-types/src/endpoints.zod.ts) (lines 12-14).

### Resolving Namespace Context in Middleware

After the lookup middleware processes a request, the namespace UUID is available in the authentication context:

```typescript
// In a request handler after the lookup-endpoint middleware
export async function handleEndpointMcp(req: Request) {
  // namespaceUuid is injected by the middleware (see line 28)
  const nsUuid = req.authReq.namespaceUuid;

  // Fetch namespace configuration for permission checks
  const namespace = await namespacesRepository.findByUuid(nsUuid);
  // Enforce namespace-level policies or route to the correct MCP server
}

```

### Enforcing Visibility Constraints

The backend prevents visibility mismatches between endpoints and namespaces:

```typescript
if (input.public && namespace.private) {
  throw new PermissionError(
    `Public endpoints can only use public namespaces. Namespace "${namespace.name}" is private`,
  );
}

```

This validation appears at line 63 of [`apps/backend/src/trpc/endpoints.impl.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/trpc/endpoints.impl.ts) for creation operations and line 321 for updates.

## Key Files Reference

| File | Role |
|------|------|
| [`packages/zod-types/src/endpoints.zod.ts`](https://github.com/metatool-ai/metamcp/blob/main/packages/zod-types/src/endpoints.zod.ts) | Zod schema defining the `namespaceUuid` field for all endpoint records. |
| [`apps/backend/src/trpc/endpoints.impl.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/trpc/endpoints.impl.ts) | Business logic enforcing visibility rules between endpoints and namespaces. |
| [`apps/backend/src/middleware/lookup-endpoint-middleware.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/middleware/lookup-endpoint-middleware.ts) | Middleware that resolves endpoints and injects `namespaceUuid` into request context. |
| [`apps/backend/src/routers/public-metamcp/streamable-http.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/streamable-http.ts) | Public proxy routes utilizing namespace UUID for session management. |
| [`apps/backend/src/routers/mcp-proxy/metamcp.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/mcp-proxy/metamcp.ts) | Namespace-level MCP proxy router where endpoints are accessed via their parent namespace. |
| [`apps/backend/src/trpc/namespaces.impl.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/trpc/namespaces.impl.ts) | Namespace data access and permission helpers used by endpoint logic. |

## Summary

- **Every endpoint stores a `namespaceUuid`** in its data model, creating a permanent parent-child relationship defined in [`packages/zod-types/src/endpoints.zod.ts`](https://github.com/metatool-ai/metamcp/blob/main/packages/zod-types/src/endpoints.zod.ts).
- **Visibility rules are strictly enforced**: public endpoints can only exist in public namespaces, with validation occurring in [`apps/backend/src/trpc/endpoints.impl.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/trpc/endpoints.impl.ts) at lines 63 and 321.
- **Runtime resolution injects the namespace UUID** into request contexts via [`apps/backend/src/middleware/lookup-endpoint-middleware.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/middleware/lookup-endpoint-middleware.ts) (line 28), enabling downstream permission checks.
- **All endpoint traffic routes through the parent namespace**, whether via public MetaMCP streams or the namespace-level MCP proxy at `/mcp-proxy/metamcp/:uuid`.

## Frequently Asked Questions

### Can an endpoint exist without a namespace in MetaMCP?

No. The Zod schema in [`packages/zod-types/src/endpoints.zod.ts`](https://github.com/metatool-ai/metamcp/blob/main/packages/zod-types/src/endpoints.zod.ts) requires every endpoint to have a `namespaceUuid` field (lines 12, 37, 61, and 134). The database layer and business logic both treat this as a mandatory foreign key relationship, making namespaces a required parent entity for all endpoints.

### What happens if I try to create a public endpoint in a private namespace?

The system prevents this operation and throws a permission error. In [`apps/backend/src/trpc/endpoints.impl.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/trpc/endpoints.impl.ts), lines 63 and 321 contain guards that check if `input.public` is true while `namespace.private` is true, throwing a `PermissionError` with the message "Public endpoints can only use public namespaces" to maintain visibility consistency.

### How does the middleware determine which namespace an endpoint belongs to?

The [`lookup-endpoint-middleware.ts`](https://github.com/metatool-ai/metamcp/blob/main/lookup-endpoint-middleware.ts) resolves the endpoint by its identifier and extracts the `namespace_uuid` field from the database record. At line 28, it assigns this value to `authReq.namespaceUuid`, injecting the namespace UUID into the request context before any business logic handlers execute, making it available for downstream permission checks and routing decisions.

### Are endpoints accessed directly by their own UUID or through their namespace?

Endpoints are always accessed through their parent namespace, never in isolation. The MCP proxy router in [`apps/backend/src/routers/mcp-proxy/metamcp.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/mcp-proxy/metamcp.ts) (line 87) defines the route pattern `/mcp-proxy/metamcp/:uuid`, where the UUID parameter represents the namespace identifier. Public streaming endpoints similarly derive the namespace UUID from the endpoint record to route traffic correctly through the namespace proxy.