-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcp_server.py
More file actions
executable file
·187 lines (156 loc) · 5.11 KB
/
mcp_server.py
File metadata and controls
executable file
·187 lines (156 loc) · 5.11 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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env python3
"""
SimpleMCP - MCP Server STDIO Implementation
This is a Model Context Protocol (MCP) server that exposes the story-telling
service using the official Anthropic MCP specification. It can be connected
to any MCP-compatible client that supports STDIO transport.
The server provides two tools:
- list_stories: Get a list of all available stories
- get_story: Retrieve a specific story by its ID
Usage:
python mcp_server.py
For MCP clients using STDIO transport, add this to your client configuration:
{
"mcpServers": {
"story-teller": {
"command": "python",
"args": ["/absolute/path/to/SimpleMCP/mcp_server.py"]
}
}
}
Example clients: Claude Desktop, Claude Code (STDIO mode), custom MCP clients
"""
import asyncio
import json
import sys
from typing import Any
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import (
Tool,
TextContent,
ImageContent,
EmbeddedResource,
)
import story_manager
# Create the MCP server instance
app = Server("story-teller")
@app.list_tools()
async def list_tools() -> list[Tool]:
"""
List all available tools.
This is called by MCP clients to discover what tools the server provides.
"""
return [
Tool(
name="list_stories",
description="List all available stories. Returns an array of story objects with id and title for each story.",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_story",
description="Get a specific story by its ID. Returns the complete story including id, title, and full text content.",
inputSchema={
"type": "object",
"properties": {
"story_id": {
"type": "string",
"description": "The unique identifier of the story (e.g., 'squirrel_and_owl', 'bear_loses_roar')",
"enum": [
"squirrel_and_owl",
"bear_loses_roar",
"turtle_wants_to_fly",
"lonely_firefly",
"rabbit_and_carrot"
]
}
},
"required": ["story_id"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: Any) -> list[TextContent | ImageContent | EmbeddedResource]:
"""
Handle tool calls from MCP clients.
Args:
name: The name of the tool being called
arguments: Dictionary of arguments for the tool
Returns:
List of content objects (text, images, or embedded resources)
"""
if name == "list_stories":
# Call the core business logic
stories = story_manager.list_stories()
# Format the response as MCP TextContent
return [
TextContent(
type="text",
text=json.dumps(stories, indent=2)
)
]
elif name == "get_story":
# Validate that story_id was provided
if "story_id" not in arguments:
return [
TextContent(
type="text",
text="Error: story_id parameter is required"
)
]
story_id = arguments["story_id"]
try:
# Call the core business logic
story = story_manager.get_story(story_id)
# Format the response as a nicely formatted story
story_text = f"""# {story['title']}
{story['text']}
---
Story ID: {story['id']}
"""
return [
TextContent(
type="text",
text=story_text
)
]
except KeyError as e:
# Story not found
return [
TextContent(
type="text",
text=f"Error: {str(e)}"
)
]
else:
# Unknown tool
return [
TextContent(
type="text",
text=f"Error: Unknown tool '{name}'"
)
]
async def main():
"""
Main entry point for the MCP server.
Runs the server using STDIO transport (reads from stdin, writes to stdout).
This is the standard transport for local MCP client integrations.
"""
# Log server startup to stderr (so it doesn't interfere with MCP protocol on stdout)
print("[MCP Server] SimpleMCP Story Teller Server starting...", file=sys.stderr)
print("[MCP Server] Using STDIO transport", file=sys.stderr)
print("[MCP Server] Ready to accept connections from MCP clients", file=sys.stderr)
# Run the server using STDIO transport
async with stdio_server() as (read_stream, write_stream):
await app.run(
read_stream,
write_stream,
app.create_initialization_options()
)
if __name__ == "__main__":
# Run the async main function
asyncio.run(main())