My First Site Using Vite + React, HTML, and CSS.
One Vite + React terminal. Path routes (/about, /work, /developers, …) are the same URLs for humans and agents. Bio, projects, skills, and contact live in src/lib; React stages render them, and MCP / REST / /ask / generated markdown are adapters over that same data. There is no parallel HTML site.
Installation
npm i
Development
npm run dev
Terminal
The human UI is a prompt over path routes, not a PTY. ? or :help opens the same reference in the app.
Modes (chrome prefix; type the payload only):
/— live filter. Unfocused/focuses the line. Query stays on the stage while you run a command.:— command. Unfocused:focuses and switches to command mode.~— navigate by section path (work,about, …).
g then w|a|t|i|r|m|h jumps sections without the prompt. * wipes the filter.
Line editor (bash analogs on the single-line input):
↑/↓— history (localStoragekeyain_hist, consecutive-deduped)Tab/Shift+Tab— complete commands, themes, pathsCtrl+R— reverse incremental searchCtrl+A/E/U/K/W— start, end, kill-to-start, kill-to-end, kill-wordCtrl+Lor:clear— clear the line and wipe the activity log
Commands include :resume, :theme <name>, :crt, :github, :share, :mcp, :log. Full list is in the overlay.
Agent discovery
Public, read-only surfaces for AI agents (no API key):
GET /llms.txt— when-to-use indexGET /openapi.json— REST spec (/api/v1)GET /developers— developer portal- MCP product:
https://dev.actuallyitsnathaniel.com/api/mcpand/.well-known/mcp - MCP docs:
https://dev.actuallyitsnathaniel.com/api/mcp-docs - Auth skill:
/auth.md
MCP Server
api/mcp.ts exposes a Model Context Protocol server at https://dev.actuallyitsnathaniel.com/api/mcp (Node runtime, Streamable HTTP transport) with 6 tools: search_projects, get_toolbelt, get_about, get_resume, get_contact, get_github_activity. No auth — every tool reads data that's already public on the site.
To test it:
npm run test:mcp— automated check: spins up a real Node HTTP server wrapping the handler and exercises every tool (init → list → call each tool → unknown-tool error path)npx vercel dev, then point MCP Inspector (npx @modelcontextprotocol/inspector) athttp://localhost:3000/api/mcpfor an interactive UInpx vercel build— reproduces Vercel's real bundler/runtime locally; catches deploy-only failures (e.g. edge vs. node runtime bundling issues) before pushing
Gotcha: package.json has "type": "module", so Node's real ESM loader requires explicit .js extensions on every relative import reachable from api/mcp.ts (e.g. ../src/lib/portfolio.js, not ../src/lib/portfolio) — TypeScript's bundler resolution accepts either, and tsx/vercel dev silently tolerate a missing extension, so this only breaks in the actual deployed function (ERR_MODULE_NOT_FOUND, ready but 500ing on every request). npm run test:mcp and vercel dev cannot catch this class of bug. To verify for real: npx vercel build, then load the compiled output directly under plain Node —
cd .vercel/output/functions/api/mcp.func && node --input-type=module -e "await import('./api/mcp.js')"
If that throws ERR_MODULE_NOT_FOUND, an extension is missing somewhere in the import chain. This is also why api/mcp.ts reads from src/lib/skills.ts (plain data) instead of src/Components/skills/skills-data.ts — the latter pulls in JSX icon components with their own relative imports, widening the surface area for this exact bug.
Connecting from Claude
Claude's custom-connector UI (claude.ai and Claude Desktop) currently forces an OAuth Dynamic Client Registration attempt on any custom remote MCP connector, even ones — like this one — that advertise no auth at all. That produces a "Couldn't register with … sign-in service" error and is a known, Anthropic-acknowledged, currently-unfixed limitation of the connector UI (closed "not planned": anthropics/claude-ai-mcp#457, #402) — not a bug in this server.
Workaround for Claude Desktop: bypass the web connector flow with a local mcp-remote stdio bridge instead. Add to claude_desktop_config.json:
{
"mcpServers": {
"nathaniel-portfolio": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://dev.actuallyitsnathaniel.com/api/mcp"]
}
}
}
Restart Claude Desktop after editing. Other MCP clients that don't go through the web custom-connector flow (Claude Code CLI, MCP Inspector, etc.) connect directly with no workaround needed.