MCP Fusion/Security and governance/Conectores multi-tenant

Conectores multi-tenant

Pergunte à IA sobre a Vinkius

Um conector, muitos tenants, nenhum módulo especial: resolução do tenant por requisição, visibilidade de capacidades filtrada por tags e Presenters baseados em função que mostram a cada tenant o que ele pode ver.

Atender vários clientes com um único conector não é um recurso que você adiciona depois; é uma propriedade de como contexto, visibilidade e percepção são construídos. O MCP Fusion não tem um módulo de tenancy porque as peças que você já usa se compõem em um só padrão. Esta página mostra a receita.

1. Resolva o tenant por requisição

Cada requisição começa com um ctx novo, portanto o tenant é decidido uma vez, antes de qualquer handler:

typescript
interface AppContext {
  db: PrismaClient;
  tenantId: string;
  role: 'viewer' | 'admin';
}

registry.attachToServer(server, {
  contextFactory: async (extra) => {
    const claims = await verify(extra.session?.authToken);
    return {
      db: pool.forTenant(claims.tenant_id),
      tenantId: claims.tenant_id,
      role: claims.role,
    };
  },
});

Duas regras tornam isso seguro. A factory retorna um objeto novo por requisição: nenhuma requisição pode observar o contexto de outra. O middleware escreve nesse objeto com proteções contra poluição de protótipo, para que um nome de argumento malicioso não alcance __proto__. Os handlers usam ctx.db ou ctx.tenantId como única porta para os dados, e o id do tenant nunca vem dos argumentos da ferramenta.

2. Limite capacidades por tag

Tenants raramente recebem a mesma superfície. Tags e um filtro decidem o que existe para cada pessoa:

typescript
const filterFor = (role: string) =>
  role === 'admin'
    ? { anyTag: ['public', 'admin'] }
    : { tags: ['public'], exclude: ['internal'] };

attachToServer(server, { filter: filterFor(ctx.role) });

Nesse formato, uma implantação gratuita expõe ferramentas públicas, uma implantação empresarial expõe ferramentas administrativas e a base de código dos handlers é idêntica. O filtro é avaliado onde a lista de ferramentas é construída, sob o próprio contexto da requisição. Consulte Tool exposition.

3. Modele a percepção por função

A visibilidade decide quais ferramentas uma função vê; a percepção decide o que essas ferramentas mostram. O padrão verificado usa duas ferramentas sobre um handler, selecionadas pelo filtro da etapa 2:

typescript
const listPeople = async (input, ctx) => ctx.db.people.findMany();

f.query('people.list_public')
  .describe('List people in the tenant, without contact details')
  .tags('public')
  .returns(ViewerPresenter)          // schema without email or phone
  .handle(listPeople);

f.query('people.list_admin')
  .describe('List people in the tenant with full records')
  .tags('admin')
  .returns(AdminPresenter)
  .handle(listPeople);               // same handler function

Um agente com função viewer recebe somente people.list_public e nunca vê campos de contato; um agente admin recebe ambas, com o Presenter completo. As regras de campos e a redação ficam em um só lugar por público, e o digest do contrato registra as duas superfícies. Regras contextuais, escritas como (data, ctx) => string[], acrescentam orientação dependente da função. Consulte Models and Presenters.

4. Isole credenciais por tenant

As chaves de fornecedores também não devem ser compartilhadas entre tenants. Declare-as com defineCredentials e leia-as por requisição: no Vinkius Cloud, o runtime injeta os segredos de cada comprador em cada requisição e, localmente, o mesmo accessor lê seu ambiente. Consulte Credentials.

5. Atribua custo e tráfego

Cada chamada pode ser atribuída: passe ctx.tenantId como chave de rate limit para que um tenant não esgote o orçamento de outro e emita o id do tenant em eventos de auditoria e telemetria. No console da Vinkius, o mesmo conector mostra custo e confiabilidade por servidor, documentados em AI spend e Tool reliability.

O padrão em uma tabela

ConcernMechanismWhere it lives
IdentityJWT, API key or OAuth tokencontextFactory + auth middleware
Data isolationper-tenant client from the contextcontextFactory
Capability visibilitytags + filtertool list construction
Field isolationrole-based PresentersPresenter per audience
Secret isolationBYOC credentialsruntime injection
Fair userate-limit key from ctxrate limiter middleware
Proofcontract digest + audit eventslockfile and audit sink

Não existe um switch de runtime para esquecer nem um cache entre tenants para configurar incorretamente, porque nada é compartilhado a menos que você o compartilhe explicitamente. Essa é a diferença entre um conector multi-tenant e um conector single-tenant com uma coluna de tenant.

Próximos passos