MCP prompts
Paste a code snippet and get a review — but the reviewing instructions don't
Showcase — MCP prompts
Paste a code snippet and get a review — but the reviewing instructions don't
live in this app. They're a prompt on an MCP server. The backend calls
prompts/get("code_review") with your code, the server renders its own
template into ready-to-send messages, and those go to the model. Prompts are
the third MCP primitive: tools do actions, resources carry context, prompts
hold instructions — so a tool provider can ship the optimized prompt right
alongside the tool, versioned together. Improve the server's prompt and every
client improves without redeploying.
Run
bash bootstrap-secrets.sh # reads ../../../../.env, writes secrets/
docker compose up --build # default: PROVIDER=openai
Open http://localhost:3000.
To run against Gemini instead:
PROVIDER=gemini docker compose up --build
What's where
backend/mcp_server.py— the MCP server:code_reviewandexplain_changeprompt templates, exposed viaprompts/listandprompts/get. It owns the wording; the client only fills the slots.backend/mcp_client.py— the from-scratch MCP client (shared): handshake, thenprompts/list/prompts/get.backend/ai_openai.py/backend/ai_gemini.py— fetch the rendered prompt and send its messages to the model.backend/main.py— identical FastAPI loader; reads PROVIDER and dispatches.frontend/app/page.tsx— code box + review.
Stop
docker compose down
Run locally
Download the project as a ZIP and run it with Docker. Brings up a FastAPI backend + Next.js frontend on localhost:3000.
unzip mcp-prompts.zip
cd mcp-prompts
bash bootstrap-secrets.sh # one-time: pulls API keys into ./secrets
docker compose up --build # default provider: openai
# or: PROVIDER=gemini docker compose up --build
Type some input, pick a provider, and run the same code shown in Source against the live API. Sign-in required.
The same modules the Run button hits. The whole project (frontend, Dockerfile, compose) is in the ZIP under README.
backend/ai_openai.py
"""Showcase 3 (OpenAI): prompts the server owns.
The client doesn't write the reviewing instructions — the MCP server does.
We `prompts/get` the `code_review` prompt with the user's snippet, get back
fully-composed messages, and send them straight to the model. Update the
prompt on the server and every client improves without redeploying.
"""
from openai import OpenAI
from mcp_client import MCPClient
_client = OpenAI()
_MODEL = "gpt-5.4-nano"
def run(code: str) -> str:
with MCPClient() as mcp:
mcp.list_prompts() # discovery — a client could let the user pick one
got = mcp.get_prompt("code_review", {"code": code.strip()}) # prompts/get
# MCP prompt messages → OpenAI input turns.
input_list = [
{"role": m["role"], "content": m["content"]["text"]}
for m in got["messages"]
]
response = _client.responses.create(model=_MODEL, input=input_list)
return response.output_text
backend/ai_gemini.py
"""Showcase 3 (Gemini): the same server-owned prompt, a different model.
Same `prompts/get` call, same server-authored messages. Only the mapping to
the model's message format changes (MCP's `assistant` role becomes Gemini's
`model`). The prompt engineering stays on the server, versioned with the tool
it belongs to.
"""
import os
from google import genai
from google.genai import types
from mcp_client import MCPClient
_client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
_MODEL = "gemini-3.1-flash-lite"
_ROLE = {"user": "user", "assistant": "model"} # MCP role → Gemini role
def run(code: str) -> str:
with MCPClient() as mcp:
mcp.list_prompts() # discovery — a client could let the user pick one
got = mcp.get_prompt("code_review", {"code": code.strip()}) # prompts/get
contents = [
types.Content(
role=_ROLE.get(m["role"], "user"),
parts=[types.Part(text=m["content"]["text"])],
)
for m in got["messages"]
]
response = _client.models.generate_content(model=_MODEL, contents=contents)
return response.text or ""
Project files
.gitignoreREADME.es.mdREADME.mdbackend/Dockerfilebackend/ai_gemini.pybackend/ai_openai.pybackend/main.pybackend/mcp_client.pybackend/mcp_server.pybackend/requirements.txtbootstrap-secrets.shdocker-compose.ymlfrontend/Dockerfilefrontend/app/layout.tsxfrontend/app/page.tsxfrontend/next.config.tsfrontend/package.jsonfrontend/tsconfig.json