Install the TypeScript MCP SDK and scaffold the support-triage server skeleton — the foundation for modules 03 and 04
Quando construí o sistema de automação de suporte, cada nova integração começava da mesma forma: escrever serialização personalizada, conectar autenticação, tratar erros em um formato sob medida — depois repetir tudo para a próxima ferramenta. A base de conhecimento da equipe de suporte, o sistema de tickets e o motor de roteamento tinham cada um seu próprio formato. Dar a uma IA acesso a qualquer um deles significava construir um adaptador avulso.
O MCP padroniza essas conexões. Mas o SDK TypeScript vai além: fornece prova em tempo de compilação de que seus handlers correspondem ao protocolo. Os schemas de requisição — ListResourcesRequestSchema, ReadResourceRequestSchema e os equivalentes para ferramentas — são objetos TypeScript. Quando você passa um para setRequestHandler, o TypeScript verifica que seu callback recebe e retorna o formato correto. Tipo errado? A build falha. Sem surpresas em tempo de execução.
Essa segurança em tempo de compilação é a razão de usar o SDK tipado em vez de rotas HTTP ad hoc ou a superfície de API baseada em string que exemplos mais antigos mostram.
A única regra: Todo handler neste percurso usa a forma de schema tipado —
server.setRequestHandler(ListResourcesRequestSchema, async () => ...) — nunca a
forma baseada em string que passa uma string simples como 'resources/list' como primeiro argumento.
Você nunca verá a superfície de API errada neste curso.
Neste módulo você instalará o SDK, configurará o TypeScript e criará o esqueleto do servidor de triagem de suporte. Recursos vêm no módulo 03; ferramentas vêm no módulo 04. O trabalho deste módulo é acertar o frame para que o restante tenha onde se encaixar.
O servidor de triagem de suporte precisa de uma dependência de runtime: o SDK do MCP. Ferramentas de desenvolvimento — TypeScript, tsx, tipos do Node.js — ficam separadas para nunca serem enviadas para produção.
Adicione "type": "module" ao package.json (o SDK do MCP usa sintaxe de módulo ES). Em seguida, crie o tsconfig.json. Duas configurações são críticas: "module": "Node16" e "moduleResolution": "Node16". O SDK importa seus próprios módulos com extensões .js — a resolução Node16 lida com isso corretamente; a resolução CommonJS as rejeita.
CommonJS não funcionará aqui. Se você definir "module": "CommonJS" ou omitir "type": "module"
do package.json, importações de @modelcontextprotocol/sdk/server/index.js falharão com
"Cannot find module." Node16 é o alvo correto para este SDK.
Adicione um script dev ao package.json para poder executar src/index.ts diretamente sem compilar:
Em seguida, crie o diretório fonte: mkdir src.
A classe Server é o núcleo de todo servidor MCP. Ela mantém a identidade do servidor e o registry de handlers que você preencherá mais tarde. Crie src/index.ts:
O campo name é visível para usuários finais em ferramentas como o Claude Desktop. support-triage-server diz ao desenvolvedor de relance o que esse servidor faz. my-server ou mcp-server-1 não transmite nada útil.
A instância de Server agora existe em memória e mantém seu registry de handlers. Mas ainda não consegue receber nenhuma mensagem. Antes de continuar a leitura, preveja: o que ainda está faltando e o que aconteceria se você tentasse chamar um handler diretamente sem isso?
O servidor não tem canal de entrada/saída — é um registry sem conexão com o mundo externo. Chamar um handler diretamente contornaria o protocolo completamente, ignorando o parsing de requisições, o wrapping de erros e o envelope de resposta que os clientes MCP esperam. A peça que falta é o transport.
Pense no transport como o cabo de força de uma lâmpada. A lâmpada sabe exatamente o que fazer — emitir luz sob demanda — mas não faz nada até ser conectada. StdioServerTransport é o cabo padrão para desenvolvimento local: conecta a entrada e saída do seu servidor ao stdin e stdout do processo, que é como o Claude Desktop e outros clientes MCP se comunicam.
Nunca use console.log() em um servidor MCP. Ele escreve no stdout, que o cliente MCP
lê como dados de protocolo. Use process.stderr.write() para toda saída de status e depuração.
O src/index.ts completo nesta etapa é um arquivo de 17 linhas — intencionalmente mínimo:
Isso não é um stub. É um servidor MCP válido e em execução. Apenas ainda não tem recursos ou ferramentas. Quando um cliente de IA se conecta e pergunta "quais recursos você tem?", receberá uma lista vazia — que é a resposta correta do protocolo para um servidor sem handlers registrados.
Execute o servidor com tsx para confirmar que ele inicia sem erros:
O que você tem: Um servidor MCP válido que inicia, conecta seu transport e aguarda clientes de IA. No módulo 03 você adiciona recursos de artigos da base de conhecimento e histórico de tickets. No módulo 04 você adiciona ferramentas de classificação, roteamento e escalonamento. Cada módulo adiciona uma camada a este esqueleto.
Se você estivesse adicionando este servidor MCP a um monorepo TypeScript existente — um que já tem seu próprio tsconfig.json e pipeline de build — quais partes desta configuração você reutilizaria do monorepo e quais são específicas do servidor MCP?
As configurações Node16 do tsconfig.json e "type": "module" no package.json são requisitos do SDK do MCP. Se o monorepo já usa Node16 ESM, você pode adicionar o servidor como um pacote de workspace e reutilizar o pipeline de build do monorepo. O único código verdadeiramente específico do MCP é o que fica em src/index.ts. Manter o código do servidor separado do scaffolding é o que o torna portável entre projetos.
Application-level questions to confirm you understand the setup choices, not just the steps.
1. Which import path correctly brings in the MCP `Server` class?
Correct Answer: B
The SDK uses sub-path exports. The Server class lives at `server/index.js`. Using the package root (`@modelcontextprotocol/sdk`) fails to resolve the named export; the other two package names do not exist.
2. Why must status messages go to `process.stderr` instead of `console.log` in an MCP server?
Correct Answer: B
MCP clients receive messages over stdout. A stray `console.log` line is not valid JSON-RPC and the client will fail to parse it, breaking the connection. stderr is a separate channel that clients ignore.
3. What does `await server.connect(transport)` do at runtime?
Correct Answer: C
`connect()` wires the transport's read/write streams to the server's message dispatcher. After this call the server listens for incoming JSON-RPC messages on stdin and writes responses to stdout.
4. A Server instance with no handlers registered is...
Correct Answer: B
A handler-less server starts and runs correctly. It returns `{ resources: [] }` and `{ tools: [] }` — valid MCP protocol responses, just not useful yet. This is why building the skeleton first and adding handlers incrementally works.
5. Which TypeScript setting is required for the MCP SDK to resolve its `.js` module extensions?
Correct Answer: C
The SDK imports its own sub-modules with explicit `.js` extensions (ESM style). Node16 resolution allows this. CommonJS resolution rejects `.js` extensions on TypeScript imports; Bundler works for bundled output but not for direct Node.js execution.
6. In the power-cord analogy, what does `StdioServerTransport` connect?
Correct Answer: C
StdioServerTransport reads JSON-RPC messages from stdin and writes responses to stdout. This is the channel Claude Desktop and other MCP clients use. Without it, the Server instance is a handler registry with no way to receive requests.
7. The `name` field in `new Server({ name, version })` is...
Correct Answer: B
Claude Desktop and other MCP clients show the server name when listing available servers. A descriptive name like `support-triage-server` tells a developer what the server does at a glance. `my-server` or `server-1` conveys nothing.
8. After calling `await server.connect(transport)` with no handlers registered, what does the server return when an AI client asks for the list of resources?
Correct Answer: C
The MCP SDK has a built-in default handler for `resources/list` that returns an empty array. An empty list is a perfectly valid response that tells the client 'this server exists but has no resources yet.' This is why the incremental build approach works.
Construa um servidor MCP mínimo que exponha um único recurso fixo — uma mensagem de boas-vindas em info://welcome — usando os handlers de schema tipados.
Passos:
Server, StdioServerTransport, ListResourcesRequestSchema e ReadResourceRequestSchemaServer com nome 'welcome-server' versão '1.0.0'ListResourcesRequestSchema retornando um recurso (uri 'info://welcome', name 'Welcome Message', mimeType 'text/plain')ReadResourceRequestSchema retornando 'Welcome to MCP!' para o URI de boas-vindas e lançando erro para qualquer outro URIStdioServerTransport, conecte o servidor e escreva uma linha de status em process.stderrDica: ListResourcesRequestSchema retorna {resources: [...]}. ReadResourceRequestSchema retorna {contents: [{uri, mimeType, text}]}. Se o URI não corresponder, lance new Error("Resource not found: " + uri).
ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
const server = new Server({ name: "welcome-server", version: "1.0.0" });
// TODO: adicionar handler ListResourcesRequestSchema // TODO: adicionar handler ReadResourceRequestSchema
const transport = new StdioServerTransport(); await server.connect(transport); process.stderr.write("welcome-server running\n"); </CodeExample>
Solução
<CodeExample title="Solução" language="typescript"> server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [ { uri: "info://welcome", name: "Welcome Message", mimeType: "text/plain" }, ], }));server.setRequestHandler(ReadResourceRequestSchema, async (req) => { const { uri } = req.params; if (uri !== "info://welcome") { throw new Error("Resource not found: " + uri); } return { contents: [{ uri, mimeType: "text/plain", text: "Welcome to MCP!" }], }; }); </CodeExample>
Com o esqueleto do servidor estabelecido, o módulo 03 preenche os recursos. Você usará ListResourcesRequestSchema e ReadResourceRequestSchema — os handlers de schema tipados que dão ao servidor de triagem de suporte sua primeira capacidade real: responder a consultas de IA sobre artigos da base de conhecimento e histórico recente de tickets.
O padrão que você usará no módulo 03 é o mesmo que este módulo estabelece: importe o schema, passe-o para setRequestHandler, implemente o callback tipado. A superfície de API tipada que você aprendeu aqui é a base sobre a qual o restante do percurso é construído.