Skip to main content
Glama
vishwakanth183

PortfolioMCP

README.md
# PortfolioMCP

A publicly deployable, MCP-powered portfolio: a recruiter or visitor can chat
with a candidate's portfolio and get grounded, factual answers about skills,
projects, experience and role fit — backed by a real Model Context Protocol
(MCP) server, not a hardcoded FAQ.

## Documentation

This README covers setup and a high-level overview. For depth:

- **[docs/MCP.md](docs/MCP.md)** — the MCP tools/resources/prompts this
  project exposes, why each exists, the exact request flow from a chat
  question to a grounded answer, and how to extend it.
- **[docs/AGENTIC_WORKFLOW.md](docs/AGENTIC_WORKFLOW.md)** — the research +
  content agent workflow: architecture, agent tool-selection, prompts,
  state/retention, and the human-in-the-loop approval flow (`/admin`).
- **[docs/WORKFLOW_VS_AGENTIC_AI.md](docs/WORKFLOW_VS_AGENTIC_AI.md)** —
  conceptual explainer: what actually makes this a "workflow" versus a
  pile of buttons, what "agentic" means here versus a scripted pipeline,
  with exact code citations for each.
- **[docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)** — how to deploy the frontend
  and backend on free hosting tiers, and why they need different kinds of
  hosts.

## Status

