mcp-gen

Transforme suas funções TypeScript digitadas em um servidor MCP; os esquemas de ferramenta, recurso e prompt são inferidos a partir dos seus tipos e JSDoc. Sem biblioteca de esquemas, sem decoradores, sem código repetitivo.

Documentação

mcp-gen

Transforme suas funções TypeScript tipadas em um servidor MCP. Sem biblioteca de schema, sem decorators, sem boilerplate — o schema é inferido dos seus tipos.

mcp-gen: a typed TypeScript function becomes an MCP server's tool schema

mcp-gen lê funções TypeScript exportadas e gera definições de ferramenta, recurso e prompt do Model Context Protocol a partir delas — usando o verificador de tipos do TypeScript (via ts-morph) para transformar cada tipo de parâmetro em um JSON Schema e cada comentário JSDoc em uma descrição. Ele pode emitir os schemas como JSON, servir um servidor MCP ao vivo ou abrir um playground ao vivo onde você chama suas ferramentas no navegador enquanto edita.

Se suas funções são tipadas, elas já são ferramentas MCP.


Início rápido

Escreva funções simples e tipadas com JSDoc comum:

// tools.ts

/**
 * Greets a person by name and age.
 * @param name - The person's name
 * @param age - The person's age in years
 */
export function greet(name: string, age: number): string {
  return `Hello ${name}, age ${age}`;
}

/**
 * Echoes a message back after a tick.
 * @param msg - The message to echo back
 */
export async function slowEcho(msg: string): Promise<string> {
  return `echo: ${msg}`;
}

Gere os schemas das ferramentas:

mcp-gen tools.ts
{
  "tools": [
    {
      "name": "greet",
      "description": "Greets a person by name and age.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "The person's name" },
          "age":  { "type": "number", "description": "The person's age in years" }
        },
        "required": ["name", "age"]
      }
    }
    // ... slowEcho
  ]
}

A maneira mais rápida de realmente testá-las — o playground ao vivo. Ele observa seu arquivo, renderiza um formulário de entrada para cada ferramenta a partir do schema inferido e o executa diretamente no seu navegador enquanto você edita:

mcp-gen dev tools.ts          # then open the printed http://127.0.0.1:4000/ URL

Ou execute como um servidor MCP real:

mcp-gen serve tools.ts --port 3000

serve vincula 127.0.0.1 (loopback) por padrão — ele executa seu código local quando suas ferramentas são chamadas, portanto não é acessível fora da máquina, a menos que você peça. Para expô-lo na rede, opte explicitamente com --host (ex.: mcp-gen serve tools.ts --host 0.0.0.0); isso imprime um aviso, já que o endpoint passa a ser acessível por outras máquinas.

Antes de expô-lo, ative a autenticação por bearer token. Configure uma ou mais chaves com --api-key <key> (repetível) ou a variável de ambiente MCP_GEN_API_KEYS separada por vírgulas — se qualquer chave estiver definida, a autenticação está ligada e toda requisição a /mcp deve conter Authorization: Bearer <key> (uma chave ausente, malformada ou incorreta é rejeitada com 401 antes de qualquer ferramenta ser executada). Sem chaves definidas, a autenticação está desligada e o comportamento permanece inalterado. Quando a autenticação está ligada, o aviso de "sem autenticação" fora da máquina é substituído por uma confirmação de uma linha de que um token é necessário. Veja Implantação em produção.

É isso. Os nomes dos parâmetros, tipos, obrigatoriedade e descrições vêm todos do código que você já escreveu.

Como funciona

  • Tipos viram schemas. Os parâmetros de cada função exportada são convertidos em um JSON Schema inputSchema pelo verificador de tipos do TypeScript. Parâmetros opcionais (age?: number) são omitidos de required; tipos de retorno são capturados (e Promise<T> é desembrulhado).
  • JSDoc vira documentação. O resumo da função vira o description da ferramenta; cada @param vira o description dessa propriedade.
  • Falhe alto, nunca falhe em silêncio. Uma função que não pode ser convertida em um schema válido — por exemplo, um genérico não vinculado em posição de entrada (identity<T>(value: T)) — é excluída e relatada, nunca emitida como algo quebrado. Funções limpas ainda são geradas; o código de saída informa se alguma falhou (veja abaixo).

O que ele trata

Ele é construído para funcionar em bases de código reais, não apenas em brinquedos de arquivo único:

  • genéricos (restritos e não vinculados), e um erro claro naqueles que não podem ser representados
  • tipos importados de outros módulos e reexportados sob aliases
  • múltiplos estilos de exportação (nomeada, padrão, com alias)
  • descoberta de tsconfig.json e resolução de alias de caminho
  • detecção de tipos não serializáveis (em vez de emitir schema inválido)
  • funções async (tipos de retorno aguardados); uma ferramenta que lança erro retorna isError em vez de derrubar o servidor

Recursos e prompts

