mcp-craft 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rishav
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-craft
3
+ Version: 0.1.0
4
+ Summary: A lightweight, production-ready developer framework for building Model Context Protocol (MCP) servers with a FastAPI-like experience.
5
+ Author: Rishav Sharma
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
15
+ Requires-Python: >=3.11
16
+ Requires-Dist: mcp>=1.0.0
17
+ Requires-Dist: pydantic>=2.0.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest-asyncio>=0.20.0; extra == 'dev'
20
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
21
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
22
+ Provides-Extra: django
23
+ Requires-Dist: django>=4.0.0; extra == 'django'
24
+ Provides-Extra: fastapi
25
+ Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
26
+ Requires-Dist: starlette>=0.27.0; extra == 'fastapi'
27
+ Requires-Dist: uvicorn>=0.20.0; extra == 'fastapi'
28
+ Provides-Extra: flask
29
+ Requires-Dist: flask>=2.0.0; extra == 'flask'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # mcp-craft
33
+
34
+ A modern, lightweight, production-ready framework for building **Model Context Protocol (MCP)** servers in Python with a developer experience inspired by **FastAPI**.
35
+
36
+ `mcp-craft` wraps the official MCP Python SDK to offer tool discovery, dependency injection, middleware chains, authentication, schema validation, and framework integrations (FastAPI, Flask, Django) without reimplementing the protocol.
37
+
38
+ ---
39
+
40
+ ## Features
41
+
42
+ - **Declarative Tool Registration**: Decorators (`@app.tool`) on functions and classes with automatic Pydantic-based schema generation and validation.
43
+ - **FastAPI-like Dependency Injection**: A lightweight, standalone DI engine supporting sync and async dependencies (`Depends`).
44
+ - **Flexible Middleware Pipeline**: Starlette-like async middleware with support for custom interceptors and built-in middlewares (`LoggingMiddleware`, `AuthenticationMiddleware`, `MetricsMiddleware`, `RateLimitMiddleware`).
45
+ - **Structured Authentication Helpers**: Easily secure your MCP server with API Keys, Bearer tokens, or custom callback functions.
46
+ - **Rich Context Object**: Expose execution context (`context.user`, `context.request`, `context.logger`, `context.metadata`, `context.storage`) to all tools automatically.
47
+ - **Error Handling**: Standard exception mapping that sanitizes tracebacks and converts Python errors to protocol-compliant MCP errors.
48
+ - **Extensible Plugin System**: Install reusable plugins (`app.install(plugin)`) to hook into startup, shutdown, middlewares, or register dependencies and tools.
49
+ - **Integrations**: Standalone runtime (via stdio) and first-class FastAPI, Flask, and Django integrations.
50
+ - **Testing Utilities**: A dedicated `TestMCPClient` and mocking helpers for rapid tool testing without network layers.
51
+
52
+ ---
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install mcp-craft
58
+ ```
59
+
60
+ Or install with integrations:
61
+
62
+ ```bash
63
+ # For FastAPI / Starlette support
64
+ pip install "mcp-craft[fastapi]"
65
+
66
+ # For development / testing
67
+ pip install "mcp-craft[dev]"
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Quick Start (Standalone / Stdio)
73
+
74
+ Creating a server is as simple as defining your application and registering your tools.
75
+
76
+ ```python
77
+ # server.py
78
+ import asyncio
79
+ from mcp_craft import MCPApplication
80
+
81
+ app = MCPApplication(
82
+ name="Math Server",
83
+ version="1.0.0",
84
+ description="Exposes basic mathematical tools"
85
+ )
86
+
87
+ @app.tool()
88
+ async def add(a: int, b: int) -> int:
89
+ """Add two numbers together."""
90
+ return a + b
91
+
92
+ if __name__ == "__main__":
93
+ app.run()
94
+ ```
95
+
96
+ Run it locally with:
97
+ ```bash
98
+ python server.py
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Dependency Injection
104
+
105
+ Inject shared components or services using `Depends`:
106
+
107
+ ```python
108
+ from mcp_craft import MCPApplication, Depends
109
+
110
+ app = MCPApplication(name="DI Server")
111
+
112
+ def get_db():
113
+ # Setup database connection
114
+ return {"conn": "active"}
115
+
116
+ async def get_current_user(context):
117
+ # Retrieve user from the execution context
118
+ return context.user
119
+
120
+ @app.tool()
121
+ async def fetch_profile(
122
+ user = Depends(get_current_user),
123
+ db = Depends(get_db)
124
+ ):
125
+ """Retrieve profile for the authenticated user."""
126
+ return {"username": user.get("name"), "status": "active", "db": db}
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Middleware & Authentication
132
+
133
+ Add global logic like logging, metrics, rate-limiting, and authentication:
134
+
135
+ ```python
136
+ from mcp_craft import MCPApplication, APIKeyAuthentication
137
+ from mcp_craft.middleware import LoggingMiddleware, AuthenticationMiddleware, RateLimitMiddleware
138
+
139
+ app = MCPApplication(name="Secure Server")
140
+
141
+ # Configure authentication helper
142
+ auth_helper = APIKeyAuthentication(key="secret-token-123", header_name="x-api-key")
143
+
144
+ # Register middleware in order of execution
145
+ app.add_middleware(LoggingMiddleware)
146
+ app.add_middleware(AuthenticationMiddleware, auth_handler=auth_helper)
147
+ app.add_middleware(RateLimitMiddleware, limit=30, period=60.0) # 30 calls per minute
148
+ ```
149
+
150
+ ---
151
+
152
+ ## FastAPI Integration
153
+
154
+ Mount your MCP server onto a FastAPI app using the Server-Sent Events (SSE) protocol:
155
+
156
+ ```python
157
+ from fastapi import FastAPI
158
+ from mcp_craft import MCPApplication
159
+ from mcp_craft.integrations.fastapi import mount_mcp
160
+ import uvicorn
161
+
162
+ mcp_app = MCPApplication(name="Mounted Server")
163
+
164
+ @mcp_app.tool()
165
+ def hello(name: str) -> str:
166
+ """Say hello."""
167
+ return f"Hello, {name}!"
168
+
169
+ app = FastAPI()
170
+ # This registers:
171
+ # GET /mcp/sse - SSE connection route
172
+ # POST /mcp/messages - Client message gateway
173
+ mount_mcp(app, mcp_app, path="/mcp")
174
+
175
+ if __name__ == "__main__":
176
+ uvicorn.run(app, host="127.0.0.1", port=8000)
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Testing Tools
182
+
183
+ Unit test your tools cleanly without running servers or network loops:
184
+
185
+ ```python
186
+ import pytest
187
+ from mcp_craft import MCPApplication
188
+ from mcp_craft.testing import TestMCPClient
189
+
190
+ app = MCPApplication(name="Test App")
191
+
192
+ @app.tool()
193
+ def square(x: int) -> int:
194
+ return x * x
195
+
196
+ @pytest.mark.asyncio
197
+ async def test_square():
198
+ client = TestMCPClient(app)
199
+ result = await client.call_tool("square", {"x": 5})
200
+ assert result.content[0].text == "25"
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Development & Publishing
206
+
207
+ To package and build:
208
+ ```bash
209
+ # Install packaging tool
210
+ pip install build hatch
211
+
212
+ # Build source distribution and wheel
213
+ python3 -m build
214
+ ```
215
+
216
+ ---
217
+
218
+ ## License
219
+
220
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -0,0 +1,189 @@
1
+ # mcp-craft
2
+
3
+ A modern, lightweight, production-ready framework for building **Model Context Protocol (MCP)** servers in Python with a developer experience inspired by **FastAPI**.
4
+
5
+ `mcp-craft` wraps the official MCP Python SDK to offer tool discovery, dependency injection, middleware chains, authentication, schema validation, and framework integrations (FastAPI, Flask, Django) without reimplementing the protocol.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - **Declarative Tool Registration**: Decorators (`@app.tool`) on functions and classes with automatic Pydantic-based schema generation and validation.
12
+ - **FastAPI-like Dependency Injection**: A lightweight, standalone DI engine supporting sync and async dependencies (`Depends`).
13
+ - **Flexible Middleware Pipeline**: Starlette-like async middleware with support for custom interceptors and built-in middlewares (`LoggingMiddleware`, `AuthenticationMiddleware`, `MetricsMiddleware`, `RateLimitMiddleware`).
14
+ - **Structured Authentication Helpers**: Easily secure your MCP server with API Keys, Bearer tokens, or custom callback functions.
15
+ - **Rich Context Object**: Expose execution context (`context.user`, `context.request`, `context.logger`, `context.metadata`, `context.storage`) to all tools automatically.
16
+ - **Error Handling**: Standard exception mapping that sanitizes tracebacks and converts Python errors to protocol-compliant MCP errors.
17
+ - **Extensible Plugin System**: Install reusable plugins (`app.install(plugin)`) to hook into startup, shutdown, middlewares, or register dependencies and tools.
18
+ - **Integrations**: Standalone runtime (via stdio) and first-class FastAPI, Flask, and Django integrations.
19
+ - **Testing Utilities**: A dedicated `TestMCPClient` and mocking helpers for rapid tool testing without network layers.
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install mcp-craft
27
+ ```
28
+
29
+ Or install with integrations:
30
+
31
+ ```bash
32
+ # For FastAPI / Starlette support
33
+ pip install "mcp-craft[fastapi]"
34
+
35
+ # For development / testing
36
+ pip install "mcp-craft[dev]"
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Quick Start (Standalone / Stdio)
42
+
43
+ Creating a server is as simple as defining your application and registering your tools.
44
+
45
+ ```python
46
+ # server.py
47
+ import asyncio
48
+ from mcp_craft import MCPApplication
49
+
50
+ app = MCPApplication(
51
+ name="Math Server",
52
+ version="1.0.0",
53
+ description="Exposes basic mathematical tools"
54
+ )
55
+
56
+ @app.tool()
57
+ async def add(a: int, b: int) -> int:
58
+ """Add two numbers together."""
59
+ return a + b
60
+
61
+ if __name__ == "__main__":
62
+ app.run()
63
+ ```
64
+
65
+ Run it locally with:
66
+ ```bash
67
+ python server.py
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Dependency Injection
73
+
74
+ Inject shared components or services using `Depends`:
75
+
76
+ ```python
77
+ from mcp_craft import MCPApplication, Depends
78
+
79
+ app = MCPApplication(name="DI Server")
80
+
81
+ def get_db():
82
+ # Setup database connection
83
+ return {"conn": "active"}
84
+
85
+ async def get_current_user(context):
86
+ # Retrieve user from the execution context
87
+ return context.user
88
+
89
+ @app.tool()
90
+ async def fetch_profile(
91
+ user = Depends(get_current_user),
92
+ db = Depends(get_db)
93
+ ):
94
+ """Retrieve profile for the authenticated user."""
95
+ return {"username": user.get("name"), "status": "active", "db": db}
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Middleware & Authentication
101
+
102
+ Add global logic like logging, metrics, rate-limiting, and authentication:
103
+
104
+ ```python
105
+ from mcp_craft import MCPApplication, APIKeyAuthentication
106
+ from mcp_craft.middleware import LoggingMiddleware, AuthenticationMiddleware, RateLimitMiddleware
107
+
108
+ app = MCPApplication(name="Secure Server")
109
+
110
+ # Configure authentication helper
111
+ auth_helper = APIKeyAuthentication(key="secret-token-123", header_name="x-api-key")
112
+
113
+ # Register middleware in order of execution
114
+ app.add_middleware(LoggingMiddleware)
115
+ app.add_middleware(AuthenticationMiddleware, auth_handler=auth_helper)
116
+ app.add_middleware(RateLimitMiddleware, limit=30, period=60.0) # 30 calls per minute
117
+ ```
118
+
119
+ ---
120
+
121
+ ## FastAPI Integration
122
+
123
+ Mount your MCP server onto a FastAPI app using the Server-Sent Events (SSE) protocol:
124
+
125
+ ```python
126
+ from fastapi import FastAPI
127
+ from mcp_craft import MCPApplication
128
+ from mcp_craft.integrations.fastapi import mount_mcp
129
+ import uvicorn
130
+
131
+ mcp_app = MCPApplication(name="Mounted Server")
132
+
133
+ @mcp_app.tool()
134
+ def hello(name: str) -> str:
135
+ """Say hello."""
136
+ return f"Hello, {name}!"
137
+
138
+ app = FastAPI()
139
+ # This registers:
140
+ # GET /mcp/sse - SSE connection route
141
+ # POST /mcp/messages - Client message gateway
142
+ mount_mcp(app, mcp_app, path="/mcp")
143
+
144
+ if __name__ == "__main__":
145
+ uvicorn.run(app, host="127.0.0.1", port=8000)
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Testing Tools
151
+
152
+ Unit test your tools cleanly without running servers or network loops:
153
+
154
+ ```python
155
+ import pytest
156
+ from mcp_craft import MCPApplication
157
+ from mcp_craft.testing import TestMCPClient
158
+
159
+ app = MCPApplication(name="Test App")
160
+
161
+ @app.tool()
162
+ def square(x: int) -> int:
163
+ return x * x
164
+
165
+ @pytest.mark.asyncio
166
+ async def test_square():
167
+ client = TestMCPClient(app)
168
+ result = await client.call_tool("square", {"x": 5})
169
+ assert result.content[0].text == "25"
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Development & Publishing
175
+
176
+ To package and build:
177
+ ```bash
178
+ # Install packaging tool
179
+ pip install build hatch
180
+
181
+ # Build source distribution and wheel
182
+ python3 -m build
183
+ ```
184
+
185
+ ---
186
+
187
+ ## License
188
+
189
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -0,0 +1,63 @@
1
+ from typing import Dict, Any
2
+ from mcp_craft import MCPApplication, Depends, Context, APIKeyAuthentication
3
+ from mcp_craft.middleware import LoggingMiddleware, AuthenticationMiddleware, RateLimitMiddleware
4
+
5
+ # 1. Initialize the Application
6
+ app = MCPApplication(
7
+ name="MCP Demo Server",
8
+ version="1.0.0",
9
+ description="A server demonstrating the capabilities of the mcp_craft framework"
10
+ )
11
+
12
+ # 2. Configure Authentication and Middleware
13
+ auth_helper = APIKeyAuthentication(key="secret-token-123", header_name="x-api-key")
14
+
15
+ app.add_middleware(LoggingMiddleware)
16
+ # app.add_middleware(AuthenticationMiddleware, auth_handler=auth_helper)
17
+ app.add_middleware(RateLimitMiddleware, limit=10, period=60.0) # Limit 10 calls per minute
18
+
19
+ # 3. Setup Lifecycle Hooks
20
+ @app.on_startup
21
+ def on_startup():
22
+ print("[Lifecycle] MCP server starting up...")
23
+
24
+ @app.on_shutdown
25
+ async def on_shutdown():
26
+ print("[Lifecycle] MCP server shutting down...")
27
+
28
+ # 4. Dependency Provider
29
+ def get_system_status():
30
+ return {"status": "operational", "load": "low"}
31
+
32
+ async def get_user_identity(context: Context):
33
+ # Retrieve the user object populated by AuthenticationMiddleware
34
+ return context.user
35
+
36
+ # 5. Register Tools
37
+ @app.tool()
38
+ async def get_status(
39
+ status: Dict[str, Any] = Depends(get_system_status),
40
+ user: Dict[str, Any] = Depends(get_user_identity)
41
+ ) -> Dict[str, Any]:
42
+ """
43
+ Get the current system status.
44
+ This tool uses FastAPI-style dependency injection and inherits execution context.
45
+ """
46
+ return {
47
+ "status": status,
48
+ "caller": user.get("identity") if user else "anonymous"
49
+ }
50
+
51
+ @app.tool()
52
+ def hello(name: str) -> str:
53
+ """
54
+ Say hello to the caller.
55
+ """
56
+ return f"Hello, {name}!"
57
+
58
+ # 6. Run the application
59
+ if __name__ == "__main__":
60
+ # To run this example locally:
61
+ # 1. Use an MCP client (such as Claude Desktop) pointing to this file.
62
+ # 2. Provide the 'x-api-key: secret-token-123' metadata during connection or request headers.
63
+ app.run()