Skip to content

Commit 2467f8e

Browse files
authored
Merge pull request modelcontextprotocol#21 from modelcontextprotocol/davidsp/concepts
Python version of the concepts pages
2 parents 2cfd5fd + 18454d3 commit 2467f8e

File tree

5 files changed

+369
-43
lines changed

5 files changed

+369
-43
lines changed

docs/concepts/architecture.mdx

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,37 @@ The protocol layer handles message framing, request/response linking, and high-l
5656
</Tab>
5757
<Tab title="Python">
5858
```python
59-
# Python implementation coming soon
59+
class Session(BaseSession[RequestT, NotificationT, ResultT]):
60+
async def send_request(
61+
self,
62+
request: RequestT,
63+
result_type: type[Result]
64+
) -> Result:
65+
"""
66+
Send request and wait for response. Raises McpError if response contains error.
67+
"""
68+
# Request handling implementation
69+
70+
async def send_notification(
71+
self,
72+
notification: NotificationT
73+
) -> None:
74+
"""Send one-way notification that doesn't expect response."""
75+
# Notification handling implementation
76+
77+
async def _received_request(
78+
self,
79+
responder: RequestResponder[ReceiveRequestT, ResultT]
80+
) -> None:
81+
"""Handle incoming request from other side."""
82+
# Request handling implementation
83+
84+
async def _received_notification(
85+
self,
86+
notification: ReceiveNotificationT
87+
) -> None:
88+
"""Handle incoming notification from other side."""
89+
# Notification handling implementation
6090
```
6191
</Tab>
6292
</Tabs>
@@ -212,7 +242,32 @@ Here's a basic example of implementing an MCP server:
212242
</Tab>
213243
<Tab title="Python">
214244
```python
215-
# Python implementation coming soon
245+
import asyncio
246+
import mcp.types as types
247+
from mcp.server import Server
248+
from mcp.server.stdio import stdio_server
249+
250+
app = Server("example-server")
251+
252+
@app.list_resources()
253+
async def list_resources() -> list[types.Resource]:
254+
return [
255+
types.Resource(
256+
uri="example://resource",
257+
name="Example Resource"
258+
)
259+
]
260+
261+
async def main():
262+
async with stdio_server() as streams:
263+
await app.run(
264+
streams[0],
265+
streams[1],
266+
app.create_initialization_options()
267+
)
268+
269+
if __name__ == "__main__":
270+
asyncio.run(main)
216271
```
217272
</Tab>
218273
</Tabs>

docs/concepts/prompts.mdx

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,85 @@ Here's a complete example of implementing prompts in an MCP server:
292292
</Tab>
293293
<Tab title="Python">
294294
```python
295-
# Python implementation coming soon
295+
from mcp.server import Server
296+
import mcp.types as types
297+
298+
# Define available prompts
299+
PROMPTS = {
300+
"git-commit": types.Prompt(
301+
name="git-commit",
302+
description="Generate a Git commit message",
303+
arguments=[
304+
types.PromptArgument(
305+
name="changes",
306+
description="Git diff or description of changes",
307+
required=True
308+
)
309+
],
310+
),
311+
"explain-code": types.Prompt(
312+
name="explain-code",
313+
description="Explain how code works",
314+
arguments=[
315+
types.PromptArgument(
316+
name="code",
317+
description="Code to explain",
318+
required=True
319+
),
320+
types.PromptArgument(
321+
name="language",
322+
description="Programming language",
323+
required=False
324+
)
325+
],
326+
)
327+
}
328+
329+
# Initialize server
330+
app = Server("example-prompts-server")
331+
332+
@app.list_prompts()
333+
async def list_prompts() -> list[types.Prompt]:
334+
return list(PROMPTS.values())
335+
336+
@app.get_prompt()
337+
async def get_prompt(
338+
name: str, arguments: dict[str, str] | None = None
339+
) -> types.GetPromptResult:
340+
if name not in PROMPTS:
341+
raise ValueError(f"Prompt not found: {name}")
342+
343+
if name == "git-commit":
344+
changes = arguments.get("changes") if arguments else ""
345+
return types.GetPromptResult(
346+
messages=[
347+
types.PromptMessage(
348+
role="user",
349+
content=types.TextContent(
350+
type="text",
351+
text=f"Generate a concise but descriptive commit message "
352+
f"for these changes:\n\n{changes}"
353+
)
354+
)
355+
]
356+
)
357+
358+
if name == "explain-code":
359+
code = arguments.get("code") if arguments else ""
360+
language = arguments.get("language", "Unknown") if arguments else "Unknown"
361+
return types.GetPromptResult(
362+
messages=[
363+
types.PromptMessage(
364+
role="user",
365+
content=types.TextContent(
366+
type="text",
367+
text=f"Explain how this {language} code works:\n\n{code}"
368+
)
369+
)
370+
]
371+
)
372+
373+
raise ValueError("Prompt implementation not found")
296374
```
297375
</Tab>
298376
</Tabs>