Servidores MCP podem expor três tipos de coisas — ferramentas (ações), recursos (dados) e prompts (modelos reutilizáveis). mcp-gen infere todos os três a partir das mesmas exportações tipadas; uma única tag JSDoc escolhe qual. Uma função sem tag é uma ferramenta, exatamente como antes — nada muda para o código existente.

Recursos — @resource <uri>

Marque uma função com @resource e um URI. Se o URI tiver {placeholders} que correspondam aos nomes dos parâmetros, ele se torna um modelo de recurso (os parâmetros validam a URL); sem espaços reservados, é um recurso estático. O valor de retorno é o conteúdo — um string é servido como text/plain, qualquer outra coisa como application/json. Adicione @mime <type> para substituir.

/**
 * Read a user record by id.
 * @resource users://{id}      — templated: {id} matches the `id` param
 * @param id - The user id
 */
export function getUser(id: string): { id: string; name: string } {
  return { id, name: `User ${id}` };
}

/**
 * The current app configuration.
 * @resource config://app       — static: no placeholders
 */
export function appConfig() {
  return { theme: "dark", version: "1.1.0" };
}

/**
 * @resource info://build
 * @mime text/plain             — override the content type
 */
export function buildInfo(): string {
  return "mcp-gen build 1.1.0";
}

Prompts — @prompt

Marque uma função com @prompt. Seus parâmetros se tornam os argumentos do prompt (nomes e descrições de @param). Retorne uma string para uma única mensagem de usuário, ou um array de mensagens { role, content } para passá-las adiante como estão.

/**
 * A code-review prompt.
 * @prompt
 * @param language - The programming language
 * @param code - The code to review
 */
export function reviewPrompt(language: string, code: string): string {
  return `Please review this ${language} code:\n\n${code}`;
}

Execute mcp-gen serve e um cliente MCP conectado pode listar e ler seus recursos e obter seus prompts, além de chamar ferramentas. Recursos e prompts passam pelo mesmo caminho exato que as ferramentas — mesma inferência de tipos, mesma validação, mesma execução — e a mesma regra de falha alta se aplica: por exemplo, um modelo @resource cujo {var} não corresponde a um parâmetro é excluído e relatado, nunca meio-registrado.

CLI

mcp-gen <file.ts> [--debug] [--tsconfig <path>]                                        Generate tool schemas as JSON (stdout)
mcp-gen serve <file.ts> [--port N] [--host <addr>] [--api-key <key>]... [--tsconfig <path>]   Start a live MCP server (default port 3000; binds 127.0.0.1; PORT/HOST env honored)
mcp-gen dev <file.ts> [--port N] [--tsconfig <path>]                                   Live playground UI, watches + reloads (default port 4000)
mcp-gen check <file.ts> [--update] [--snapshot <path>] [--tsconfig <path>]             Guard the tool surface against breaking changes (CI)

A geração escreve JSON legível por máquina na saída padrão (sempre inclui tools; inclui errors/warnings quando presentes); mensagens legíveis por humanos vão para stderr. Códigos de saída:

CódigoSignificado
0toda função exportada convertida limpa
1uma ou mais funções falharam — as limpas ainda são emitidas, falhas listadas em errors
2falha em nível de arquivo (não encontrado / não analisável / nada servível)

Implantação em produção

Para executar serve como um servidor MCP acessível pela rede, vincule uma interface pública e exija um bearer token. Passe as chaves pelo ambiente (não --api-key) para que o segredo nunca caia no histórico do shell ou em uma listagem de processos:

# one or more comma-separated keys; every caller must send `Authorization: Bearer <key>`
MCP_GEN_API_KEYS="$(openssl rand -hex 32)" mcp-gen serve tools.ts --host 0.0.0.0
  • Chaves via env em produção, não na CLI. --api-key é conveniente para testes locais, mas uma flag é visível para qualquer pessoa que possa listar processos (ps); MCP_GEN_API_KEYS mantém o segredo fora de argv. Ambas as fontes são unidas, divididas por vírgulas e aparadas, e qualquer chave não vazia liga a autenticação.
  • PORT / HOST são respeitados. Quando você omite --port / --host, serve recorre às variáveis de ambiente PORT e HOST antes de seus padrões (3000 / 127.0.0.1) — então ele se encaixa diretamente em uma plataforma que injeta PORT. Uma flag explícita --port / --host sempre substitui a variável de ambiente.
  • A autenticação é fail-closed. Com chaves configuradas, uma requisição a /mcp com um token ausente, malformado ou não correspondente é rejeitada com 401 {"error":"unauthorized"} antes do transporte MCP — então nenhum código de ferramenta, recurso ou prompt é executado. As chaves são comparadas em tempo constante.
  • Sem chaves = exposto e não autenticado. Vincule um --host não loopback (ou HOST) sem nenhuma chave configurada e serve continua imprimindo o aviso alto de exposição. Configure uma chave para proteger o endpoint (e silenciar o aviso).

Em uma plataforma que injeta PORT (e opcionalmente HOST), você fornece apenas as chaves:

MCP_GEN_API_KEYS="key-a,key-b" mcp-gen serve tools.ts --host 0.0.0.0   # PORT taken from the environment

