npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@7leirbag/my-first-mcp

v1.0.2

Published

Servidor MCP educacional com tools de data/hora

Readme

@7leirbag/my-first-mcp

Servidor MCP (Model Context Protocol) educacional escrito em TypeScript. O objetivo deste projeto é demonstrar o ciclo completo de desenvolvimento de um MCP server: implementação local → build → publicação no npm → consumo via npx em qualquer cliente compatível (Kiro, Claude Desktop, etc.).


Por que TypeScript?

JavaScript puro funcionaria, mas TypeScript foi escolhido por razões práticas:

  • Tipagem estática: as interfaces do SDK MCP (McpServer, StdioServerTransport, CallToolResult) são complexas. Com tipos, o editor aponta erros antes de rodar qualquer coisa.
  • Autocompletar: ao implementar cada tool, o TypeScript garante que a resposta retornada tem exatamente a forma que o SDK espera — { content: [{ type: "text", text: string }] }.
  • Documentação viva: as interfaces em src/types.ts servem como contrato entre as tools e o entry point. Qualquer desvio vira erro de compilação, não bug em produção.
  • Ecossistema: o SDK oficial @modelcontextprotocol/sdk é escrito em TypeScript e exporta seus tipos, então aproveitamos isso ao máximo.

O custo é um passo extra de compilação (tsc), mas o ganho em clareza e segurança compensa — especialmente num projeto educacional onde entender as interfaces é o objetivo.


Como o MCP funciona

O Model Context Protocol define um padrão de comunicação entre um cliente (ex: Kiro, Claude Desktop) e um servidor que expõe ferramentas (tools). A comunicação acontece via JSON-RPC 2.0.

O transporte usado aqui é stdio: o cliente inicia o processo do servidor e troca mensagens pelo stdin/stdout. Não há porta de rede, não há servidor HTTP — tudo é local e efêmero.

Cliente MCP (Kiro)
    │
    │  stdin  →  JSON-RPC request
    ▼
Processo Node.js (@7leirbag/my-first-mcp)
    │
    │  stdout →  JSON-RPC response
    ▼
Cliente MCP (Kiro)

Quando o cliente fecha a conexão (fecha o stdin), o processo do servidor encerra automaticamente.


Estrutura do projeto

my-first-mcp/
├── src/
│   ├── index.ts              # Entry point: instancia o servidor e registra as tools
│   ├── types.ts              # Interfaces compartilhadas entre as tools
│   └── tools/
│       ├── datetime.ts       # Tool: get_current_datetime
│       ├── server-info.ts    # Tool: get_server_info
│       └── date-diff.ts      # Tool: calculate_date_diff
├── dist/                     # Saída do compilador TypeScript (gerado pelo build)
├── scripts/
│   └── add-shebang.cjs       # Script pós-build: injeta #!/usr/bin/env node
├── package.json
└── tsconfig.json

Passo a passo: o que foi feito para o MCP funcionar

1. Configurar o projeto

package.json com os campos essenciais para publicação e execução:

{
  "name": "@7leirbag/my-first-mcp",
  "type": "module",
  "main": "dist/index.js",
  "bin": { "my-first-mcp": "dist/index.js" },
  "files": ["dist"],
  "engines": { "node": ">=18" }
}
  • "type": "module" — habilita ES Modules, necessário para top-level await no entry point
  • "bin" — diz ao npm qual arquivo executar quando o pacote for chamado via npx
  • "files" — garante que apenas a pasta dist/ (código compilado) seja publicada no registry

tsconfig.json com configurações para Node.js moderno:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "dist",
    "strict": true
  }
}
  • module: Node16 — usa a resolução de módulos do Node.js, exigindo extensão .js nos imports
  • target: ES2022 — permite top-level await e outras features modernas

2. Implementar as tools

Cada tool é uma função pura em src/tools/ que recebe parâmetros e retorna um ToolResponse:

interface ToolResponse {
  content: Array<{ type: "text"; text: string }>;
  isError?: boolean;
}

Esse é o contrato do SDK MCP: toda tool deve retornar um objeto com content contendo um array de blocos de texto. Se algo der errado, isError: true sinaliza o erro para o cliente.

get_current_datetime — usa Intl.DateTimeFormat para validar o timezone IANA e formatar a data sem offset:

export function getCurrentDatetime(params: { timezone?: string }): ToolResponse

get_server_info — captura startedAt no momento do boot do módulo (variável de nível de módulo) e retorna metadados do servidor:

