Pular para o conteúdo principal

Tutorial: Construa um gerenciador de tarefas

SDK Python disponível

MCP Auth também está disponível para Python! Confira o repositório do SDK Python para instalação e uso.

Neste tutorial, vamos construir um servidor MCP de gerenciador de tarefas com autenticação e autorização de usuários. Seguindo a especificação MCP mais recente, nosso servidor MCP atuará como um Resource Server OAuth 2.0 que valida tokens de acesso e aplica permissões baseadas em escopo.

Após concluir este tutorial, você terá:

  • ✅ Uma compreensão básica de como configurar controle de acesso baseado em papel (RBAC) em seu servidor MCP.
  • ✅ Um servidor MCP que atua como Resource Server, consumindo tokens de acesso emitidos por um Authorization Server.
  • ✅ Uma implementação funcional de aplicação de permissões baseadas em escopo para operações de tarefas.

Visão geral

O tutorial envolverá os seguintes componentes:

  • Cliente MCP (VS Code): Um editor de código com suporte MCP integrado que atua como cliente OAuth 2.0/OIDC. Ele inicia o fluxo de autorização com o authorization server e obtém tokens de acesso para autenticar requisições ao servidor MCP.
  • Authorization Server: Um provedor OAuth 2.1 ou OpenID Connect que gerencia identidades de usuários, autentica usuários e emite tokens de acesso com escopos apropriados para clientes autorizados.
  • Servidor MCP (Resource Server): De acordo com a especificação MCP mais recente, o servidor MCP atua como Resource Server no framework OAuth 2.0. Ele valida tokens de acesso emitidos pelo authorization server e aplica permissões baseadas em escopo para operações de tarefas.

Esta arquitetura segue o fluxo padrão do OAuth 2.0 onde:

  • O VS Code solicita recursos protegidos em nome do usuário
  • O Authorization Server autentica o usuário e emite tokens de acesso
  • O Servidor MCP valida tokens e serve recursos protegidos com base nas permissões concedidas

Aqui está um diagrama de alto nível da interação entre esses componentes:

Entenda seu authorization server

Tokens de acesso com escopos

Para implementar controle de acesso baseado em papel (RBAC) em seu servidor MCP, seu authorization server precisa suportar a emissão de tokens de acesso com escopos. Escopos representam as permissões que um usuário recebeu.

Logto oferece suporte a RBAC por meio de seus recursos de API (conforme RFC 8707: Resource Indicators for OAuth 2.0) e funcionalidades de papéis. Veja como configurar:

  1. Faça login no Logto Console (ou em seu Logto Console auto-hospedado)

  2. Crie recurso de API e escopos:

    • Vá em "API Resources"
    • Crie um novo recurso de API chamado "Todo Manager"
    • Adicione os seguintes escopos:
      • create:todos: "Criar novas tarefas"
      • read:todos: "Ler todas as tarefas"
      • delete:todos: "Excluir qualquer tarefa"
  3. Crie papéis (recomendado para facilitar o gerenciamento):

    • Vá em "Roles"
    • Crie um papel "Admin" e atribua todos os escopos (create:todos, read:todos, delete:todos)
    • Crie um papel "User" e atribua apenas o escopo create:todos
  4. Atribua permissões:

    • Vá em "Users"
    • Selecione um usuário
    • Você pode:
      • Atribuir papéis na aba "Roles" (recomendado)
      • Ou atribuir escopos diretamente na aba "Permissions"

Os escopos serão incluídos na reivindicação scope do token de acesso JWT como uma string separada por espaços.

Validando tokens e verificando permissões

De acordo com a especificação MCP mais recente, o servidor MCP atua como Resource Server no framework OAuth 2.0. Como Resource Server, o servidor MCP tem as seguintes responsabilidades:

  1. Validação de token: Verificar a autenticidade e integridade dos tokens de acesso recebidos dos clientes MCP
  2. Aplicação de escopos: Extrair e validar os escopos do token de acesso para determinar quais operações o cliente está autorizado a executar
  3. Proteção de recursos: Servir apenas recursos protegidos (executar ferramentas) quando o cliente apresentar tokens válidos com permissões suficientes

