# Ações IA e MCP executáveis

Registre e execute ações WU sem provedor; conecte um relay MCP real e verifique schema, permissões, autenticação, cancelamento e limpeza.

<span id="una-acción-no-necesita-un-proveedor-llm"></span>

<span class="section-anchor" id="section-1"></span>

## Uma ação não precisa de um provedor LLM

`wu.ai.execute` invoca um handler registrado. Você pode usá-lo a partir de sua própria interface, de um agente externo ou de um teste sem configurar `provider`, criar prompts nem inserir uma API key. Os provedores são necessários para operações que conversam com modelos; o registro e a execução direta de ações funcionam separadamente.

A receita `examples/ai/local-actions.mjs` executa uma soma real e verifica rejeições antes que o handler faça seu cálculo.

[Baixe o projeto de receitas](/examples/wu-server-recipes.zip), extraia o ZIP e execute `npm install` para obter as dependências. Inclui as mesmas ações usadas pelos exemplos Node e MCP, junto com seus testes.

```sh
node examples/ai/local-actions.mjs
node scripts/verify-server-examples.mjs
```

<span id="registrar-habilitar-y-ejecutar"></span>

<span class="section-anchor" id="section-2"></span>

## Registrar, habilitar e executar

```js
import wu from 'wu-framework';

const ai = await wu.aiReady();
ai.init({ permissions: {
  executeActions: true,
  readStore: false,
  writeStore: false,
  emitEvents: false,
  readDOM: false,
  modifyDOM: false,
  readDiagnostics: false,
  navigate: false,
  network: false,
} });

ai.action('sum_local', {
  description: 'Suma dos números sin efectos externos',
  parameters: {
    type: 'object',
    properties: { a: { type: 'number' }, b: { type: 'number' } },
    required: ['a', 'b'],
  },
  handler({ a, b }) {
    if (!Number.isFinite(a) || !Number.isFinite(b) || !Number.isFinite(a + b)) {
      throw new Error('Se requieren números y resultado finitos');
    }
    return { sum: a + b };
  },
});

const outcome = await ai.execute('sum_local', { a: 2, b: 3 });
// { success: true, result: { sum: 5 } }
```

Aguarde `aiReady()` antes de operações que retornam dados. `action` retorna o objeto IA para encadear registros. `execute` retorna uma promessa com `{ success, result? , reason? }`; uma falha de permissão ou validação normalmente é representada por `success: false`, não pelo lançamento de uma exceção para o chamador.

`ai.tools()` expõe schemas do catálogo para clientes externos. O fato de uma ferramenta aparecer nessa lista não concede permissão para executá-la.

<span id="schema-permiso-y-reglas-de-dominio"></span>

<span class="section-anchor" id="section-3"></span>

## Schema, permissão e regras de domínio

A validação de parâmetros do WU é deliberadamente pequena: verifica campos obrigatórios, tipos de propriedades de primeiro nível — incluindo `integer` — e `enum`. Não é um validador completo de JSON Schema. Regras como limites numéricos, `additionalProperties`, formatos e validação recursiva exigem validação do produto antes do efeito.

A receita testa um campo ausente, uma string onde se esperava um número e um valor não finito. O primeiro e o segundo caso são rejeitados pelo WU; o terceiro é rejeitado pelo handler com uma regra explícita. Um contador demonstra que apenas o caso permitido chegou ao cálculo.

```js
ai.permissions.configure({ executeActions: false });
const result = await ai.execute('sum_local', { a: 2, b: 3 });
// { success: false, reason: 'Permission denied: executeActions' }
```

Uma ação pode declarar `permissions: ['readStore']` ou `permissionsWhen(params)`. As flags exigidas são verificadas antes da validação e do handler. A API fornecida como segundo argumento oferece apenas as operações declaradas e habilitadas, por exemplo `getState`, `setState`, `emit` ou `fetch`.

Mantenha estes controles separados:

