MCP Fusion/Core concepts/Gating de estado FSM
Gating de estado FSM
Anti-alucinação temporal: vincule tools a estados do workflow para que uma ação fora de ordem desapareça fisicamente da lista de tools, em vez de ser rejeitada depois que o agente tenta executá-la.
A alucinação mais cara em um workflow de agente não é um valor errado: é chamar a etapa quatro antes da etapa três. O agente vê uma tool, chama, o servidor rejeita e o turno é desperdiçado. O MCP Fusion remove a etapa do menu.
Vincule uma tool a um estado
export default f.action('invoice.discharge')
.describe('Discharge an approved invoice')
.bindState('approved', 'DISCHARGE')
.handle(async (input, ctx) => discharge(input.id));bindState(states, transition) significa: esta tool aparece em tools/list somente enquanto o workflow está em um dos estados indicados e, após uma chamada bem-sucedida, dispara transition. Os estados vêm de uma máquina que você configura uma vez:
const fsm = f.fsm({
id: 'invoice',
initial: 'draft',
states: {
draft: { on: { SUBMIT: 'review' } },
review: { on: { APPROVE: 'approved', REJECT: 'draft' } },
approved: { on: { DISCHARGE: 'discharged' } },
discharged: { type: 'final' },
},
});A forma é compatível com XState v5. XState é um peer opcional: quando está instalado, o gate executa um actor real; sem ele, o gate usa uma tabela de transições manual integrada, então o recurso degrada com elegância em vez de falhar na inicialização.
O que o agente vivencia
- Em
draft,invoice.dischargenão está na lista. O agente não pode chamar o que não consegue ver. - Na tool que leva a
approved, a chamada bem-sucedida move a máquina e o servidor envianotifications/tools/list_changed. - O cliente atualiza a lista e agora
invoice.dischargeaparece com sua própria descrição.
Isso é mais forte que uma guarda: uma guarda rejeita depois da tentativa, enquanto o gating remove a tentação. Erros de validação sobre ordenação desaparecem dos logs porque o conflito de ordem não pode ser expresso.
O gating também é aplicado no caminho da chamada, não apenas na lista. Um cliente que adivinhar o nome de uma tool ainda recebe FORBIDDEN com as ações permitidas, então a segurança nunca depende de o cliente atualizar o menu.
Divulgação progressiva no schema
Um conector vinculado a FSM também pode reduzir o próprio contexto. compactDescription() dá à tool uma descrição curta enquanto a máquina está no estado inicial, e o .describe() completo chega nos estados posteriores. O menu do agente em draft é menor e mais preciso que a mesma tool em approved, sem uma segunda implantação.
Estado serverless e stateless
Uma máquina de estados é estado durável, e os transportes stateless do MCP 2.0 não têm uma sessão onde armazená-la. Três mecanismos cobrem esse caso:
stateHandleKey: a chamada da tool pode carregar um argumento de handle explícito que o modelo devolve, o padrão recomendado pela especificação para fluxos stateless- id da sessão: quando o transporte possui um (
Mcp-Session-Id), o gate armazena o estado por sessão - fallback por attachment: um servidor single-tenant sem nenhuma das chaves usa uma identidade em processo
A persistência é uma interface FsmStateStore que você implementa:
interface FsmStateStore {
load(handle: string): Promise<{ state: string; updatedAt: string } | undefined>;
save(handle: string, snapshot: { state: string; updatedAt: string }): Promise<void>;
}Use o store em memória para um processo único ou conecte-o a Redis, DynamoDB, um KV de edge ou uma linha de banco de dados. O framework clona e restaura o gate por requisição, então requisições concorrentes nunca compartilham uma máquina por acidente.
Quando usar
- Fluxos de aprovação e revisão, nada pode ser descarregado antes da aprovação
- Pagamento e fulfillment, capture depois da autorização, nunca antes
- Migrações em várias etapas e janelas de manutenção destrutiva
- Qualquer situação em que uma ordem errada custe dinheiro ou dados e uma chamada rejeitada ainda custe um turno
O gating de FSM se combina com Exposição de tools, pois a superfície visível muda com o estado, e com Roteamento, pois tools vinculadas a estados vivem em seus próprios arquivos. Os handlers não mudam: sempre foram escritos para um estado do mundo.
Próximos passos
- Tools: os métodos de builder em torno de
bindState - Sincronização de estado: o outro problema temporal, dados desatualizados
- Economia de tokens: por que o menu menor compensa