Quando seu servidor MCP recebe uma requisição, ele executa o seguinte processo de validação:

  1. Extrai o token de acesso do cabeçalho Authorization (formato Bearer token)
  2. Valida a assinatura e expiração do token de acesso
  3. Extrai os escopos e informações do usuário do token validado
  4. Verifica se o token possui os escopos necessários para a operação solicitada

Por exemplo, se um usuário quiser criar uma nova tarefa, seu token de acesso deve incluir o escopo create:todos. Veja como funciona o fluxo de validação do Resource Server:

Registro dinâmico de cliente

O Registro Dinâmico de Cliente não é necessário para este tutorial, mas pode ser útil se você quiser automatizar o processo de registro do cliente MCP com seu authorization server. Veja Is Dynamic Client Registration required? para mais detalhes.

Entenda RBAC no gerenciador de tarefas

Para fins de demonstração, implementaremos um sistema simples de controle de acesso baseado em papel (RBAC) em nosso servidor MCP de gerenciador de tarefas. Isso mostrará os princípios básicos do RBAC mantendo a implementação simples.

nota

Embora este tutorial demonstre gerenciamento de escopos baseado em RBAC, é importante notar que nem todos os provedores de autenticação implementam gerenciamento de escopos por meio de papéis. Alguns provedores podem ter suas próprias implementações e mecanismos exclusivos para gerenciar controle de acesso e permissões.

Ferramentas e escopos

Nosso servidor MCP de gerenciador de tarefas fornece três ferramentas principais:

  • create-todo: Criar uma nova tarefa
  • get-todos: Listar todas as tarefas
  • delete-todo: Excluir uma tarefa pelo ID

Para controlar o acesso a essas ferramentas, definimos os seguintes escopos:

  • create:todos: Permite criar novas tarefas
  • delete:todos: Permite excluir tarefas existentes
  • read:todos: Permite consultar e recuperar a lista de todas as tarefas

Papéis e permissões

Definiremos dois papéis com diferentes níveis de acesso:

Papelcreate:todosread:todosdelete:todos
Admin
User
  • User: Um usuário comum que pode criar tarefas e visualizar ou excluir apenas suas próprias tarefas
  • Admin: Um administrador que pode criar, visualizar e excluir todas as tarefas, independentemente da propriedade

Propriedade do recurso

Embora a tabela de permissões acima mostre os escopos explícitos atribuídos a cada papel, há um princípio importante de propriedade do recurso a considerar:

  • Usuários não possuem os escopos read:todos ou delete:todos, mas ainda podem:
    • Ler suas próprias tarefas
    • Excluir suas próprias tarefas
  • Admins possuem permissões completas (read:todos e delete:todos), permitindo:
    • Visualizar todas as tarefas do sistema
    • Excluir qualquer tarefa, independentemente da propriedade

Isso demonstra um padrão comum em sistemas RBAC onde a propriedade do recurso concede permissões implícitas aos usuários para seus próprios recursos, enquanto papéis administrativos recebem permissões explícitas para todos os recursos.

Saiba mais

Para se aprofundar em conceitos e boas práticas de RBAC, confira Dominando RBAC: Um exemplo abrangente do mundo real.

Configure a autorização em seu provedor

Para implementar o sistema de controle de acesso que descrevemos anteriormente, você precisará configurar seu authorization server para suportar os escopos necessários. Veja como fazer isso em diferentes provedores:

Logto oferece suporte a RBAC por meio de recursos de API e funcionalidades de papéis. Veja como configurar:

  1. Faça login no Logto Console (ou em seu Logto Console auto-hospedado)

  2. Crie recurso de API e escopos:

    • Vá em "API Resources"
    • Crie um novo recurso de API chamado "Todo Manager" usando http://localhost:3001/ como indicador de recurso.
      • Importante: O indicador de recurso deve corresponder à URL do seu servidor MCP. Para este tutorial, usamos http://localhost:3001/ pois nosso servidor MCP roda na porta 3001. Em produção, use a URL real do seu servidor MCP (ex: https://seu-mcp-server.exemplo.com/).
    • Crie os seguintes escopos:
      • create:todos: "Criar novas tarefas"
      • read:todos: "Ler todas as tarefas"
      • delete:todos: "Excluir qualquer tarefa"
  3. Crie papéis (recomendado para facilitar o gerenciamento):

    • Vá em "Roles"
    • Crie um papel "Admin" e atribua todos os escopos (create:todos, read:todos, delete:todos)
    • Crie um papel "User" e atribua apenas o escopo create:todos
    • Na página de detalhes do papel "User", vá para a aba "General" e defina o papel "User" como o "Default role".
  4. Gerencie papéis e permissões dos usuários:

    • Para novos usuários:
      • Eles receberão automaticamente o papel "User" pois o definimos como padrão
    • Para usuários existentes:
      • Vá em "User management"
      • Selecione um usuário
      • Atribua papéis ao usuário na aba "Roles"