const startedAt = new Date().toISOString(); // capturado uma vez, no boot

export function getServerInfo(): ToolResponse

calculate_date_diff — valida ambas as datas com regex + new Date(), calcula a diferença absoluta em minutos e decompõe em dias, horas e minutos:

export function calculateDateDiff(params: { date1: string; date2: string }): ToolResponse

3. Registrar as tools no servidor MCP

Em src/index.ts, o McpServer do SDK oficial é instanciado e cada tool é registrada com seu schema Zod:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({ name: "my-first-mcp", version: "1.0.0" });

server.tool("get_current_datetime", "Descrição...", {
  timezone: z.string().optional().describe("Fuso horário IANA. Padrão: UTC"),
}, (params) => getCurrentDatetime(params));

// ... demais tools

const transport = new StdioServerTransport();
await server.connect(transport); // conecta via stdin/stdout

process.stdin.on("close", () => process.exit(0)); // encerra quando o cliente desconecta

O schema Zod serve dois propósitos: validação dos parâmetros recebidos e geração automática do JSON Schema que o cliente usa para saber como chamar a tool.

4. Adicionar o shebang no arquivo compilado

O TypeScript não preserva o #!/usr/bin/env node no arquivo compilado. Sem ele, o sistema operacional não sabe que deve usar o Node.js para executar o arquivo diretamente.

O script scripts/add-shebang.cjs resolve isso após o tsc:

const fs = require("fs");
const file = "dist/index.js";
const content = fs.readFileSync(file, "utf8");
if (!content.startsWith("#!/usr/bin/env node")) {
  fs.writeFileSync(file, "#!/usr/bin/env node\n" + content);
}
fs.chmodSync(file, "755"); // permissão de execução

O script usa extensão .cjs porque o package.json tem "type": "module" — sem isso, o Node tentaria interpretá-lo como ESM e o require() falharia.

O build completo fica:

npm run build
# equivale a: tsc && node scripts/add-shebang.cjs

5. Publicar no npm

# Autenticar com um Granular Access Token (com bypass 2FA habilitado)
npm config set //registry.npmjs.org/:_authToken SEU_TOKEN

# Publicar
npm publish --access public

O campo "files": ["dist"] no package.json garante que apenas o código compilado vai para o registry — sem src/, sem node_modules/, sem arquivos de configuração desnecessários.

6. Configurar no cliente MCP (Kiro)

Em ~/.kiro/settings/mcp.json:

{
  "mcpServers": {
    "my-first-mcp": {
      "command": "npx",
      "args": ["-y", "@7leirbag/my-first-mcp"]
    }
  }
}

O Kiro lê essa configuração, executa npx -y @7leirbag/my-first-mcp (que baixa e inicia o pacote automaticamente), e se comunica com o processo via stdin/stdout. A flag -y evita a confirmação interativa do npx.


Tools disponíveis

get_current_datetime

Retorna a data e hora atual no formato ISO 8601.

| Parâmetro | Tipo | Obrigatório | Padrão | Descrição | |------------|--------|-------------|--------|------------------------------------| | timezone | string | não | UTC | Identificador IANA do fuso horário |

// Resposta
{ "datetime": "2026-03-15T16:29:31", "timezone": "UTC" }

get_server_info

Retorna metadados do servidor. Sem parâmetros.

// Resposta
{
  "name": "@7leirbag/my-first-mcp",
  "version": "1.0.0",
  "status": "running",
  "startedAt": "2026-03-15T16:27:29.185Z",
  "tools": ["get_current_datetime", "get_server_info", "calculate_date_diff"]
}

calculate_date_diff

Calcula a diferença absoluta entre duas datas.

| Parâmetro | Tipo | Obrigatório | Descrição | |-----------|--------|-------------|------------------------------------| | date1 | string | sim | Data no formato ISO 8601 ou YYYY-MM-DD | | date2 | string | sim | Data no formato ISO 8601 ou YYYY-MM-DD |

// Resposta
{ "days": 73, "hours": 0, "minutes": 0, "totalMinutes": 105120 }

Desenvolvimento local

# Instalar dependências
npm install

# Compilar
npm run build

# Rodar testes
npm test

Para usar a versão local no Kiro sem publicar no npm, aponte o mcp.json para o arquivo compilado diretamente:

{
  "mcpServers": {
    "my-first-mcp-local": {
      "command": "node",
      "args": ["C:/caminho/para/o/projeto/dist/index.js"]
    }
  }
}

"# my-first-mcp"