Python MCP Server for Code Graph Extraction

Extrai e analisa estruturas de código Python, com foco em relações de importação/exportação.

Documentação

Python MCP Server for Code Graph Extraction

Este servidor MCP (Model Context Protocol) fornece ferramentas para extrair e analisar estruturas de código Python, com foco nas relações de importação/exportação entre arquivos. Esta é uma implementação leve que não requer um sistema de agente, facilitando a integração em qualquer aplicação Python.

Recursos

  • Descoberta de Relações de Código: Analisa relações de importação entre arquivos Python
  • Extração Inteligente de Código: Extrai apenas as seções de código mais relevantes para permanecer dentro dos limites de tokens
  • Contexto de Diretório: Inclui arquivos do mesmo diretório para fornecer melhor contexto
  • Inclusão de Documentação: Sempre inclui arquivos README.md (ou variantes) para fornecer documentação do projeto
  • Formatação Amigável para LLM: Formata código com metadados adequados para modelos de linguagem
  • Suporte ao Protocolo MCP: Totalmente compatível com o padrão JSON-RPC do Model Context Protocol

A Ferramenta get_python_code

O servidor expõe uma ferramenta poderosa de extração de código que:

  • Analisa um arquivo Python alvo e descobre todos os módulos, classes e funções importados
  • Retorna o código completo do arquivo alvo
  • Inclui código para todos os objetos referenciados de outros arquivos
  • Adiciona arquivos contextuais adicionais do mesmo diretório
  • Respeita os limites de tokens para evitar sobrecarregar modelos de linguagem

Instalação

# Clone the repository
git clone https://github.com/yourusername/python-mcp-new.git
cd python-mcp-new

# Create a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows, use: venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

Variáveis de Ambiente

Crie um arquivo .env com base no .env.example fornecido:

# Token limit for extraction
TOKEN_LIMIT=8000

Uso

Configurando para Clientes MCP

Para configurar este servidor MCP para uso em clientes compatíveis com MCP (como Codeium Windsurf), adicione a seguinte configuração ao arquivo de configuração MCP do seu cliente:

{
  "mcpServers": {
    "python-code-explorer": {
      "command": "python",
      "args": [
        "/path/to/python-mcp-new/server.py"
      ],
      "env": {
        "TOKEN_LIMIT": "8000"
      }
    }
  }
}

Substitua /path/to/python-mcp-new/server.py pelo caminho absoluto para o arquivo server.py no seu sistema.

Você também pode personalizar as variáveis de ambiente:

  • TOKEN_LIMIT: Limite máximo de tokens para extração de código (padrão: 8000)

Exemplos de Uso

Chamada Direta de Função

from agent import get_python_code

# Get Python code structure for a specific file
result = get_python_code(
    target_file="/home/user/project/main.py",
    root_repo_path="/home/user/project"  # Optional, defaults to target file directory
)

# Process the result
target_file = result["target_file"]
print(f"Main file: {target_file['file_path']}")
print(f"Docstring: {target_file['docstring']}")

# Display related files
for ref_file in result["referenced_files"]:
    print(f"Related file: {ref_file['file_path']}")
    print(f"Object: {ref_file['object_name']}")
    print(f"Type: {ref_file['object_type']}")

# See if we're close to the token limit
print(f"Token usage: {result['token_count']}/{result['token_limit']}")

Exemplo de Resposta (Chamada Direta de Função)

{
    "target_file": {
        "file_path": "main.py",
        "code": "import os\nimport sys\nfrom utils.helpers import format_output\n\ndef main():\n    args = sys.argv[1:]\n    if not args:\n        print('No arguments provided')\n        return\n    \n    result = format_output(args[0])\n    print(result)\n\nif __name__ == '__main__':\n    main()",
        "type": "target",
        "docstring": ""
    },
    "referenced_files": [
        {
            "file_path": "utils/helpers.py",
            "object_name": "format_output",
            "object_type": "function",
            "code": "def format_output(text):\n    \"\"\"Format the input text for display.\"\"\"\n    if not text:\n        return ''\n    return f'Output: {text.upper()}'\n",
            "docstring": "Format the input text for display.",
            "truncated": false
        }
    ],
    "additional_files": [
        {
            "file_path": "config.py",
            "code": "# Configuration settings\n\nDEBUG = True\nVERSION = '1.0.0'\nMAX_RETRIES = 3\n",
            "type": "related_by_directory",
            "docstring": "Configuration settings for the application."
        }
    ],
    "total_files": 3,
    "token_count": 450,
    "token_limit": 8000
}

Usando o Protocolo MCP

Listando Ferramentas Disponíveis

from agent import handle_mcp_request
import json

# List available tools
list_request = {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
}

