#
tokens: 6683/50000 6/7 files (page 1/2)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 2. Use http://codebase.md/lightfate/ssh-tools-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .gitignore
├── main.py
├── mcp_requirements.txt
├── pyproject.toml
├── python_mcp.md
├── README.md
├── requirements.txt
└── ssh_server.py
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Python
 2 | __pycache__/
 3 | *.py[cod]
 4 | *$py.class
 5 | *.so
 6 | .Python
 7 | build/
 8 | develop-eggs/
 9 | dist/
10 | downloads/
11 | eggs/
12 | .eggs/
13 | lib/
14 | lib64/
15 | parts/
16 | sdist/
17 | var/
18 | wheels/
19 | *.egg-info/
20 | .installed.cfg
21 | *.egg
22 | 
23 | # Virtual Environment
24 | .env
25 | .venv
26 | env/
27 | venv/
28 | ENV/
29 | 
30 | # IDE
31 | .idea/
32 | .vscode/
33 | *.swp
34 | *.swo
35 | .cursor/
36 | 
37 | # Logs
38 | *.log
39 | 
40 | # Local development
41 | .DS_Store
42 | Thumbs.db
43 | 
44 | # Project specific
45 | uv.lock 
```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
1 | mcp>=0.1.0
2 | paramiko>=3.4.0 
```

--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------

```python
1 | def main():
2 |     print("Hello from ssh-tools-mcp!")
3 | 
4 | 
5 | if __name__ == "__main__":
6 |     main()
7 | 
```

--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [project]
 2 | name = "ssh-tools-mcp"
 3 | version = "0.1.0"
 4 | description = "Add your description here"
 5 | readme = "README.md"
 6 | requires-python = ">=3.10"
 7 | dependencies = [
 8 |     "httpx>=0.28.1",
 9 |     "mcp[cli]",
10 |     "paramiko",
11 | ]
12 | 
```

--------------------------------------------------------------------------------
/ssh_server.py:
--------------------------------------------------------------------------------

```python
  1 | from mcp.server.fastmcp import FastMCP
  2 | import paramiko
  3 | from dataclasses import dataclass
  4 | from typing import Optional
  5 | import json
  6 | 
  7 | # Create an MCP server
  8 | mcp = FastMCP("SSH Tools")
  9 | 
 10 | class SSHConnection:
 11 |     def __init__(self, hostname: str, password: str, username: str = "root", port: int = 22):
 12 |         self.hostname = hostname
 13 |         self.username = username
 14 |         self.password = password
 15 |         self.port = port
 16 |         self.client = None
 17 | 
 18 |     def connect(self):
 19 |         if self.client is not None:
 20 |             return
 21 |             
 22 |         self.client = paramiko.SSHClient()
 23 |         self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 24 |         self.client.connect(
 25 |             hostname=self.hostname,
 26 |             username=self.username,
 27 |             password=self.password,
 28 |             port=self.port
 29 |         )
 30 | 
 31 |     def disconnect(self):
 32 |         if self.client:
 33 |             self.client.close()
 34 |             self.client = None
 35 | 
 36 |     def execute_command(self, command: str) -> str:
 37 |         if not self.client:
 38 |             self.connect()
 39 |             
 40 |         stdin, stdout, stderr = self.client.exec_command(command)
 41 |         output = stdout.read().decode()
 42 |         error = stderr.read().decode()
 43 |         
 44 |         if error:
 45 |             return f"Error: {error}"
 46 |         return output
 47 | 
 48 | @dataclass
 49 | class SSHConnectionInfo:
 50 |     hostname: str
 51 |     password: str
 52 |     username: str = "root"
 53 |     port: int = 22
 54 | 
 55 | # Global connection storage
 56 | current_connection: Optional[SSHConnection] = None
 57 | 
 58 | @mcp.tool()
 59 | def connect_ssh(hostname: str, password: str, username: str = "root", port: int = 22) -> str:
 60 |     """Connect to a remote server via SSH
 61 |     
 62 |     Args:
 63 |         hostname: The IP address or hostname of the server
 64 |         password: The SSH password
 65 |         username: The SSH username (default: root)
 66 |         port: The SSH port (default: 22)
 67 |     """
 68 |     global current_connection
 69 |     
 70 |     try:
 71 |         if current_connection:
 72 |             current_connection.disconnect()
 73 |             
 74 |         connection = SSHConnection(hostname, password, username, port)
 75 |         connection.connect()
 76 |         current_connection = connection
 77 |         return "Successfully connected to the server!"
 78 |     except Exception as e:
 79 |         return f"Failed to connect: {str(e)}"
 80 | 
 81 | @mcp.tool()
 82 | def run_command(command: str) -> str:
 83 |     """Run a command on the connected SSH server
 84 |     
 85 |     Args:
 86 |         command: The command to execute
 87 |     """
 88 |     global current_connection
 89 |     
 90 |     if not current_connection:
 91 |         return "Error: Not connected to any server. Please connect first using connect_ssh."
 92 |         
 93 |     try:
 94 |         return current_connection.execute_command(command)
 95 |     except Exception as e:
 96 |         return f"Failed to execute command: {str(e)}"
 97 | 
 98 | @mcp.tool()
 99 | def disconnect_ssh() -> str:
