#
tokens: 17828/50000 17/17 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── docs
│   ├── CONFIGURACAO_CERTIFICADO.md
│   ├── INSTALACAO.md
│   └── TRIBUNAIS_SUPORTADOS.md
├── examples
│   └── claude_desktop_config.json
├── LICENSE
├── package.json
├── public
│   └── index.html
├── README.md
├── src
│   ├── certificate-manager.ts
│   ├── index.ts
│   ├── pdf-processor.ts
│   ├── pje-client.ts
│   ├── test-certificate.ts
│   ├── types.ts
│   ├── utils.ts
│   └── web-server.ts
├── tsconfig.json
└── views
    └── index.ejs
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Dependências
node_modules/
package-lock.json
yarn.lock

# Arquivos de build
build/
dist/
*.js
*.d.ts
*.js.map

# Arquivos de ambiente
.env
.env.local
.env.*.local
!.env.example

# Arquivos de IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Arquivos do sistema
Thumbs.db
desktop.ini

# Logs
logs/
*.log
npm-debug.log
yarn-debug.log
yarn-error.log
lerna-debug.log
.pnpm-debug.log

# Testing
coverage/
.nyc_output/

# Temporary files
*.tmp
*.temp
temp/
tmp/

# Certificates (security)
*.pfx
*.p12
*.pem
*.key
*.crt
*.cer
certificados/
certs/

# Claude Desktop config (personal)
claude_desktop_config.json
!examples/claude_desktop_config.json

# Backup files
*.backup
*.bak

# Arquivos de upload
uploads/
*.pdf 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# 🔐 PJE MCP Server

Servidor MCP (Model Context Protocol) para integração com o sistema PJE (Processo Judicial Eletrônico) brasileiro, com suporte completo a certificados digitais A1 e A3.

## 🚀 Características

- ✅ **Integração completa com PJE** - Acesso total à API do PJE
- 🔐 **Certificados Digitais** - Suporte A1 (arquivo) e A3 (token/smartcard)
- 📋 **Gestão de Processos** - Liste, busque e acompanhe processos
- 🏛️ **Dados Judiciais** - Órgãos julgadores, classes e assuntos
- 🔍 **Filtros Avançados** - Busca com múltiplos critérios
- 🌐 **Multi-tribunal** - Funciona com qualquer tribunal PJE
- 🤖 **Claude Desktop** - Integração nativa com IA

## 📦 Instalação Rápida

```bash
git clone https://github.com/seu-usuario/pje-mcp-server.git
cd pje-mcp-server
npm install
cp .env.example .env
# Edite o arquivo .env com suas configurações
npm run build
```

## ⚙️ Configuração

### 1. Configuração Básica (.env)

```env
# URL do seu tribunal
PJE_BASE_URL=https://pje.tjce.jus.br
PJE_APP_NAME=pje-tjce-1g

# Certificado Digital (escolha uma opção)
# Opção 1: Arquivo PFX
PJE_CERTIFICATE_PFX_PATH=C:\certificado.pfx
PJE_CERTIFICATE_PFX_PASSWORD=senha123

# Opção 2: Windows Store
PJE_CERTIFICATE_THUMBPRINT=abc123...
```

### 2. Claude Desktop (Windows)

Adicione ao arquivo `%APPDATA%\Claude\claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "pje": {
      "command": "node",
      "args": ["C:\\caminho\\para\\pje-mcp-server\\build\\index.js"]
    }
  }
}
```

### 3. Claude Desktop (Mac/Linux)

Adicione ao arquivo `~/.config/claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "pje": {
      "command": "node",
      "args": ["/caminho/para/pje-mcp-server/build/index.js"]
    }
  }
}
```

## 🎯 Uso com Claude

Após configurar, reinicie o Claude Desktop e use comandos naturais:

```
"Configure o PJE do TJCE"
"Liste meus processos"
"Busque o processo 1234567-89.2024.8.06.0001"
"Mostre os órgãos julgadores"
"Quais são minhas audiências esta semana?"
```

## 🔐 Certificados Digitais

### Identificar seu Certificado (Windows)

```cmd
certutil -store My
```

### Tipos Suportados

| Tipo | Descrição | Configuração |
|------|-----------|--------------|
| A1 | Arquivo .pfx/.p12 | `PJE_CERTIFICATE_PFX_PATH` |
| A3 | Token/Smartcard | `PJE_CERTIFICATE_THUMBPRINT` |

### Certificadoras Homologadas

- SERPRO
- Certisign
- Serasa Experian
- Valid
- Soluti
- AC Caixa

## 🏛️ Tribunais Testados

- **TJCE** - Tribunal de Justiça do Ceará
- **TRF5** - Tribunal Regional Federal da 5ª Região
- **TJMG** - Tribunal de Justiça de Minas Gerais
- **TJSP** - Tribunal de Justiça de São Paulo
- **TJRJ** - Tribunal de Justiça do Rio de Janeiro

## 📝 Comandos Disponíveis

### Configuração
- `pje_configurar` - Configura conexão com o tribunal
- `pje_configurar_certificado` - Configura certificado digital
- `pje_listar_certificados` - Lista certificados instalados
- `pje_info_certificado` - Informações do certificado atual
- `pje_status` - Status da configuração

### Consultas
- `pje_listar_processos` - Lista processos com filtros
- `pje_buscar_processo` - Busca processo por número
- `pje_listar_orgaos_julgadores` - Lista órgãos
- `pje_listar_classes` - Classes processuais
- `pje_listar_assuntos` - Assuntos disponíveis

## 🛠️ Desenvolvimento

### Estrutura do Projeto

```
pje-mcp-server/
├── src/                    # Código fonte TypeScript
│   ├── index.ts           # Servidor principal
│   ├── certificate-manager.ts  # Gerenciamento de certificados
│   └── types.ts           # Tipos e interfaces
├── build/                 # Código compilado (gerado)
├── docs/                  # Documentação adicional
├── examples/              # Exemplos de configuração
└── package.json          # Configuração do projeto
```

### Scripts Disponíveis

```bash
npm run build    # Compila o TypeScript
npm run start    # Inicia o servidor
npm run dev      # Compila e inicia
npm run clean    # Limpa arquivos compilados
```

## 🐛 Solução de Problemas

### Erro: "Certificado não encontrado"
```bash
# Liste certificados disponíveis
certutil -store My
# Copie o thumbprint correto para o .env
```

### Erro: "Comando não encontrado"
- Reinicie o Claude Desktop completamente
- Verifique o caminho no claude_desktop_config.json

### Erro: "Autenticação falhou"
- Verifique a validade do certificado
- Confirme a URL do tribunal
- Teste com outro certificado

## 🤝 Contribuindo

1. Faça um Fork do projeto
2. Crie sua Feature Branch (`git checkout -b feature/NovaFuncionalidade`)
3. Commit suas mudanças (`git commit -m 'Add: Nova funcionalidade'`)
4. Push para a Branch (`git push origin feature/NovaFuncionalidade`)
5. Abra um Pull Request

## 📄 Licença

Este projeto está sob a licença MIT. Veja o arquivo [LICENSE](LICENSE) para mais detalhes.

## 🔗 Links Úteis

