marona-sdk 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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Blessing Nyuwani
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,191 @@
1
+ Metadata-Version: 2.4
2
+ Name: marona-sdk
3
+ Version: 0.1.0
4
+ Summary: Official developer SDK for building Marona-compatible apps, tool servers, skills, and workflows.
5
+ Author: Blessing Nyuwani
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://www.marona.ai
8
+ Project-URL: Repository, https://github.com/BlessingNyuwani/agentnet-mcp-sdk
9
+ Project-URL: Documentation, https://hub.marona.ai
10
+ Keywords: marona,sdk,mcp,agents,ai,tools,workflows
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: fastapi<1.0,>=0.115
23
+ Requires-Dist: httpx<1.0,>=0.28
24
+ Requires-Dist: mcp<2.0,>=1.28
25
+ Requires-Dist: pydantic<3.0,>=2.10
26
+ Requires-Dist: uvicorn[standard]<1.0,>=0.34
27
+ Provides-Extra: dev
28
+ Requires-Dist: build<2.0,>=1.2; extra == "dev"
29
+ Requires-Dist: pytest<9.0,>=8.3; extra == "dev"
30
+ Requires-Dist: twine<7.0,>=6.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # Marona SDK
34
+
35
+ Marona SDK is the official developer SDK for building Marona-compatible apps,
36
+ MCP servers, skills, tool servers, and workflows.
37
+
38
+ It is not the runtime client SDK. Use `marona` when you want an application to
39
+ call a Marona-compatible runtime. Use `marona-sdk` when you are building
40
+ developer-side integrations that need the Marona tool contract.
41
+
42
+ The SDK helps projects produce the Marona standard automatically:
43
+
44
+ - `GET /health`
45
+ - `GET /manifest`
46
+ - `GET /hub-registration`
47
+ - `POST /mcp/` using the official MCP Python SDK `FastMCP`
48
+ - Tool outputs with `status`, `success`, `message`, `content`,
49
+ `content_type`, `presentation_hint`, and `context`
50
+
51
+ ## Install For Local Development
52
+
53
+ ```bash
54
+ python3.11 -m venv .venv
55
+ .venv/bin/pip install -e ".[dev]"
56
+ ```
57
+
58
+ ## Install In A Developer Integration Repo
59
+
60
+ Developer integration repos can depend on this SDK like any other pip package:
61
+
62
+ ```bash
63
+ pip install marona-sdk
64
+ ```
65
+
66
+ In `requirements.txt`:
67
+
68
+ ```text
69
+ marona-sdk
70
+ ```
71
+
72
+ It installs from the package index and imports as `marona_sdk`.
73
+
74
+ ## Minimal Server
75
+
76
+ ```python
77
+ from marona_sdk import AgentApp, success
78
+
79
+ agent_app = AgentApp(
80
+ name="Hello Tool Server",
81
+ server_name="hello-tools",
82
+ slug="hello",
83
+ description="Example Marona-compatible tool server.",
84
+ category="Tools",
85
+ )
86
+
87
+ @agent_app.tool(description="Say hello to a user.")
88
+ def say_hello(name: str) -> dict:
89
+ return success(f"Hello {name}.", greeting=f"Hello {name}.")
90
+
91
+ app = agent_app.create_fastapi_app()
92
+ ```
93
+
94
+ ## Standard Tool Results
95
+
96
+ All Marona-compatible tools should return the SDK result shape. The required
97
+ fields are:
98
+
99
+ - `status`: machine-readable result status.
100
+ - `success`: boolean result success flag.
101
+ - `message`: short user-facing status line.
102
+ - `content`: primary user-facing text/content for the agent to use.
103
+ - `content_type`: provider-neutral semantic type, for example `text`, `document`, `message`, `list`, `media`, or `search_results`.
104
+ - `presentation_hint`: provider-neutral usage hint, for example `display_as_provided`.
105
+ - `context`: short provider-neutral guidance for interpreting the result.
106
+
107
+ Provider-specific payloads must live under generic standard fields:
108
+
109
+ - `data`: one structured provider-specific object.
110
+ - `items`: a list of structured provider-specific objects.
111
+ - `count`: item count when `items` is used.
112
+ - `artifacts`: generic artifact descriptors.
113
+ - `job`: generic async job metadata.
114
+
115
+ If a tool declares its own `output_schema`, the SDK merges these standard fields
116
+ into that schema before exposing `/manifest` and `/hub-registration`.
117
+
118
+ ## Standard Tool Inputs For User Files
119
+
120
+ Tools that consume uploaded files should declare the SDK-standard
121
+ `attachments` input property. The Edge runtime injects the current conversation
122
+ files into that array automatically, so the tool does not need custom runtime
123
+ logic or a provider-specific input name.
124
+
125
+ ```python
126
+ from marona_sdk import standard_attachments_property
127
+
128
+ input_schema = {
129
+ "type": "object",
130
+ "properties": {
131
+ "question": {"type": "string"},
132
+ "attachments": standard_attachments_property(),
133
+ },
134
+ "required": [],
135
+ "additionalProperties": False,
136
+ }
137
+ ```
138
+
139
+ Each attachment can include `artifact_id`, `filename`, `mime_type`, `kind`,
140
+ `url`, `file_url`, `content_base64`, `content`, and `metadata`.
141
+
142
+ Example:
143
+
144
+ ```python
145
+ return success(
146
+ "Loaded email.",
147
+ content=email_text,
148
+ content_type="email_message",
149
+ presentation_hint="display_as_provided",
150
+ context="Return content as provided unless the user asks for a summary.",
151
+ )
152
+ ```
153
+
154
+ Run it:
155
+
156
+ ```bash
157
+ uvicorn examples.hello_server:app --host 127.0.0.1 --port 62900
158
+ ```
159
+
160
+ Then inspect:
161
+
162
+ ```text
163
+ http://127.0.0.1:62900/health
164
+ http://127.0.0.1:62900/hub-registration
165
+ http://127.0.0.1:62900/mcp/
166
+ ```
167
+
168
+ ## Developer Hub Helper
169
+
170
+ `DeveloperHubClient` is only for developer workflow commands such as create,
171
+ sync, and submit. Apps, devices, bots, and user interfaces should use the
172
+ separate `marona` runtime client package.
173
+
174
+ ## Release
175
+
176
+ Build and verify the package before uploading:
177
+
178
+ ```bash
179
+ rm -rf dist build marona_sdk.egg-info
180
+ python3.11 -m build
181
+ python3.11 -m twine check dist/*
182
+ ```
183
+
184
+ Upload with a PyPI token:
185
+
186
+ ```bash
187
+ TWINE_USERNAME=__token__ TWINE_PASSWORD='PYPI_TOKEN' python3.11 -m twine upload dist/*
188
+ ```
189
+
190
+ For the first upload of a new package, PyPI requires an account-scoped upload
191
+ token. After the project exists, use a project-scoped token for normal releases.
@@ -0,0 +1,159 @@
1
+ # Marona SDK
2
+
3
+ Marona SDK is the official developer SDK for building Marona-compatible apps,
4
+ MCP servers, skills, tool servers, and workflows.
5
+
6
+ It is not the runtime client SDK. Use `marona` when you want an application to
7
+ call a Marona-compatible runtime. Use `marona-sdk` when you are building
8
+ developer-side integrations that need the Marona tool contract.
9
+
10
+ The SDK helps projects produce the Marona standard automatically:
11
+
12
+ - `GET /health`
13
+ - `GET /manifest`
14
+ - `GET /hub-registration`
15
+ - `POST /mcp/` using the official MCP Python SDK `FastMCP`
16
+ - Tool outputs with `status`, `success`, `message`, `content`,
17
+ `content_type`, `presentation_hint`, and `context`
18
+
19
+ ## Install For Local Development
20
+
21
+ ```bash
22
+ python3.11 -m venv .venv
23
+ .venv/bin/pip install -e ".[dev]"
24
+ ```
25
+
26
+ ## Install In A Developer Integration Repo
27
+
28
+ Developer integration repos can depend on this SDK like any other pip package:
29
+
30
+ ```bash
31
+ pip install marona-sdk
32
+ ```
33
+
34
+ In `requirements.txt`:
35
+
36
+ ```text
37
+ marona-sdk
38
+ ```
39
+
40
+ It installs from the package index and imports as `marona_sdk`.
41
+
42
+ ## Minimal Server
43
+
44
+ ```python
45
+ from marona_sdk import AgentApp, success
46
+
47
+ agent_app = AgentApp(
48
+ name="Hello Tool Server",
49
+ server_name="hello-tools",
50
+ slug="hello",
51
+ description="Example Marona-compatible tool server.",
52
+ category="Tools",
53
+ )
54
+
55
+ @agent_app.tool(description="Say hello to a user.")
56
+ def say_hello(name: str) -> dict:
57
+ return success(f"Hello {name}.", greeting=f"Hello {name}.")
58
+
59
+ app = agent_app.create_fastapi_app()
60
+ ```
61
+
62
+ ## Standard Tool Results
63
+
64
+ All Marona-compatible tools should return the SDK result shape. The required
65
+ fields are:
66
+
67
+ - `status`: machine-readable result status.
68
+ - `success`: boolean result success flag.
69
+ - `message`: short user-facing status line.
70
+ - `content`: primary user-facing text/content for the agent to use.
71
+ - `content_type`: provider-neutral semantic type, for example `text`, `document`, `message`, `list`, `media`, or `search_results`.
72
+ - `presentation_hint`: provider-neutral usage hint, for example `display_as_provided`.
73
+ - `context`: short provider-neutral guidance for interpreting the result.
74
+
75
+ Provider-specific payloads must live under generic standard fields:
76
+
77
+ - `data`: one structured provider-specific object.
78
+ - `items`: a list of structured provider-specific objects.
79
+ - `count`: item count when `items` is used.
80
+ - `artifacts`: generic artifact descriptors.
81
+ - `job`: generic async job metadata.
82
+
83
+ If a tool declares its own `output_schema`, the SDK merges these standard fields
84
+ into that schema before exposing `/manifest` and `/hub-registration`.
85
+
86
+ ## Standard Tool Inputs For User Files
87
+
88
+ Tools that consume uploaded files should declare the SDK-standard
89
+ `attachments` input property. The Edge runtime injects the current conversation
90
+ files into that array automatically, so the tool does not need custom runtime
91
+ logic or a provider-specific input name.
92
+
93
+ ```python
94
+ from marona_sdk import standard_attachments_property
95
+
96
+ input_schema = {
97
+ "type": "object",
98
+ "properties": {
99
+ "question": {"type": "string"},
100
+ "attachments": standard_attachments_property(),
101
+ },
102
+ "required": [],
103
+ "additionalProperties": False,
104
+ }
105
+ ```
106
+
107
+ Each attachment can include `artifact_id`, `filename`, `mime_type`, `kind`,
108
+ `url`, `file_url`, `content_base64`, `content`, and `metadata`.
109
+
110
+ Example:
111
+
112
+ ```python
113
+ return success(
114
+ "Loaded email.",
115
+ content=email_text,
116
+ content_type="email_message",
117
+ presentation_hint="display_as_provided",
118
+ context="Return content as provided unless the user asks for a summary.",
119
+ )
120
+ ```
121
+
122
+ Run it:
123
+
124
+ ```bash
125
+ uvicorn examples.hello_server:app --host 127.0.0.1 --port 62900
126
+ ```
127
+
128
+ Then inspect:
129
+
130
+ ```text
131
+ http://127.0.0.1:62900/health
132
+ http://127.0.0.1:62900/hub-registration
133
+ http://127.0.0.1:62900/mcp/
134
+ ```
135
+
136
+ ## Developer Hub Helper
137
+
138
+ `DeveloperHubClient` is only for developer workflow commands such as create,
139
+ sync, and submit. Apps, devices, bots, and user interfaces should use the
140
+ separate `marona` runtime client package.
141
+
142
+ ## Release
143
+
144
+ Build and verify the package before uploading:
145
+
146
+ ```bash
147
+ rm -rf dist build marona_sdk.egg-info
148
+ python3.11 -m build
149
+ python3.11 -m twine check dist/*
150
+ ```
151
+
152
+ Upload with a PyPI token:
153
+
154
+ ```bash
155
+ TWINE_USERNAME=__token__ TWINE_PASSWORD='PYPI_TOKEN' python3.11 -m twine upload dist/*
156
+ ```
157
+
158
+ For the first upload of a new package, PyPI requires an account-scoped upload
159
+ token. After the project exists, use a project-scoped token for normal releases.
@@ -0,0 +1,25 @@
1
+ from marona_sdk.hub import DeveloperHubClient
2
+ from marona_sdk.models import (
3
+ PermissionSpec,
4
+ ToolSpec,
5
+ standard_attachment_schema,
6
+ standard_attachments_property,
7
+ standard_output_schema,
8
+ )
9
+ from marona_sdk.results import failure, success
10
+ from marona_sdk.server import AgentApp
11
+
12
+ __version__ = "0.1.0"
13
+
14
+ __all__ = [
15
+ "AgentApp",
16
+ "DeveloperHubClient",
17
+ "PermissionSpec",
18
+ "ToolSpec",
19
+ "standard_attachment_schema",
20
+ "standard_attachments_property",
21
+ "standard_output_schema",
22
+ "failure",
23
+ "success",
24
+ "__version__",
25
+ ]
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+
6
+ def main() -> None:
7
+ parser = argparse.ArgumentParser(
8
+ prog="marona-sdk",
9
+ description="Marona SDK developer helpers.",
10
+ )
11
+ parser.add_argument(
12
+ "command",
13
+ choices=["version"],
14
+ help="Command to run. More commands will be added as the SDK grows.",
15
+ )
16
+ args = parser.parse_args()
17
+ if args.command == "version":
18
+ print("marona-sdk 0.1.0")
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+
8
+ class DeveloperHubClient:
9
+ """Small helper for developer workflows. Runtime edge sync belongs in Edge SDK."""
10
+
11
+ def __init__(self, *, hub_url: str, token: str, timeout_seconds: float = 30) -> None:
12
+ self.hub_url = hub_url.rstrip("/")
13
+ self.token = token
14
+ self.timeout_seconds = timeout_seconds
15
+
16
+ async def create_agent_app(self, registration_payload: dict[str, Any]) -> dict[str, Any]:
17
+ return await self._request("POST", "/portal/developer/agent-apps", json=registration_payload)
18
+
19
+ async def sync_agent_app(self, agent_app_id: str) -> dict[str, Any]:
20
+ return await self._request("POST", f"/portal/developer/agent-apps/{agent_app_id}/sync-mcp-server")
21
+
22
+ async def submit_agent_app(self, agent_app_id: str, comments: str | None = None) -> dict[str, Any]:
23
+ return await self._request(
24
+ "POST",
25
+ f"/portal/developer/agent-apps/{agent_app_id}/submit",
26
+ json={"comments": comments} if comments else {},
27
+ )
28
+
29
+ async def _request(
30
+ self,
31
+ method: str,
32
+ path: str,
33
+ *,
34
+ json: dict[str, Any] | None = None,
35
+ ) -> dict[str, Any]:
36
+ async with httpx.AsyncClient(
37
+ base_url=self.hub_url,
38
+ timeout=self.timeout_seconds,
39
+ headers={"Authorization": f"Bearer {self.token}"},
40
+ ) as client:
41
+ response = await client.request(method, path, json=json)
42
+ response.raise_for_status()
43
+ return response.json()
@@ -0,0 +1,202 @@
1
+ from __future__ import annotations
2
+
3
+ from copy import deepcopy
4
+ from typing import Any, Literal
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+
9
+ STANDARD_OUTPUT_SCHEMA: dict[str, Any] = {
10
+ "type": "object",
11
+ "properties": {
12
+ "status": {"type": "string"},
13
+ "success": {"type": "boolean"},
14
+ "message": {"type": "string"},
15
+ "content": {
16
+ "type": "string",
17
+ "description": "Primary user-facing content the agent can display or reason over.",
18
+ },
19
+ "content_type": {
20
+ "type": "string",
21
+ "description": "Provider-neutral semantic type for content, such as text, document, message, list, media, or search_results.",
22
+ },
23
+ "presentation_hint": {
24
+ "type": "string",
25
+ "description": "Provider-neutral presentation hint, such as display_as_provided or summarize_if_requested.",
26
+ },
27
+ "context": {
28
+ "type": "string",
29
+ "description": "Provider-neutral guidance for interpreting this result.",
30
+ },
31
+ "data": {
32
+ "type": "object",
33
+ "description": "Provider-specific structured object payload. Keep provider fields inside this object.",
34
+ "additionalProperties": True,
35
+ },
36
+ "items": {
37
+ "type": "array",
38
+ "description": "Provider-specific structured list payload. Use for search/list results from any MCP.",
39
+ "items": {"type": "object", "additionalProperties": True},
40
+ },
41
+ "count": {
42
+ "type": "integer",
43
+ "description": "Number of items represented in items when applicable.",
44
+ },
45
+ "artifacts": {
46
+ "type": "array",
47
+ "description": "Generic artifacts produced by the tool.",
48
+ "items": {
49
+ "type": "object",
50
+ "properties": {
51
+ "type": {"type": "string"},
52
+ "label": {"type": "string"},
53
+ "mime_type": {"type": "string"},
54
+ "url": {"type": "string"},
55
+ "base64": {"type": "string"},
56
+ "text": {"type": "string"},
57
+ "external_id": {"type": "string"},
58
+ "filename": {"type": "string"},
59
+ "metadata": {"type": "object", "additionalProperties": True},
60
+ },
61
+ "additionalProperties": True,
62
+ },
63
+ },
64
+ "job": {
65
+ "type": "object",
66
+ "description": "Generic async job payload with provider-specific details.",
67
+ "additionalProperties": True,
68
+ },
69
+ },
70
+ "required": ["status", "success", "message", "content", "content_type", "presentation_hint", "context"],
71
+ "additionalProperties": True,
72
+ }
73
+
74
+
75
+ STANDARD_ATTACHMENT_SCHEMA: dict[str, Any] = {
76
+ "type": "object",
77
+ "description": "Provider-neutral user file/artifact passed by the runtime.",
78
+ "properties": {
79
+ "artifact_id": {
80
+ "type": "string",
81
+ "description": "Runtime artifact id for this attachment, when available.",
82
+ },
83
+ "filename": {
84
+ "type": "string",
85
+ "description": "Original or display filename.",
86
+ },
87
+ "mime_type": {
88
+ "type": "string",
89
+ "description": "MIME type, for example application/pdf or image/png.",
90
+ },
91
+ "kind": {
92
+ "type": "string",
93
+ "description": "Runtime artifact kind, for example document, image, audio, video, or file.",
94
+ },
95
+ "url": {
96
+ "type": "string",
97
+ "description": "Runtime-accessible URL for the attachment, when available.",
98
+ },
99
+ "file_url": {
100
+ "type": "string",
101
+ "description": "Runtime-accessible file URL for tools that consume file_url.",
102
+ },
103
+ "content_base64": {
104
+ "type": "string",
105
+ "description": "Base64-encoded attachment bytes when the runtime sends inline bytes.",
106
+ },
107
+ "content": {
108
+ "type": "string",
109
+ "description": "Inline text content when the attachment is text-like.",
110
+ },
111
+ "metadata": {
112
+ "type": "object",
113
+ "description": "Runtime or provider-specific attachment metadata.",
114
+ "additionalProperties": True,
115
+ },
116
+ },
117
+ "additionalProperties": True,
118
+ }
119
+
120
+ STANDARD_ATTACHMENTS_PROPERTY: dict[str, Any] = {
121
+ "type": "array",
122
+ "description": (
123
+ "User-provided files or runtime artifacts. Declare this property on any "
124
+ "tool that can consume uploaded files; the Edge runtime injects the "
125
+ "current conversation attachments automatically."
126
+ ),
127
+ "items": STANDARD_ATTACHMENT_SCHEMA,
128
+ }
129
+
130
+
131
+ def standard_attachment_schema() -> dict[str, Any]:
132
+ return deepcopy(STANDARD_ATTACHMENT_SCHEMA)
133
+
134
+
135
+ def standard_attachments_property() -> dict[str, Any]:
136
+ return deepcopy(STANDARD_ATTACHMENTS_PROPERTY)
137
+
138
+
139
+ def standard_output_schema(schema: dict[str, Any] | None = None) -> dict[str, Any]:
140
+ if schema is None:
141
+ return deepcopy(STANDARD_OUTPUT_SCHEMA)
142
+
143
+ merged = deepcopy(schema)
144
+ base = deepcopy(STANDARD_OUTPUT_SCHEMA)
145
+ merged["type"] = merged.get("type") or "object"
146
+ merged["properties"] = {
147
+ **base["properties"],
148
+ **(merged.get("properties") or {}),
149
+ }
150
+ required = list(dict.fromkeys([*base["required"], *(merged.get("required") or [])]))
151
+ merged["required"] = required
152
+ merged.setdefault("additionalProperties", True)
153
+ return merged
154
+
155
+
156
+ class PermissionSpec(BaseModel):
157
+ key: str = Field(pattern=r"^[a-zA-Z0-9_.:-]+$")
158
+ name: str
159
+ description: str | None = None
160
+ required: bool = True
161
+ scope: str | None = None
162
+
163
+
164
+ class ToolSpec(BaseModel):
165
+ name: str
166
+ title: str | None = None
167
+ description: str
168
+ input_schema: dict[str, Any]
169
+ output_schema: dict[str, Any] = Field(default_factory=standard_output_schema)
170
+ is_destructive: bool = False
171
+ requires_user_confirmation: bool = False
172
+
173
+ def descriptor(self) -> dict[str, Any]:
174
+ return {
175
+ "name": self.name,
176
+ "title": self.title or self.name.replace("_", " ").title(),
177
+ "description": self.description,
178
+ "input_schema": self.input_schema,
179
+ "output_schema": standard_output_schema(self.output_schema),
180
+ "is_destructive": self.is_destructive,
181
+ "requires_user_confirmation": self.requires_user_confirmation,
182
+ }
183
+
184
+ def mcp_descriptor(self) -> dict[str, Any]:
185
+ return {
186
+ "name": self.name,
187
+ "title": self.title or self.name.replace("_", " ").title(),
188
+ "description": self.description,
189
+ "inputSchema": self.input_schema,
190
+ "annotations": {
191
+ "readOnlyHint": not self.is_destructive,
192
+ "destructiveHint": self.is_destructive,
193
+ "openWorldHint": True,
194
+ },
195
+ }
196
+
197
+
198
+ class AuthConfig(BaseModel):
199
+ is_auth_required: bool = False
200
+ auth_type: Literal["none", "oauth2", "api_key", "bearer_token", "custom"] = "none"
201
+ auth_instructions: str | None = None
202
+ connection_schema: dict[str, Any] | None = None
@@ -0,0 +1 @@
1
+