100 |     """Disconnect from the current SSH server"""
101 |     global current_connection
102 |     
103 |     if current_connection:
104 |         current_connection.disconnect()
105 |         current_connection = None
106 |         return "Successfully disconnected from the server!"
107 |     return "Not connected to any server."
108 | 
109 | if __name__ == "__main__":
110 |     mcp.run() 
```

--------------------------------------------------------------------------------
/python_mcp.md:
--------------------------------------------------------------------------------

```markdown
  1 | # MCP Python SDK
  2 | 
  3 | <div align="center">
  4 | 
  5 | <strong>Python implementation of the Model Context Protocol (MCP)</strong>
  6 | 
  7 | [![PyPI][pypi-badge]][pypi-url]
  8 | [![MIT licensed][mit-badge]][mit-url]
  9 | [![Python Version][python-badge]][python-url]
 10 | [![Documentation][docs-badge]][docs-url]
 11 | [![Specification][spec-badge]][spec-url]
 12 | [![GitHub Discussions][discussions-badge]][discussions-url]
 13 | 
 14 | </div>
 15 | 
 16 | <!-- omit in toc -->
 17 | ## Table of Contents
 18 | 
 19 | - [MCP Python SDK](#mcp-python-sdk)
 20 |   - [Overview](#overview)
 21 |   - [Installation](#installation)
 22 |   - [Quickstart](#quickstart)
 23 |   - [What is MCP?](#what-is-mcp)
 24 |   - [Core Concepts](#core-concepts)
 25 |     - [Server](#server)
 26 |     - [Resources](#resources)
 27 |     - [Tools](#tools)
 28 |     - [Prompts](#prompts)
 29 |     - [Images](#images)
 30 |     - [Context](#context)
 31 |   - [Running Your Server](#running-your-server)
 32 |     - [Development Mode](#development-mode)
 33 |     - [Claude Desktop Integration](#claude-desktop-integration)
 34 |     - [Direct Execution](#direct-execution)
 35 |   - [Examples](#examples)
 36 |     - [Echo Server](#echo-server)
 37 |     - [SQLite Explorer](#sqlite-explorer)
 38 |   - [Advanced Usage](#advanced-usage)
 39 |     - [Low-Level Server](#low-level-server)
 40 |     - [Writing MCP Clients](#writing-mcp-clients)
 41 |     - [MCP Primitives](#mcp-primitives)
 42 |     - [Server Capabilities](#server-capabilities)
 43 |   - [Documentation](#documentation)
 44 |   - [Contributing](#contributing)
 45 |   - [License](#license)
 46 | 
 47 | [pypi-badge]: https://img.shields.io/pypi/v/mcp.svg
 48 | [pypi-url]: https://pypi.org/project/mcp/
 49 | [mit-badge]: https://img.shields.io/pypi/l/mcp.svg
 50 | [mit-url]: https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE
 51 | [python-badge]: https://img.shields.io/pypi/pyversions/mcp.svg
 52 | [python-url]: https://www.python.org/downloads/
 53 | [docs-badge]: https://img.shields.io/badge/docs-modelcontextprotocol.io-blue.svg
 54 | [docs-url]: https://modelcontextprotocol.io
 55 | [spec-badge]: https://img.shields.io/badge/spec-spec.modelcontextprotocol.io-blue.svg
 56 | [spec-url]: https://spec.modelcontextprotocol.io
 57 | [discussions-badge]: https://img.shields.io/github/discussions/modelcontextprotocol/python-sdk
 58 | [discussions-url]: https://github.com/modelcontextprotocol/python-sdk/discussions
 59 | 
 60 | ## Overview
 61 | 
 62 | The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This Python SDK implements the full MCP specification, making it easy to:
 63 | 
 64 | - Build MCP clients that can connect to any MCP server
 65 | - Create MCP servers that expose resources, prompts and tools
 66 | - Use standard transports like stdio and SSE
 67 | - Handle all MCP protocol messages and lifecycle events
 68 | 
 69 | ## Installation
 70 | 
 71 | We recommend using [uv](https://docs.astral.sh/uv/) to manage your Python projects:
 72 | 
 73 | ```bash
 74 | uv add "mcp[cli]"
 75 | ```
 76 | 
 77 | Alternatively:
 78 | ```bash
 79 | pip install mcp
 80 | ```
 81 | 
 82 | ## Quickstart
 83 | 
 84 | Let's create a simple MCP server that exposes a calculator tool and some data:
 85 | 
 86 | ```python
 87 | # server.py
 88 | from mcp.server.fastmcp import FastMCP
 89 | 
 90 | # Create an MCP server
 91 | mcp = FastMCP("Demo")
 92 | 
 93 | # Add an addition tool
 94 | @mcp.tool()
 95 | def add(a: int, b: int) -> int:
 96 |     """Add two numbers"""
 97 |     return a + b
 98 | 
 99 | # Add a dynamic greeting resource
100 | @mcp.resource("greeting://{name}")
101 | def get_greeting(name: str) -> str:
102 |     """Get a personalized greeting"""
103 |     return f"Hello, {name}!"
104 | ```
105 | 
106 | You can install this server in [Claude Desktop](https://claude.ai/download) and interact with it right away by running:
107 | ```bash
108 | mcp install server.py
109 | ```
110 | 
111 | Alternatively, you can test it with the MCP Inspector:
112 | ```bash
113 | mcp dev server.py
114 | ```
115 | 
116 | ## What is MCP?
117 | 
118 | The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
119 | 
120 | - Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
121 | - Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
122 | - Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
123 | - And more!
124 | 
125 | ## Core Concepts
126 | 
127 | ### Server
128 | 
129 | The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
130 | 
131 | ```python
132 | # Add lifespan support for startup/shutdown with strong typing
133 | from dataclasses import dataclass
134 | from typing import AsyncIterator
135 | from mcp.server.fastmcp import FastMCP
136 | 
137 | # Create a named server
138 | mcp = FastMCP("My App")
139 | 
140 | # Specify dependencies for deployment and development
141 | mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
142 | 
143 | @dataclass
144 | class AppContext:
145 |     db: Database  # Replace with your actual DB type
146 | 
147 | @asynccontextmanager
148 | async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
149 |     """Manage application lifecycle with type-safe context"""
150 |     try:
151 |         # Initialize on startup
152 |         await db.connect()
153 |         yield AppContext(db=db)
154 |     finally:
155 |         # Cleanup on shutdown
156 |         await db.disconnect()
157 | 
158 | # Pass lifespan to server
159 | mcp = FastMCP("My App", lifespan=app_lifespan)
160 | 
161 | # Access type-safe lifespan context in tools
162 | @mcp.tool()
163 | def query_db(ctx: Context) -> str:
164 |     """Tool that uses initialized resources"""
165 |     db = ctx.request_context.lifespan_context["db"]
166 |     return db.query()
167 | ```
168 | 
169 | ### Resources
170 | 
171 | Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
172 | 
173 | ```python
174 | @mcp.resource("config://app")
175 | def get_config() -> str:
176 |     """Static configuration data"""
177 |     return "App configuration here"
178 | 
179 | @mcp.resource("users://{user_id}/profile")
180 | def get_user_profile(user_id: str) -> str:
181 |     """Dynamic user data"""
182 |     return f"Profile data for user {user_id}"
183 | ```
184 | 
185 | ### Tools
186 | 
187 | Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
188 | 
189 | ```python
190 | @mcp.tool()
191 | def calculate_bmi(weight_kg: float, height_m: float) -> float:
192 |     """Calculate BMI given weight in kg and height in meters"""
193 |     return weight_kg / (height_m ** 2)
194 | 
195 | @mcp.tool()
196 | async def fetch_weather(city: str) -> str:
197 |     """Fetch current weather for a city"""
198 |     async with httpx.AsyncClient() as client:
199 |         response = await client.get(f"https://api.weather.com/{city}")
200 |         return response.text
201 | ```
202 | 
203 | ### Prompts
204 | 
205 | Prompts are reusable templates that help LLMs interact with your server effectively:
206 | 
207 | ```python
208 | @mcp.prompt()
209 | def review_code(code: str) -> str:
210 |     return f"Please review this code:\n\n{code}"
211 | 
212 | @mcp.prompt()
213 | def debug_error(error: str) -> list[Message]:
214 |     return [
215 |         UserMessage("I'm seeing this error:"),
216 |         UserMessage(error),
217 |         AssistantMessage("I'll help debug that. What have you tried so far?")
218 |     ]
219 | ```
220 | 
221 | ### Images
222 | 
223 | FastMCP provides an `Image` class that automatically handles image data:
224 | 
225 | ```python
226 | from mcp.server.fastmcp import FastMCP, Image
227 | from PIL import Image as PILImage
228 | 
229 | @mcp.tool()
230 | def create_thumbnail(image_path: str) -> Image:
231 |     """Create a thumbnail from an image"""
232 |     img = PILImage.open(image_path)
233 |     img.thumbnail((100, 100))
234 |     return Image(data=img.tobytes(), format="png")
235 | ```
236 | 
237 | ### Context
238 | 
239 | The Context object gives your tools and resources access to MCP capabilities:
240 | 
241 | ```python
242 | from mcp.server.fastmcp import FastMCP, Context
243 | 
244 | @mcp.tool()
245 | async def long_task(files: list[str], ctx: Context) -> str:
246 |     """Process multiple files with progress tracking"""
247 |     for i, file in enumerate(files):
248 |         ctx.info(f"Processing {file}")
249 |         await ctx.report_progress(i, len(files))
250 |         data, mime_type = await ctx.read_resource(f"file://{file}")
251 |     return "Processing complete"
252 | ```
253 | 
254 | ## Running Your Server
255 | 
256 | ### Development Mode
257 | 
258 | The fastest way to test and debug your server is with the MCP Inspector:
259 | 
260 | ```bash
261 | mcp dev server.py
262 | 
263 | # Add dependencies
264 | mcp dev server.py --with pandas --with numpy
265 | 
266 | # Mount local code
267 | mcp dev server.py --with-editable .
268 | ```
269 | 
270 | ### Claude Desktop Integration
271 | 
272 | Once your server is ready, install it in Claude Desktop:
273 | 
274 | ```bash
275 | mcp install server.py
276 | 
277 | # Custom name
278 | mcp install server.py --name "My Analytics Server"
279 | 
280 | # Environment variables
281 | mcp install server.py -v API_KEY=abc123 -v DB_URL=postgres://...
282 | mcp install server.py -f .env
283 | ```
284 | 
285 | ### Direct Execution
286 | 
287 | For advanced scenarios like custom deployments:
288 | 
289 | ```python
290 | from mcp.server.fastmcp import FastMCP
291 | 
292 | mcp = FastMCP("My App")
293 | 
294 | if __name__ == "__main__":
295 |     mcp.run()
296 | ```
297 | 
298 | Run it with:
299 | ```bash
300 | python server.py
301 | # or
302 | mcp run server.py
303 | ```
304 | 
305 | ## Examples
306 | 
307 | ### Echo Server
308 | 
309 | A simple server demonstrating resources, tools, and prompts:
310 | 
311 | ```python
312 | from mcp.server.fastmcp import FastMCP
313 | 
314 | mcp = FastMCP("Echo")
315 | 
316 | @mcp.resource("echo://{message}")
317 | def echo_resource(message: str) -> str:
318 |     """Echo a message as a resource"""
319 |     return f"Resource echo: {message}"
320 | 
321 | @mcp.tool()
322 | def echo_tool(message: str) -> str:
323 |     """Echo a message as a tool"""
324 |     return f"Tool echo: {message}"
325 | 
326 | @mcp.prompt()
327 | def echo_prompt(message: str) -> str:
328 |     """Create an echo prompt"""
329 |     return f"Please process this message: {message}"
330 | ```
331 | 
332 | ### SQLite Explorer
333 | 
334 | A more complex example showing database integration:
335 | 
336 | ```python
337 | from mcp.server.fastmcp import FastMCP
338 | import sqlite3
339 | 
340 | mcp = FastMCP("SQLite Explorer")
341 | 
342 | @mcp.resource("schema://main")
343 | def get_schema() -> str:
344 |     """Provide the database schema as a resource"""
345 |     conn = sqlite3.connect("database.db")
346 |     schema = conn.execute(
347 |         "SELECT sql FROM sqlite_master WHERE type='table'"
348 |     ).fetchall()
349 |     return "\n".join(sql[0] for sql in schema if sql[0])
350 | 
351 | @mcp.tool()
352 | def query_data(sql: str) -> str:
353 |     """Execute SQL queries safely"""
354 |     conn = sqlite3.connect("database.db")
355 |     try:
356 |         result = conn.execute(sql).fetchall()
357 |         return "\n".join(str(row) for row in result)
358 |     except Exception as e:
359 |         return f"Error: {str(e)}"
360 | ```
361 | 
362 | ## Advanced Usage
363 | 
364 | ### Low-Level Server
365 | 
366 | For more control, you can use the low-level server implementation directly. This gives you full access to the protocol and allows you to customize every aspect of your server, including lifecycle management through the lifespan API:
367 | 
368 | ```python
369 | from contextlib import asynccontextmanager
370 | from typing import AsyncIterator
371 | 
372 | @asynccontextmanager
373 | async def server_lifespan(server: Server) -> AsyncIterator[dict]:
374 |     """Manage server startup and shutdown lifecycle."""
375 |     try:
376 |         # Initialize resources on startup
377 |         await db.connect()
378 |         yield {"db": db}
379 |     finally:
380 |         # Clean up on shutdown
381 |         await db.disconnect()
382 | 
383 | # Pass lifespan to server
384 | server = Server("example-server", lifespan=server_lifespan)
385 | 
386 | # Access lifespan context in handlers
387 | @server.call_tool()
388 | async def query_db(name: str, arguments: dict) -> list:
389 |     ctx = server.request_context
390 |     db = ctx.lifespan_context["db"]
391 |     return await db.query(arguments["query"])
392 | ```
393 | 
394 | The lifespan API provides:
395 | - A way to initialize resources when the server starts and clean them up when it stops
396 | - Access to initialized resources through the request context in handlers
397 | - Type-safe context passing between lifespan and request handlers
398 | 
399 | ```python
400 | from mcp.server.lowlevel import Server, NotificationOptions
401 | from mcp.server.models import InitializationOptions
402 | import mcp.server.stdio
403 | import mcp.types as types
404 | 
405 | # Create a server instance
406 | server = Server("example-server")
407 | 
408 | @server.list_prompts()
409 | async def handle_list_prompts() -> list[types.Prompt]:
410 |     return [
411 |         types.Prompt(
412 |             name="example-prompt",
413 |             description="An example prompt template",
414 |             arguments=[
415 |                 types.PromptArgument(
416 |                     name="arg1",
417 |                     description="Example argument",
418 |                     required=True
419 |                 )
420 |             ]
421 |         )
422 |     ]
423 | 
424 | @server.get_prompt()
425 | async def handle_get_prompt(
426 |     name: str,
427 |     arguments: dict[str, str] | None
428 | ) -> types.GetPromptResult:
429 |     if name != "example-prompt":
430 |         raise ValueError(f"Unknown prompt: {name}")
431 | 
432 |     return types.GetPromptResult(
433 |         description="Example prompt",
434 |         messages=[
435 |             types.PromptMessage(
436 |                 role="user",
437 |                 content=types.TextContent(
438 |                     type="text",
439 |                     text="Example prompt text"
440 |                 )
441 |             )
442 |         ]
443 |     )
444 | 
445 | async def run():
446 |     async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
447 |         await server.run(
448 |             read_stream,
449 |             write_stream,
450 |             InitializationOptions(
451 |                 server_name="example",
452 |                 server_version="0.1.0",
453 |                 capabilities=server.get_capabilities(
454 |                     notification_options=NotificationOptions(),
455 |                     experimental_capabilities={},
456 |                 )
457 |             )
458 |         )
459 | 
460 | if __name__ == "__main__":
461 |     import asyncio
462 |     asyncio.run(run())
463 | ```
464 | 
465 | ### Writing MCP Clients
466 | 
467 | The SDK provides a high-level client interface for connecting to MCP servers:
468 | 
469 | ```python
470 | from mcp import ClientSession, StdioServerParameters
471 | from mcp.client.stdio import stdio_client
472 | 
473 | # Create server parameters for stdio connection
474 | server_params = StdioServerParameters(
475 |     command="python", # Executable
476 |     args=["example_server.py"], # Optional command line arguments
477 |     env=None # Optional environment variables
478 | )
479 | 
480 | # Optional: create a sampling callback
481 | async def handle_sampling_message(message: types.CreateMessageRequestParams) -> types.CreateMessageResult:
482 |     return types.CreateMessageResult(
483 |         role="assistant",
484 |         content=types.TextContent(
485 |             type="text",
486 |             text="Hello, world! from model",
487 |         ),
488 |         model="gpt-3.5-turbo",
489 |         stopReason="endTurn",
490 |     )
491 | 
492 | async def run():
493 |     async with stdio_client(server_params) as (read, write):
494 |         async with ClientSession(read, write, sampling_callback=handle_sampling_message) as session:
495 |             # Initialize the connection
496 |             await session.initialize()
497 | 
498 |             # List available prompts
499 |             prompts = await session.list_prompts()
500 | 
501 |             # Get a prompt
502 |             prompt = await session.get_prompt("example-prompt", arguments={"arg1": "value"})
503 | 
504 |             # List available resources
505 |             resources = await session.list_resources()
506 | 
507 |             # List available tools
508 |             tools = await session.list_tools()
509 | 
510 |             # Read a resource
511 |             content, mime_type = await session.read_resource("file://some/path")
512 | 
513 |             # Call a tool
514 |             result = await session.call_tool("tool-name", arguments={"arg1": "value"})
515 | 
516 | if __name__ == "__main__":
517 |     import asyncio
518 |     asyncio.run(run())
519 | ```
520 | 
521 | ### MCP Primitives
522 | 
523 | The MCP protocol defines three core primitives that servers can implement:
524 | 
525 | | Primitive | Control               | Description                                         | Example Use                  |
526 | |-----------|-----------------------|-----------------------------------------------------|------------------------------|
527 | | Prompts   | User-controlled       | Interactive templates invoked by user choice        | Slash commands, menu options |
528 | | Resources | Application-controlled| Contextual data managed by the client application   | File contents, API responses |
529 | | Tools     | Model-controlled      | Functions exposed to the LLM to take actions        | API calls, data updates      |
530 | 
531 | ### Server Capabilities
532 | 
533 | MCP servers declare capabilities during initialization:
534 | 
535 | | Capability  | Feature Flag                 | Description                        |
536 | |-------------|------------------------------|------------------------------------|
537 | | `prompts`   | `listChanged`                | Prompt template management         |
538 | | `resources` | `subscribe`<br/>`listChanged`| Resource exposure and updates      |
539 | | `tools`     | `listChanged`                | Tool discovery and execution       |
540 | | `logging`   | -                            | Server logging configuration       |
541 | | `completion`| -                            | Argument completion suggestions    |
542 | 
543 | ## Documentation
544 | 
545 | - [Model Context Protocol documentation](https://modelcontextprotocol.io)
546 | - [Model Context Protocol specification](https://spec.modelcontextprotocol.io)
547 | - [Officially supported servers](https://github.com/modelcontextprotocol/servers)
548 | 
549 | ## Contributing
550 | 
551 | We are passionate about supporting contributors of all levels of experience and would love to see you get involved in the project. See the [contributing guide](CONTRIBUTING.md) to get started.
552 | 
553 | ## License
554 | 
555 | This project is licensed under the MIT License - see the LICENSE file for details.
```
Page 1/2FirstPrevNextLast