derekhuynen-mcp-server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@derekhuynen-mcp-servertell me about Derek's professional background"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
derekhuynen-mcp-server
A production-grade reference MCP server in TypeScript: one core, two transports, strict types, real tests, Docker, and CI

A production-grade reference implementation of a Model Context Protocol (MCP) server in TypeScript. One transport-agnostic core, two transports (stdio + Streamable HTTP), strict types, real tests, Docker, and CI. Clone it, read it, template it.
Most MCP examples are toy, single-file stdio scripts. This is what a real MCP server looks like: a clean core that registers tools, resources, and prompts once and serves them over two transports, backed by a validated data layer, a full test suite, a multi-stage Docker build, and CI.
The data it serves happens to be a real professional profile (mine), so the example is end-to-end and honest rather than foo/bar. But the reason to star it is the architecture and the patterns, which transfer to any MCP server you want to build.
Why you might care
The production shape of an MCP server, not a snippet: clear module boundaries, a
buildServer()factory, and thin transport entrypoints.Two transports from one core. Run it locally over stdio (Claude Desktop / Claude Code) or deploy it as a stateless Streamable HTTP service. No logic duplicated between them.
Actually tested. 42 tests, including a real in-memory MCP client driving the server (not mocks).
Deploy-ready. Multi-stage Dockerfile, docker-compose, health check, CORS, rate limiting, graceful shutdown, structured logging, env-based config.
Type-safe end to end. A Zod schema is the single source of truth, with inferred TypeScript types throughout.
A pattern worth stealing: the served content is generated from a single source of truth into a validated, reviewed snapshot, so the public surface never drifts.
Related MCP server: personal-resume-agent
What it exposes
Tools
Tool | Arguments | Description |
| none | Identity, title, summary, links |
| none | Email and profile links |
| none | Skills grouped by category |
| none | Public portfolio projects |
|
| Roles and engagements, optionally filtered |
|
| Keyword search across roles and projects |
Resources: profile://summary, profile://resume
Prompts: recruiter_pitch (arg: role)
See it in action
Once wired into an MCP client like Claude, the model can call the tools to answer questions about the data:
You: What has Derek done with RAG?
Claude: (calls get_experience { "skill": "RAG" })
Three RAG engagements stand out:
- PG&E GenAI Regulatory Chatbot (Azure OpenAI + Azure AI Search)
- HarperCollins Book Catalog RAG Chatbot (semantic search over 500 books)
- A hospital document-processing proof of conceptThe tool call behind that answer returns plain JSON:
// get_experience { "skill": "RAG" } -> (one entry shown, trimmed)
[
{
"slug": "neudesic-pge-genai-chatbot",
"project": "GenAI Regulatory Chatbot",
"title": "AI Developer",
"employer": "Neudesic (an IBM Company)",
"client": "PG&E (Pacific Gas & Electric)",
"start": "2025-01",
"end": "2025-03",
"summary": "Core engineer on an enterprise RAG chatbot that let PG&E staff query regulatory, claims, and compliance documents in natural language with real-time, grounded citations.",
"skills": ["RAG", "Azure OpenAI", "Semantic Kernel", "Azure AI Search"],
"featured": true,
},
]Quick start
npm install
npm run buildRun over stdio (local MCP clients)
npm run start:stdioWire it into Claude Desktop (claude_desktop_config.json) or Claude Code:
{
"mcpServers": {
"derek": {
"command": "node",
"args": ["/absolute/path/to/derekhuynen-mcp-server/dist/transports/stdio.js"]
}
}
}Run over HTTP
npm run start:http
# GET http://localhost:3000/health
# POST http://localhost:3000/mcp (Streamable HTTP MCP endpoint)Example initialize call:
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'Run with Docker
docker compose up --build
curl http://localhost:3000/healthConfiguration
Env var | Default | Purpose |
|
| HTTP port |
|
| pino log level |
|
| Rate-limit window in milliseconds |
|
| Max requests per window |
|
| Comma-separated allowed origins |
|
| Trusted proxy hop count (for correct client IPs) |
Architecture
A transport-agnostic core (buildServer(profile)) registers all tools, resources, and prompts against an in-memory profile loaded and validated from src/data/profile.json. Two thin entrypoints connect transports to a freshly built server:
flowchart TB
subgraph Clients["MCP clients"]
CD["Claude Desktop / Claude Code<br/>(stdio)"]
HC["HTTP client<br/>(Streamable HTTP)"]
end
subgraph Server["derekhuynen-mcp-server"]
STDIO["transports/stdio.ts"]
HTTPT["transports/http.ts<br/>Express: health, CORS, rate limit"]
CORE["buildServer(profile)<br/>tools · resources · prompts"]
Q["core/queries.ts<br/>(pure business logic)"]
end
DATA[("data/profile.json<br/>Zod-validated snapshot")]
CD --> STDIO
HC --> HTTPT
STDIO --> CORE
HTTPT --> CORE
CORE --> Q
Q --> DATAThe module layout:
src/
data/
schema.ts Zod schema + inferred types (single source of truth)
loader.ts parse + validate the snapshot (fail fast)
profile.json generated, public-safe data snapshot
core/
queries.ts pure business logic (unit-tested)
tools.ts registerTools() thin adapters over queries
resources.ts registerResources()
prompts.ts registerPrompts()
server.ts buildServer(profile) factory
transports/
stdio.ts stdio entrypoint
http.ts Express + Streamable HTTP (health, CORS, rate limit, shutdown)The key property: one server definition, two entrypoints. Both transports call the same buildServer(), so they can never drift in what they expose.
Use it as a template
Building your own MCP server? Here is the map:
Replace
src/data/with your own data shape and Zod schema.Rewrite
src/core/queries.tswith your domain logic (keep it pure; it stays easy to test).Adjust the registrations in
src/core/{tools,resources,prompts}.ts.Leave
server.tsand the transports mostly as-is. That plumbing is the reusable part.
How the data stays honest
src/data/profile.json is not hand-written. It is generated from a separate source of truth by scripts/generate-profile.mjs (npm run generate), which strips anything private and validates the result against the schema before it can ship. This keeps the public surface accurate and is a pattern worth reusing whenever a server exposes curated data.
Development
npm run dev:http # hot TS run of the HTTP server
npm run dev:stdio # hot TS run of the stdio server
npm test # vitest
npm run lint
npm run typecheckDeploy
The repo ships deploy-ready (Dockerfile + compose). The HTTP image is stateless and runs on any container host (Azure Container Apps, Fly.io, Cloud Run, a VPS, and so on). There is no authentication because all data is public by design; the endpoint is protected by Helmet security headers, rate limiting, and CORS. Behind a proxy, set TRUST_PROXY so client IPs (and therefore rate limiting) are accurate.
Tech stack
TypeScript (strict, ESM) - @modelcontextprotocol/sdk - Zod - Express - pino - Vitest - Docker - GitHub Actions.
License
MIT (c) Derek Huynen
If this helped you understand or build an MCP server, a star is appreciated. It helps other developers find it.
Available Tools
1 toolget_profileGet ProfileA
Derek Huynen's identity, title, summary, and links.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses the returned fields (identity, title, summary, links) but does not mention any behavioral traits like authentication, caching, or side effects. For a simple read operation, the disclosure is minimal but not misleading.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that efficiently communicates the output content. No wasted words, and it earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-output-schema tool, the description adequately covers what the tool returns. However, it could mention any limitations or return format to be fully complete, but it's not deficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, so the baseline is 4. The description adds no parameter details because none are needed. The schema coverage is 100% with no properties, so the description does not need to compensate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly specifies the tool returns Derek Huynen's identity, title, summary, and links. The verb 'get' is implied by the name and the description adds specifics about the resource's content. With no sibling tools to differentiate, this is well-defined.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance on when or when not to use this tool. Since there are no sibling tools, explicit alternatives are not needed, but the description could state that this is the single way to retrieve the profile. The usage context is implied but not articulated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Only one tool exists, so there is no possibility of confusion between tools.
The single tool name follows a clear verb_noun pattern, consistent with itself.
A single tool is minimal but may be appropriate for a static profile server; however, it borders on too few for most use cases.
The server only provides a 'get' operation with no update or other profile management capabilities, leaving significant gaps for a profile service.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Public portfolio MCP for resume, services, availability, project evidence, and introductions.
Profile server for kazejev.com: biography, skills, projects and education.
Hosted MCP server for live public-data APIs and Skills for AI agents.
PerfectPost is a LinkedIn content management platform. This MCP server gives AI assistants read and write access to a user's PerfectPost account: published posts with their engagement analytics, drafts lifecycle (create / edit / schedule), and LinkedIn profile data.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceAn MCP server that provides a structured API for AI agents to query a person's resume, including profile, projects, writing, and gated access to experience and skills.
- AlicenseNot gradedqualityDmaintenanceExposes a personalized AI agent that reads your resume and provides intelligent responses about your professional background through a standardized MCP server interface with RAG capabilities.MIT
- FlicenseAqualityBmaintenanceMCP server that exposes a resume as callable tools and resources, enabling AI agents to query experience, skills, projects, and contact information via natural language.3
- AlicenseAqualityBmaintenanceExposes a personal portfolio of projects, skills, and resume as callable tools for MCP-compatible AI assistants like Claude Desktop.4MIT
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/derekhuynen/derekhuynen-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server