docs/concepts/resources.mdx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,33 @@ Here's a simple example of implementing resource support in an MCP server:
186186
</Tab>
187187
<Tab title="Python">
188188
```python
189-
# Python implementation coming soon
189+
app = Server("example-server")
190+
191+
@app.list_resources()
192+
async def list_resources() -> list[types.Resource]:
193+
return [
194+
types.Resource(
195+
uri="file:///logs/app.log",
196+
name="Application Logs",
197+
mimeType="text/plain"
198+
)
199+
]
200+
201+
@app.read_resource()
202+
async def read_resource(uri: AnyUrl) -> str:
203+
if str(uri) == "file:///logs/app.log":
204+
log_contents = await read_log_file()
205+
return log_contents
206+
207+
raise ValueError("Resource not found")
208+
209+
# Start server
210+
async with stdio_server() as streams:
211+
await app.run(
212+
streams[0],
213+
streams[1],
214+
app.create_initialization_options()
215+
)
190216
```
191217
</Tab>
192218
</Tabs>

docs/concepts/tools.mdx

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,36 @@ Here's an example of implementing a basic tool in an MCP server:
8282
</Tab>
8383
<Tab title="Python">
8484
```python
85-
# Python implementation coming soon
85+
app = Server("example-server")
86+
87+
@app.list_tools()
88+
async def list_tools() -> list[types.Tool]:
89+
return [
90+
types.Tool(
91+
name="calculate_sum",
92+
description="Add two numbers together",
93+
inputSchema={
94+
"type": "object",
95+
"properties": {
96+
"a": {"type": "number"},
97+
"b": {"type": "number"}
98+
},
99+
"required": ["a", "b"]
100+
}
101+
)
102+
]
103+
104+
@app.call_tool()
105+
async def call_tool(
106+
name: str,
107+
arguments: dict
108+
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
109+
if name == "calculate_sum":
110+
a = arguments["a"]
111+
b = arguments["b"]
112+
result = a + b
113+
return [types.TextContent(type="text", text=str(result))]
114+
raise ValueError(f"Tool not found: {name}")
86115
```
87116
</Tab>
88117
</Tabs>
@@ -212,30 +241,59 @@ Tool errors should be reported within the result object, not as MCP protocol-lev
212241

213242
Here's an example of proper error handling for tools:
214243

215-
```typescript
216-
try {
217-
// Tool operation
218-
const result = performOperation();
219-
return {
220-
content: [
221-
{
222-
type: "text",
223-
text: `Operation successful: ${result}`
224-
}
225-
]
226-
};
227-
} catch (error) {
228-
return {
229-
isError: true,
230-
content: [
231-
{
232-
type: "text",
233-
text: `Error: ${error.message}`
234-
}
235-
]
236-
};
237-
}
238-
```
244+
<Tabs>
245+
<Tab title="TypeScript">
246+
```typescript
247+
try {
248+
// Tool operation
249+
const result = performOperation();
250+
return {
251+
content: [
252+
{
253+
type: "text",
254+
text: `Operation successful: ${result}`
255+
}
256+
]
257+
};
258+
} catch (error) {
259+
return {
260+
isError: true,
261+
content: [
262+
{
263+
type: "text",
264+
text: `Error: ${error.message}`
265+
}
266+
]
267+
};
268+
}
269+
```
270+
</Tab>
271+
<Tab title="Python">
272+
```python
273+
try:
274+
# Tool operation
275+
result = perform_operation()
276+
return types.CallToolResult(
277+
content=[
278+
types.TextContent(
279+
type="text",
280+
text=f"Operation successful: {result}"
281+
)
282+
]
283+
)
284+
except Exception as error:
285+
return types.CallToolResult(
286+
isError=True,
287+
content=[
288+
types.TextContent(
289+
type="text",
290+
text=f"Error: {str(error)}"
291+
)
292+
]
293+
)
294+
```
295+
</Tab>
296+
</Tabs>
239297

240298
This approach allows the LLM to see that an error occurred and potentially take corrective action or request human intervention.
241299

0 commit comments

Comments
 (0)