response = handle_mcp_request(list_request)
print(json.dumps(response, indent=2))

Exemplo de Resposta (tools/list)

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_python_code",
        "description": "Return the code of a target Python file and related files based on import/export proximity.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "target_file": {
              "type": "string",
              "description": "Path to the Python file to analyze."
            },
            "root_repo_path": {
              "type": "string",
              "description": "Root directory of the repository. If not provided, the directory of the target file will be used."
            }
          },
          "required": ["target_file"]
        }
      }
    ]
  }
}

Chamando a Ferramenta get_python_code

from agent import handle_mcp_request
import json

# Call the get_python_code tool
tool_request = {
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
        "name": "get_python_code",
        "arguments": {
            "target_file": "/home/user/project/main.py",
            "root_repo_path": "/home/user/project"  # Optional
        }
    }
}

response = handle_mcp_request(tool_request)
print(json.dumps(response, indent=2))

Exemplo de Resposta (tools/call)

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Python code analysis for /home/user/project/main.py"
      },
      {
        "type": "resource",
        "resource": {
          "uri": "resource://python-code/main.py",
          "mimeType": "application/json",
          "data": {
            "target_file": {
              "file_path": "main.py",
              "code": "import os\nimport sys\nfrom utils.helpers import format_output\n\ndef main():\n    args = sys.argv[1:]\n    if not args:\n        print('No arguments provided')\n        return\n    \n    result = format_output(args[0])\n    print(result)\n\nif __name__ == '__main__':\n    main()",
              "type": "target",
              "docstring": ""
            },
            "referenced_files": [
              {
                "file_path": "utils/helpers.py",
                "object_name": "format_output",
                "object_type": "function",
                "code": "def format_output(text):\n    \"\"\"Format the input text for display.\"\"\"\n    if not text:\n        return ''\n    return f'Output: {text.upper()}'\n",
                "docstring": "Format the input text for display.",
                "truncated": false
              }
            ],
            "additional_files": [
              {
                "file_path": "config.py",
                "code": "# Configuration settings\n\nDEBUG = True\nVERSION = '1.0.0'\nMAX_RETRIES = 3\n",
                "type": "related_by_directory",
                "docstring": "Configuration settings for the application."
              }
            ],
            "total_files": 3,
            "token_count": 450,
            "token_limit": 8000
          }
        }
      }
    ],
    "isError": false
  }
}

Tratamento de Erros

from agent import handle_mcp_request

# Call with invalid file path
faulty_request = {
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
        "name": "get_python_code",
        "arguments": {
            "target_file": "/path/to/nonexistent.py"
        }
    }
}

response = handle_mcp_request(faulty_request)
print(json.dumps(response, indent=2))

Exemplo de Resposta de Erro

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Error processing Python code: No such file or directory: '/path/to/nonexistent.py'"
      }
    ],
    "isError": true
  }
}

Testes

Execute os testes para verificar a funcionalidade:

python -m unittest discover tests

Componentes Principais

  • agent.py: Contém a função get_python_code e manipuladores personalizados do protocolo MCP
  • code_grapher.py: Implementa a classe CodeGrapher para análise de código Python
  • server.py: Implementação completa do servidor MCP usando o SDK Python MCP
  • run_server.py: Ferramenta CLI para executar o servidor MCP
  • examples/: Scripts de exemplo mostrando como usar o servidor e o cliente MCP
  • tests/: Casos de teste abrangentes para toda a funcionalidade

Detalhes do Formato de Resposta

A ferramenta get_python_code retorna um objeto JSON estruturado com os seguintes campos:

CampoTipoDescrição
target_fileObjetoInformações sobre o arquivo Python alvo
referenced_filesArrayLista de objetos importados pelo arquivo alvo
additional_filesArrayArquivos de contexto adicionais do mesmo diretório
total_filesNúmeroNúmero total de arquivos incluídos na resposta
token_countNúmeroContagem aproximada de tokens em todo o código incluído
token_limitNúmeroLimite máximo de tokens configurado para extração

Objeto de Arquivo Alvo

CampoTipoDescrição
file_pathStringCaminho relativo para o arquivo a partir da raiz do repositório
codeStringCódigo-fonte completo do arquivo
typeStringSempre "target"
docstringStringDocstring de nível de módulo, se disponível

Objeto de Arquivo Referenciado

CampoTipoDescrição
file_pathStringCaminho relativo para o arquivo
object_nameStringNome do objeto importado (classe, função, etc.)
object_typeStringTipo do objeto ("class", "function", etc.)
codeStringCódigo-fonte do objeto específico
docstringStringDocstring do objeto, se disponível
truncatedBooleanoSe o código foi truncado devido aos limites de tokens

Objeto de Arquivo Adicional