| Controle | Decide |
| --- | --- |
| Capabilities da app WU | Acesso técnico a store, eventos e RPC por meio de sua facade |
| Flags IA | Se o subsistema pode executar ações, ler DOM, gravar estado ou usar a rede |
| Autorização de domínio | Qual operação de negócio o servidor permite ao ator autenticado |
| Capacidade do executor | Se o backend ou runner implementa cancelamento, transação ou outra operação |

Os handlers são código confiável do host. Uma closure pode acessar objetos globais fora da API fornecida; o registro não é um sandbox para JavaScript hostil. Para ações com efeitos no backend, use um serviço que revalide identidade, schema, escopo e autorização. Estas receitas mantêm cálculos puros e não acessam drivers privilegiados.

<span id="confirmación-y-cleanup"></span>

<span class="section-anchor" id="section-4"></span>

## Confirmação e cleanup

```js
const stop = wu.on('ai:tool:confirm', event => {
  // La receta de rechazo no concede ninguna aprobación.
  ai.rejectTool(event.data.callId);
});

try {
  const result = await ai.execute('sum_with_confirmation', { a: 2, b: 3 });
  // success: false; reason: 'User denied action'
} finally {
  stop();
  ai.destroy();
  await wu.destroy();
}
```

A ação `sum_with_confirmation` está registrada em `examples/ai/register-actions.mjs` com `confirm: true`. Uma UI que obtenha uma decisão afirmativa usa `confirmTool(callId)`; `rejectTool` resolve a recusa. Sem uma decisão, a confirmação expira após 30 segundos e nega a execução.

Resolva ou rejeite as confirmações pendentes antes de destruir o subsistema e remova as inscrições instaladas pela integração. `destroy` limpa os recursos de IA; não cancela arbitrariamente promessas ou efeitos capturados por handlers próprios. Também não transforma o histórico em memória em uma auditoria durável.

<span id="mcp-del-cliente-al-navegador-vivo"></span>

<span class="section-anchor" id="section-5"></span>

## MCP: do cliente ao navegador ativo

O servidor MCP do pacote é um relay. O cliente fala MCP/JSON-RPC por stdio; o relay envia comandos por WebSocket à ponte de uma página com WU carregado. A ação é executada nessa página, com suas permissões IA.

```text
Cliente MCP → stdio → wu-mcp-server → WebSocket → wu.mcp → wu.ai.execute
```

Execute a receita completa:

```sh
node examples/mcp/local-relay.mjs
node scripts/verify-server-examples.mjs --mcp
```

A receita inicia o servidor empacotado por meio do export `wu-framework/mcp-server`, serve o bundle UMD instalado a partir de um listener local e abre Chromium headless. No Windows, usa Edge; em outros sistemas, usa o Chromium do Playwright. Se o navegador do Playwright estiver ausente, instale seus binários com `npx playwright install chromium`. Você pode escolher um canal instalado por meio de `WU_BROWSER_CHANNEL`.

Não precisa de um cliente MCP externo instalado: `examples/mcp/stdio-client.mjs` implementa apenas as operações JSON-RPC necessárias para inicializar, listar ferramentas, invocar e cancelar uma espera. Para uma integração geral, use um cliente MCP que gerencie o protocolo completo.

<span id="conectar-tu-propio-cliente"></span>

<span class="section-anchor" id="section-6"></span>

## Conectar seu próprio cliente

O pacote instala o executável `wu-mcp-server`. Configure seu ambiente a partir do host que inicia esse processo. Não coloque o token em uma URL nem o publique no código do frontend.

| Variável | Comportamento |
| --- | --- |
| `WU_MCP_TOKEN` | Obrigatório, exceto com adesão ao modo inseguro; entre 16 e 4096 bytes |
| `WU_MCP_HOST` | `127.0.0.1` por padrão |
| `WU_MCP_PORT` | `19100`; aceita 1–65535 |
| `WU_MCP_ORIGINS` | Origens HTTP(S) exatas separadas por vírgulas; sem caminhos |
| `WU_MCP_TIMEOUT` | Espera pela resposta da ponte: 30000 ms por padrão, intervalo 50–300000 |
| `WU_MCP_AUTH_TIMEOUT` | Espera pela autenticação: 5000 ms por padrão, intervalo 50–60000 |
| `WU_MCP_MAX_PAYLOAD` | 1048576 bytes por padrão, intervalo 1024–16777216 |
| `WU_MCP_INSECURE` | Apenas `1` permite omitir o token; a receita mantém a autenticação obrigatória |

