Skip to content

Example server to expose a fetch tool #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Python SDK Examples

This folders aims to provide simple examples of using the Python SDK. Please refer to the
[example-servers repository](https://github.com/modelcontextprotocol/example-servers)
for real-world servers.
1 change: 1 addition & 0 deletions examples/servers/simple-prompt/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11
42 changes: 42 additions & 0 deletions examples/servers/simple-prompt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# MCP Simple Prompt

A simple MCP server that exposes a customizable prompt template with optional context and topic parameters.

## Usage

Start the server using either stdio (default) or SSE transport:

```bash
# Using stdio transport (default)
mcp-simple-prompt

# Using SSE transport on custom port
mcp-simple-prompt --transport sse --port 8000
```

The server exposes a prompt named "simple" that accepts two optional arguments:

- `context`: Additional context to consider
- `topic`: Specific topic to focus on

## Example

Using the MCP client, you can retrieve the prompt like this:

```python
from mcp.client import ClientSession

async with ClientSession() as session:
await session.initialize()

# List available prompts
prompts = await session.list_prompts()
print(prompts)

# Get the prompt with arguments
prompt = await session.get_prompt("simple", {
"context": "User is a software developer",
"topic": "Python async programming"
})
print(prompt)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import sys

from server import main

sys.exit(main())
132 changes: 132 additions & 0 deletions examples/servers/simple-prompt/mcp_simple_prompt/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import anyio
import click
import mcp.types as types
from mcp.server import Server


@click.group()
def cli():
pass


@cli.command()
@click.option("--port", default=8000, help="Port to listen on for SSE")
@click.option(
"--transport",
type=click.Choice(["stdio", "sse"]),
default="stdio",
help="Transport type",
)
def main(port: int, transport: str) -> int:
return anyio.run(_amain, port, transport)


def create_messages(
context: str | None = None, topic: str | None = None
) -> list[types.PromptMessage]:
"""Create the messages for the prompt."""
messages = []

# Add context if provided
if context:
messages.append(
types.PromptMessage(
role="user",
content=types.TextContent(
type="text", text=f"Here is some relevant context: {context}"
),
)
)

# Add the main prompt
prompt = "Please help me with "
if topic:
prompt += f"the following topic: {topic}"
else:
prompt += "whatever questions I may have."

messages.append(
types.PromptMessage(
role="user", content=types.TextContent(type="text", text=prompt)
)
)

return messages


async def _amain(port: int, transport: str) -> int:
app = Server("mcp-simple-prompt")

@app.list_prompts()
async def list_prompts() -> list[types.Prompt]:
return [
types.Prompt(
name="simple",
description="A simple prompt that can take optional context and topic "
"arguments",
arguments=[
types.PromptArgument(
name="context",
description="Additional context to consider",
required=False,
),
types.PromptArgument(
name="topic",
description="Specific topic to focus on",
required=False,
),
],
)
]

@app.get_prompt()
async def get_prompt(
name: str, arguments: dict[str, str] | None = None
) -> types.GetPromptResult:
if name != "simple":
raise ValueError(f"Unknown prompt: {name}")

if arguments is None:
arguments = {}

return types.GetPromptResult(
messages=create_messages(
context=arguments.get("context"), topic=arguments.get("topic")
),
description="A simple prompt with optional context and topic arguments",
)

if transport == "sse":
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.routing import Route

sse = SseServerTransport("/messages")

async def handle_sse(scope, receive, send):
async with sse.connect_sse(scope, receive, send) as streams:
await app.run(
streams[0], streams[1], app.create_initialization_options()
)

async def handle_messages(scope, receive, send):
await sse.handle_post_message(scope, receive, send)

starlette_app = Starlette(
debug=True,
routes=[
Route("/sse", endpoint=handle_sse),
Route("/messages", endpoint=handle_messages, methods=["POST"]),
],
)

import uvicorn

uvicorn.run(starlette_app, host="0.0.0.0", port=port)
else:
from mcp.server.stdio import stdio_server

async with stdio_server() as streams:
await app.run(streams[0], streams[1], app.create_initialization_options())

return 0
47 changes: 47 additions & 0 deletions examples/servers/simple-prompt/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[project]
name = "mcp-simple-prompt"
version = "0.1.0"
description = "A simple MCP server exposing a customizable prompt"
readme = "README.md"
requires-python = ">=3.10"
authors = [{ name = "Anthropic, PBC." }]
maintainers = [
{ name = "David Soria Parra", email = "davidsp@anthropic.com" },
{ name = "Justin Spahr-Summers", email = "justin@anthropic.com" },
]
keywords = ["mcp", "llm", "automation", "web", "fetch"]
license = { text = "MIT" }
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
]
dependencies = ["anyio>=4.6.2.post1", "click>=8.1.7", "httpx>=0.27.2", "mcp"]

[project.scripts]
mcp-simple-prompt = "mcp_simple_prompt.server:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["mcp_simple_prompt"]

[tool.pyright]
include = ["mcp_simple_prompt"]
venvPath = "."
venv = ".venv"

[tool.ruff.lint]
select = ["E", "F", "I"]
ignore = []

[tool.ruff]
line-length = 88
target-version = "py310"

[tool.uv]
dev-dependencies = ["pyright>=1.1.378", "pytest>=8.3.3", "ruff>=0.6.9"]
Loading