CampoTipoDescrição
file_pathStringCaminho relativo para o arquivo
codeStringCódigo-fonte completo do arquivo
typeStringTipo de relação (ex.: "related_by_directory")
docstringStringDocstring de nível de módulo, se disponível

Usando o Servidor com SDK MCP

Este projeto agora inclui um servidor Model Context Protocol (MCP) completo, construído com o Python MCP SDK oficial. O servidor expõe nossa funcionalidade de extração de código de forma padronizada, que pode ser usada com qualquer cliente MCP, incluindo o Claude Desktop.

Iniciando o Servidor

# Start the server with default settings
python run_server.py

# Specify a custom name
python run_server.py --name "My Code Explorer"

# Use a specific .env file
python run_server.py --env-file .env.production

Usando o Modo de Desenvolvimento MCP

Com o SDK MCP instalado, você pode executar o servidor em modo de desenvolvimento usando a CLI MCP:

# Install the MCP CLI
pip install "mcp[cli]"

# Start the server in development mode with the Inspector UI
mcp dev server.py

Isso iniciará o MCP Inspector, uma interface web para testar e depurar seu servidor.

Integração com Claude Desktop

Você pode instalar o servidor no Claude Desktop para acessar suas ferramentas de exploração de código diretamente do Claude:

# Install the server in Claude Desktop
mcp install server.py

# With custom configuration
mcp install server.py --name "Python Code Explorer" -f .env

Implantação Personalizada do Servidor

Para implantações personalizadas, você pode usar o servidor MCP diretamente:

from server import mcp

# Configure the server
mcp.name = "Custom Code Explorer"

# Run the server
mcp.run()

Usando o Cliente MCP

Você pode usar o SDK Python MCP para conectar-se ao servidor programaticamente. Veja o exemplo fornecido em examples/mcp_client_example.py:

from mcp.client import Client, Transport

# Connect to the server
client = Client(Transport.subprocess(["python", "server.py"]))
client.initialize()

# List available tools
for tool in client.tools:
    print(f"Tool: {tool.name}")

# Use the get_code tool
result = client.tools.get_code(target_file="path/to/your/file.py")
print(f"Found {len(result['referenced_files'])} referenced files")

# Clean up
client.shutdown()

Execute o exemplo:

python examples/mcp_client_example.py [optional_target_file.py]

Adicionando Ferramentas Adicionais

Você pode adicionar ferramentas adicionais ao servidor MCP decorando funções com o decorador @mcp.tool() em server.py:

@mcp.tool()
def analyze_imports(target_file: str) -> Dict[str, Any]:
    """Analyze all imports in a Python file."""
    # Implementation code here
    return {
        "file": target_file,
        "imports": [],  # List of imports found
        "analysis": ""  # Analysis of the imports
    }
    
@mcp.tool()
def find_python_files(directory: str, pattern: str = "*.py") -> list[str]:
    """Find Python files matching a pattern in a directory."""
    from pathlib import Path
    return [str(p) for p in Path(directory).glob(pattern) if p.is_file()]

Você também pode adicionar endpoints de recursos para fornecer dados diretamente:

@mcp.resource("python_stats://{directory}")
def get_stats(directory: str) -> Dict[str, Any]:
    """Get statistics about Python files in a directory."""
    from pathlib import Path
    stats = {
        "directory": directory,
        "file_count": 0,
        "total_lines": 0,
        "average_lines": 0
    }
    
    files = list(Path(directory).glob("**/*.py"))
    stats["file_count"] = len(files)
    
    if files:
        total_lines = 0
        for file in files:
            with open(file, "r") as f:
                total_lines += len(f.readlines())
        stats["total_lines"] = total_lines
        stats["average_lines"] = total_lines / len(files)
    
    return stats

Integração com Model Context Protocol

Este projeto adota totalmente o padrão Model Context Protocol (MCP), oferecendo duas opções de implementação:

  1. Integração MCP Nativa: A implementação original em agent.py fornece uma interface JSON-RPC direta compatível com MCP.

  2. Integração com SDK MCP: A nova implementação em server.py utiliza o SDK Python MCP oficial para uma experiência mais robusta e rica em recursos.

Benefícios da Integração MCP

  • Interface Padronizada: Disponibiliza suas ferramentas para qualquer cliente compatível com MCP
  • Segurança Aprimorada: Modelo de permissões e controles de recursos integrados
  • Melhor Integração com LLM: Integração perfeita com Claude Desktop e outras plataformas de LLM
  • Experiência de Desenvolvimento Aprimorada: Ferramentas abrangentes como o MCP Inspector

Versão do Protocolo MCP

Esta implementação suporta a versão 0.7.0 do Protocolo MCP.

Para mais informações sobre MCP, consulte a documentação oficial.