Tool servers MCP
Declare um servidor como
[tool_servers.<name>] em config.toml. Dê a ele exatamente um transporte. command cria um processo e fala stdio. url fala HTTP streamable sobre https, ou sobre http em loopback. Uma declaração com os dois, ou com nenhum, recusa carregar.
dir, headers, oauth, timeout_ms e enabled. Cada servidor declarado conecta na inicialização a menos que você defina enabled = false.
O Narya mantém uma sessão de vida longa por servidor e reconecta com backoff. Quando um servidor desconecta, o Narya retira as ferramentas dele do registro, então o modelo nunca vê as ferramentas de um servidor que saiu.
Defina oauth = true para um servidor remoto que faz login. O Narya mantém a conexão aberta, imprime a URL de autorização e escuta em 127.0.0.1:7666 pelo callback enquanto o login está aberto. Um login que ninguém responde custa esse único servidor e nada mais. Uma execução de uma só vez não pode completar um login, e ela diz isso.
Servidores de ferramentas de um repositório confiado
O Narya lê o
.mcp.json na raiz de um repositório em que você confia, no formato do Claude Code, e inicia os servidores que ele declara. Apenas as sessões desse repositório recebem as ferramentas deles.
- Um servidor sem
type, ou comtypedefinido comostdio, lêcommand,argseenv. - Um servidor com
typedefinido comohttpoustreamable-httplêurleheaders, e faz login quando o servidor pede. - O Narya expande
${VAR}e${VAR:-default}. Um servidor que nomeia uma variável não definida sem padrão, ou uma das variáveis do próprio Narya, não inicia. - O Narya ignora qualquer outra chave e registra isso no log dele.
CLAUDE_PROJECT_DIR definido como essa raiz. Ele recebe o ambiente que um hook de repositório recebe, mais o próprio env. O Narya não inicia um servidor cujo nome o host já tem, e o host mantém a própria fonte com esse nome.
O .mcp.json que o Narya lê primeiro sob a sua resposta de confiança inicia com essa resposta. Um .mcp.json alterado não inicia nada até que uma pessoa o permita em uma conversa acompanhada. Uma mudança longa demais para mostrar inteira em uma pergunta não inicia. O Narya para os servidores de um repositório quando você retira a confiança, e depois de uma hora sem uso.
Em um contêiner que clonou um repositório, apenas os servidores de comando do arquivo do repositório clonado rodam, dentro do contêiner.
Cada repositório faz login nos seus servidores por conta própria, sob o nome <name> in <repository>. Quando servidores de um mesmo nome em dois repositórios definem uma ferramenta de forma diferente, o Narya oferece uma definição. O narya host status lista esses servidores com o repositório deles e nomeia as ferramentas que as sessões de um repositório não recebem.
Árvores de ferramentas OpenAPI
Declare
[tool_trees.<name>] para transformar um documento OpenAPI em uma árvore de ferramentas chamável. As chaves são spec, base_url, headers, timeout_ms e enabled. Um caminho spec relativo resolve contra o seu Narya home. Defina base_url quando o documento não declara servidor próprio. O Narya deriva as ferramentas uma vez na inicialização. Nenhum servidor roda, e nenhuma sessão reconecta.
Scripts confinados
O Narya roda ECMAScript em um motor confinado. O motor não alcança sistema de arquivos, rede, ambiente nem carregador de módulos. Ele não tem avaliação dinâmica. A profundidade de chamadas para em 4.096, e o código-fonte para em 256 KiB. Três chamadores o usam: a ferramenta
run_program do modelo, os workflows e a descoberta de ferramentas.
A API do host
O host serve uma API HTTP, e cada cliente a conduz. A API do host descreve o transporte, o stream de eventos e os envelopes.
Pacotes
O
narya ext add <source> instala um pacote a partir de um caminho local ou de uma referência de módulo Go. O narya ext list, o remove, o enable e o disable gerenciam o que você instalou.
Um pacote que declara apenas recursos acrescenta agentes, skills, comandos e hooks, e é instalado por cópia. Um pacote com código Go é compilado no seu binário do Narya, então precisa de um toolchain Go local. O Narya pede que você confie em um pacote que traz código ou hooks antes de instalá-lo. Acrescente --yes para pular essa pergunta em um script.
Extensões registradas
Para acrescentar uma extensão que roda como um serviço HTTPS próprio, registre-a com
POST /v1/extensions. Isso exige a permissão extensions:manage. O corpo exige dois campos: name, no formato publisher/extension, e endpoint. Os outros campos são opcionais: description, points, slots, position, grants, models e enabled.
O endpoint deve ser uma URL https://, e isso vale também para endereços de loopback. O host resolve o endereço antes de gravar o registro. Ele recusa um endereço de loopback ou privado, a menos que allow_private_endpoints na tabela [extensions] do config.toml admita essa faixa. Nenhuma configuração admite outro endereço fora da internet pública, como um endereço link-local ou multicast.
Um slot exclusivo comporta uma extensão. Um registro que reivindica um slot exclusivo que outra extensão ocupa recebe 409 com NRY-0006. Para admitir os dois, indique o vencedor desse slot em prefer na tabela [extensions].
A resposta traz o segredo da extensão, uma única vez. Nenhuma leitura o devolve de novo. Para trocar o segredo, chame POST /v1/extensions/{publisher}/{name}/secret. A resposta traz o novo segredo e o momento em que o antigo deixa de funcionar.
O host assina cada chamada à extensão com o segredo. Até o segredo antigo deixar de funcionar, o Narya-Signature carrega uma assinatura para cada segredo, separadas por um espaço. Aceite a chamada quando uma delas for verificada com o segredo que você guarda. A extensão assina as próprias chamadas da mesma forma, e ela pode chamar apenas o stream de eventos.
A extensão serve as próprias operações no endpoint dela. O host chama /transform nos pontos de decisão em que a extensão atua. Ele chama /models e /supply quando a extensão fornece modelos, /tools quando ela publica ferramentas, e /invoke para rodar uma operação nomeada. O host não segue um redirecionamento da extensão.
Um cliente alcança uma extensão pelo host com POST /v1/extensions/{name}/invoke. O token de um membro comum basta. O host assina a chamada encaminhada, então o cliente não precisa do segredo.
Uma resposta de /invoke acima de 1 MiB faz a chamada falhar. O modelo lê no máximo os primeiros 30.000 bytes do texto de uma resposta de ferramenta de uma extensão. Um aviso antes desse texto diz ao modelo que o resto não pode ser alcançado, e o modelo lê a chamada como falha. A parte estruturada machine da resposta passa sem mudança.
Agentes, skills, comandos e hooks
O Narya lê os formatos do próprio Claude Code sem nenhuma mudança. Agentes são arquivos markdown com frontmatter YAML, e o corpo é o prompt. As chaves são
name, description, tools, disallowedTools, model e effort, e um arquivo sem name recebe o nome do arquivo. Um agente no seu Narya home ou em .narya/agents também lê mode e hidden. O Narya ignora qualquer outra chave.
tools é uma allowlist e nunca uma concessão: o Narya cruza a lista de um filho com a do pai, então um agente filho pode perder ferramentas, nunca ganhar. disallowedTools remove as ferramentas que nomeia, e uma entrada com uma regra entre parênteses remove a ferramenta inteira. effort define o nível de raciocínio dos turnos do agente: low, medium, high ou max.
O Narya lê agentes do seu Narya home, depois de ~/.claude/agents, depois dos .claude/agents e .narya/agents de um repositório em que você confia. Quatro agentes vêm no binário: explore, general, plan e review.
Skills seguem o padrão Agent Skills: um diretório que guarda um SKILL.md. O Narya lê a mesma escada, ~/.claude/skills incluído, e a relê a cada requisição. Uma skill que você acrescenta no meio da sessão chega no turno seguinte.
Comandos vêm do seu Narya home, de ~/.claude/commands, e dos .claude/commands e .narya/commands de um repositório em que você confia.
Hooks vêm da tabela hooks do ~/.claude/settings.json, e do mesmo arquivo em um repositório em que você confia. Uma tabela hooks alterada só vale depois que uma pessoa a permite em uma conversa acompanhada. Veja Quando uma mudança de configuração vale. O Narya os lê com as chaves de stdin e os códigos de saída que esses scripts já usam. Quatro eventos têm correspondência: PreToolUse, PostToolUse, UserPromptSubmit e SessionStart. Outros eventos, como Stop, SubagentStop, Notification, PreCompact e SessionEnd, não têm equivalente. O Narya os pula e registra isso no log dele.
Os hooks do próprio Narya
Declare
[[hooks]] em config.toml com point, command, timeout_ms, fail e match. fail não tem padrão, então declare-o. Uma mudança neles vale no próximo início do host depois que uma pessoa permite o novo config.toml.
match filtra nomes de ferramentas em before-tool-call e after-tool-call. Use um nome de ferramenta ou uma expressão regular Go que corresponda ao nome inteiro, como read|write. Um valor vazio ou * corresponde a todas as ferramentas. Outros pontos de hook não aceitam um match não vazio.
Quatro pontos decidem, e um hook ali pode parar o que ele antecede:
before-tool-call, before-model-request, after-tool-call, at-permission-ask.
Oito pontos observam, e um hook ali fica sabendo o que aconteceu sem mudar nada:
session-started, lane-started, lane-finished, delegation-created, child-asked, skill-invoked, permission-denied, session-compacted.
O arquivo do próprio repositório não pode declarar at-permission-ask.
Delegação
Delegação é uma chamada de ferramenta. Defina os limites dela em
[delegation] no config.toml. A chave max_depth conta os níveis abaixo da sua conversa, e 0 desliga a delegação. Defina max_concurrent para limitar quantas lanes uma conversa roda em qualquer instante.
