---
title: Empacotar um .adapp
---

# Empacotar um .adapp

Pacotes `.adapp` são gerados pelo comando Artisan `mcp:pack-app`. Ele monta o `manifest.json`, calcula o `checksum` e grava o ZIP — você nunca escreve esses arquivos na mão.

## Assinatura do comando

```bash
php artisan mcp:pack-app
    {catalog?}            # ID (UUID) ou name (slug) de um McpCatalog a empacotar
    {--openapi=}          # caminho do spec OpenAPI (.json ou .yaml/.yml) — modo alternativo
    {--out=}              # caminho de saída do .adapp
    {--endpoint=}         # endpoint HTTPS do servidor MCP
    {--name=}             # slug do pacote (OBRIGATÓRIO no modo --openapi)
    {--label=}            # label legível
    {--description=}      # descrição
    {--category=}         # categoria
```

Sem `--out`, o pacote é gravado em `storage/app/adapp/`.

## Modo catálogo

Empacota um `McpCatalog` já existente (e o `McpServer` associado, se houver).

```bash
php artisan mcp:pack-app atende-direito --out=atende-direito.adapp
```

- Se o catálogo tiver um `McpServer` vinculado, o `endpoint` é lido de `McpServer.config` (chaves `endpoint` ou `url`).
- Se não houver server associado, informe `--endpoint` explicitamente.
- O manifest gerado leva `tools[]` + os arquivos `tools/*.json` a partir das tools já persistidas do servidor.

```bash
php artisan mcp:pack-app <uuid-do-catalogo> --endpoint=https://mcp.exemplo.com/v1
```

## Modo OpenAPI

Empacota diretamente a partir de um spec OpenAPI, sem passar por um catálogo existente.

<Passos>
<Passo>

Tenha um spec OpenAPI válido (`.json`, `.yaml` ou `.yml`) com pelo menos um servidor em `servers[]`, URL **HTTPS** e porta **443** — outras portas são rejeitadas.

</Passo>
<Passo>

Rode o comando informando `--openapi`, `--name` e `--out` (obrigatórios neste modo):

```bash
php artisan mcp:pack-app --openapi=spec.json \
  --name=minha-api \
  --label="Minha API" \
  --out=minha-api.adapp
```

</Passo>
<Passo>

Se o spec não tiver `servers[0].url` utilizável, informe o endpoint manualmente:

```bash
php artisan mcp:pack-app --openapi=spec.json \
  --name=minha-api --label="Minha API" --out=minha-api.adapp \
  --endpoint=https://api.exemplo.com
```

</Passo>
<Passo>

O comando gera `manifest.json` (com `transport: openapi`) + `openapi.json` dentro do ZIP. As tools **não** são materializadas no pacote — só serão derivadas no momento do import.

</Passo>
</Passos>

### OpenAPI → tools {#openapi-tools}

No import, o conversor deriva uma tool para cada combinação `path` + método HTTP:

- **Nome da tool**: usa `operationId` quando presente; senão o fallback é `metodo_path` (slug do path template, ex.: `get_v1_test`).
- **`inputSchema`**: montado a partir de `parameters` (path/query/header) + `requestBody` (`application/json`).
- **`required_secrets`**: derivados dos `security schemes` do spec, no formato `{ key, label, required }`.
- **`http_binding`**: gerado automaticamente por tool (ver [Manifesto → http_binding](./manifesto#http-binding-v1)).

Resolução de `$ref` no spec é **só local** (`#/components/...`) — referências externas não são seguidas — com profundidade máxima de 10 níveis, como proteção anticiclo.

### Regras de endpoint e porta

O(s) servidor(es) em `servers[]` do spec precisam respeitar:

- URL **HTTPS** obrigatória.
- Porta **443**, OU qualquer porta ≥ 1024 que não esteja na blocklist.
- Portas **< 1024** são bloqueadas.
- Blocklist explícita, independente da faixa: `8080`, `8443`, `9090`, `9200`, `5432`, `6379`, `11211`.

### Security schemes suportados

| Suportado | Rejeitado (422) |
|-----------|------------------|
| `apiKey` (em `header` ou `query`) | `oauth2` |
| `http` com `bearer` | `openIdConnect` |
| `http` com `basic` | `apiKey` em `cookie` |

Cada scheme suportado vira uma entrada em `required_secrets` (`{ key, label, required }`) e o `credential_ref` da tool aponta para ela (ex.: `"required_secrets[0].key"`).

## Ícone

Ícones **não são baixados por URL** — isso é uma decisão de segurança para evitar SSRF durante o empacotamento. Só arquivos locais com extensão `png`, `jpg`, `jpeg` ou `webp` são embarcados no pacote; caso contrário, `manifest.icon` fica `null`.

## Próximos passos

- [Importar um .adapp](./importar) — como publicar o pacote gerado no catálogo global.
- [Templates e exemplos](./exemplos) — receita fim-a-fim (gerar → empacotar → importar).