Sem `WU_MCP_ORIGINS`, são aceitas páginas HTTP(S) de loopback; um cliente WebSocket sem Origin não passa por essa verificação. A receita restringe o relay à origem exata do servidor que acabou de criar.

Na página, uma integração confiável entrega o token efêmero à ponte:

```js
await wu.mcp.connect(relayUrl, { token: sessionToken });
```

A promessa carrega o módulo e inicia a conexão; não garante que o handshake já tenha terminado. Verifique `wu.mcp.isConnected()` e consulte `wu_conexion` a partir do cliente MCP para observar as duas pontas. O relay aceita uma ponte autenticada ativa por vez.

<span id="herramientas-y-lectura-de-resultados"></span>

<span class="section-anchor" id="section-7"></span>

## Ferramentas e leitura de resultados

| Ferramenta | Argumentos principais |
| --- | --- |
| `wu_conexion` | `{}`; estado do relay mesmo sem uma página conectada |
| `wu_list_actions` | `{}`; catálogo de ações da página |
| `wu_execute_action` | `{ action, params? }` |
| `wu_get_state` | `{ path? }`; exige `readStore` |
| `wu_set_state` | `{ path, value }`; exige `writeStore` |
| `wu_emit_event` | `{ event, data? }`; rejeita namespaces `wu:`, `system:` e `app:` |

O relay também registra ferramentas de estado do WU, apps, eventos, navegação, DOM, diagnóstico e montagem. `tools/list` retorna o catálogo exato da versão instalada. Suas permissões continuam sendo aplicadas dentro da página.

Há dois níveis de resultado: o envelope MCP e o resultado da ação. Uma ação negada pode viajar em um envelope `isError: false` e conter `success: false` no JSON de `content[0].text`. Verifique ambos:

```js
const response = await client.callTool('wu_execute_action', {
  action: 'sum_local', params: { a: 2, b: 3 },
});
if (response.isError) throw new Error(response.content[0].text);
const outcome = JSON.parse(response.content[0].text);
if (!outcome.success) throw new Error(outcome.reason);
console.log(outcome.result);
```

Esse trecho usa o cliente mínimo da receita. A assinatura de `callTool` em outro SDK pode ser diferente.

<span id="cancelación-que-puedes-observar"></span>

<span class="section-anchor" id="section-8"></span>

## Cancelamento que você pode observar

A receita envia `notifications/cancelled` quando cancela a espera por uma solicitação MCP. Depois verifica que o handler `bounded_sum`, já iniciado no navegador, termina seu atraso fixo e seu cálculo. O relay não transmite um `AbortSignal` para `wu.ai.execute`.

Portanto, cancelar uma espera não demonstra que o trabalho parou. Para operações longas com efeitos, projete um serviço com identificador de operação, autorização de `status`/`cancel` e cancelamento cooperativo do executor. WASM/WASI pode hospedar lógica portátil, mas o host ainda precisa implementar esses contratos e o transporte de rede. O [serviço conectado com WU](/pt/docs/guides/browser-backend/) mostra um caso diferente: conecta o signal RPC à terminação efetiva de seu Worker.

Ao terminar, chame `wu.mcp.disconnect()` para interromper reconexões e liberar seus interceptadores. O teste verifica que `fetch` e `console.log` recuperam suas referências anteriores, que o relay já não vê uma app conectada e que os processos criados são fechados. Consulte [extensões e IA](/pt/docs/framework/advanced/) e [segurança](/pt/docs/framework/security/) para conhecer os limites do runtime.