Gerenciamento de papéis programático

Você também pode usar a Management API do Logto para gerenciar papéis de usuários programaticamente. Isso é especialmente útil para automação ou ao construir painéis administrativos.

Ao solicitar um token de acesso, o Logto incluirá os escopos na reivindicação scope do token com base nas permissões do papel do usuário.

Barra no final do indicador de recurso

Sempre inclua uma barra (/) no final do indicador de recurso. Devido a um bug atual no SDK oficial MCP, clientes usando o SDK adicionarão automaticamente uma barra ao final dos identificadores de recurso ao iniciar requisições de autenticação. Se seu indicador de recurso não incluir a barra, a validação do recurso falhará para esses clientes. (O VS Code não é afetado por esse bug.)

Após configurar seu authorization server, os usuários receberão tokens de acesso contendo seus escopos concedidos. O servidor MCP usará esses escopos para determinar:

  • Se um usuário pode criar novas tarefas (create:todos)
  • Se um usuário pode visualizar todas as tarefas (read:todos) ou apenas as suas
  • Se um usuário pode excluir qualquer tarefa (delete:todos) ou apenas as suas

Configure o servidor MCP

Usaremos os SDKs oficiais MCP para criar nosso servidor MCP de gerenciador de tarefas.

Crie um novo projeto

Configure um novo projeto Node.js:

mkdir mcp-server
cd mcp-server
npm init -y # Ou use `pnpm init`
npm pkg set type="module"
npm pkg set main="todo-manager.ts"
npm pkg set scripts.start="node --experimental-strip-types todo-manager.ts"
nota

Estamos usando TypeScript em nossos exemplos pois o Node.js v22.6.0+ suporta rodar TypeScript nativamente usando a flag --experimental-strip-types. Se você estiver usando JavaScript, o código será semelhante - apenas certifique-se de usar Node.js v22.6.0 ou superior. Veja a documentação do Node.js para detalhes.

Instale o MCP SDK e dependências

npm install @modelcontextprotocol/sdk express zod

Ou qualquer outro gerenciador de pacotes de sua preferência, como pnpm ou yarn.

Crie o servidor MCP

Crie um arquivo chamado todo-manager.ts e adicione o seguinte código:

// todo-manager.ts

import { z } from 'zod';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express, { type Request, type Response } from 'express';

// Crie um servidor MCP
const server = new McpServer({
  name: 'Todo Manager',
  version: '0.0.0',
});

server.registerTool(
  'create-todo',
  {
    description: 'Criar uma nova tarefa',
    inputSchema: { content: z.string() },
  },
  async ({ content }) => {
    return {
      content: [{ type: 'text', text: JSON.stringify({ error: 'Not implemented' }) }],
    };
  }
);

server.registerTool(
  'get-todos',
  {
    description: 'Listar todas as tarefas',
    inputSchema: {},
  },
  async () => {
    return {
      content: [{ type: 'text', text: JSON.stringify({ error: 'Not implemented' }) }],
    };
  }
);

server.registerTool(
  'delete-todo',
  {
    description: 'Excluir uma tarefa pelo id',
    inputSchema: { id: z.string() },
  },
  async ({ id }) => {
    return {
      content: [{ type: 'text', text: JSON.stringify({ error: 'Not implemented' }) }],
    };
  }
);

// Abaixo está o código boilerplate da documentação do MCP SDK
const PORT = 3001;
const app = express();