- [Documentação do MCP](https://modelcontextprotocol.io)
- [Claude Desktop](https://claude.ai/download)
- [Documentação do PJE](https://www.pje.jus.br/wiki)

## 📞 Suporte

- **Issues**: [GitHub Issues](https://github.com/seu-usuario/pje-mcp-server/issues)
- **Discussões**: [GitHub Discussions](https://github.com/seu-usuario/pje-mcp-server/discussions)
- **Email**: [email protected]

---

Desenvolvido com ❤️ para a comunidade jurídica brasileira 
```

--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------

```typescript
import { exec } from 'child_process';
import { promisify } from 'util';

export const execAsync = promisify(exec); 
```

--------------------------------------------------------------------------------
/examples/claude_desktop_config.json:
--------------------------------------------------------------------------------

```json
{
  "mcpServers": {
    "pje": {
      "command": "node",
      "args": ["C:\\Users\\seu-usuario\\pje-mcp-server\\build\\index.js"],
      "env": {
        "NODE_ENV": "production"
      }
    },
    "pje-dev": {
      "command": "node",
      "args": ["C:\\Users\\seu-usuario\\pje-mcp-server-dev\\build\\index.js"],
      "env": {
        "NODE_ENV": "development",
        "PJE_DEBUG": "true"
      }
    }
  }
} 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "moduleResolution": "node",
    "lib": ["ES2022"],
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": false,
    "sourceMap": false,
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "build",
    "dist",
    "examples",
    "docs"
  ]
} 
```

--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------

```typescript
export interface PJEProcesso {
  id: string;
  numero: string;
  classe: string;
  assunto: string;
  dataDistribuicao: string;
  valorCausa: number;
  partes: PJEParte[];
  movimentos: PJEMovimento[];
}

export interface PJEParte {
  tipo: "ATIVO" | "PASSIVO";
  nome: string;
  cpfCnpj?: string;
  advogados?: PJEAdvogado[];
}

export interface PJEAdvogado {
  nome: string;
  oab: string;
}

export interface PJEMovimento {
  data: string;
  descricao: string;
  tipo: string;
  documentos?: PJEDocumento[];
}

export interface PJEDocumento {
  id: string;
  nome: string;
  tipo: string;
  dataJuntada: string;
}

export interface PJEOrgaoJulgador {
  id: string;
  nome: string;
  tipo: string;
  competencia: string;
}

export interface PJEClasse {
  id: string;
  codigo: string;
  nome: string;
  sigla: string;
}

export interface PJEAssunto {
  id: string;
  codigo: string;
  nome: string;
  codigoPai?: string;
} 
```

--------------------------------------------------------------------------------
/src/test-certificate.ts:
--------------------------------------------------------------------------------

```typescript
import * as dotenv from 'dotenv';
import { CertificateManager } from './certificate-manager.js';

// Carregar variáveis de ambiente
dotenv.config();

async function testCertificate() {
    try {
        console.log('Variáveis de ambiente carregadas:');
        console.log('PJE_CERTIFICATE_THUMBPRINT:', process.env.PJE_CERTIFICATE_THUMBPRINT);
        console.log('PJE_CERTIFICATE_PASSWORD:', process.env.PJE_CERTIFICATE_PASSWORD);

        if (!process.env.PJE_CERTIFICATE_THUMBPRINT || !process.env.PJE_CERTIFICATE_PASSWORD) {
            throw new Error('Configuração do certificado não encontrada');
        }

        const config = {
            certificateThumbprint: process.env.PJE_CERTIFICATE_THUMBPRINT,
            certificatePassword: process.env.PJE_CERTIFICATE_PASSWORD
        };

        console.log('Configuração do certificado:', config);

        const certificateManager = new CertificateManager(config);
        await certificateManager.initialize();

        console.log('Certificado inicializado com sucesso!');
    } catch (error) {
        console.error('Erro ao testar certificado:', error);
        process.exit(1);
    }
}

testCertificate(); 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "pje-mcp-server",
  "version": "1.0.0",
  "description": "Servidor MCP para integração com o sistema PJE (Processo Judicial Eletrônico) brasileiro",
  "main": "build/index.js",
  "scripts": {
    "build": "tsc",
    "start": "node build/index.js",
    "start:web": "node build/web-server.js",
    "dev": "tsc && node build/index.js",
    "test": "node build/test-server.js",
    "clean": "rm -rf build",
    "prepare": "npm run build"
  },
  "keywords": [
    "pje",
    "processo-judicial-eletronico",
    "mcp",
    "model-context-protocol",
    "api",
    "juridico",
    "certificado-digital",
    "tribunal",
    "tjce",
    "trf5"
  ],
  "author": "",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/seu-usuario/pje-mcp-server.git"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.5.0",
    "axios": "^1.9.0",
    "body-parser": "^2.2.0",
    "dotenv": "^16.5.0",
    "ejs": "^3.1.10",
    "express": "^4.21.2",
    "multer": "^1.4.5-lts.1",
    "node-forge": "^1.3.1",
    "pdf-lib": "^1.17.1",
    "pdf-parse": "^1.1.1"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "@types/multer": "^1.4.11",
    "@types/node": "^20.17.51",
    "@types/node-forge": "^1.3.11",
    "typescript": "^5.8.3"
  },
  "files": [
    "build",
    "docs",
    "examples",
    "public"
  ],
  "bin": {
    "pje-mcp-server": "build/index.js"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}

```

--------------------------------------------------------------------------------
/docs/INSTALACAO.md:
--------------------------------------------------------------------------------

```markdown
# 📦 Guia de Instalação Completo

## Pré-requisitos

- Node.js 18 ou superior
- NPM ou Yarn
- Git
- Certificado Digital (A1 ou A3)
- Claude Desktop instalado

## Instalação Passo a Passo

### 1. Clone o Repositório

```bash
git clone https://github.com/seu-usuario/pje-mcp-server.git
cd pje-mcp-server
```

### 2. Instale as Dependências

```bash
npm install
```

### 3. Configure o Ambiente

```bash
# Copie o arquivo de exemplo
cp .env.example .env

# Edite com suas configurações
notepad .env  # Windows
nano .env     # Linux/Mac
```

### 4. Configure seu Tribunal

Edite o arquivo `.env`:

```env
# TJCE - Ceará
PJE_BASE_URL=https://pje.tjce.jus.br
PJE_APP_NAME=pje-tjce-1g

# TRF5 - 5ª Região
# PJE_BASE_URL=https://pje.trf5.jus.br
# PJE_APP_NAME=pje-trf5

# TJMG - Minas Gerais
# PJE_BASE_URL=https://pje.tjmg.jus.br
# PJE_APP_NAME=pje-tjmg-1g
```

### 5. Configure o Certificado Digital

#### Opção A: Arquivo PFX (A1)

```env
PJE_CERTIFICATE_PFX_PATH=C:\Users\seu-usuario\certificado.pfx
PJE_CERTIFICATE_PFX_PASSWORD=sua-senha
```

#### Opção B: Windows Store (A3)

1. Liste os certificados:
```cmd
certutil -store My
```

2. Copie o thumbprint:
```env
PJE_CERTIFICATE_THUMBPRINT=1234567890abcdef...
```

### 6. Compile o Projeto

```bash
npm run build
```

### 7. Configure o Claude Desktop

#### Windows

1. Abra o arquivo:
```
%APPDATA%\Claude\claude_desktop_config.json
```

2. Adicione a configuração:
```json
{
  "mcpServers": {
    "pje": {
      "command": "node",
      "args": ["C:\\Users\\seu-usuario\\pje-mcp-server\\build\\index.js"]
    }
  }
}
```

#### Mac/Linux

1. Abra o arquivo:
```
~/.config/claude/claude_desktop_config.json
```

2. Adicione a configuração:
```json
{
  "mcpServers": {
    "pje": {
      "command": "node",
      "args": ["/home/seu-usuario/pje-mcp-server/build/index.js"]
    }
  }
}
```

### 8. Reinicie o Claude Desktop

- Feche completamente (Ctrl+Q ou Cmd+Q)
- Aguarde 5 segundos
- Abra novamente

### 9. Teste a Instalação

No Claude, digite:
```
Verifique o status do PJE
```

Se tudo estiver correto, você verá as informações de configuração.

## Instalação Global (Opcional)

Para usar em qualquer lugar:

```bash
# Instale globalmente
npm install -g .

# Configure no Claude Desktop
{
  "mcpServers": {
    "pje": {
      "command": "pje-mcp-server"
    }
  }
}
```

## Troubleshooting

### Erro: "Cannot find module"
```bash
npm install
npm run build
```

### Erro: "Permission denied"
- Windows: Execute como Administrador
- Linux/Mac: Use `sudo` se necessário

### Erro: "Tool not found"
- Verifique se o caminho no claude_desktop_config.json está correto
- Certifique-se de que o Claude foi reiniciado 
```

--------------------------------------------------------------------------------
/src/pje-client.ts:
--------------------------------------------------------------------------------

```typescript
import { Agent } from 'https';
import { CertificateManager } from './certificate-manager.js';
import { ProcessInfo } from './pdf-processor.js';

interface PJEClientConfig {
    baseUrl: string;
    appName: string;
    certificate: {
        certificateThumbprint: string;
        certificatePassword: string;
    };
}

export class PJEClient {
    private config: PJEClientConfig;
    private certificateManager: CertificateManager | null = null;
    private agent: Agent | null = null;

    constructor(config: PJEClientConfig) {
        this.config = config;
    }

    async initializeCertificate(): Promise<void> {
        console.log('Inicializando certificado...');
        if (!this.config.certificate) {
            throw new Error('Configuração do certificado não fornecida');
        }

        try {
            this.certificateManager = new CertificateManager({
                certificateThumbprint: this.config.certificate.certificateThumbprint,
                certificatePassword: this.config.certificate.certificatePassword
            });

            await this.certificateManager.initialize();
            this.agent = this.certificateManager.getAgent();
            console.log('Certificado inicializado com sucesso');
        } catch (error) {
            console.error('Erro ao inicializar certificado:', error);
            throw error;
        }
    }

    async authenticateWithCertificate(): Promise<void> {
        if (!this.agent) {
            throw new Error('Certificado não inicializado');
        }

        // Aqui você implementaria a autenticação com o PJE
        // Por enquanto, vamos apenas simular que a autenticação foi bem-sucedida
        console.log('Autenticado com sucesso usando certificado digital');
    }

    async buscarProcesso(numeroProcesso: string): Promise<any> {
        if (!this.agent) {
            throw new Error('Certificado não inicializado');
        }

        // Aqui você implementaria a busca do processo no PJE
        // Por enquanto, vamos retornar um objeto simulado
        return {
            numeroProcesso,
            classe: 'Procedimento Comum Cível',
            assunto: 'Indenização por Dano Material',
            orgaoJulgador: '1ª Vara Cível',
            partes: [
                { tipo: 'Autor', nome: 'João da Silva' },
                { tipo: 'Réu', nome: 'Empresa XYZ Ltda' }
            ]
        };
    }

    async peticionar(processInfo: ProcessInfo): Promise<string> {
        if (!this.agent) {
            throw new Error('Certificado não inicializado');
        }

        // Aqui você implementaria o peticionamento no PJE
        // Por enquanto, vamos retornar um número de protocolo simulado
        const protocol = Math.random().toString(36).substring(2, 15);
        console.log('Petição protocolada com sucesso:', {
            numeroProcesso: processInfo.numeroProcesso,
            tipoPeticao: processInfo.tipoPeticao,
            protocol
        });

        return protocol;
    }
} 
```

--------------------------------------------------------------------------------
/src/pdf-processor.ts:
--------------------------------------------------------------------------------

```typescript
import fs from 'fs/promises';
// @ts-ignore
const pdfParse = require('pdf-parse');

export interface ProcessInfo {
    numeroProcesso: string;
    tipoPeticao: string;
    classeProcessual: string;
    orgaoJulgador: string;
    assunto: string;
}

export async function extractProcessInfo(pdfPath: string): Promise<ProcessInfo> {
    try {
        console.log('Lendo arquivo PDF:', pdfPath);
        // Ler o arquivo PDF
        const pdfBuffer = await fs.readFile(pdfPath);
        
        console.log('Extraindo texto do PDF...');
        // Extrair texto do PDF
        const data = await pdfParse(pdfBuffer);
        const fullText = data.text;
        
        console.log('Texto extraído do PDF:', fullText.substring(0, 500) + '...');

        // Extrair número do processo usando regex
        const processoMatch = fullText.match(/\d{20}/);
        if (!processoMatch) {
            console.log('Número do processo não encontrado. Tentando outros formatos...');
            // Tentar outros formatos comuns de número de processo
            const formatos = [
                /\d{7}-\d{2}\.\d{4}\.\d{1,2}\.\d{2}\.\d{4}/, // 0000000-00.0000.0.00.0000
                /\d{20}/, // 00000000000000000000
                /\d{7}-\d{2}\.\d{4}\.\d{1,2}\.\d{2}\.\d{4}\.\d{4}/ // 0000000-00.0000.0.00.0000.0000
            ];
            
            for (const formato of formatos) {
                const match = fullText.match(formato);
                if (match) {
                    console.log('Número do processo encontrado com formato alternativo:', match[0]);
                    return {
                        numeroProcesso: match[0],
                        tipoPeticao: 'Petição Intermediária',
                        classeProcessual: '',
                        orgaoJulgador: '',
                        assunto: ''
                    };
                }
            }
            
            throw new Error('Número do processo não encontrado no PDF');
        }

        console.log('Número do processo encontrado:', processoMatch[0]);

        // Extrair tipo de petição (assumindo que é sempre "Petição Intermediária")
        const tipoPeticao = 'Petição Intermediária';

        // Extrair classe processual (assumindo que está após "Classe:")
        const classeMatch = fullText.match(/Classe:\s*([^\n]+)/i);
        const classeProcessual = classeMatch ? classeMatch[1].trim() : '';

        // Extrair órgão julgador (assumindo que está após "Órgão Julgador:")
        const orgaoMatch = fullText.match(/Órgão Julgador:\s*([^\n]+)/i);
        const orgaoJulgador = orgaoMatch ? orgaoMatch[1].trim() : '';

        // Extrair assunto (assumindo que está após "Assunto:")
        const assuntoMatch = fullText.match(/Assunto:\s*([^\n]+)/i);
        const assunto = assuntoMatch ? assuntoMatch[1].trim() : '';

        return {
            numeroProcesso: processoMatch[0],
            tipoPeticao,
            classeProcessual,
            orgaoJulgador,
            assunto
        };
    } catch (error) {
        console.error('Erro ao processar PDF:', error);
        throw new Error('Erro ao processar o arquivo PDF');
    }
} 
```

--------------------------------------------------------------------------------
/docs/TRIBUNAIS_SUPORTADOS.md:
--------------------------------------------------------------------------------

```markdown
# 🏛️ Tribunais Suportados

## Configurações por Tribunal

### Região Nordeste

#### TJCE - Tribunal de Justiça do Ceará
```env
PJE_BASE_URL=https://pje.tjce.jus.br
PJE_APP_NAME=pje-tjce-1g  # 1º grau
PJE_APP_NAME=pje-tjce-2g  # 2º grau
```

#### TJBA - Tribunal de Justiça da Bahia
```env
PJE_BASE_URL=https://pje.tjba.jus.br
PJE_APP_NAME=pje-tjba-1g
PJE_APP_NAME=pje-tjba-2g
```

#### TJPE - Tribunal de Justiça de Pernambuco
```env
PJE_BASE_URL=https://pje.tjpe.jus.br
PJE_APP_NAME=pje-tjpe-1g
PJE_APP_NAME=pje-tjpe-2g
```

### Região Sudeste

#### TJSP - Tribunal de Justiça de São Paulo
```env
PJE_BASE_URL=https://pje.tjsp.jus.br
PJE_APP_NAME=pje-tjsp-1g
PJE_APP_NAME=pje-tjsp-2g
```

#### TJMG - Tribunal de Justiça de Minas Gerais
```env
PJE_BASE_URL=https://pje.tjmg.jus.br
PJE_APP_NAME=pje-tjmg-1g
PJE_APP_NAME=pje-tjmg-2g
```

#### TJRJ - Tribunal de Justiça do Rio de Janeiro
```env
PJE_BASE_URL=https://pje.tjrj.jus.br
PJE_APP_NAME=pje-tjrj-1g
PJE_APP_NAME=pje-tjrj-2g
```

### Tribunais Regionais Federais

#### TRF1 - 1ª Região
```env
PJE_BASE_URL=https://pje1g.trf1.jus.br
PJE_APP_NAME=pje-trf1
```

#### TRF2 - 2ª Região
```env
PJE_BASE_URL=https://pje.trf2.jus.br
PJE_APP_NAME=pje-trf2
```

#### TRF3 - 3ª Região
```env
PJE_BASE_URL=https://pje.trf3.jus.br
PJE_APP_NAME=pje-trf3
```

#### TRF4 - 4ª Região
```env
PJE_BASE_URL=https://pje.trf4.jus.br
PJE_APP_NAME=pje-trf4
```

#### TRF5 - 5ª Região
```env
PJE_BASE_URL=https://pje.trf5.jus.br
PJE_APP_NAME=pje-trf5
```

#### TRF6 - 6ª Região
```env
PJE_BASE_URL=https://pje.trf6.jus.br
PJE_APP_NAME=pje-trf6
```

### Tribunais Superiores

#### STJ - Superior Tribunal de Justiça
```env
PJE_BASE_URL=https://pje.stj.jus.br
PJE_APP_NAME=pje-stj
```

#### TST - Tribunal Superior do Trabalho
```env
PJE_BASE_URL=https://pje.tst.jus.br
PJE_APP_NAME=pje-tst
```

## Particularidades por Tribunal

### TJSP
- Maior volume de processos
- Requer certificado ICP-Brasil
- APIs otimizadas para alto volume

### TJMG
- Integração com SINTER
- Suporte a peticionamento em lote
- APIs específicas para precatórios

### TRF5
- Abrange: PE, AL, SE, PB, RN, CE
- APIs unificadas para toda região
- Suporte a JEF (Juizado Especial Federal)

## Testando Conexão

### Comando Básico
```
Configure o PJE do [TRIBUNAL]
```

### Verificar Endpoints
```
Liste os órgãos julgadores
```

### Testar Autenticação
```
Liste meus processos
```

## URLs Alternativas

Alguns tribunais possuem URLs diferentes para:

### Produção
- URL principal do tribunal

### Homologação
- Geralmente: `https://pje-homo.tribunal.jus.br`
- Para testes antes da produção

### Treinamento
- Geralmente: `https://pje-treina.tribunal.jus.br`
- Para capacitação de usuários

## Suporte Específico

### Consulta Pública
Todos os tribunais suportam:
- Busca por número
- Consulta de movimentações
- Download de documentos públicos

### Funcionalidades Autenticadas
Com certificado digital:
- Peticionamento
- Consulta completa
- Download de documentos sigilosos
- Intimações

## Status de Implementação

| Tribunal | Consulta | Peticionamento | Observações |
|----------|----------|----------------|-------------|
| TJCE | ✅ | ✅ | Totalmente funcional |
| TRF5 | ✅ | ✅ | Totalmente funcional |
| TJMG | ✅ | ⚠️ | Em testes |
| TJSP | ✅ | 🔄 | Em desenvolvimento |
| Outros | ✅ | ❓ | Não testado |

Legenda:
- ✅ Funcionando
- ⚠️ Parcialmente
- 🔄 Em desenvolvimento
- ❓ Não testado 
```

--------------------------------------------------------------------------------
/docs/CONFIGURACAO_CERTIFICADO.md:
--------------------------------------------------------------------------------

```markdown
# 🔐 Configuração de Certificado Digital

## Tipos de Certificado

### Certificado A1 (Arquivo)

- **Formato**: .pfx ou .p12
- **Validade**: 1 ano
- **Armazenamento**: Arquivo no computador
- **Mobilidade**: Pode ser copiado

### Certificado A3 (Token/Smartcard)

- **Formato**: Hardware (token USB ou cartão)
- **Validade**: 3 anos
- **Armazenamento**: Dispositivo criptográfico
- **Mobilidade**: Precisa do dispositivo físico

## Configuração por Tipo

### 1. Certificado A1 (Arquivo PFX)

#### Passo 1: Localize seu arquivo
```bash
# Geralmente em:
C:\Users\seu-usuario\Documents\certificados\
C:\certificados\
```

#### Passo 2: Configure no .env
```env
PJE_CERTIFICATE_PFX_PATH=C:\caminho\para\seu\certificado.pfx
PJE_CERTIFICATE_PFX_PASSWORD=senha-do-certificado
```

#### Passo 3: Teste
```bash
node build/index.js
```

### 2. Certificado A3 (Windows Store)

#### Passo 1: Instale o driver do token
- Safenet (tokens brancos)
- eToken (tokens azuis)
- Outros conforme fabricante

#### Passo 2: Liste os certificados
```cmd
certutil -store My
```

Saída esperada:
```
================ Certificate 0 ================
Serial Number: 1234567890abcdef
Issuer: CN=AC SOLUTI Multipla v5, O=ICP-Brasil
Subject: CN=SEU NOME:12345678900
Cert Hash(sha1): a1b2c3d4e5f6789012345678901234567890abcd
```

#### Passo 3: Configure no .env

Por thumbprint:
```env
PJE_CERTIFICATE_THUMBPRINT=a1b2c3d4e5f6789012345678901234567890abcd
```

Por subject:
```env
PJE_CERTIFICATE_SUBJECT=CN=SEU NOME:12345678900
```

## Identificando seu Certificado

### No Windows

1. Abra o Gerenciador de Certificados:
```cmd
certmgr.msc
```

2. Navegue para:
   - Pessoal > Certificados

3. Procure por certificados com:
   - Seu nome
   - CPF ou CNPJ
   - Válidos (não expirados)

### Verificando Validade

```powershell
# PowerShell
Get-ChildItem Cert:\CurrentUser\My | Select Subject, NotAfter
```

## Problemas Comuns

### "Certificado não encontrado"

1. Verifique se está instalado:
```cmd
certutil -store My | findstr "Subject"
```

2. Confirme o thumbprint:
```cmd
certutil -store My | findstr "Cert Hash"
```

### "Senha incorreta"

Para A1:
- Verifique a senha do arquivo PFX
- Tente abrir com outro programa
- Solicite nova senha ao emissor

### "Token não reconhecido"

Para A3:
1. Instale o driver do fabricante
2. Reinicie o computador
3. Verifique no Gerenciador de Dispositivos
4. Teste com o software do fabricante

## Certificadoras Homologadas

### SERPRO
- Site: https://certificados.serpro.gov.br
- Suporte: 0800 728 0323
- Driver: Fornecido na compra

### Certisign
- Site: https://www.certisign.com.br
- Suporte: 0800 701 1799
- Driver: https://drivers.certisign.com.br

### Serasa Experian
- Site: https://serasa.certificadodigital.com.br
- Suporte: 0800 773 7272
- Driver: No site de suporte

### Valid
- Site: https://www.validcertificadora.com.br
- Suporte: 0800 774 4414
- Driver: Central de downloads

## Melhores Práticas

1. **Backup do A1**
   - Guarde cópia em local seguro
   - Use senha forte
   - Não compartilhe

2. **Cuidados com A3**
   - Não remova durante uso
   - Mantenha drivers atualizados
   - Teste periodicamente

3. **Renovação**
   - A1: Anualmente
   - A3: A cada 3 anos
   - Agende com antecedência

4. **Segurança**
   - Nunca envie por email
   - Não salve senha em texto
   - Use gerenciador de senhas

## Comandos Úteis

### Testar certificado
```bash
# No Claude Desktop
"Liste os certificados digitais"
"Mostre informações do meu certificado"
"Verifique a validade do certificado"
```

### Exportar certificado (backup A1)
```cmd
certutil -exportPFX -p "senha" My "thumbprint" "backup.pfx"
```

### Importar certificado
```cmd
certutil -importPFX "arquivo.pfx"
``` 
```

--------------------------------------------------------------------------------
/src/certificate-manager.ts:
--------------------------------------------------------------------------------

```typescript
import { Agent } from 'https';
import { exec } from 'child_process';
import { promisify } from 'util';
import * as fs from 'fs/promises';
import * as path from 'path';

const execAsync = promisify(exec);

export interface CertificateConfig {
  certificateThumbprint: string;
  certificatePath?: string;
  certificatePassword: string;
  pfxPath?: string;
  pfxPassword?: string;
  certificateSubject?: string;
}

interface TokenCertificate {
  thumbprint: string;
  provider: string;
}

interface TokenKey {
  password: string;
  provider: string;
}

export class CertificateManager {
  private config: CertificateConfig;
  private agent: Agent | null = null;

  constructor(config: CertificateConfig) {
    this.config = config;
  }

  async initialize(): Promise<void> {
    console.log('Iniciando CertificateManager com config:', {
      ...this.config,
      certificatePassword: '***' // Ocultar senha nos logs
    });
    
    if (!this.config.certificateThumbprint) {
      throw new Error('Thumbprint do certificado não fornecido');
    }

    try {
      // Verificar se o certificado está disponível
      console.log('Verificando certificado no repositório...');
      const { stdout, stderr } = await execAsync(`certutil -user -store My "${this.config.certificateThumbprint}"`);
      
      if (stderr) {
        console.error('Erro ao verificar certificado:', stderr);
      }
      
      console.log('Resposta do certutil:', stdout);
      
      if (!stdout.includes(this.config.certificateThumbprint)) {
        throw new Error('Certificado não encontrado no repositório');
      }

      // Verificar se o token está conectado
      console.log('Verificando status do token...');
      const { stdout: tokenStatus } = await execAsync('certutil -user -csp "SafeSign IC Standard Windows Cryptographic Service Provider" -key');
      console.log('Status do token:', tokenStatus);

      // Configurar o agente HTTPS com o certificado do token
      console.log('Configurando agente HTTPS com certificado do token...');
      const cert: TokenCertificate = {
        thumbprint: this.config.certificateThumbprint,
        provider: 'SafeSign IC Standard Windows Cryptographic Service Provider'
      };

      const key: TokenKey = {
        password: this.config.certificatePassword,
        provider: 'SafeSign IC Standard Windows Cryptographic Service Provider'
      };

      this.agent = new Agent({
        rejectUnauthorized: false,
        cert: cert as any,
        key: key as any,
        ciphers: 'HIGH:!aNULL:!MD5:!RC4',
        minVersion: 'TLSv1.2',
        secureOptions: 0x00000001 // SSL_OP_NO_SSLv2
      });

      console.log('Certificado inicializado com sucesso');
    } catch (error) {
      console.error('Erro detalhado ao inicializar certificado:', error);
      if (error instanceof Error) {
        throw new Error(`Falha ao inicializar certificado: ${error.message}`);
      }
      throw new Error('Falha ao inicializar certificado');
    }
  }

  getAgent(): Agent {
    if (!this.agent) {
      throw new Error('Certificado não inicializado');
    }
    return this.agent;
  }

  getHttpsAgent(): Agent {
    if (!this.agent) {
      throw new Error('Certificado não inicializado');
    }
    return this.agent;
  }

  getCertificate(): any {
    if (!this.agent) {
      throw new Error('Certificado não inicializado');
    }
    return this.agent.options.cert || this.agent.options.pfx;
  }

  getCertificateInfo(): any {
    return {
      thumbprint: this.config.certificateThumbprint,
      path: this.config.certificatePath,
      hasPassword: !!this.config.certificatePassword,
      provider: 'SafeSign IC Standard Windows Cryptographic Service Provider'
    };
  }
} 
```

--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------

```html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PJE - Peticionamento em Lote</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .upload-area {
            border: 2px dashed #ccc;
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            cursor: pointer;
            margin: 20px 0;
        }
        .upload-area:hover {
            border-color: #0d6efd;
        }
        .file-list {
            margin-top: 20px;
        }
        .protocol-list {
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div class="container py-5">
        <h1 class="mb-4">PJE - Peticionamento em Lote</h1>
        
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">Upload de Petições</h5>
                <div class="upload-area" id="uploadArea">
                    <p class="mb-0">Arraste e solte os arquivos PDF aqui ou clique para selecionar</p>
                    <input type="file" id="fileInput" multiple accept=".pdf" style="display: none">
                </div>
                
                <div class="file-list" id="fileList"></div>
                
                <button class="btn btn-primary" id="uploadButton" disabled>
                    Enviar Petições
                </button>
            </div>
        </div>
        
        <div class="protocol-list" id="protocolList"></div>
    </div>

    <script>
        const uploadArea = document.getElementById('uploadArea');
        const fileInput = document.getElementById('fileInput');
        const fileList = document.getElementById('fileList');
        const uploadButton = document.getElementById('uploadButton');
        const protocolList = document.getElementById('protocolList');
        
        let selectedFiles = [];
        
        // Configurar área de upload
        uploadArea.addEventListener('click', () => fileInput.click());
        uploadArea.addEventListener('dragover', (e) => {
            e.preventDefault();
            uploadArea.style.borderColor = '#0d6efd';
        });
        uploadArea.addEventListener('dragleave', () => {
            uploadArea.style.borderColor = '#ccc';
        });
        uploadArea.addEventListener('drop', (e) => {
            e.preventDefault();
            uploadArea.style.borderColor = '#ccc';
            handleFiles(e.dataTransfer.files);
        });
        
        fileInput.addEventListener('change', (e) => {
            handleFiles(e.target.files);
        });
        
        function handleFiles(files) {
            selectedFiles = Array.from(files).filter(file => file.type === 'application/pdf');
            updateFileList();
            uploadButton.disabled = selectedFiles.length === 0;
        }
        
        function updateFileList() {
            fileList.innerHTML = selectedFiles.map(file => `
                <div class="alert alert-info">
                    ${file.name}
                </div>
            `).join('');
        }
        
        uploadButton.addEventListener('click', async () => {
            uploadButton.disabled = true;
            uploadButton.textContent = 'Enviando...';
            
            for (const file of selectedFiles) {
                const formData = new FormData();
                formData.append('petition', file);
                
                try {
                    console.log('Enviando arquivo:', file.name);
                    const response = await fetch('/peticionar', {
                        method: 'POST',
                        body: formData
                    });
                    
                    console.log('Resposta recebida:', response.status);
                    const result = await response.json();
                    console.log('Resultado:', result);
                    
                    if (result.success) {
                        protocolList.innerHTML += `
                            <div class="alert alert-success">
                                <strong>${file.name}</strong><br>
                                Protocolo: ${result.protocol}<br>
                                Processo: ${result.processInfo.numeroProcesso}
                            </div>
                        `;
                    } else {
                        protocolList.innerHTML += `
                            <div class="alert alert-danger">
                                <strong>${file.name}</strong><br>
                                Erro: ${result.error}
                                ${result.details ? `<br>Detalhes: ${result.details}` : ''}
                            </div>
                        `;
                    }
                } catch (error) {
                    console.error('Erro ao enviar arquivo:', error);
                    protocolList.innerHTML += `
                        <div class="alert alert-danger">
                            <strong>${file.name}</strong><br>
                            Erro ao enviar arquivo: ${error.message}
                        </div>
                    `;
                }
            }
            
            uploadButton.textContent = 'Enviar Petições';
            uploadButton.disabled = false;
            selectedFiles = [];
            updateFileList();
        });
    </script>
</body>
</html> 
```

--------------------------------------------------------------------------------
/src/web-server.ts:
--------------------------------------------------------------------------------

```typescript
import 'dotenv/config';
import express from 'express';
import multer from 'multer';
import path from 'path';
import { PJEClient } from './pje-client.js';
import { extractProcessInfo } from './pdf-processor.js';

const app = express();
const upload = multer({ dest: 'uploads/' });

// Configuração do Express
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.set('views', path.join(process.cwd(), 'views'));

// Middleware para log de requisições
app.use((req, res, next) => {
    console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
    next();
});

// Rota principal
app.get('/', (req, res) => {
  res.render('index', {
    title: 'PJE MCP Server - Interface Web',
    tools: [
      { id: 'buscar-processo', name: 'Buscar Processo', icon: '🔍' },
      { id: 'peticionar', name: 'Petição Eletrônica', icon: '📝' },
      { id: 'peticionar-lote', name: 'Petição em Lote', icon: '📦' },
      { id: 'listar-processos', name: 'Listar Processos', icon: '📋' },
      { id: 'listar-orgaos', name: 'Órgãos Julgadores', icon: '🏛️' },
      { id: 'listar-classes', name: 'Classes Processuais', icon: '📚' },
      { id: 'listar-assuntos', name: 'Assuntos Processuais', icon: '📑' }
    ]
  });
});

// Rota para buscar processo
app.post('/buscar-processo', async (req, res) => {
  try {
    const numeroProcesso = req.body.numeroProcesso;
    
    if (!process.env.PJE_CERTIFICATE_THUMBPRINT || !process.env.PJE_CERTIFICATE_PASSWORD) {
      throw new Error('Configuração do certificado não encontrada');
    }

    // Configurar cliente PJE
    const pjeClient = new PJEClient({
      baseUrl: process.env.PJE_BASE_URL || 'https://pje.tjce.jus.br',
      appName: process.env.PJE_APP_NAME || 'pje-tjce-1g',
      certificate: {
        certificateThumbprint: process.env.PJE_CERTIFICATE_THUMBPRINT,
        certificatePassword: process.env.PJE_CERTIFICATE_PASSWORD
      }
    });

    // Inicializar certificado
    await pjeClient.initializeCertificate();
    await pjeClient.authenticateWithCertificate();

    // Buscar processo
    const processo = await pjeClient.buscarProcesso(numeroProcesso);

    res.json({
      success: true,
      processo
    });
  } catch (error) {
    console.error('Erro ao buscar processo:', error);
    res.status(500).json({
      success: false,
      error: error instanceof Error ? error.message : 'Erro ao buscar processo'
    });
  }
});

// Rota para upload de petições
app.post('/peticionar', upload.single('petition'), async (req, res) => {
  try {
    console.log('Recebendo petição...');
    
    if (!req.file) {
      console.log('Nenhum arquivo enviado');
      return res.status(400).json({ error: 'Nenhum arquivo enviado' });
    }

    console.log('Arquivo recebido:', req.file);

    if (!process.env.PJE_CERTIFICATE_THUMBPRINT || !process.env.PJE_CERTIFICATE_PASSWORD) {
      console.log('Configuração do certificado não encontrada');
      throw new Error('Configuração do certificado não encontrada');
    }

    console.log('Extraindo informações do PDF...');
    // Extrair informações do processo do PDF
    const processInfo = await extractProcessInfo(req.file.path);
    console.log('Informações extraídas:', processInfo);
    
    console.log('Configurando cliente PJE...');
    // Configurar cliente PJE
    const pjeClient = new PJEClient({
      baseUrl: process.env.PJE_BASE_URL || 'https://pje.tjce.jus.br',
      appName: process.env.PJE_APP_NAME || 'pje-tjce-1g',
      certificate: {
        certificateThumbprint: process.env.PJE_CERTIFICATE_THUMBPRINT,
        certificatePassword: process.env.PJE_CERTIFICATE_PASSWORD
      }
    });

    console.log('Inicializando certificado...');
    // Inicializar certificado
    await pjeClient.initializeCertificate();
    await pjeClient.authenticateWithCertificate();

    console.log('Realizando peticionamento...');
    // Fazer o peticionamento
    const protocol = await pjeClient.peticionar(processInfo);

    console.log('Petição protocolada com sucesso:', protocol);

    // Retornar recibo do protocolo
    res.json({
      success: true,
      protocol,
      processInfo
    });

  } catch (error) {
    console.error('Erro detalhado ao processar petição:', error);
    res.status(500).json({ 
      error: 'Erro ao processar petição',
      details: error instanceof Error ? error.message : 'Erro desconhecido'
    });
  }
});

// Rota para upload de petições em lote
app.post('/peticionar-lote', upload.array('petitions', 10), async (req, res) => {
  try {
    if (!req.files || !Array.isArray(req.files)) {
      return res.status(400).json({ error: 'Nenhum arquivo enviado' });
    }

    if (!process.env.PJE_CERTIFICATE_THUMBPRINT || !process.env.PJE_CERTIFICATE_PASSWORD) {
      throw new Error('Configuração do certificado não encontrada');
    }

    const results = [];
    const pjeClient = new PJEClient({
      baseUrl: process.env.PJE_BASE_URL || 'https://pje.tjce.jus.br',
      appName: process.env.PJE_APP_NAME || 'pje-tjce-1g',
      certificate: {
        certificateThumbprint: process.env.PJE_CERTIFICATE_THUMBPRINT,
        certificatePassword: process.env.PJE_CERTIFICATE_PASSWORD
      }
    });

    await pjeClient.initializeCertificate();
    await pjeClient.authenticateWithCertificate();

    for (const file of req.files) {
      try {
        const processInfo = await extractProcessInfo(file.path);
        const protocol = await pjeClient.peticionar(processInfo);
        results.push({
          file: file.originalname,
          success: true,
          protocol,
          processInfo
        });
      } catch (error) {
        results.push({
          file: file.originalname,
          success: false,
          error: error instanceof Error ? error.message : 'Erro ao processar petição'
        });
      }
    }

    res.json({
      success: true,
      results
    });

  } catch (error) {
    console.error('Erro ao processar lote de petições:', error);
    res.status(500).json({ error: 'Erro ao processar lote de petições' });
  }
});

// Iniciar servidor
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Servidor web rodando na porta ${PORT}`);
}); 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  Tool,
} from "@modelcontextprotocol/sdk/types.js";
import axios, { AxiosInstance, AxiosResponse } from "axios";
import dotenv from "dotenv";
import { CertificateManager, CertificateConfig } from "./certificate-manager.js";
import { execAsync } from "./utils.js";

// Carrega as configurações do arquivo .env
dotenv.config();

interface PJEConfig {
  baseUrl: string;
  ssoUrl?: string;
  clientId?: string;
  clientSecret?: string;
  username?: string;
  password?: string;
  appName?: string;
  certificate?: CertificateConfig;
}

interface PJEResponse<T = any> {
  status: "ok" | "error" | "in-progress";
  code: string;
  messages: string[];
  result: T;
  "page-info"?: {
    current: number;
    last: number;
    size: number;
    count: number;
  };
}

class PJEClient {
  private axiosInstance: AxiosInstance;
  private accessToken?: string;
  private config: PJEConfig;
  private certificateManager?: CertificateManager;

  constructor(config: PJEConfig) {
    this.config = config;
    
    const axiosConfig: any = {
      baseURL: config.baseUrl,
      headers: {
        "Content-Type": "application/json",
      },
      timeout: parseInt(process.env.PJE_TIMEOUT_MS || "30000"),
    };
    
    if (config.certificate) {
      this.certificateManager = new CertificateManager(config.certificate);
    }
    
    this.axiosInstance = axios.create(axiosConfig);

    this.axiosInstance.interceptors.request.use((config) => {
      if (this.accessToken) {
        config.headers.Authorization = `Bearer ${this.accessToken}`;
      }
      if (this.config.appName) {
        config.headers["X-pje-legacy-app"] = this.config.appName;
      }
      return config;
    });
  }

  async initializeCertificate(): Promise<void> {
    if (!this.certificateManager) {
      throw new Error("Nenhum certificado configurado");
    }
    
    try {
      await this.certificateManager.initialize();
      
      const httpsAgent = this.certificateManager.getHttpsAgent();
      
      this.axiosInstance = axios.create({
        baseURL: this.config.baseUrl,
        headers: {
          "Content-Type": "application/json",
        },
        timeout: parseInt(process.env.PJE_TIMEOUT_MS || "30000"),
        httpsAgent: httpsAgent
      });
      
      this.axiosInstance.interceptors.request.use((config) => {
        if (this.accessToken) {
          config.headers.Authorization = `Bearer ${this.accessToken}`;
        }
        if (this.config.appName) {
          config.headers["X-pje-legacy-app"] = this.config.appName;
        }
        return config;
      });
    } catch (error) {
      throw new Error(`Erro ao inicializar certificado: ${error}`);
    }
  }
  
  async authenticateWithCertificate(): Promise<void> {
    if (!this.certificateManager) {
      throw new Error("Certificado não inicializado");
    }
    
    try {
      const response = await this.axiosInstance.post('/api/v1/auth/certificate', {
        certificate: this.certificateManager.getCertificate()
      });
      
      this.accessToken = response.data.access_token;
    } catch (error) {
      throw new Error(`Erro na autenticação por certificado: ${error}`);
    }
  }
  
  getCertificateInfo(): any {
    if (!this.certificateManager) {
      throw new Error("Nenhum certificado configurado");
    }
    return this.certificateManager.getCertificateInfo();
  }

  async authenticate(): Promise<void> {
    if (!this.config.ssoUrl || !this.config.clientId || !this.config.clientSecret) {
      throw new Error("Configuração de SSO incompleta");
    }

    try {
      const response = await axios.post(
        this.config.ssoUrl,
        new URLSearchParams({
          grant_type: "password",
          client_id: this.config.clientId,
          client_secret: this.config.clientSecret,
          username: this.config.username || "",
          password: this.config.password || "",
          scope: "openid",
        }),
        {
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
        }
      );

      this.accessToken = response.data.access_token;
    } catch (error) {
      throw new Error(`Erro na autenticação: ${error}`);
    }
  }

  async listarProcessos(filter?: any, fields?: string[], order?: any, page?: number, size?: number): Promise<PJEResponse> {
    const params: any = {};
    
    if (filter) {
      params.filter = typeof filter === "string" ? filter : JSON.stringify(filter);
    }
    if (fields) {
      params.fields = Array.isArray(fields) ? JSON.stringify(fields) : fields;
    }
    if (order) {
      params.order = typeof order === "string" ? order : JSON.stringify(order);
    }
    if (page || size) {
      params.page = JSON.stringify({ page: page || 1, size: size || 20 });
    }

    const response = await this.axiosInstance.get("/api/v1/processos", { params });
    return response.data;
  }

  async buscarProcesso(id: string): Promise<PJEResponse> {
    const response = await this.axiosInstance.get(`/api/v1/processos/${id}`);
    return response.data;
  }

  async listarOrgaosJulgadores(): Promise<PJEResponse> {
    const response = await this.axiosInstance.get("/api/v1/orgaos-julgadores");
    return response.data;
  }

  async listarClasses(): Promise<PJEResponse> {
    const response = await this.axiosInstance.get("/api/v1/classes");
    return response.data;
  }

  async listarAssuntos(): Promise<PJEResponse> {
    const response = await this.axiosInstance.get("/api/v1/assuntos");
    return response.data;
  }
}

class PJEServer {
  private server: Server;
  private pjeClient?: PJEClient;

  constructor() {
    this.server = new Server(
      {
        name: "pje-mcp-server",
        version: "1.0.0",
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    this.setupToolHandlers();
  }

  private setupToolHandlers() {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "pje_configurar",
            description: "Configura a conexão com o PJE",
            inputSchema: {
              type: "object",
              properties: {
                baseUrl: { type: "string", description: "URL base da API do PJE" },
                appName: { type: "string", description: "Nome da aplicação" },
              },
              required: ["baseUrl"],
            },
          },
          {
            name: "pje_listar_processos",
            description: "Lista processos com filtros opcionais",
            inputSchema: {
              type: "object",
              properties: {
                filter: { type: "string", description: "Filtro para busca" },
                page: { type: "number", description: "Número da página" },
                size: { type: "number", description: "Tamanho da página" },
              },
            },
          },
          {
            name: "pje_buscar_processo",
            description: "Busca um processo específico por ID",
            inputSchema: {
              type: "object",
              properties: {
                id: { type: "string", description: "ID do processo" },
              },
              required: ["id"],
            },
          },
          {
            name: "pje_listar_orgaos_julgadores",
            description: "Lista órgãos julgadores",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
          {
            name: "pje_listar_classes",
            description: "Lista classes processuais",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
          {
            name: "pje_listar_assuntos",
            description: "Lista assuntos processuais",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
          {
            name: "pje_status",
            description: "Verifica o status da configuração e conexão do PJE",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
          {
            name: "pje_configurar_certificado",
            description: "Configura autenticação por certificado digital",
            inputSchema: {
              type: "object",
              properties: {
                pfxPath: { type: "string", description: "Caminho para arquivo .pfx/.p12" },
                pfxPassword: { type: "string", description: "Senha do arquivo .pfx/.p12" },
                certificateThumbprint: { type: "string", description: "Thumbprint do certificado no Windows" },
                certificateSubject: { type: "string", description: "Subject do certificado no Windows" },
              },
            },
          },
          {
            name: "pje_listar_certificados",
            description: "Lista certificados digitais disponíveis no Windows",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
          {
            name: "pje_info_certificado",
            description: "Mostra informações sobre o certificado configurado",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
        ],
      };
    });

    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      try {
        switch (request.params.name) {
          case "pje_configurar":
            return await this.configurarPJE(request.params.arguments);
          case "pje_listar_processos":
            if (!this.pjeClient) throw new Error("PJE não configurado");
            return await this.listarProcessos(request.params.arguments);
          case "pje_buscar_processo":
            if (!this.pjeClient) throw new Error("PJE não configurado");
            return await this.buscarProcesso(request.params.arguments);
          case "pje_listar_orgaos_julgadores":
            if (!this.pjeClient) throw new Error("PJE não configurado");
            return await this.listarOrgaosJulgadores();
          case "pje_listar_classes":
            if (!this.pjeClient) throw new Error("PJE não configurado");
            return await this.listarClasses();
          case "pje_listar_assuntos":
            if (!this.pjeClient) throw new Error("PJE não configurado");
            return await this.listarAssuntos();
          case "pje_status":
            return await this.verificarStatus();
          case "pje_configurar_certificado":
            return await this.configurarCertificado(request.params.arguments);
          case "pje_listar_certificados":
            return await this.listarCertificados();
          case "pje_info_certificado":
            return await this.infoCertificado();
          default:
            throw new Error(`Ferramenta desconhecida: ${request.params.name}`);
        }
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `Erro: ${error instanceof Error ? error.message : String(error)}`,
            },
          ],
        };
      }
    });
  }

  private async configurarPJE(args: any) {
    const config: PJEConfig = {
      baseUrl: args.baseUrl || process.env.PJE_BASE_URL || "https://pje.tjce.jus.br",
      appName: args.appName || process.env.PJE_APP_NAME || "pje-tjce-1g",
      ssoUrl: args.ssoUrl || process.env.PJE_SSO_URL,
      clientId: args.clientId || process.env.PJE_CLIENT_ID,
      clientSecret: args.clientSecret || process.env.PJE_CLIENT_SECRET,
      username: args.username || process.env.PJE_USERNAME,
      password: args.password || process.env.PJE_PASSWORD,
    };
    
    const certificateConfig: CertificateConfig = {
      certificateThumbprint: '7db4b6cc9de4785944bcf1c8f3cde03355733b84',
      certificatePassword: '123456'
    };

    this.pjeClient = new PJEClient(config);

    if (certificateConfig) {
      try {
        await this.pjeClient.initializeCertificate();
        try {
          await this.pjeClient.authenticateWithCertificate();
          return {
            content: [
              {
                type: "text",
                text: `✅ PJE configurado com sucesso!\n\n🎯 **Configuração:**\n- URL: ${config.baseUrl}\n- App: ${config.appName}\n- Autenticação: 🔐 Certificado Digital\n\n✅ **Pronto para usar todas as funcionalidades!**`,
              },
            ],
          };
        } catch (authError) {
          return {
            content: [
              {
                type: "text",
                text: `⚠️ PJE configurado com certificado!\n\n🎯 **Configuração:**\n- URL: ${config.baseUrl}\n- App: ${config.appName}\n- Certificado: ✅ Carregado\n- Autenticação: ⚠️ Falha na autenticação\n\n**Erro:** ${authError instanceof Error ? authError.message : String(authError)}`,
              },
            ],
          };
        }
      } catch (certError) {
        return {
          content: [
            {
              type: "text",
              text: `❌ PJE configurado sem certificado!\n\n🎯 **Configuração:**\n- URL: ${config.baseUrl}\n- App: ${config.appName}\n- Certificado: ❌ Erro ao carregar\n\n**Erro:** ${certError instanceof Error ? certError.message : String(certError)}`,
            },
          ],
        };
      }
    }

    if (config.ssoUrl && config.clientId && config.clientSecret && config.username && config.password) {
      try {
        await this.pjeClient.authenticate();
        return {
          content: [
            {
              type: "text",
              text: `✅ PJE configurado com sucesso!\n\n🎯 **Configuração:**\n- URL: ${config.baseUrl}\n- App: ${config.appName}\n- Autenticação: ✅ SSO autenticado\n\n✅ **Pronto para usar todas as funcionalidades!**`,
            },
          ],
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `⚠️ PJE configurado com erro na autenticação!\n\n🎯 **Configuração:**\n- URL: ${config.baseUrl}\n- App: ${config.appName}\n- Autenticação: ❌ Falha no SSO\n\n❌ **Erro:** ${error instanceof Error ? error.message : String(error)}`,
            },
          ],
        };
      }
    }

    return {
      content: [
        {
          type: "text",
          text: `✅ PJE configurado!\n\n🎯 **Configuração:**\n- URL: ${config.baseUrl}\n- App: ${config.appName}\n- Autenticação: ⚠️ Apenas consultas públicas\n\n💡 **Para funcionalidades completas:**\nConfigure certificado digital ou credenciais no arquivo .env`,
        },
      ],
    };
  }

  private async listarProcessos(args: any) {
    const { filter, page, size } = args;
    const result = await this.pjeClient!.listarProcessos(filter, undefined, undefined, page, size);

    return {
      content: [
        {
          type: "text",
          text: `📋 **Processos encontrados:**\n\n${JSON.stringify(result, null, 2)}`,
        },
      ],
    };
  }

  private async buscarProcesso(args: any) {
    const { id } = args;
    const result = await this.pjeClient!.buscarProcesso(id);

    return {
      content: [
        {
          type: "text",
          text: `📄 **Detalhes do processo:**\n\n${JSON.stringify(result, null, 2)}`,
        },
      ],
    };
  }

  private async listarOrgaosJulgadores() {
    const result = await this.pjeClient!.listarOrgaosJulgadores();

    return {
      content: [
        {
          type: "text",
          text: `🏛️ **Órgãos julgadores:**\n\n${JSON.stringify(result, null, 2)}`,
        },
      ],
    };
  }

  private async listarClasses() {
    const result = await this.pjeClient!.listarClasses();

    return {
      content: [
        {
          type: "text",
          text: `📚 **Classes processuais:**\n\n${JSON.stringify(result, null, 2)}`,
        },
      ],
    };
  }

  private async listarAssuntos() {
    const result = await this.pjeClient!.listarAssuntos();

    return {
      content: [
        {
          type: "text",
          text: `📑 **Assuntos processuais:**\n\n${JSON.stringify(result, null, 2)}`,
        },
      ],
    };
  }

  private async verificarStatus() {
    const envConfig = {
      baseUrl: process.env.PJE_BASE_URL,
      appName: process.env.PJE_APP_NAME,
      ssoUrl: process.env.PJE_SSO_URL,
      clientId: process.env.PJE_CLIENT_ID,
      clientSecret: process.env.PJE_CLIENT_SECRET,
      username: process.env.PJE_USERNAME ? '***' : undefined,
      password: process.env.PJE_PASSWORD ? '***' : undefined,
      certificatePath: process.env.PJE_CERTIFICATE_PFX_PATH,
      certificatePassword: process.env.PJE_CERTIFICATE_PFX_PASSWORD ? '***' : undefined,
      certificateThumbprint: process.env.PJE_CERTIFICATE_THUMBPRINT,
    };

    let statusText = `🔍 **STATUS DO PJE MCP SERVER**\n\n`;
    statusText += `🔧 **Configuração do arquivo .env:**\n`;
    statusText += `- URL Base: ${envConfig.baseUrl || '❌ Não configurado'}\n`;
    statusText += `- App Name: ${envConfig.appName || '❌ Não configurado'}\n`;
    statusText += `- SSO URL: ${envConfig.ssoUrl || '❌ Não configurado'}\n`;
    statusText += `- Client ID: ${envConfig.clientId || '❌ Não configurado'}\n`;
    statusText += `- Client Secret: ${envConfig.clientSecret || '❌ Não configurado'}\n`;
    statusText += `- Username: ${envConfig.username || '❌ Não configurado'}\n`;
    statusText += `- Password: ${envConfig.password || '❌ Não configurado'}\n\n`;
    
    statusText += `🔐 **Certificado Digital:**\n`;
    statusText += `- Arquivo PFX: ${envConfig.certificatePath || '❌ Não configurado'}\n`;
    statusText += `- Senha PFX: ${envConfig.certificatePassword || '❌ Não configurado'}\n`;
    statusText += `- Thumbprint: ${envConfig.certificateThumbprint || '❌ Não configurado'}\n\n`;

    statusText += `🔗 **Conexão:**\n`;
    if (!this.pjeClient) {
      statusText += `- Status: ❌ Cliente não configurado\n`;
      statusText += `- Solução: Execute 'pje_configurar' primeiro\n\n`;
    } else {
      statusText += `- Status: ✅ Cliente configurado\n`;
      if ((this.pjeClient as any).accessToken) {
        statusText += `- Autenticação: ✅ Token ativo\n`;
      } else if ((this.pjeClient as any).certificateManager) {
        statusText += `- Autenticação: 🔐 Certificado configurado\n`;
      } else {
        statusText += `- Autenticação: ⚠️ Apenas consultas públicas\n`;
      }
    }

    statusText += `\n💡 **Próximos passos:**\n`;
    if (!envConfig.baseUrl) {
      statusText += `1. Configure PJE_BASE_URL no arquivo .env\n`;
    }
    if (!envConfig.certificatePath && !envConfig.ssoUrl) {
      statusText += `2. Configure certificado digital ou credenciais SSO no arquivo .env\n`;
    }
    if (!this.pjeClient) {
      statusText += `3. Execute: 'Configure o PJE'\n`;
    } else {
      statusText += `3. ✅ Pronto para usar!\n`;
    }

    return {
      content: [
        {
          type: "text",
          text: statusText,
        },
      ],
    };
  }

  private async configurarCertificado(args: any) {
    try {
      const thumbprint = args.certificateThumbprint || process.env.PJE_CERTIFICATE_THUMBPRINT;
      const password = args.certificatePassword || process.env.PJE_CERTIFICATE_PASSWORD;
      if (!thumbprint || !password) {
        throw new Error('Thumbprint e senha do certificado são obrigatórios');
      }
      const certificateConfig: CertificateConfig = {
        certificateThumbprint: thumbprint,
        certificatePassword: password
      };

      if (!this.pjeClient) {
        const config: PJEConfig = {
          baseUrl: process.env.PJE_BASE_URL || "https://pje.tjce.jus.br",
          appName: process.env.PJE_APP_NAME || "pje-tjce-1g",
          certificate: certificateConfig,
        };
        this.pjeClient = new PJEClient(config);
      } else {
        (this.pjeClient as any).config.certificate = certificateConfig;
        (this.pjeClient as any).certificateManager = new CertificateManager(certificateConfig);
      }

      await this.pjeClient.initializeCertificate();
      
      try {
        await this.pjeClient.authenticateWithCertificate();
        return {
          content: [
            {
              type: "text",
              text: `🔐 **Certificado Digital Configurado com Sucesso!**\n\n✅ Certificado carregado e autenticado\n🎯 Pronto para usar com todas as funcionalidades do PJE\n\n**Informações do Certificado:**\n${JSON.stringify(this.pjeClient.getCertificateInfo(), null, 2)}`,
            },
          ],
        };
      } catch (authError) {
        return {
          content: [
            {
              type: "text",
              text: `⚠️ **Certificado Carregado, mas Autenticação Falhou**\n\nCertificado foi carregado, mas a autenticação no PJE falhou.\nErro: ${authError}\n\n**Informações do Certificado:**\n${JSON.stringify(this.pjeClient.getCertificateInfo(), null, 2)}`,
            },
          ],
        };
      }
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `❌ **Erro ao Configurar Certificado Digital**\n\n${error instanceof Error ? error.message : String(error)}\n\n**Dicas:**\n1. Verifique se o arquivo .pfx existe no caminho especificado\n2. Confirme se a senha do certificado está correta\n3. Para certificados do Windows, use o thumbprint ou subject\n4. Execute 'pje_listar_certificados' para ver certificados disponíveis`,
          },
        ],
      };
    }
  }

  private async listarCertificados() {
    try {
      const { stdout } = await execAsync('certutil -store My');
      return {
        content: [
          {
            type: "text",
            text: `🔍 **Certificados Digitais Disponíveis no Windows**\n\n${stdout}`,
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `❌ **Erro ao Listar Certificados**\n\n${error instanceof Error ? error.message : String(error)}\n\n**Nota:** Esta funcionalidade requer Windows e acesso ao Certificate Store.`,
          },
        ],
      };
    }
  }

  private async infoCertificado() {
    try {
      if (!this.pjeClient || !(this.pjeClient as any).certificateManager) {
        return {
          content: [
            {
              type: "text",
              text: `❌ **Nenhum Certificado Configurado**\n\nExecute 'pje_configurar_certificado' primeiro para carregar um certificado digital.`,
            },
          ],
        };
      }
      
      const info = this.pjeClient.getCertificateInfo();
      
      let texto = `🎯 **Informações do Certificado Digital Atual**\n\n`;
      
      texto += `**Subject:**\n`;
      info.subject.forEach((attr: any) => {
        texto += `- ${attr.name}: ${attr.value}\n`;
      });
      
      texto += `\n**Emissor:**\n`;
      info.issuer.forEach((attr: any) => {
        texto += `- ${attr.name}: ${attr.value}\n`;
      });
      
      texto += `\n**Detalhes Técnicos:**\n`;
      texto += `- Serial Number: ${info.serialNumber}\n`;
      texto += `- Thumbprint: ${info.thumbprint}\n`;
      texto += `- Válido de: ${new Date(info.notBefore).toLocaleString('pt-BR')}\n`;
      texto += `- Válido até: ${new Date(info.notAfter).toLocaleString('pt-BR')}\n`;
      
      const agora = new Date();
      const validade = new Date(info.notAfter);
      
      if (agora > validade) {
        texto += `\n⚠️ **AVISO: Certificado EXPIRADO!**\n`;
      } else {
        const diasRestantes = Math.floor((validade.getTime() - agora.getTime()) / (1000 * 60 * 60 * 24));
        texto += `\n✅ **Certificado válido por mais ${diasRestantes} dias**\n`;
      }
      
      return {
        content: [
          {
            type: "text",
            text: texto,
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `❌ **Erro ao Obter Informações do Certificado**\n\n${error instanceof Error ? error.message : String(error)}`,
          },
        ],
      };
    }
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error("Servidor MCP do PJE iniciado");
  }
}

const server = new PJEServer();
server.run().catch(console.error); 
```