AI Project Explorer
AI Project Explorer
A Python Model Context Protocol server that exposes GitHub repository exploration tools through local STDIO and remote Streamable HTTP transports.
The server ships two transports:
Transport | Entry point | Use case |
STDIO |
| Local development, MCP Inspector, |
Streamable HTTP |
| Portfolio backend, remote deployment |
Architecture
Local learning path:
client.py or llm_client.py
↓ STDIO
server.py
↓
GitHub public REST API
Portfolio production path:
Portfolio Express backend
↓ Streamable HTTP + bearer token
http_server.py
↓
Shared MCP tools (app/mcp_server.py)
↓
GitHub public REST APIflowchart LR
L[LinkedIn Featured link] --> P[Portfolio Ask AI page]
P --> B[Portfolio Express backend and LLM host]
B -->|Streamable HTTP and bearer token| M[Remote Python MCP server]
M --> T1[list_repositories]
M --> T2[get_repository_readme]
T1 --> G[GitHub public REST API]
T2 --> G
C[Local client.py or llm_client.py] -->|STDIO| S[Local MCP server]
S --> T1
S --> T2Project structure
ai-project-explorer/
server.py — STDIO entry point (local dev, MCP Inspector)
http_server.py — Streamable HTTP entry point (production)
remote_client.py — Smoke-test client for the HTTP server
client.py — Manual STDIO client
llm_client.py — LLM-powered STDIO client
app/
__init__.py
config.py — Environment variable configuration and validation
github_client.py — GitHub public REST API calls
mcp_server.py — Shared MCPServer instance + tool definitions
tests/
test_github_client.py
test_mcp_tools.py
test_http_server.py
.env.example
Dockerfile
.dockerignore
requirements.txtMCP tools
Both transports expose the same two tools:
list_repositories(username, limit=10)
Lists recently-updated public GitHub repositories for a user.
get_repository_readme(username, repository)
Fetches the raw README content for a repository.
Tool names and JSON schemas are identical between STDIO and HTTP transports.
Stateless HTTP operation
The HTTP server uses stateless_http=True when mounting the MCP transport. Both tools are simple request/response operations with no shared state between calls, so a session manager is unnecessary. Stateless mode is simpler to deploy and scale horizontally.
Setup
# Clone
git clone https://github.com/shravanthivr/ai-project-explorer.git
cd ai-project-explorer
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Copy environment template
cp .env.example .env
# Edit .env and fill in optional valuesFor local development, leave ALLOWED_GITHUB_USERNAME unset to allow lookups
for any public GitHub username. For a public portfolio deployment, set it to
the single account your deployment should serve:
ALLOWED_GITHUB_USERNAME=your-github-usernameCommands
Run the STDIO server (local dev)
python server.pyRun the manual STDIO client
python client.pyRun the LLM-powered STDIO client
python llm_client.pyRun the MCP Inspector
npm run inspectorRun the Streamable HTTP server
uvicorn http_server:app --host 0.0.0.0 --port 8000
# or
python http_server.pyCheck the health endpoint
curl http://localhost:8000/healthz
# → {"status":"ok","service":"ai-project-explorer-mcp"}Run the remote smoke-test client
# Set the server URL (and optional token)
export MCP_SERVER_URL=http://localhost:8000
export MCP_SERVER_AUTH_TOKEN=your-token # if auth is enabled
export REMOTE_CLIENT_GITHUB_USER=your-github-username
# Discover tools only
python remote_client.py
# Discover tools and call list_repositories
python remote_client.py --list-repos
# Or pass the username explicitly
python remote_client.py --list-repos --username your-github-usernameRun tests
pytest tests/ -vBuild and run the Docker image
docker build -t ai-project-explorer .
docker run --rm -p 8000:8000 \
-e PORT=8000 \
-e ALLOWED_GITHUB_USERNAME=your-github-username \
-e MCP_SERVER_AUTH_TOKEN=your-token \
ai-project-explorerEnvironment variables
Variable | Default | Required | Description |
|
| No | Bind address for HTTP server |
|
| No | Bind port for HTTP server |
| (unset) | Production | Restricts tools to this username only when configured |
|
| No | GitHub API base URL |
|
| No | GitHub request timeout |
|
| No | Maximum repositories returned |
|
| No | README truncation limit |
| (unset) | No | GitHub token (raises rate limit to 5 000/hr) |
| (unset) | Production | Bearer token for |
Security model
Browser → MCP: The browser never calls this server directly. Only the portfolio Express backend does.
Browser → GitHub: The browser never calls GitHub. All GitHub requests happen server-side.
MCP token: The bearer token is held only by the portfolio backend. It is never exposed to the browser or frontend code.
OpenAI credentials: Remain in the portfolio backend. This server has no knowledge of them.
Username restriction: Source code is reusable by default. Leave
ALLOWED_GITHUB_USERNAMEunset for local development or unrestricted self-hosted use. Set it in a public deployment to restrict the MCP tools to one GitHub account; calls for any other username are rejected before reaching GitHub.Public data only: Only public GitHub repositories and READMEs are accessible. No authentication to GitHub is needed for reading public data; the optional
GITHUB_TOKENonly raises the unauthenticated rate limit.
MCP versus direct REST
This project intentionally uses MCP for several reasons:
MCP adds value because:
The portfolio LLM can discover tools dynamically via
list_tools().Tool schemas are standardised — the model receives typed parameter definitions.
Tool execution is decoupled from model orchestration (the Express backend decides how to call tools; the Python server just executes them).
The same tools are reused by local STDIO clients and the deployed portfolio backend.
More tools can be added later (e.g.
search_code,list_issues) without redesigning the frontend API contract.
A direct REST endpoint would be simpler when:
There is only one fixed operation.
No model chooses or sequences tools.
Tool discovery and interoperability are unnecessary.
The service is only used by one tightly-coupled client.
This project intentionally uses MCP as a learning and portfolio demonstration, while recognising that a direct REST endpoint would require fewer components for this small two-tool use case.
Why I built this
I wanted to understand MCP by building a real tool — learning how clients discover tools, how servers expose capabilities, how AI assistants invoke external functions, and the difference between local (STDIO) and remote (Streamable HTTP) transports.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/shravanthivr/ai-project-explorer'
If you have feedback or need assistance with the MCP directory API, please join our Discord server