Skip to content

Commit e176644

Browse files
committed
add simple resource example
1 parent b1d41bb commit e176644

File tree

7 files changed

+213
-0
lines changed

7 files changed

+213
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.11
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# MCP Simple Resource
2+
3+
A simple MCP server that exposes sample text files as resources.
4+
5+
## Usage
6+
7+
Start the server using either stdio (default) or SSE transport:
8+
9+
```bash
10+
# Using stdio transport (default)
11+
mcp-simple-resource
12+
13+
# Using SSE transport on custom port
14+
mcp-simple-resource --transport sse --port 8000
15+
```
16+
17+
The server exposes some basic text file resources that can be read by clients.
18+
19+
## Example
20+
21+
Using the MCP client, you can read the resources like this:
22+
23+
```python
24+
from mcp.client import ClientSession
25+
26+
async with ClientSession() as session:
27+
await session.initialize()
28+
29+
# List available resources
30+
resources = await session.list_resources()
31+
print(resources)
32+
33+
# Read a specific resource
34+
resource = await session.read_resource(resources[0].uri)
35+
print(resource)
36+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import sys
2+
3+
from server import main
4+
5+
sys.exit(main())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import anyio
2+
import click
3+
import mcp.types as types
4+
from mcp.server import AnyUrl, Server
5+
6+
7+
@click.group()
8+
def cli():
9+
pass
10+
11+
12+
@cli.command()
13+
@click.option("--port", default=8000, help="Port to listen on for SSE")
14+
@click.option(
15+
"--transport",
16+
type=click.Choice(["stdio", "sse"]),
17+
default="stdio",
18+
help="Transport type",
19+
)
20+
def main(port: int, transport: str) -> int:
21+
return anyio.run(_amain, port, transport)
22+
23+
24+
SAMPLE_RESOURCES = {
25+
"greeting": "Hello! This is a sample text resource.",
26+
"help": "This server provides a few sample text resources for testing.",
27+
"about": "This is the simple-resource MCP server implementation.",
28+
}
29+
30+
31+
async def _amain(port: int, transport: str) -> int:
32+
app = Server("mcp-simple-resource")
33+
34+
@app.list_resources()
35+
async def list_resources() -> list[types.Resource]:
36+
return [
37+
types.Resource(
38+
uri=AnyUrl(f"file:///{name}.txt"),
39+
name=name,
40+
description=f"A sample text resource named {name}",
41+
mimeType="text/plain",
42+
)
43+
for name in SAMPLE_RESOURCES.keys()
44+
]
45+
46+
@app.read_resource()
47+
async def read_resource(uri: AnyUrl) -> str | bytes:
48+
assert uri.path is not None
49+
name = uri.path.replace(".txt", "").lstrip("/")
50+
51+
if name not in SAMPLE_RESOURCES:
52+
raise ValueError(f"Unknown resource: {uri}")
53+
54+
return SAMPLE_RESOURCES[name]
55+
56+
if transport == "sse":
57+
from mcp.server.sse import SseServerTransport
58+
from starlette.applications import Starlette
59+
from starlette.routing import Route
60+
61+
sse = SseServerTransport("/messages")
62+
63+
async def handle_sse(scope, receive, send):
64+
async with sse.connect_sse(scope, receive, send) as streams:
65+
await app.run(
66+
streams[0], streams[1], app.create_initialization_options()
67+
)
68+
69+
async def handle_messages(scope, receive, send):
70+
await sse.handle_post_message(scope, receive, send)
71+
72+
starlette_app = Starlette(
73+
debug=True,
74+
routes=[
75+
Route("/sse", endpoint=handle_sse),
76+
Route("/messages", endpoint=handle_messages, methods=["POST"]),
77+
],
78+
)
79+
80+
import uvicorn
81+
82+
uvicorn.run(starlette_app, host="0.0.0.0", port=port)
83+
else:
84+
from mcp.server.stdio import stdio_server
85+
86+
async with stdio_server() as streams:
87+
await app.run(streams[0], streams[1], app.create_initialization_options())
88+
89+
return 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[project]
2+
name = "mcp-simple-resource"
3+
version = "0.1.0"
4+
description = "A simple MCP server exposing sample text resources"
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
authors = [{ name = "Anthropic, PBC." }]
8+
maintainers = [
9+
{ name = "David Soria Parra", email = "[email protected]" },
10+
{ name = "Justin Spahr-Summers", email = "[email protected]" },
11+
]
12+
keywords = ["mcp", "llm", "automation", "web", "fetch"]
13+
license = { text = "MIT" }
14+
classifiers = [
15+
"Development Status :: 4 - Beta",
16+
"Intended Audience :: Developers",
17+
"License :: OSI Approved :: MIT License",
18+
"Programming Language :: Python :: 3",
19+
"Programming Language :: Python :: 3.10",
20+
]
21+
dependencies = ["anyio>=4.6.2.post1", "click>=8.1.7", "httpx>=0.27.2", "mcp"]
22+
23+
[project.scripts]
24+
mcp-simple-resource = "mcp_simple_resource.server:main"
25+
26+
[build-system]
27+
requires = ["hatchling"]
28+
build-backend = "hatchling.build"
29+
30+
[tool.hatch.build.targets.wheel]
31+
packages = ["mcp_simple_resource"]
32+
33+
[tool.pyright]
34+
include = ["mcp_simple_resource"]
35+
venvPath = "."
36+
venv = ".venv"
37+
38+
[tool.ruff.lint]
39+
select = ["E", "F", "I"]
40+
ignore = []
41+
42+
[tool.ruff]
43+
line-length = 88
44+
target-version = "py310"
45+
46+
[tool.uv]
47+
dev-dependencies = ["pyright>=1.1.378", "pytest>=8.3.3", "ruff>=0.6.9"]

uv.lock

+34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)