vs-mcp-agent 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.
- vs_mcp_agent-0.1.0/PKG-INFO +956 -0
- vs_mcp_agent-0.1.0/README.md +925 -0
- vs_mcp_agent-0.1.0/pyproject.toml +55 -0
- vs_mcp_agent-0.1.0/setup.cfg +4 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/__init__.py +49 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/auth/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/auth/vs_mcp_auth.py +46 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/auth/vs_mcp_security.py +16 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/base/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/base/vs_base_prompt.py +14 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/base/vs_base_resource.py +14 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/base/vs_base_tool.py +14 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/config/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/config/vs_agent_mcp_config.py +21 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/decorator/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/decorator/prompt.py +11 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/decorator/resource.py +11 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/decorator/tool.py +14 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/decorator/vs_mcp_server_decorator.py +11 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/decorator/vs_mcp_server_registry.py +40 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/factory/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/factory/vs_mcp_server_factory.py +23 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/lifecycle/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/lifecycle/vs_mcp_lifecycle.py +14 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/registry/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/registry/vs_prompt_registry.py +28 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/registry/vs_resource_registry.py +29 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/registry/vs_tool_registry.py +38 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/schema/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/schema/vs_prompt_response.py +11 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/schema/vs_resource_response.py +12 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/schema/vs_tool_response.py +63 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/server/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/server/vs_fast_mcp_server.py +162 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/server/vs_mcp_server.py +34 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/tools/__init__.py +0 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/tools/vs_health_tool.py +33 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent/tools/vs_ping_tool.py +18 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent.egg-info/PKG-INFO +956 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent.egg-info/SOURCES.txt +41 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent.egg-info/dependency_links.txt +1 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent.egg-info/requires.txt +15 -0
- vs_mcp_agent-0.1.0/vs_mcp_agent.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,956 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vs-mcp-agent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP agent framework for Viveka Sutra — build FastMCP-powered agents with tools, resources, and prompts
|
|
5
|
+
Project-URL: Homepage, https://vivekasutra.com/
|
|
6
|
+
Project-URL: Source, https://github.com/vivekasutra/viveka-mula
|
|
7
|
+
Keywords: mcp,fastmcp,agent,tools,async,viveka,vs
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: Other/Proprietary 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 :: Python Modules
|
|
15
|
+
Classifier: Framework :: AsyncIO
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: pydantic>=2.0
|
|
20
|
+
Requires-Dist: vs-common>=0.1.3
|
|
21
|
+
Provides-Extra: fastmcp
|
|
22
|
+
Requires-Dist: fastmcp>=2.0; extra == "fastmcp"
|
|
23
|
+
Requires-Dist: uvicorn>=0.29; extra == "fastmcp"
|
|
24
|
+
Provides-Extra: security
|
|
25
|
+
Requires-Dist: vs-security; extra == "security"
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: build; extra == "dev"
|
|
28
|
+
Requires-Dist: twine; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
31
|
+
|
|
32
|
+
# vs-mcp-agent
|
|
33
|
+
|
|
34
|
+
MCP server framework for Viveka Sutra — build agents that expose tools, resources, and prompts over the Model Context Protocol, with pluggable server implementations, lifecycle hooks, and unified auth.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Overview
|
|
39
|
+
|
|
40
|
+
`vs-mcp-agent` provides everything needed to build an MCP server: base classes for tools, resources, and prompts; decorators that self-register them at import time; a pluggable server factory; and lifecycle hooks. `VsFastMcpServer` ships as the built-in implementation backed by FastMCP, and auto-registers as `"fastmcp"` when its module is imported.
|
|
41
|
+
|
|
42
|
+
The library is server-agnostic by design. `VsMcpServerFactory` maps string keys to `VsMcpServer` subclasses — swap or add implementations without changing application code.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## The Problem It Solves
|
|
47
|
+
|
|
48
|
+
Every MCP agent needs tools, auth, and a server. Without a shared framework, each agent re-implements the same wiring boilerplate.
|
|
49
|
+
|
|
50
|
+
### Without vs-mcp-agent
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from fastmcp import FastMCP
|
|
54
|
+
|
|
55
|
+
mcp = FastMCP(name="my-agent")
|
|
56
|
+
|
|
57
|
+
# manually wire each tool
|
|
58
|
+
@mcp.tool(name="search_docs")
|
|
59
|
+
async def search_docs(query: str) -> dict:
|
|
60
|
+
# auth? write it yourself
|
|
61
|
+
# error handling? write it yourself
|
|
62
|
+
results = await _do_search(query)
|
|
63
|
+
return {"results": results}
|
|
64
|
+
|
|
65
|
+
mcp.run(transport="streamable-http")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### With vs-mcp-agent
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from vs_mcp_agent.decorator.tool import tool
|
|
72
|
+
from vs_mcp_agent.schema.vs_tool_response import VsToolResponse
|
|
73
|
+
from vs_mcp_agent.auth.vs_mcp_security import VsMcpSecurity
|
|
74
|
+
|
|
75
|
+
@tool(name="search_docs", description="Search VS library documentation",
|
|
76
|
+
guards=[VsMcpSecurity(roles=["user"])])
|
|
77
|
+
async def search_docs(query: str) -> VsToolResponse:
|
|
78
|
+
return VsToolResponse(status="success", result=await _do_search(query))
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Tools self-register, auth is declarative, and the server wires everything at startup.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Installation
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install vs-mcp-agent
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
With FastMCP server support:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install vs-mcp-agent[fastmcp]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
With auth support:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install vs-mcp-agent[fastmcp,security]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Dependencies
|
|
106
|
+
|
|
107
|
+
| Library | Required | Purpose |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `pydantic` | Yes | Tool, resource, and prompt input/output schemas |
|
|
110
|
+
| `vs-common` | Yes | Config, logging |
|
|
111
|
+
| `fastmcp` | No — install with `[fastmcp]` extra | FastMCP server implementation |
|
|
112
|
+
| `uvicorn` | No — install with `[fastmcp]` extra | ASGI server for HTTP transports |
|
|
113
|
+
| `vs-security` | No — install with `[security]` extra | JWT auth for `VsMcpAuthMiddleware` and `VsMcpSecurity` |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
All MCP config keys live under the `[agent]` section of `config.ini`.
|
|
120
|
+
|
|
121
|
+
| Key | Default | Description |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `agent.name` | `vs-agent` | MCP server name |
|
|
124
|
+
| `agent.version` | `0.1.0` | MCP server version |
|
|
125
|
+
| `agent.description` | `""` | MCP server description |
|
|
126
|
+
| `agent.transport` | `streamable-http` | Transport: `stdio`, `sse`, `streamable-http` |
|
|
127
|
+
| `agent.host` | `0.0.0.0` | Host to bind (HTTP transports only) |
|
|
128
|
+
| `agent.port` | `8080` | Port to bind (HTTP transports only) |
|
|
129
|
+
| `agent.auth_enabled` | `false` | Enable JWT auth middleware (HTTP transports only) |
|
|
130
|
+
|
|
131
|
+
**`config.ini` example:**
|
|
132
|
+
|
|
133
|
+
```ini
|
|
134
|
+
[agent]
|
|
135
|
+
name = my-agent
|
|
136
|
+
version = 1.0.0
|
|
137
|
+
transport = streamable-http
|
|
138
|
+
host = 0.0.0.0
|
|
139
|
+
port = 8080
|
|
140
|
+
auth_enabled = true
|
|
141
|
+
|
|
142
|
+
[auth]
|
|
143
|
+
secret_key = your-secret-key
|
|
144
|
+
algorithm = HS256
|
|
145
|
+
|
|
146
|
+
[logging]
|
|
147
|
+
level = INFO
|
|
148
|
+
file_path = ./logs/agent.log
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Transport options:**
|
|
152
|
+
|
|
153
|
+
| Transport | Description |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `stdio` | Standard input/output — for local use by Claude Desktop and similar clients |
|
|
156
|
+
| `sse` | HTTP + Server-Sent Events |
|
|
157
|
+
| `streamable-http` | HTTP with streamable responses — recommended for network-accessible agents |
|
|
158
|
+
|
|
159
|
+
`host` and `port` are ignored for `stdio` transport.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Quick Start
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from vs_common.config.vs_ini_config import VsIniConfig
|
|
167
|
+
from vs_common.log.vs_log_manager import VsLogManager
|
|
168
|
+
from vs_common.schema.vs_log_config import VsLogConfig
|
|
169
|
+
from vs_mcp_agent.server.vs_fast_mcp_server import VsFastMcpServer # noqa — auto-registers "fastmcp"
|
|
170
|
+
from vs_mcp_agent.factory.vs_mcp_server_factory import VsMcpServerFactory
|
|
171
|
+
from vs_mcp_agent.decorator.vs_mcp_server_registry import mcp_server_registry
|
|
172
|
+
|
|
173
|
+
import my_agent.tools # noqa — registers @tool functions
|
|
174
|
+
import my_agent.resources # noqa — registers @resource classes
|
|
175
|
+
import my_agent.prompts # noqa — registers @prompt classes
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@mcp_server_registry(hooks="my_agent.lifecycle")
|
|
179
|
+
def main():
|
|
180
|
+
config = VsIniConfig("config.ini")
|
|
181
|
+
VsLogManager.init(VsLogConfig(level=config.get("logging.level", default="INFO")))
|
|
182
|
+
|
|
183
|
+
server = VsMcpServerFactory.get("fastmcp", config)
|
|
184
|
+
server.run()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
if __name__ == "__main__":
|
|
188
|
+
main()
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## How It All Fits Together
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
Application Startup
|
|
197
|
+
└── import VsFastMcpServer # auto-registers "fastmcp" into VsMcpServerFactory
|
|
198
|
+
└── import my_agent.tools # @tool decorators self-register into VsToolRegistry
|
|
199
|
+
└── import my_agent.resources # @resource decorators self-register into VsResourceRegistry
|
|
200
|
+
└── import my_agent.prompts # @prompt decorators self-register into VsPromptRegistry
|
|
201
|
+
|
|
202
|
+
@mcp_server_registry(hooks="my_agent.lifecycle")
|
|
203
|
+
└── imports my_agent.lifecycle # @mcp_startup / @mcp_shutdown self-register into hook lists
|
|
204
|
+
|
|
205
|
+
VsMcpServerFactory.get("fastmcp", config)
|
|
206
|
+
└── constructs VsAgentMcpConfig(config)
|
|
207
|
+
└── instantiates VsFastMcpServer(mcp_config)
|
|
208
|
+
|
|
209
|
+
server.run()
|
|
210
|
+
├── calls startup() → runs @mcp_startup hooks in order
|
|
211
|
+
├── wires VsToolRegistry → FastMCP tools
|
|
212
|
+
├── wires VsResourceRegistry → FastMCP resources
|
|
213
|
+
├── wires VsPromptRegistry → FastMCP prompts
|
|
214
|
+
├── wires built-in tools: ping, health
|
|
215
|
+
└── starts server on configured transport
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## VsMcpServer
|
|
221
|
+
|
|
222
|
+
Abstract base class for all MCP server implementations. Provides lifecycle hook execution and logging. All concrete servers must extend this.
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from vs_mcp_agent.server.vs_mcp_server import VsMcpServer
|
|
226
|
+
from vs_mcp_agent.config.vs_agent_mcp_config import VsAgentMcpConfig
|
|
227
|
+
from vs_mcp_agent.decorator.vs_mcp_server_decorator import mcp_server
|
|
228
|
+
from vs_mcp_agent.factory.vs_mcp_server_factory import VsMcpServerFactory
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@mcp_server("my-mcp")
|
|
232
|
+
class MyCustomMcpServer(VsMcpServer):
|
|
233
|
+
|
|
234
|
+
def __init__(self, config: VsAgentMcpConfig):
|
|
235
|
+
super().__init__(config)
|
|
236
|
+
|
|
237
|
+
def run(self) -> None:
|
|
238
|
+
... # start your MCP server here
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
VsMcpServerFactory.register("my-mcp", MyCustomMcpServer)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`startup()` and `shutdown()` on the base class iterate `@mcp_startup` and `@mcp_shutdown` hooks. Always call `super().startup()` and `super().shutdown()` to keep lifecycle hooks running.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## VsMcpServerFactory
|
|
249
|
+
|
|
250
|
+
Registry that maps string keys to `VsMcpServer` subclasses. Used to resolve and instantiate a server at startup without hardcoding the implementation.
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
from vs_mcp_agent.factory.vs_mcp_server_factory import VsMcpServerFactory
|
|
254
|
+
|
|
255
|
+
# register a custom implementation
|
|
256
|
+
VsMcpServerFactory.register("my-mcp", MyCustomMcpServer)
|
|
257
|
+
|
|
258
|
+
# get an instance — factory constructs VsAgentMcpConfig(config) internally
|
|
259
|
+
server = VsMcpServerFactory.get("my-mcp", config)
|
|
260
|
+
server.run()
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`VsFastMcpServer` registers itself as `"fastmcp"` automatically when its module is imported — no manual `register()` call needed.
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
from vs_mcp_agent.server.vs_fast_mcp_server import VsFastMcpServer # noqa — triggers auto-register
|
|
267
|
+
|
|
268
|
+
server = VsMcpServerFactory.get("fastmcp", config)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## @mcp_server
|
|
274
|
+
|
|
275
|
+
Decorator that marks a class as a named MCP server implementation. Validates that the class extends `VsMcpServer`.
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
from vs_mcp_agent.decorator.vs_mcp_server_decorator import mcp_server
|
|
279
|
+
|
|
280
|
+
@mcp_server("my-mcp")
|
|
281
|
+
class MyCustomMcpServer(VsMcpServer):
|
|
282
|
+
...
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Sets `cls._vs_mcp_server_key = key` on the class. Used by `mcp_server_registry` when scanning packages.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## mcp_server_registry
|
|
290
|
+
|
|
291
|
+
Scans packages for `@mcp_server`-decorated classes and `@mcp_startup`/`@mcp_shutdown` hooks, and auto-registers them. Works as a decorator on the `main()` function or as a plain call. All parameters are optional.
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
from vs_mcp_agent.decorator.vs_mcp_server_registry import mcp_server_registry
|
|
295
|
+
|
|
296
|
+
# as a decorator
|
|
297
|
+
@mcp_server_registry(server="my_pkg.server", hooks="my_pkg.lifecycle")
|
|
298
|
+
def main():
|
|
299
|
+
...
|
|
300
|
+
|
|
301
|
+
# as a plain call
|
|
302
|
+
mcp_server_registry(hooks="my_agent.lifecycle")
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
| Parameter | Description |
|
|
306
|
+
|---|---|
|
|
307
|
+
| `server` | Package path to scan for `@mcp_server`-decorated classes. Use for custom server implementations. Not needed for `"fastmcp"` — it auto-registers on import. |
|
|
308
|
+
| `hooks` | Package path to scan for `@mcp_startup` / `@mcp_shutdown` functions. Importing the module triggers self-registration. |
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Lifecycle Hooks
|
|
313
|
+
|
|
314
|
+
Use `@mcp_startup` and `@mcp_shutdown` to run code when the MCP server starts and stops — loading tool indexes, closing connections, etc.
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
from vs_mcp_agent.lifecycle.vs_mcp_lifecycle import mcp_startup, mcp_shutdown
|
|
318
|
+
|
|
319
|
+
@mcp_startup
|
|
320
|
+
async def load_tool_index():
|
|
321
|
+
await ToolIndex.load()
|
|
322
|
+
|
|
323
|
+
@mcp_shutdown
|
|
324
|
+
async def close_connections():
|
|
325
|
+
await ToolIndex.close()
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Hooks self-register into global lists at import time. They are executed in registration order. Both sync and async hooks are supported.
|
|
329
|
+
|
|
330
|
+
Register hook modules with `mcp_server_registry` so they are imported before the server starts:
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
@mcp_server_registry(hooks="my_agent.lifecycle")
|
|
334
|
+
def main():
|
|
335
|
+
...
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`VsMcpServer.startup()` iterates `_mcp_startup_hooks`. `VsMcpServer.shutdown()` iterates `_mcp_shutdown_hooks`.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Tools
|
|
343
|
+
|
|
344
|
+
Tools are actions the agent can perform. The MCP client (orchestrator or Claude) calls tools to delegate work.
|
|
345
|
+
|
|
346
|
+
### Function-style (stateless)
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
from vs_mcp_agent.decorator.tool import tool
|
|
350
|
+
from vs_mcp_agent.schema.vs_tool_response import VsToolResponse
|
|
351
|
+
|
|
352
|
+
@tool(name="search_docs", description="Search VS library documentation")
|
|
353
|
+
async def search_docs(query: str) -> VsToolResponse:
|
|
354
|
+
results = await _do_search(query)
|
|
355
|
+
return VsToolResponse(status="success", result=results, summary="Found results")
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Class-style (stateful, with dependency injection)
|
|
359
|
+
|
|
360
|
+
Use when the tool needs a client, config, or any injected dependency.
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
from pydantic import BaseModel
|
|
364
|
+
from vs_mcp_agent.base.vs_base_tool import VsBaseTool
|
|
365
|
+
from vs_mcp_agent.decorator.tool import tool
|
|
366
|
+
from vs_mcp_agent.schema.vs_tool_response import VsToolResponse
|
|
367
|
+
|
|
368
|
+
@tool(name="search_docs", description="Search VS library documentation")
|
|
369
|
+
class SearchDocsTool(VsBaseTool):
|
|
370
|
+
|
|
371
|
+
class Input(BaseModel):
|
|
372
|
+
query: str
|
|
373
|
+
|
|
374
|
+
def __init__(self):
|
|
375
|
+
self._client = MySearchClient()
|
|
376
|
+
|
|
377
|
+
async def execute(self, input: Input) -> VsToolResponse:
|
|
378
|
+
results = await self._client.search(input.query)
|
|
379
|
+
return VsToolResponse(status="success", result=results, summary="Found results")
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Both styles self-register in `VsToolRegistry` at import time. `VsFastMcpServer` reads `VsToolRegistry` at `run()` and wires everything into FastMCP automatically.
|
|
383
|
+
|
|
384
|
+
### @tool parameters
|
|
385
|
+
|
|
386
|
+
| Parameter | Type | Required | Default | Description |
|
|
387
|
+
|---|---|---|---|---|
|
|
388
|
+
| `name` | `str` | Yes | — | Tool name exposed to the MCP client |
|
|
389
|
+
| `description` | `str` | Yes | — | Shown in MCP tool list |
|
|
390
|
+
| `roles` | `List[str]` | No | `[]` | Allowed roles (informational — enforce via guards) |
|
|
391
|
+
| `guards` | `List[Callable]` | No | `[]` | Async callables run before the tool executes |
|
|
392
|
+
|
|
393
|
+
### VsToolResponse
|
|
394
|
+
|
|
395
|
+
All tool functions must return `VsToolResponse`.
|
|
396
|
+
|
|
397
|
+
| Field | Type | Description |
|
|
398
|
+
|---|---|---|
|
|
399
|
+
| `status` | `"success"` \| `"error"` \| `"clarification"` \| `"not_supported"` | Outcome signal for the orchestrator |
|
|
400
|
+
| `result` | `Optional[Any]` | Return payload on success |
|
|
401
|
+
| `summary` | `str` | Human-readable summary of what happened |
|
|
402
|
+
| `confidence` | `Optional[float]` | Confidence score (0–1) |
|
|
403
|
+
| `artifacts_extracted` | `List[ArtifactEntry]` | Structured data extracted during execution |
|
|
404
|
+
| `user_preferences_extracted` | `List[UserPreferenceEntry]` | User preferences inferred during execution |
|
|
405
|
+
| `active_highlights` | `List[ActiveHighlight]` | Key highlights from the result |
|
|
406
|
+
| `tokens_consumed` | `int` | Token count if the tool called an LLM |
|
|
407
|
+
| `error` | `Optional[ErrorDetail]` | Error detail when `status="error"` |
|
|
408
|
+
| `clarification_needed` | `Optional[ClarificationDetail]` | Clarification questions when `status="clarification"` |
|
|
409
|
+
| `not_supported` | `Optional[NotSupportedDetail]` | Reason when `status="not_supported"` |
|
|
410
|
+
|
|
411
|
+
**Status values:**
|
|
412
|
+
|
|
413
|
+
| Status | When to use |
|
|
414
|
+
|---|---|
|
|
415
|
+
| `success` | Tool completed successfully |
|
|
416
|
+
| `error` | Tool failed — populate `error` with `ErrorDetail` |
|
|
417
|
+
| `clarification` | Need more input from the user — populate `clarification_needed` |
|
|
418
|
+
| `not_supported` | Request is out of scope — populate `not_supported` with a reason |
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Resources
|
|
423
|
+
|
|
424
|
+
Resources expose read-only data — documents, schemas, configs — that the MCP client can fetch by URI.
|
|
425
|
+
|
|
426
|
+
```python
|
|
427
|
+
from pydantic import BaseModel
|
|
428
|
+
from vs_mcp_agent.base.vs_base_resource import VsBaseResource
|
|
429
|
+
from vs_mcp_agent.decorator.resource import resource
|
|
430
|
+
from vs_mcp_agent.schema.vs_resource_response import VsResourceResponse
|
|
431
|
+
|
|
432
|
+
@resource(uri="docs://api-schema", description="Returns the API schema document")
|
|
433
|
+
class ApiSchemaResource(VsBaseResource):
|
|
434
|
+
|
|
435
|
+
class Input(BaseModel):
|
|
436
|
+
version: str = "latest"
|
|
437
|
+
|
|
438
|
+
async def fetch(self, input: Input) -> VsResourceResponse:
|
|
439
|
+
schema = await _load_schema(input.version)
|
|
440
|
+
return VsResourceResponse(status="success", result=schema)
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
`@resource` parameters:
|
|
444
|
+
|
|
445
|
+
| Parameter | Type | Required | Description |
|
|
446
|
+
|---|---|---|---|
|
|
447
|
+
| `uri` | `str` | Yes | URI the MCP client uses to fetch this resource |
|
|
448
|
+
| `description` | `str` | Yes | Shown in MCP resource list |
|
|
449
|
+
|
|
450
|
+
`VsResourceResponse` fields:
|
|
451
|
+
|
|
452
|
+
| Field | Type | Description |
|
|
453
|
+
|---|---|---|
|
|
454
|
+
| `status` | `"success"` \| `"error"` \| `"not_supported"` | Outcome |
|
|
455
|
+
| `result` | `Optional[Any]` | Resource data on success |
|
|
456
|
+
| `error` | `Optional[ErrorDetail]` | Error detail when `status="error"` |
|
|
457
|
+
| `not_supported` | `Optional[NotSupportedDetail]` | Reason when `status="not_supported"` |
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Prompts
|
|
462
|
+
|
|
463
|
+
Prompts expose reusable prompt templates that the MCP client can request by name.
|
|
464
|
+
|
|
465
|
+
```python
|
|
466
|
+
from pydantic import BaseModel
|
|
467
|
+
from vs_mcp_agent.base.vs_base_prompt import VsBasePrompt
|
|
468
|
+
from vs_mcp_agent.decorator.prompt import prompt
|
|
469
|
+
from vs_mcp_agent.schema.vs_prompt_response import VsPromptResponse
|
|
470
|
+
|
|
471
|
+
@prompt(name="summarise_doc", description="Prompt to summarise a document")
|
|
472
|
+
class SummariseDocPrompt(VsBasePrompt):
|
|
473
|
+
|
|
474
|
+
class Input(BaseModel):
|
|
475
|
+
topic: str
|
|
476
|
+
length: str = "short"
|
|
477
|
+
|
|
478
|
+
async def generate(self, input: Input) -> VsPromptResponse:
|
|
479
|
+
text = f"Summarise the following in {input.length} form. Topic: {input.topic}"
|
|
480
|
+
return VsPromptResponse(status="success", prompt=text)
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
`@prompt` parameters:
|
|
484
|
+
|
|
485
|
+
| Parameter | Type | Required | Description |
|
|
486
|
+
|---|---|---|---|
|
|
487
|
+
| `name` | `str` | Yes | Prompt name exposed to the MCP client |
|
|
488
|
+
| `description` | `str` | Yes | Shown in MCP prompt list |
|
|
489
|
+
|
|
490
|
+
`VsPromptResponse` fields:
|
|
491
|
+
|
|
492
|
+
| Field | Type | Description |
|
|
493
|
+
|---|---|---|
|
|
494
|
+
| `status` | `"success"` \| `"error"` | Outcome |
|
|
495
|
+
| `prompt` | `Optional[str]` | The rendered prompt string on success |
|
|
496
|
+
| `error` | `Optional[ErrorDetail]` | Error detail when `status="error"` |
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Authorization
|
|
501
|
+
|
|
502
|
+
### VsMcpSecurity
|
|
503
|
+
|
|
504
|
+
Guard for MCP-only tools. Reads the auth context set by `VsMcpAuthMiddleware` after JWT verification.
|
|
505
|
+
|
|
506
|
+
```python
|
|
507
|
+
from vs_mcp_agent.auth.vs_mcp_security import VsMcpSecurity
|
|
508
|
+
|
|
509
|
+
@tool(name="admin_tool", description="Admin only", guards=[VsMcpSecurity(roles=["admin"])])
|
|
510
|
+
async def admin_tool(query: str) -> VsToolResponse:
|
|
511
|
+
...
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
**No roles (auth only):**
|
|
515
|
+
|
|
516
|
+
```python
|
|
517
|
+
guards=[VsMcpSecurity()] # rejects unauthenticated callers, any role allowed
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Multiple roles (any match):**
|
|
521
|
+
|
|
522
|
+
```python
|
|
523
|
+
guards=[VsMcpSecurity(roles=["admin", "editor"])] # passes if caller has admin OR editor
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Enable auth middleware by setting `agent.auth_enabled = true` in `config.ini`. `VsFastMcpServer` wires `VsMcpAuthMiddleware` automatically when auth is enabled.
|
|
527
|
+
|
|
528
|
+
### Custom guards
|
|
529
|
+
|
|
530
|
+
Any async callable that raises `PermissionError` on failure works as a guard:
|
|
531
|
+
|
|
532
|
+
```python
|
|
533
|
+
async def require_verified_user():
|
|
534
|
+
ctx = get_auth_context()
|
|
535
|
+
if not ctx or not ctx.is_verified:
|
|
536
|
+
raise PermissionError("Verified account required")
|
|
537
|
+
|
|
538
|
+
@tool(name="sensitive_tool", description="Verified users only",
|
|
539
|
+
guards=[VsMcpSecurity(roles=["user"]), require_verified_user])
|
|
540
|
+
async def sensitive_tool(query: str) -> VsToolResponse:
|
|
541
|
+
...
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
Multiple guards run in order — all must pass before the tool executes.
|
|
545
|
+
|
|
546
|
+
### VsMcpAuthMiddleware
|
|
547
|
+
|
|
548
|
+
Starlette middleware that validates JWT tokens on every incoming request (except `/.well-known/` paths). Sets the auth context so `VsMcpSecurity` and `get_auth_context()` work inside tools.
|
|
549
|
+
|
|
550
|
+
`VsFastMcpServer` registers `VsMcpAuthMiddleware` automatically when `agent.auth_enabled = true`. You do not need to wire it manually.
|
|
551
|
+
|
|
552
|
+
```python
|
|
553
|
+
from vs_mcp_agent.auth.vs_mcp_auth import get_auth_context
|
|
554
|
+
|
|
555
|
+
@tool(name="whoami", description="Return caller identity")
|
|
556
|
+
async def whoami() -> VsToolResponse:
|
|
557
|
+
ctx = get_auth_context()
|
|
558
|
+
return VsToolResponse(status="success", result={"username": ctx.username})
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
## Built-in Tools
|
|
564
|
+
|
|
565
|
+
Every `VsFastMcpServer` instance registers two tools automatically:
|
|
566
|
+
|
|
567
|
+
| Tool | Description |
|
|
568
|
+
|---|---|
|
|
569
|
+
| `ping` | Liveness check. Returns `{"pong": true, "timestamp": "..."}`. |
|
|
570
|
+
| `health` | Returns agent name, version, transport, and uptime in seconds. |
|
|
571
|
+
|
|
572
|
+
These are always available to MCP clients without any configuration.
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Extending vs-mcp-agent
|
|
577
|
+
|
|
578
|
+
### Adding a custom MCP server implementation
|
|
579
|
+
|
|
580
|
+
Implement `VsMcpServer`, decorate with `@mcp_server`, and register:
|
|
581
|
+
|
|
582
|
+
```python
|
|
583
|
+
from vs_mcp_agent.server.vs_mcp_server import VsMcpServer
|
|
584
|
+
from vs_mcp_agent.config.vs_agent_mcp_config import VsAgentMcpConfig
|
|
585
|
+
from vs_mcp_agent.decorator.vs_mcp_server_decorator import mcp_server
|
|
586
|
+
from vs_mcp_agent.factory.vs_mcp_server_factory import VsMcpServerFactory
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
@mcp_server("my-mcp")
|
|
590
|
+
class MyMcpServer(VsMcpServer):
|
|
591
|
+
|
|
592
|
+
def __init__(self, config: VsAgentMcpConfig):
|
|
593
|
+
super().__init__(config)
|
|
594
|
+
|
|
595
|
+
def run(self) -> None:
|
|
596
|
+
self._wire_tools()
|
|
597
|
+
# start your server
|
|
598
|
+
|
|
599
|
+
def _wire_tools(self) -> None:
|
|
600
|
+
from vs_mcp_agent.registry.vs_tool_registry import VsToolRegistry
|
|
601
|
+
for name, entry in VsToolRegistry.get_all().items():
|
|
602
|
+
... # register into your server
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
VsMcpServerFactory.register("my-mcp", MyMcpServer)
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
Then use it by key:
|
|
609
|
+
|
|
610
|
+
```python
|
|
611
|
+
server = VsMcpServerFactory.get("my-mcp", config)
|
|
612
|
+
server.run()
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
Or scan the package automatically:
|
|
616
|
+
|
|
617
|
+
```python
|
|
618
|
+
@mcp_server_registry(server="my_pkg.server")
|
|
619
|
+
def main():
|
|
620
|
+
server = VsMcpServerFactory.get("my-mcp", config)
|
|
621
|
+
server.run()
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## Error Handling
|
|
627
|
+
|
|
628
|
+
Exceptions raised inside tool, resource, or prompt functions are caught by `VsFastMcpServer` and returned as MCP error results — the server does not crash.
|
|
629
|
+
|
|
630
|
+
For expected failures, use `VsToolResponse` with `status="error"` rather than raising:
|
|
631
|
+
|
|
632
|
+
```python
|
|
633
|
+
from vs_mcp_agent.schema.vs_tool_response import VsToolResponse, ErrorDetail
|
|
634
|
+
|
|
635
|
+
@tool(name="get_doc", description="Fetch a document by ID")
|
|
636
|
+
async def get_doc(doc_id: str) -> VsToolResponse:
|
|
637
|
+
doc = await repo.find(doc_id)
|
|
638
|
+
if doc is None:
|
|
639
|
+
return VsToolResponse(
|
|
640
|
+
status="error",
|
|
641
|
+
error=ErrorDetail(code="NOT_FOUND", message=f"Document '{doc_id}' not found", retryable=False),
|
|
642
|
+
)
|
|
643
|
+
return VsToolResponse(status="success", result=doc)
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## Class Reference
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
### VsMcpServer
|
|
653
|
+
|
|
654
|
+
Abstract base class for all MCP server implementations.
|
|
655
|
+
|
|
656
|
+
**Constructor:**
|
|
657
|
+
|
|
658
|
+
| Parameter | Type | Description |
|
|
659
|
+
|---|---|---|
|
|
660
|
+
| `config` | `VsAgentMcpConfig` | Parsed MCP configuration |
|
|
661
|
+
|
|
662
|
+
**Methods:**
|
|
663
|
+
|
|
664
|
+
| Method | Signature | Description |
|
|
665
|
+
|---|---|---|
|
|
666
|
+
| `startup` | `async startup() -> None` | Runs `@mcp_startup` hooks in order. Call `super().startup()` to keep hook execution. |
|
|
667
|
+
| `shutdown` | `async shutdown() -> None` | Runs `@mcp_shutdown` hooks in order. Call `super().shutdown()` to keep hook execution. |
|
|
668
|
+
| `run` | `run() -> None` | Abstract. Start the MCP server. |
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
### VsMcpServerFactory
|
|
673
|
+
|
|
674
|
+
Registry mapping string keys to `VsMcpServer` subclasses. Thread-safe class-level dict.
|
|
675
|
+
|
|
676
|
+
**Methods:**
|
|
677
|
+
|
|
678
|
+
| Method | Signature | Description |
|
|
679
|
+
|---|---|---|
|
|
680
|
+
| `register` | `register(key: str, server_class: Type[VsMcpServer]) -> None` | Register a server class. Raises `TypeError` if not a `VsMcpServer` subclass. |
|
|
681
|
+
| `get` | `get(key: str, config: VsBaseConfig) -> VsMcpServer` | Construct and return a server instance. Raises `KeyError` if key not registered. Wraps `config` in `VsAgentMcpConfig` internally. |
|
|
682
|
+
|
|
683
|
+
**Notes:**
|
|
684
|
+
- `VsFastMcpServer` auto-registers as `"fastmcp"` when its module is imported.
|
|
685
|
+
- Import `VsFastMcpServer` before calling `VsMcpServerFactory.get("fastmcp", config)`.
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
### VsAgentMcpConfig
|
|
690
|
+
|
|
691
|
+
Parsed MCP configuration. Constructed from `VsBaseConfig` by reading the `[agent]` section.
|
|
692
|
+
|
|
693
|
+
**Fields:**
|
|
694
|
+
|
|
695
|
+
| Field | Type | Default | Description |
|
|
696
|
+
|---|---|---|---|
|
|
697
|
+
| `name` | `str` | `vs-agent` | MCP server name |
|
|
698
|
+
| `version` | `str` | `0.1.0` | MCP server version |
|
|
699
|
+
| `description` | `str` | `""` | MCP server description |
|
|
700
|
+
| `transport` | `str` | `streamable-http` | Transport type |
|
|
701
|
+
| `host` | `str` | `0.0.0.0` | Bind host |
|
|
702
|
+
| `port` | `int` | `8080` | Bind port |
|
|
703
|
+
| `auth_enabled` | `bool` | `False` | Enable JWT auth middleware |
|
|
704
|
+
|
|
705
|
+
**Notes:**
|
|
706
|
+
- Raises `ValueError` on construction if `transport` is not one of `stdio`, `sse`, `streamable-http`.
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
### VsFastMcpServer
|
|
711
|
+
|
|
712
|
+
Built-in `VsMcpServer` implementation backed by FastMCP. Auto-registers as `"fastmcp"` on import.
|
|
713
|
+
|
|
714
|
+
**Behaviour at `run()`:**
|
|
715
|
+
1. Reads `VsToolRegistry`, `VsResourceRegistry`, `VsPromptRegistry` and wires all entries into FastMCP.
|
|
716
|
+
2. Applies guard proxies to guarded tools.
|
|
717
|
+
3. Registers built-in `ping` and `health` tools.
|
|
718
|
+
4. If `auth_enabled`, wires `VsMcpAuthMiddleware`.
|
|
719
|
+
5. For `stdio` transport: calls `mcp.run(transport="stdio")`.
|
|
720
|
+
6. For HTTP transports: wraps the ASGI lifespan to call `startup()`/`shutdown()`, then starts uvicorn.
|
|
721
|
+
|
|
722
|
+
**Notes:**
|
|
723
|
+
- Requires `fastmcp` and `uvicorn` — install with `pip install vs-mcp-agent[fastmcp]`.
|
|
724
|
+
- `mcp` property exposes the underlying `FastMCP` instance for advanced configuration.
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
### `@mcp_server`
|
|
729
|
+
|
|
730
|
+
Decorator. Marks a class as a named MCP server implementation. Validates that the class extends `VsMcpServer`.
|
|
731
|
+
|
|
732
|
+
**Parameters:**
|
|
733
|
+
|
|
734
|
+
| Parameter | Type | Required | Description |
|
|
735
|
+
|---|---|---|---|
|
|
736
|
+
| `key` | `str` | Yes | Registry key used with `VsMcpServerFactory.get(key, config)` |
|
|
737
|
+
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
### `mcp_server_registry`
|
|
741
|
+
|
|
742
|
+
Scans packages for `@mcp_server` classes and `@mcp_startup`/`@mcp_shutdown` functions and registers them. Works as a function decorator or a plain call.
|
|
743
|
+
|
|
744
|
+
**Parameters:**
|
|
745
|
+
|
|
746
|
+
| Parameter | Type | Description |
|
|
747
|
+
|---|---|---|
|
|
748
|
+
| `server` | `Optional[str]` | Package path to scan for `@mcp_server` classes |
|
|
749
|
+
| `hooks` | `Optional[str]` | Package path to scan for lifecycle hook functions |
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
### `@mcp_startup` / `@mcp_shutdown`
|
|
754
|
+
|
|
755
|
+
Decorators. Register a function into the global `_mcp_startup_hooks` or `_mcp_shutdown_hooks` list at import time. Both sync and async functions are supported.
|
|
756
|
+
|
|
757
|
+
```python
|
|
758
|
+
from vs_mcp_agent.lifecycle.vs_mcp_lifecycle import mcp_startup, mcp_shutdown
|
|
759
|
+
|
|
760
|
+
@mcp_startup
|
|
761
|
+
async def on_start():
|
|
762
|
+
...
|
|
763
|
+
|
|
764
|
+
@mcp_shutdown
|
|
765
|
+
def on_stop():
|
|
766
|
+
...
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
Hooks are called in registration order by `VsMcpServer.startup()` and `VsMcpServer.shutdown()`.
|
|
770
|
+
|
|
771
|
+
---
|
|
772
|
+
|
|
773
|
+
### `@tool`
|
|
774
|
+
|
|
775
|
+
Decorator. Registers a function or class in `VsToolRegistry` at import time.
|
|
776
|
+
|
|
777
|
+
**Parameters:**
|
|
778
|
+
|
|
779
|
+
| Parameter | Type | Required | Default | Description |
|
|
780
|
+
|---|---|---|---|---|
|
|
781
|
+
| `name` | `str` | Yes | — | Tool name exposed to the MCP client |
|
|
782
|
+
| `description` | `str` | Yes | — | Shown in MCP tool list |
|
|
783
|
+
| `roles` | `List[str]` | No | `[]` | Allowed roles (informational) |
|
|
784
|
+
| `guards` | `List[Callable]` | No | `[]` | Async callables run before the tool executes |
|
|
785
|
+
|
|
786
|
+
**Notes:**
|
|
787
|
+
- Each `name` must be unique. Duplicate names raise `ValueError`.
|
|
788
|
+
- Class-style: target must extend `VsBaseTool` and implement `execute(input) -> VsToolResponse`.
|
|
789
|
+
- Function-style: target must be an async callable.
|
|
790
|
+
|
|
791
|
+
---
|
|
792
|
+
|
|
793
|
+
### VsBaseTool
|
|
794
|
+
|
|
795
|
+
Abstract base class for class-style tools.
|
|
796
|
+
|
|
797
|
+
**Inner class:**
|
|
798
|
+
|
|
799
|
+
| Name | Description |
|
|
800
|
+
|---|---|
|
|
801
|
+
| `Input` | Pydantic `BaseModel` subclass. Define fields here for typed input. |
|
|
802
|
+
|
|
803
|
+
**Methods:**
|
|
804
|
+
|
|
805
|
+
| Method | Signature | Description |
|
|
806
|
+
|---|---|---|
|
|
807
|
+
| `execute` | `async execute(input: Input) -> VsToolResponse` | Abstract. Implement tool logic here. |
|
|
808
|
+
|
|
809
|
+
---
|
|
810
|
+
|
|
811
|
+
### `@resource`
|
|
812
|
+
|
|
813
|
+
Decorator. Registers a class in `VsResourceRegistry` at import time.
|
|
814
|
+
|
|
815
|
+
**Parameters:**
|
|
816
|
+
|
|
817
|
+
| Parameter | Type | Required | Description |
|
|
818
|
+
|---|---|---|---|
|
|
819
|
+
| `uri` | `str` | Yes | URI the MCP client uses to fetch this resource |
|
|
820
|
+
| `description` | `str` | Yes | Shown in MCP resource list |
|
|
821
|
+
|
|
822
|
+
**Notes:**
|
|
823
|
+
- Target must extend `VsBaseResource` and implement `fetch(input) -> VsResourceResponse`.
|
|
824
|
+
- Each `uri` must be unique. Duplicate URIs raise `ValueError`.
|
|
825
|
+
|
|
826
|
+
---
|
|
827
|
+
|
|
828
|
+
### VsBaseResource
|
|
829
|
+
|
|
830
|
+
Abstract base class for resources.
|
|
831
|
+
|
|
832
|
+
**Inner class:**
|
|
833
|
+
|
|
834
|
+
| Name | Description |
|
|
835
|
+
|---|---|
|
|
836
|
+
| `Input` | Pydantic `BaseModel` subclass. Define fields for fetch parameters. |
|
|
837
|
+
|
|
838
|
+
**Methods:**
|
|
839
|
+
|
|
840
|
+
| Method | Signature | Description |
|
|
841
|
+
|---|---|---|
|
|
842
|
+
| `fetch` | `async fetch(input: Input) -> VsResourceResponse` | Abstract. Return the resource data. |
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
### `@prompt`
|
|
847
|
+
|
|
848
|
+
Decorator. Registers a class in `VsPromptRegistry` at import time.
|
|
849
|
+
|
|
850
|
+
**Parameters:**
|
|
851
|
+
|
|
852
|
+
| Parameter | Type | Required | Description |
|
|
853
|
+
|---|---|---|---|
|
|
854
|
+
| `name` | `str` | Yes | Prompt name exposed to the MCP client |
|
|
855
|
+
| `description` | `str` | Yes | Shown in MCP prompt list |
|
|
856
|
+
|
|
857
|
+
**Notes:**
|
|
858
|
+
- Target must extend `VsBasePrompt` and implement `generate(input) -> VsPromptResponse`.
|
|
859
|
+
- Each `name` must be unique. Duplicate names raise `ValueError`.
|
|
860
|
+
|
|
861
|
+
---
|
|
862
|
+
|
|
863
|
+
### VsBasePrompt
|
|
864
|
+
|
|
865
|
+
Abstract base class for prompts.
|
|
866
|
+
|
|
867
|
+
**Inner class:**
|
|
868
|
+
|
|
869
|
+
| Name | Description |
|
|
870
|
+
|---|---|
|
|
871
|
+
| `Input` | Pydantic `BaseModel` subclass. Define fields for prompt parameters. |
|
|
872
|
+
|
|
873
|
+
**Methods:**
|
|
874
|
+
|
|
875
|
+
| Method | Signature | Description |
|
|
876
|
+
|---|---|---|
|
|
877
|
+
| `generate` | `async generate(input: Input) -> VsPromptResponse` | Abstract. Return the rendered prompt. |
|
|
878
|
+
|
|
879
|
+
---
|
|
880
|
+
|
|
881
|
+
### VsMcpSecurity
|
|
882
|
+
|
|
883
|
+
Guard for MCP-only tools. Reads the auth context set by `VsMcpAuthMiddleware`.
|
|
884
|
+
|
|
885
|
+
**Constructor:**
|
|
886
|
+
|
|
887
|
+
| Parameter | Type | Default | Description |
|
|
888
|
+
|---|---|---|---|
|
|
889
|
+
| `roles` | `Optional[List[str]]` | `[]` | Required roles. Empty = any authenticated caller. |
|
|
890
|
+
|
|
891
|
+
**Behaviour:**
|
|
892
|
+
|
|
893
|
+
| Condition | Result |
|
|
894
|
+
|---|---|
|
|
895
|
+
| No auth context | Raises `PermissionError("Unauthenticated request")` |
|
|
896
|
+
| Auth context present, no roles required | Passes |
|
|
897
|
+
| Auth context present, caller has required role | Passes |
|
|
898
|
+
| Auth context present, caller lacks required role | Raises `PermissionError` |
|
|
899
|
+
|
|
900
|
+
---
|
|
901
|
+
|
|
902
|
+
### VsMcpAuthMiddleware
|
|
903
|
+
|
|
904
|
+
Starlette middleware. Validates `Bearer` JWT tokens on every request and sets the auth context.
|
|
905
|
+
|
|
906
|
+
**Constructor:**
|
|
907
|
+
|
|
908
|
+
| Parameter | Type | Description |
|
|
909
|
+
|---|---|---|
|
|
910
|
+
| `app` | ASGI app | The wrapped application |
|
|
911
|
+
| `jwt_provider` | `VsJWTProvider` | JWT verifier from `vs-security` |
|
|
912
|
+
|
|
913
|
+
**Notes:**
|
|
914
|
+
- `VsFastMcpServer` registers this automatically when `agent.auth_enabled = true`.
|
|
915
|
+
- Paths starting with `/.well-known/` are whitelisted and bypass auth.
|
|
916
|
+
- Sets both the MCP-local context (`_auth_context_var`) and the shared VS context (`set_auth_context`) so guards work uniformly across protocols.
|
|
917
|
+
|
|
918
|
+
---
|
|
919
|
+
|
|
920
|
+
### VsToolRegistry
|
|
921
|
+
|
|
922
|
+
Class-level registry of all `@tool`-registered functions and classes. Thread-safe.
|
|
923
|
+
|
|
924
|
+
**Methods:**
|
|
925
|
+
|
|
926
|
+
| Method | Signature | Description |
|
|
927
|
+
|---|---|---|
|
|
928
|
+
| `register_class` | `register_class(name, description, tool_class, roles, guards) -> None` | Register a class-style tool. Raises `TypeError` if not a `VsBaseTool` subclass. |
|
|
929
|
+
| `register_fn` | `register_fn(name, description, fn, roles, guards) -> None` | Register a function-style tool. |
|
|
930
|
+
| `get_all` | `get_all() -> Dict[str, _ToolEntry]` | Returns a snapshot of all registered tools. |
|
|
931
|
+
|
|
932
|
+
---
|
|
933
|
+
|
|
934
|
+
### VsResourceRegistry
|
|
935
|
+
|
|
936
|
+
Class-level registry of all `@resource`-registered classes. Thread-safe.
|
|
937
|
+
|
|
938
|
+
**Methods:**
|
|
939
|
+
|
|
940
|
+
| Method | Signature | Description |
|
|
941
|
+
|---|---|---|
|
|
942
|
+
| `register` | `register(uri, description, resource_class) -> None` | Register a resource class. Raises `TypeError` if not a `VsBaseResource` subclass. |
|
|
943
|
+
| `get_all` | `get_all() -> Dict[str, _ResourceEntry]` | Returns a snapshot of all registered resources. |
|
|
944
|
+
|
|
945
|
+
---
|
|
946
|
+
|
|
947
|
+
### VsPromptRegistry
|
|
948
|
+
|
|
949
|
+
Class-level registry of all `@prompt`-registered classes. Thread-safe.
|
|
950
|
+
|
|
951
|
+
**Methods:**
|
|
952
|
+
|
|
953
|
+
| Method | Signature | Description |
|
|
954
|
+
|---|---|---|
|
|
955
|
+
| `register` | `register(name, description, prompt_class) -> None` | Register a prompt class. Raises `TypeError` if not a `VsBasePrompt` subclass. |
|
|
956
|
+
| `get_all` | `get_all() -> Dict[str, _PromptEntry]` | Returns a snapshot of all registered prompts. |
|