app.post('/', async (request: Request, response: Response) => {
  // No modo stateless, crie uma nova instância de transport e server para cada requisição
  // para garantir isolamento completo. Uma única instância causaria colisão de IDs de requisição
  // quando múltiplos clientes conectam simultaneamente.

  try {
    const transport: StreamableHTTPServerTransport = new StreamableHTTPServerTransport({
      sessionIdGenerator: undefined,
    });
    response.on('close', async () => {
      console.log('Request closed');
      await transport.close();
      await server.close();
    });
    await server.connect(transport);
    await transport.handleRequest(request, response, request.body);
  } catch (error) {
    console.error('Erro ao lidar com requisição MCP:', error);
    if (!response.headersSent) {
      response.status(500).json({
        jsonrpc: '2.0',
        error: {
          code: -32_603,
          message: 'Internal server error',
        },
        id: null,
      });
    }
  }
});

// Notificações SSE não suportadas no modo stateless
app.get('/', async (request: Request, response: Response) => {
  console.log('Recebida requisição GET MCP');
  response.writeHead(405).end(
    JSON.stringify({
      jsonrpc: '2.0',
      error: {
        code: -32_000,
        message: 'Method not allowed.',
      },
      id: null,
    })
  );
});

// Encerramento de sessão não é necessário no modo stateless
app.delete('/', async (request: Request, response: Response) => {
  console.log('Recebida requisição DELETE MCP');
  response.writeHead(405).end(
    JSON.stringify({
      jsonrpc: '2.0',
      error: {
        code: -32_000,
        message: 'Method not allowed.',
      },
      id: null,
    })
  );
});

app.listen(PORT);

Execute o servidor com:

npm start

Integre com seu authorization server

Para completar esta seção, há várias considerações a serem feitas:

A URL do issuer do seu authorization server

Normalmente é a URL base do seu authorization server, como https://auth.example.com. Alguns provedores podem ter um caminho como https://example.logto.app/oidc, então verifique a documentação do seu provedor.

Como obter os metadados do authorization server
  • Se seu authorization server estiver em conformidade com OAuth 2.0 Authorization Server Metadata ou OpenID Connect Discovery, você pode usar as utilidades integradas do MCP Auth para buscar os metadados automaticamente.
  • Se seu authorization server não for compatível com esses padrões, você precisará especificar manualmente a URL dos metadados ou endpoints na configuração do servidor MCP. Consulte a documentação do seu provedor para os endpoints específicos.
Como registrar o cliente MCP em seu authorization server
  • Se seu authorization server suporta Dynamic Client Registration, você pode pular esta etapa pois o cliente MCP se registrará automaticamente.
  • Se seu authorization server não suporta Dynamic Client Registration, você precisará registrar manualmente o cliente MCP em seu authorization server.
Entenda os parâmetros de requisição de token

Ao solicitar tokens de acesso de diferentes authorization servers, você encontrará várias abordagens para especificar o recurso alvo e permissões. Aqui estão os principais padrões:

  • Baseado em indicador de recurso:

    • Usa o parâmetro resource para especificar a API alvo (veja RFC 8707: Resource Indicators for OAuth 2.0)
    • Comum em implementações modernas de OAuth 2.0
    • Exemplo de requisição:
      {
        "resource": "http://localhost:3001/",
        "scope": "create:todos read:todos"
      }
    • O servidor emite tokens vinculados especificamente ao recurso solicitado
  • Baseado em audience:

    • Usa o parâmetro audience para especificar o destinatário pretendido do token
    • Semelhante a indicadores de recurso, mas com semânticas diferentes
    • Exemplo de requisição:
      {
        "audience": "todo-api",
        "scope": "create:todos read:todos"
      }
  • Baseado apenas em escopo:

    • Depende apenas de escopos sem parâmetros de recurso/audience
    • Abordagem tradicional do OAuth 2.0
    • Exemplo de requisição:
      {
        "scope": "todo-api:create todo-api:read openid profile"
      }
    • Frequentemente usa escopos prefixados para namespacing de permissões
    • Comum em implementações OAuth 2.0 mais simples
Boas práticas
  • Verifique a documentação do seu provedor para os parâmetros suportados
  • Alguns provedores suportam múltiplas abordagens simultaneamente
  • Indicadores de recurso fornecem melhor segurança por restrição de audience
  • Considere usar indicadores de recurso quando disponíveis para melhor controle de acesso

