-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Expand file tree
/
Copy pathserver.py
More file actions
95 lines (78 loc) · 2.96 KB
/
server.py
File metadata and controls
95 lines (78 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import anyio
import click
from mcp import types
from mcp.server.lowlevel import Server
from mcp.server.lowlevel.helper_types import ReadResourceContents
from starlette.requests import Request
SAMPLE_RESOURCES = {
"greeting": {
"content": "Hello! This is a sample text resource.",
"title": "Welcome Message",
},
"help": {
"content": "This server provides a few sample text resources for testing.",
"title": "Help Documentation",
},
"about": {
"content": "This is the simple-resource MCP server implementation.",
"title": "About This Server",
},
}
@click.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:
app = Server("mcp-simple-resource")
@app.list_resources()
async def list_resources() -> list[types.Resource]:
return [
types.Resource(
uri=f"file:///{name}.txt",
name=name,
title=SAMPLE_RESOURCES[name]["title"],
description=f"A sample text resource named {name}",
mime_type="text/plain",
)
for name in SAMPLE_RESOURCES.keys()
]
@app.read_resource()
async def read_resource(uri: str):
from urllib.parse import urlparse
parsed = urlparse(uri)
if not parsed.path:
raise ValueError(f"Invalid resource path: {uri}")
name = parsed.path.replace(".txt", "").lstrip("/")
if name not in SAMPLE_RESOURCES:
raise ValueError(f"Unknown resource: {uri}")
return [ReadResourceContents(content=SAMPLE_RESOURCES[name]["content"], mime_type="text/plain")]
if transport == "sse":
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.responses import Response
from starlette.routing import Mount, Route
sse = SseServerTransport("/messages/")
async def handle_sse(request: Request):
async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage]
await app.run(streams[0], streams[1], app.create_initialization_options())
return Response()
starlette_app = Starlette(
debug=True,
routes=[
Route("/sse", endpoint=handle_sse, methods=["GET"]),
Mount("/messages/", app=sse.handle_post_message),
],
)
import uvicorn
uvicorn.run(starlette_app, host="127.0.0.1", port=port)
else:
from mcp.server.stdio import stdio_server
async def arun():
async with stdio_server() as streams:
await app.run(streams[0], streams[1], app.create_initialization_options())
anyio.run(arun)
return 0