chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# MCP Prompt Server Example
|
||||
|
||||
This example uses a local MCP prompt server in [server.py](server.py).
|
||||
|
||||
Run the example via:
|
||||
|
||||
```
|
||||
uv run python examples/mcp/prompt_server/main.py
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
The example uses the `MCPServerStreamableHttp` class from `agents.mcp`. The script auto-selects an open localhost port (or honors `STREAMABLE_HTTP_PORT`) and runs the server at `http://<host>:<port>/mcp`, providing user-controlled prompts that generate agent instructions. If you need a specific address, set `STREAMABLE_HTTP_PORT` and `STREAMABLE_HTTP_HOST`.
|
||||
|
||||
The server exposes prompts like `generate_code_review_instructions` that take parameters such as focus area and programming language. The agent calls these prompts to dynamically generate its system instructions based on user-provided parameters.
|
||||
|
||||
## Workflow
|
||||
|
||||
The example demonstrates two key functions:
|
||||
|
||||
1. **`show_available_prompts`** - Lists all available prompts on the MCP server, showing users what prompts they can select from. This demonstrates the discovery aspect of MCP prompts.
|
||||
|
||||
2. **`demo_code_review`** - Shows the complete user-controlled prompt workflow:
|
||||
- Calls `generate_code_review_instructions` with specific parameters (focus: "security vulnerabilities", language: "python")
|
||||
- Uses the generated instructions to create an Agent with specialized code review capabilities
|
||||
- Runs the agent against vulnerable sample code (command injection via `os.system`)
|
||||
- The agent analyzes the code and provides security-focused feedback using available tools
|
||||
|
||||
This pattern allows users to dynamically configure agent behavior through MCP prompts rather than hardcoded instructions.
|
||||
@@ -0,0 +1,131 @@
|
||||
import asyncio
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import time
|
||||
from typing import Any, cast
|
||||
|
||||
from agents import Agent, Runner, gen_trace_id, trace
|
||||
from agents.mcp import MCPServer, MCPServerStreamableHttp
|
||||
from agents.model_settings import ModelSettings
|
||||
|
||||
STREAMABLE_HTTP_HOST = os.getenv("STREAMABLE_HTTP_HOST", "127.0.0.1")
|
||||
|
||||
|
||||
def _choose_port() -> int:
|
||||
env_port = os.getenv("STREAMABLE_HTTP_PORT")
|
||||
if env_port:
|
||||
return int(env_port)
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind((STREAMABLE_HTTP_HOST, 0))
|
||||
address = cast(tuple[str, int], s.getsockname())
|
||||
return address[1]
|
||||
|
||||
|
||||
STREAMABLE_HTTP_PORT = _choose_port()
|
||||
os.environ.setdefault("STREAMABLE_HTTP_PORT", str(STREAMABLE_HTTP_PORT))
|
||||
STREAMABLE_HTTP_URL = f"http://{STREAMABLE_HTTP_HOST}:{STREAMABLE_HTTP_PORT}/mcp"
|
||||
|
||||
|
||||
async def get_instructions_from_prompt(mcp_server: MCPServer, prompt_name: str, **kwargs) -> str:
|
||||
"""Get agent instructions by calling MCP prompt endpoint (user-controlled)"""
|
||||
print(f"Getting instructions from prompt: {prompt_name}")
|
||||
|
||||
try:
|
||||
prompt_result = await mcp_server.get_prompt(prompt_name, kwargs)
|
||||
content = prompt_result.messages[0].content
|
||||
if hasattr(content, "text"):
|
||||
instructions = content.text
|
||||
else:
|
||||
instructions = str(content)
|
||||
print("Generated instructions")
|
||||
return instructions
|
||||
except Exception as e:
|
||||
print(f"Failed to get instructions: {e}")
|
||||
return f"You are a helpful assistant. Error: {e}"
|
||||
|
||||
|
||||
async def demo_code_review(mcp_server: MCPServer):
|
||||
"""Demo: Code review with user-selected prompt"""
|
||||
print("=== CODE REVIEW DEMO ===")
|
||||
|
||||
# User explicitly selects prompt and parameters
|
||||
instructions = await get_instructions_from_prompt(
|
||||
mcp_server,
|
||||
"generate_code_review_instructions",
|
||||
focus="security vulnerabilities",
|
||||
language="python",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
name="Code Reviewer Agent",
|
||||
instructions=instructions, # Instructions from MCP prompt
|
||||
model_settings=ModelSettings(tool_choice="auto"),
|
||||
)
|
||||
|
||||
message = """Please review this code:
|
||||
|
||||
def process_user_input(user_input):
|
||||
command = f"echo {user_input}"
|
||||
os.system(command)
|
||||
return "Command executed"
|
||||
|
||||
"""
|
||||
|
||||
print(f"Running: {message[:60]}...")
|
||||
result = await Runner.run(starting_agent=agent, input=message)
|
||||
print(result.final_output)
|
||||
print("\n" + "=" * 50 + "\n")
|
||||
|
||||
|
||||
async def show_available_prompts(mcp_server: MCPServer):
|
||||
"""Show available prompts for user selection"""
|
||||
print("=== AVAILABLE PROMPTS ===")
|
||||
|
||||
prompts_result = await mcp_server.list_prompts()
|
||||
print("User can select from these prompts:")
|
||||
for i, prompt in enumerate(prompts_result.prompts, 1):
|
||||
print(f" {i}. {prompt.name} - {prompt.description}")
|
||||
print()
|
||||
|
||||
|
||||
async def main():
|
||||
async with MCPServerStreamableHttp(
|
||||
name="Simple Prompt Server",
|
||||
params={"url": STREAMABLE_HTTP_URL},
|
||||
) as server:
|
||||
trace_id = gen_trace_id()
|
||||
with trace(workflow_name="Simple Prompt Demo", trace_id=trace_id):
|
||||
print(f"Trace: https://platform.openai.com/traces/trace?trace_id={trace_id}\n")
|
||||
|
||||
await show_available_prompts(server)
|
||||
await demo_code_review(server)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not shutil.which("uv"):
|
||||
raise RuntimeError("uv is not installed")
|
||||
|
||||
process: subprocess.Popen[Any] | None = None
|
||||
try:
|
||||
this_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
server_file = os.path.join(this_dir, "server.py")
|
||||
|
||||
print(f"Starting Simple Prompt Server at {STREAMABLE_HTTP_URL} ...")
|
||||
env = os.environ.copy()
|
||||
env.setdefault("STREAMABLE_HTTP_HOST", STREAMABLE_HTTP_HOST)
|
||||
env.setdefault("STREAMABLE_HTTP_PORT", str(STREAMABLE_HTTP_PORT))
|
||||
process = subprocess.Popen(["uv", "run", server_file], env=env)
|
||||
time.sleep(3)
|
||||
print("Server started\n")
|
||||
except Exception as e:
|
||||
print(f"Error starting server: {e}")
|
||||
exit(1)
|
||||
|
||||
try:
|
||||
asyncio.run(main())
|
||||
finally:
|
||||
if process:
|
||||
process.terminate()
|
||||
print("Server terminated.")
|
||||
@@ -0,0 +1,42 @@
|
||||
import os
|
||||
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
||||
STREAMABLE_HTTP_HOST = os.getenv("STREAMABLE_HTTP_HOST", "127.0.0.1")
|
||||
STREAMABLE_HTTP_PORT = int(os.getenv("STREAMABLE_HTTP_PORT", "18080"))
|
||||
|
||||
# Create server
|
||||
mcp = FastMCP("Prompt Server", host=STREAMABLE_HTTP_HOST, port=STREAMABLE_HTTP_PORT)
|
||||
|
||||
|
||||
# Instruction-generating prompts (user-controlled)
|
||||
@mcp.prompt()
|
||||
def generate_code_review_instructions(
|
||||
focus: str = "general code quality", language: str = "python"
|
||||
) -> str:
|
||||
"""Generate agent instructions for code review tasks"""
|
||||
print(f"[debug-server] generate_code_review_instructions({focus}, {language})")
|
||||
|
||||
return f"""You are a senior {language} code review specialist. Your role is to provide comprehensive code analysis with focus on {focus}.
|
||||
|
||||
INSTRUCTIONS:
|
||||
- Analyze code for quality, security, performance, and best practices
|
||||
- Provide specific, actionable feedback with examples
|
||||
- Identify potential bugs, vulnerabilities, and optimization opportunities
|
||||
- Suggest improvements with code examples when applicable
|
||||
- Be constructive and educational in your feedback
|
||||
- Focus particularly on {focus} aspects
|
||||
|
||||
RESPONSE FORMAT:
|
||||
1. Overall Assessment
|
||||
2. Specific Issues Found
|
||||
3. Security Considerations
|
||||
4. Performance Notes
|
||||
5. Recommended Improvements
|
||||
6. Best Practices Suggestions
|
||||
|
||||
Use the available tools to check current time if you need timestamps for your analysis."""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run(transport="streamable-http")
|
||||
Reference in New Issue
Block a user