Embora cada provedor possa ter requisitos específicos, os passos a seguir irão guiá-lo pelo processo de integração do VS Code e do servidor MCP com configurações específicas do provedor.

Registre o cliente MCP como um app de terceiros

Integrar o gerenciador de tarefas com o Logto é simples, pois é um provedor OpenID Connect que suporta indicadores de recurso e escopos, permitindo proteger sua API de tarefas com http://localhost:3001/ como indicador de recurso.

Como o Logto ainda não suporta Dynamic Client Registration, você precisará registrar manualmente seu cliente MCP (VS Code) como um app de terceiros em seu tenant Logto:

  1. Faça login no Logto Console (ou em seu Logto Console auto-hospedado).
  2. Navegue até Applications > Third-party apps e clique em "Create application".
  3. Selecione Native App como tipo de aplicação.
  4. Preencha os detalhes da aplicação:
    • Application name: Insira um nome para sua aplicação, ex: "MCP Client".
    • Description: Insira uma descrição, ex: "MCP client for VS Code".
  5. Defina os seguintes Redirect URIs para o VS Code:
    http://127.0.0.1
    https://vscode.dev/redirect
    
  6. Clique em "Save changes".
  7. Vá até a aba Permissions do app, na seção User, adicione as permissões create:todos, read:todos e delete:todos do recurso de API Todo Manager que você criou anteriormente.
  8. No cartão superior, você verá o valor "App ID". Copie-o para uso posterior.

Configure o MCP Auth

Primeiro, instale o SDK MCP Auth em seu projeto do servidor MCP.

pnpm add mcp-auth

Agora precisamos inicializar o MCP Auth em seu servidor MCP. No modo de recurso protegido, você precisa configurar seus metadados de recurso incluindo os authorization servers.

Existem duas formas de configurar authorization servers:

  • Pré-busca (Recomendado): Use fetchServerConfig() para buscar os metadados antes de inicializar o MCPAuth. Isso garante que a configuração seja validada na inicialização.
  • Descoberta sob demanda: Forneça apenas issuer e type - os metadados serão buscados sob demanda quando necessário. Isso é útil para runtimes edge (como Cloudflare Workers) onde não é permitido fetch assíncrono no topo do código.

Configure os metadados do recurso protegido

Primeiro, obtenha a URL do issuer do seu authorization server:

No Logto, você pode encontrar a URL do issuer na página de detalhes da sua aplicação dentro do Logto Console, na seção "Endpoints & Credentials / Issuer endpoint". Deve ser algo como https://meu-projeto.logto.app/oidc.

Agora, configure os Metadados do Recurso Protegido ao construir a instância do MCP Auth:

// todo-manager.ts

import { MCPAuth, fetchServerConfig } from 'mcp-auth';

const issuerUrl = '<issuer-url>'; // Substitua pela URL do issuer do seu authorization server

// Defina o identificador do recurso para este servidor MCP
const resourceId = 'http://localhost:3001/';

// Pré-busque a configuração do authorization server (recomendado)
const authServerConfig = await fetchServerConfig(issuerUrl, { type: 'oidc' });

// Configure o MCP Auth com os metadados do recurso protegido
const mcpAuth = new MCPAuth({
  protectedResources: {
    metadata: {
      resource: resourceId,
      authorizationServers: [authServerConfig],
      // Escopos que este servidor MCP entende
      scopesSupported: ['create:todos', 'read:todos', 'delete:todos'],
    },
  },
});

Atualize o servidor MCP

Estamos quase lá! É hora de atualizar o servidor MCP para aplicar a rota e o middleware do MCP Auth, e então implementar o controle de acesso baseado em permissões para as ferramentas do gerenciador de tarefas com base nos escopos do usuário.

Agora, aplique as rotas de metadados de recurso protegido para que clientes MCP possam recuperar os metadados esperados do recurso a partir do servidor MCP.

// todo-manager.ts

// Configure as rotas de Metadados do Recurso Protegido
// Isso expõe metadados sobre este resource server para clientes OAuth
app.use(mcpAuth.protectedResourceMetadataRouter());