Protegendo o contrato — check

check é tsc para sua superfície de ferramentas: ele captura um instantâneo das ferramentas geradas em um arquivo versionado e, em execuções posteriores, falha a compilação em mudanças quebradoras — para que uma ferramenta voltada a agentes não possa mudar silenciosamente de forma sob seus chamadores.

mcp-gen check tools.ts --update      # write the baseline (the `jest -u` of tool contracts) — commit it
mcp-gen check tools.ts               # in CI: fail if the surface broke

Mudanças quebradoras (saída 1) são julgadas da perspectiva de um chamador existente: uma ferramenta removida ou renomeada, uma propriedade removida, um parâmetro novo obrigatório, um parâmetro opcional tornado obrigatório, uma mudança de tipo, um valor de enum removido ou qualquer outro estreitamento de um sub-schema aninhado. Mudanças puramente aditivas ou de relaxamento — uma nova ferramenta, um novo parâmetro opcional, um requisito relaxado, um novo valor de enum — são seguras e nunca falham. Mudanças de descrição e tipo de retorno são relatadas como avisos.

CódigoSignificado
0sem mudanças quebradoras (ou um --update bem-sucedido)
1pelo menos uma mudança quebradora — nomeada no stderr, lista completa de mudanças como JSON na saída padrão
2falha em nível de arquivo, uso incorreto ou instantâneo ausente (nunca criado silenciosamente — imprime como criar uma linha de base)

O instantâneo é normalizado deterministicamente (ferramentas e chaves ordenadas, formatação estável), então permanece estável em bytes e revisa limpo em um PR. Padrão para <file>.mcp-snapshot.json; substitua com --snapshot.

Playground ao vivo — dev

dev é um playground ciente de tipos para o servidor que um arquivo define. Ele observa o arquivo, regenera a superfície de ferramentas a cada salvamento e serve uma pequena interface web localhost:

mcp-gen dev tools.ts            # then open the printed URL, e.g. http://127.0.0.1:4000/

Abra a URL impressa em um navegador. Para cada ferramenta, ele renderiza um formulário de entrada a partir do schema inferido (string → texto, número → número, booleano → caixa de seleção, enum → menu suspenso, arrays/objetos → caixa JSON bruto), executa a ferramenta sob demanda e mostra o resultado, o inputSchema gerado e a requisição/resposta JSON-RPC bruta — a visão de inspetor. Funções excluídas por falha alta são listadas acinzentadas com seus motivos. Salve o arquivo e a página recarrega sozinha, preservando o que você digitou.

Crucialmente, o playground executa cada ferramenta pelo mesmo caminho exato que mcp-gen serve — o mesmo carregador de módulos e o mesmo despacho nomeado→posicional — então o que você vê no navegador é o que o servidor servido faz. Ele vincula 127.0.0.1 apenas (executa seu código local sob demanda, então nunca é exposto fora da máquina), usa a porta 4000 por padrão e segue a mesma disciplina de código de saída que serve.

Faça commit do arquivo *.mcp-snapshot.json — é a linha de base com a qual todo check posterior compara, não saída de compilação. Não o adicione a .gitignore; faça o check-in junto com seu código para que o diff de um PR mostre exatamente como a superfície de ferramentas mudou.

Instalação

npm install -g @zodromon/mcp-gen

O pacote tem escopo (@zodromon/mcp-gen), mas o comando que você executa é apenas mcp-gen:

mcp-gen tools.ts

Ou execute sem instalar, via npx:

npx @zodromon/mcp-gen tools.ts

A partir do código-fonte (para desenvolver ou contribuir):

git clone https://github.com/zodromon/mcp-gen && cd mcp-gen
npm install
npm run build          # → dist/
node dist/generate-mcp-schemas.js tools.ts

Durante o desenvolvimento, você pode executá-lo diretamente sem compilar:

npm run generate -- tools.ts        # via tsx

Requer Node.js. Dependências: @modelcontextprotocol/sdk, ts-morph, typescript, jiti.

Escopo, honestamente

Bom para: expor rapidamente funções TypeScript tipadas existentes como ferramentas MCP — ferramentas internas, protótipos, qualquer coisa onde você prefere não escrever schemas de ferramentas manualmente.

Não tenta ser o maior framework MCP. Ele faz uma coisa. Se você quer decorators, um sistema de plugins ou uma plataforma gerenciada, outras boas ferramentas se encaixam melhor:

  • FastMCP — maduro e popular; você declara parâmetros via uma biblioteca de schema (Zod/ArkType/Valibot).
  • simply-mcp-ts — APIs decorator / funcional / programática.
  • O SDK MCP oficial — controle máximo, mais boilerplate.

A única diferença real de mcp-gen é gosto: nada é adicionado às suas funções — sem biblioteca de schema, sem anotações além do JSDoc que você escreveria de qualquer forma. Se isso agrada, use-o. Se não, os outros são ótimos.

Licença

MIT. Livre para usar, bifurcar ou ignorar.