- [x] Repository scaffold (server / client / data / api / frontend)
- [x] Portfolio JSON (`data/portfolio.json`) filled with real candidate data
- [x] MCP server with tools, resources and prompts (`server/portfolio_server.py`)
- [x] MCP client that discovers and exercises the server (`client/portfolio_client.py`)
- [x] Gemini-backed chat loop over the MCP tools (`api/chat_server.py`), verified against a real key
- [x] Next.js portfolio + chat UI (`frontend/`)
- [x] Initial failure-case testing (unknown project, hallucination fix — see [docs/MCP.md](docs/MCP.md))
- [x] Research agent: RSS news tools + PortfolioMCP tools, 3 structured recommendations/day, daily cron — see [docs/AGENTIC_WORKFLOW.md](docs/AGENTIC_WORKFLOW.md)
- [x] Content agent + deterministic validation + `/admin` human-review UI (approve/reject/revise, manual publish + auto-delete)
- [ ] Public deployment (see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) for the plan)
- [ ] Real LinkedIn/Medium auto-publish API integration (deferred — see [docs/AGENTIC_WORKFLOW.md](docs/AGENTIC_WORKFLOW.md#human-review--publishing))

## Architecture

```
Next.js Portfolio + Chat UI  -->  FastAPI Chat Service  -->  Python MCP Client  -->  Python MCP Server  -->  data/portfolio.json
                                        |                                                  ^
                                        `---------------------- Gemini (tool-calling) ------'
```

The MCP server (`server/portfolio_server.py`) exposes:

- **Tools** (actions/queries): `get_skills`, `get_projects`, `get_experience`, `search_profile`
- **Resources** (stable read-only context): `portfolio://profile`, `portfolio://skills`,
  `portfolio://experience`, `portfolio://projects`
- **Prompts** (reusable interaction patterns): `recruiter_summary`, `technical_profile`,
  `project_summary` — discoverable and demonstrated by the standalone client;
  see [docs/MCP.md](docs/MCP.md) for their current status relative to the live chat

`api/chat_server.py` is a FastAPI service that keeps one persistent MCP client
session open and:

- serves `GET /api/portfolio` for the Next.js landing page by reading the
  `portfolio://` resources (no duplicated data file for the frontend),
- serves `POST /api/chat`, which runs a bounded loop letting Gemini decide
  which MCP tool(s) to call, executes them against the live MCP session, and
  returns a grounded answer plus a log of which tools were used.

The LLM provider is isolated behind `server/model_adapter.py` (a small
`ModelAdapter` interface) so swapping Gemini for another provider later means
writing one new adapter class, not touching the chat loop.

## Repository layout

```
PortfolioMCP/
├── data/
│   ├── portfolio.json       # single source of truth for candidate data
│   └── runs/                # ephemeral research/draft state, git-ignored (see docs/AGENTIC_WORKFLOW.md)
├── server/
│   ├── portfolio_data.py    # loads the JSON data
│   ├── portfolio_server.py  # FastMCP server: tools, resources, prompts
│   ├── mcp_bridge.py        # shared MCP client bridge (chat API + agents)
│   ├── model_adapter.py     # provider-agnostic LLM interface
│   ├── gemini_adapter.py    # Gemini function-calling implementation
│   ├── schemas.py           # Recommendation/Draft pydantic models
│   ├── state.py             # data/runs/ JSON state store + retention
│   ├── tools/
│   │   └── news_tools.py    # RSS-based TechCrunch/Verge search + get_article
│   ├── config/
│   │   ├── platforms.py     # LinkedIn/blog content requirements
│   │   └── styles.py        # the 4 content style arcs
│   └── agents/
│       ├── agent_runtime.py    # shared bounded tool-calling loop
│       ├── tool_registry.py    # merges local + MCP tools into one ToolSpec list
│       ├── research_agent.py   # daily research agent (cron entrypoint)
│       ├── content_agent.py    # drafts content for a chosen recommendation
│       └── validators.py       # deterministic draft quality/grounding checks
├── client/
│   └── portfolio_client.py  # standalone MCP client for local testing
├── api/
│   └── chat_server.py       # FastAPI service: chat, contact, portfolio, and the research/content admin API
├── tests/
│   └── test_research_agent.py  # offline failure-case tests (no live API calls)
└── frontend/
    └── src/app/
        ├── page.tsx          # public portfolio + chat page
        └── admin/page.tsx    # private research/content review UI
```

## Local setup

### Backend (MCP server + chat API)

1. Create and activate a virtual environment, then install dependencies:

   ```bash
   python -m venv .venv
   .venv\Scripts\activate   # Windows
   pip install -r requirements.txt
   ```

2. Copy `.env.example` to `.env` and add a free
   [Google AI Studio](https://aistudio.google.com/apikey) API key:

   ```bash
   copy .env.example .env
   ```

3. (Optional) Verify the MCP core on its own — spawns the server over stdio,
   discovers its tools/resources/prompts, and exercises a few of each:

   ```bash
   python client/portfolio_client.py
   ```

4. Start the chat API (keeps one MCP session alive for the process lifetime):

   ```bash
   uvicorn api.chat_server:app --reload --port 8000
   ```

   `GET http://localhost:8000/api/health` should list the four tools.

### Frontend (Next.js)

1. Copy `frontend/.env.local.example` to `frontend/.env.local` (defaults to
   `http://localhost:8000` for the backend).
2. Install and run:

   ```bash
   cd frontend
   npm install
   npm run dev
   ```
3. Open `http://localhost:3000` — the portfolio page and chat widget should
   both load from the running backend. The private research/content review
   UI is at `http://localhost:3000/admin` (not linked from the public nav).

### Research/content agents (optional, uses live Gemini quota)

```bash
# Offline tests — no API calls, safe to run anytime
python tests/test_research_agent.py

# One real research run (also runs daily via the scheduled-tasks cron,
# or on-demand from the "Run Research Now" button in /admin)
python server/agents/research_agent.py
```

See [docs/AGENTIC_WORKFLOW.md](docs/AGENTIC_WORKFLOW.md) for the full
architecture, prompts, and retention rules.

## What this project deliberately does not include

No NestJS backend, no database or vector store, no RAG/embeddings, no
multi-agent system, no automatic social posting, no complex auth, and no
sprawling tool surface — the goal is a small, explainable MCP demonstration,
not production infrastructure.

## Sample questions the chat should be able to answer

- "What frontend frameworks does this candidate know?"
- "Tell me about the Merchant Portal project."
- "Why would this candidate be a good fit for a React role?"
- "Has this candidate worked with Kubernetes in production?" (should say "not
  found in the data" rather than guessing, since Kubernetes only appears as a
  certification topic, not production experience)