Em seguida, aplicaremos o middleware MCP Auth ao servidor MCP. Esse middleware irá lidar com autenticação e autorização das requisições recebidas, garantindo que apenas usuários autorizados possam acessar as ferramentas do gerenciador de tarefas.

// todo-manager.ts

app.use(mcpAuth.protectedResourceMetadataRouter());

// Aplique o middleware MCP Auth
app.use(
  mcpAuth.bearerAuth('jwt', {
    resource: resourceId,
    audience: resourceId,
  })
);

Neste ponto, podemos atualizar as ferramentas do gerenciador de tarefas para aproveitar o middleware MCP Auth para autenticação e autorização.

Vamos atualizar a implementação das ferramentas.

// todo-manager.ts

// outros imports...
import assert from 'node:assert';
import { fetchServerConfig, MCPAuth, MCPAuthBearerAuthError } from 'mcp-auth';
import { type AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';

// Será mencionado na próxima seção
import { TodoService } from './todo-service.js';

const assertUserId = (authInfo?: AuthInfo) => {
  const { subject } = authInfo ?? {};
  assert(subject, 'Invalid auth info');
  return subject;
};

const hasRequiredScopes = (userScopes: string[], requiredScopes: string[]): boolean => {
  return requiredScopes.every((scope) => userScopes.includes(scope));
};

const todoService = new TodoService();

server.registerTool(
  'create-todo',
  {
    description: 'Criar uma nova tarefa',
    inputSchema: { content: z.string() },
  },
  ({ content }, { authInfo }) => {
    const userId = assertUserId(authInfo);

    /**
     * Apenas usuários com o escopo 'create:todos' podem criar tarefas
     */
    if (!hasRequiredScopes(authInfo?.scopes ?? [], ['create:todos'])) {
      throw new MCPAuthBearerAuthError('missing_required_scopes');
    }

    const createdTodo = todoService.createTodo({ content, ownerId: userId });

    return {
      content: [{ type: 'text', text: JSON.stringify(createdTodo) }],
    };
  }
);

server.registerTool(
  'get-todos',
  {
    description: 'Listar todas as tarefas',
    inputSchema: {},
  },
  (_params, { authInfo }) => {
    const userId = assertUserId(authInfo);

    /**
     * Se o usuário tem o escopo 'read:todos', pode acessar todas as tarefas (todoOwnerId = undefined)
     * Se não tem, pode acessar apenas suas próprias tarefas (todoOwnerId = userId)
     */
    const todoOwnerId = hasRequiredScopes(authInfo?.scopes ?? [], ['read:todos'])
      ? undefined
      : userId;

    const todos = todoService.getAllTodos(todoOwnerId);

    return {
      content: [{ type: 'text', text: JSON.stringify(todos) }],
    };
  }
);

server.registerTool(
  'delete-todo',
  {
    description: 'Excluir uma tarefa pelo id',
    inputSchema: { id: z.string() },
  },
  ({ id }, { authInfo }) => {
    const userId = assertUserId(authInfo);

    const todo = todoService.getTodoById(id);

    if (!todo) {
      return {
        content: [{ type: 'text', text: JSON.stringify({ error: 'Failed to delete todo' }) }],
      };
    }

    /**
     * Usuários só podem excluir suas próprias tarefas
     * Usuários com o escopo 'delete:todos' podem excluir qualquer tarefa
     */
    if (todo.ownerId !== userId && !hasRequiredScopes(authInfo?.scopes ?? [], ['delete:todos'])) {
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({ error: 'Failed to delete todo' }),
          },
        ],
      };
    }

    const deletedTodo = todoService.deleteTodo(id);

    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify({
            message: `Todo ${id} deleted`,
            details: deletedTodo,
          }),
        },
      ],
    };
  }
);

Agora, crie o "serviço de tarefas" usado no código acima para implementar a funcionalidade relacionada:

Crie o arquivo todo-service.ts para o serviço de tarefas:

// todo-service.ts

type Todo = {
  id: string;
  content: string;
  ownerId: string;
  createdAt: string;
};

/**
 * Um serviço simples de tarefas para fins de demonstração.
 * Usa um array em memória para armazenar tarefas
 */
export class TodoService {
  private readonly todos: Todo[] = [];

  getAllTodos(ownerId?: string): Todo[] {
    if (ownerId) {
      return this.todos.filter((todo) => todo.ownerId === ownerId);
    }
    return this.todos;
  }

  getTodoById(id: string): Todo | undefined {
    return this.todos.find((todo) => todo.id === id);
  }

  createTodo({ content, ownerId }: { content: string; ownerId: string }): Todo {
    const todo: Todo = {
      id: this.genId(),
      content,
      ownerId,
      createdAt: new Date().toISOString(),
    };

    // eslint-disable-next-line @silverhand/fp/no-mutating-methods
    this.todos.push(todo);
    return todo;
  }

  deleteTodo(id: string): Todo | undefined {
    const index = this.todos.findIndex((todo) => todo.id === id);

    if (index === -1) {
      return undefined;
    }

    // eslint-disable-next-line @silverhand/fp/no-mutating-methods
    const [deleted] = this.todos.splice(index, 1);
    return deleted;
  }

  private genId(): string {
    return Math.random().toString(36).slice(2, 10);
  }
}

Parabéns! Implementamos com sucesso um servidor MCP completo com autenticação e autorização!

info

Confira o repositório do SDK MCP Auth Node.js para o código completo do servidor MCP (versão OIDC).

Checkpoint: Execute as ferramentas todo-manager

Reinicie seu servidor MCP e conecte o VS Code a ele. Veja como conectar com autenticação:

  1. No VS Code, pressione Command + Shift + P (macOS) ou Ctrl + Shift + P (Windows/Linux) para abrir a Command Palette.
  2. Digite MCP: Add Server... e selecione.
  3. Escolha HTTP como tipo de servidor.
  4. Insira a URL do servidor MCP: http://localhost:3001
  5. Após uma requisição OAuth ser iniciada, o VS Code solicitará que você insira o App ID. Insira o App ID copiado do seu authorization server.
  6. Como não temos um App Secret (é um cliente público), apenas pressione Enter para pular.
  7. Complete o fluxo de login no seu navegador.

Depois de fazer login e retornar ao VS Code, repita as ações do checkpoint anterior para executar as ferramentas do gerenciador de tarefas. Desta vez, você pode usar essas ferramentas com sua identidade de usuário autenticada. O comportamento das ferramentas dependerá dos papéis e permissões atribuídos ao seu usuário:

  • Se você estiver logado como User (com apenas o escopo create:todos):

    • Pode criar novas tarefas usando a ferramenta create-todo
    • Só pode visualizar e excluir suas próprias tarefas
    • Não poderá ver ou excluir tarefas de outros usuários
  • Se estiver logado como Admin (com todos os escopos: create:todos, read:todos, delete:todos):

    • Pode criar novas tarefas
    • Pode visualizar todas as tarefas do sistema usando a ferramenta get-todos
    • Pode excluir qualquer tarefa usando a ferramenta delete-todo, independentemente de quem a criou

Você pode testar esses diferentes níveis de permissão:

  1. Desconectando do servidor MCP (remova a configuração do servidor no VS Code)
  2. Fazendo login com outra conta de usuário que tenha papéis/permissões diferentes
  3. Testando as mesmas ferramentas novamente para observar como o comportamento muda de acordo com as permissões do usuário

Isso demonstra como o controle de acesso baseado em papel (RBAC) funciona na prática, onde diferentes usuários têm diferentes níveis de acesso à funcionalidade do sistema.

info

Confira o repositório do SDK MCP Auth Node.js para o código completo do servidor MCP (versão OIDC).

Notas finais

Parabéns! Você concluiu com sucesso o tutorial. Vamos recapitular o que fizemos:

  • Configuramos um servidor MCP básico com ferramentas de gerenciamento de tarefas (create-todo, get-todos, delete-todo)
  • Implementamos controle de acesso baseado em papel (RBAC) com diferentes níveis de permissão para usuários e admins
  • Integramos o servidor MCP com um authorization server usando MCP Auth
  • Configuramos o VS Code para autenticar usuários e usar tokens de acesso com escopos para chamar ferramentas

Não deixe de conferir outros tutoriais e a documentação para aproveitar ao máximo o MCP Auth.