devrev-Python-SDK 2.13.0__py3-none-any.whl → 2.14.1__py3-none-any.whl

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.
devrev/client.py CHANGED
@@ -38,6 +38,7 @@ from devrev.services.recommendations import (
38
38
  AsyncRecommendationsService,
39
39
  RecommendationsService,
40
40
  )
41
+ from devrev.services.rev_orgs import AsyncRevOrgsService, RevOrgsService
41
42
  from devrev.services.rev_users import AsyncRevUsersService, RevUsersService
42
43
  from devrev.services.search import AsyncSearchService, SearchService
43
44
  from devrev.services.slas import AsyncSlasService, SlasService
@@ -160,6 +161,7 @@ class DevRevClient:
160
161
  self._groups = GroupsService(self._http)
161
162
  self._links = LinksService(self._http)
162
163
  self._parts = PartsService(self._http)
164
+ self._rev_orgs = RevOrgsService(self._http)
163
165
  self._rev_users = RevUsersService(self._http)
164
166
  self._slas = SlasService(self._http)
165
167
  self._tags = TagsService(self._http)
@@ -242,6 +244,11 @@ class DevRevClient:
242
244
  """Access the Parts service."""
243
245
  return self._parts
244
246
 
247
+ @property
248
+ def rev_orgs(self) -> RevOrgsService:
249
+ """Access the Rev Orgs service for managing revenue organizations."""
250
+ return self._rev_orgs
251
+
245
252
  @property
246
253
  def rev_users(self) -> RevUsersService:
247
254
  """Access the Rev Users service."""
@@ -482,6 +489,7 @@ class AsyncDevRevClient:
482
489
  self._groups = AsyncGroupsService(self._http)
483
490
  self._links = AsyncLinksService(self._http)
484
491
  self._parts = AsyncPartsService(self._http)
492
+ self._rev_orgs = AsyncRevOrgsService(self._http)
485
493
  self._rev_users = AsyncRevUsersService(self._http)
486
494
  self._slas = AsyncSlasService(self._http)
487
495
  self._tags = AsyncTagsService(self._http)
@@ -564,6 +572,11 @@ class AsyncDevRevClient:
564
572
  """Access the Parts service."""
565
573
  return self._parts
566
574
 
575
+ @property
576
+ def rev_orgs(self) -> AsyncRevOrgsService:
577
+ """Access the Rev Orgs service for managing revenue organizations."""
578
+ return self._rev_orgs
579
+
567
580
  @property
568
581
  def rev_users(self) -> AsyncRevUsersService:
569
582
  """Access the Rev Users service."""
devrev/models/__init__.py CHANGED
@@ -260,6 +260,20 @@ from devrev.models.recommendations import (
260
260
  MessageRole,
261
261
  TokenUsage,
262
262
  )
263
+ from devrev.models.rev_orgs import (
264
+ RevOrg,
265
+ RevOrgsCreateRequest,
266
+ RevOrgsCreateResponse,
267
+ RevOrgsDeleteRequest,
268
+ RevOrgsDeleteResponse,
269
+ RevOrgsGetRequest,
270
+ RevOrgsGetResponse,
271
+ RevOrgsListRequest,
272
+ RevOrgsListResponse,
273
+ RevOrgSummary,
274
+ RevOrgsUpdateRequest,
275
+ RevOrgsUpdateResponse,
276
+ )
263
277
  from devrev.models.rev_users import (
264
278
  RevUser,
265
279
  RevUsersAssociationsAddRequest,
@@ -694,6 +708,19 @@ __all__ = [
694
708
  "ChatCompletionResponse",
695
709
  "GetReplyRequest",
696
710
  "GetReplyResponse",
711
+ # Rev Orgs
712
+ "RevOrg",
713
+ "RevOrgSummary",
714
+ "RevOrgsCreateRequest",
715
+ "RevOrgsCreateResponse",
716
+ "RevOrgsGetRequest",
717
+ "RevOrgsGetResponse",
718
+ "RevOrgsListRequest",
719
+ "RevOrgsListResponse",
720
+ "RevOrgsUpdateRequest",
721
+ "RevOrgsUpdateResponse",
722
+ "RevOrgsDeleteRequest",
723
+ "RevOrgsDeleteResponse",
697
724
  # Rev Users
698
725
  "RevUser",
699
726
  "RevUserSummary",
@@ -889,6 +916,12 @@ from devrev.models.accounts import (
889
916
  AccountsListResponse as _AccountsListResponse,
890
917
  )
891
918
  from devrev.models.base import TagWithValue as _TagWithValue # noqa: F811
919
+ from devrev.models.rev_orgs import ( # noqa: F811
920
+ RevOrg as _RevOrg,
921
+ )
922
+ from devrev.models.rev_orgs import (
923
+ RevOrgsListResponse as _RevOrgsListResponse,
924
+ )
892
925
  from devrev.models.works import ( # noqa: F811
893
926
  Work as _Work,
894
927
  )
@@ -904,6 +937,8 @@ _TagWithValue.model_rebuild()
904
937
  _Account.model_rebuild()
905
938
  _AccountsListResponse.model_rebuild()
906
939
  _AccountsExportResponse.model_rebuild()
940
+ _RevOrg.model_rebuild()
941
+ _RevOrgsListResponse.model_rebuild()
907
942
  _Work.model_rebuild()
908
943
  _WorksListResponse.model_rebuild()
909
944
  _WorksExportResponse.model_rebuild()
@@ -0,0 +1,159 @@
1
+ """Rev Org models for DevRev SDK.
2
+
3
+ This module contains Pydantic models for Rev Org (Revenue Organization)-related
4
+ API operations. Rev Orgs represent customer organizations in DevRev.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from datetime import datetime
10
+ from typing import Any
11
+
12
+ from pydantic import Field
13
+
14
+ from devrev.models.accounts import AccountSummary
15
+ from devrev.models.base import (
16
+ CustomSchemaSpec,
17
+ DateFilter,
18
+ DevRevBaseModel,
19
+ DevRevResponseModel,
20
+ PaginatedResponse,
21
+ TagWithValue,
22
+ UserSummary,
23
+ )
24
+
25
+
26
+ class RevOrg(DevRevResponseModel):
27
+ """DevRev Rev Org (Revenue Organization) model.
28
+
29
+ Represents a customer organization in DevRev, typically associated
30
+ with an Account.
31
+ """
32
+
33
+ id: str = Field(..., description="Rev org ID")
34
+ display_id: str | None = Field(default=None, description="Human-readable display ID")
35
+ display_name: str | None = Field(default=None, description="Rev org display name")
36
+ description: str | None = Field(default=None, description="Rev org description")
37
+ account: AccountSummary | None = Field(default=None, description="Associated account")
38
+ created_date: datetime | None = Field(default=None, description="Creation timestamp")
39
+ modified_date: datetime | None = Field(default=None, description="Last modification timestamp")
40
+ created_by: UserSummary | None = Field(
41
+ default=None, description="User who created this rev org"
42
+ )
43
+ modified_by: UserSummary | None = Field(
44
+ default=None, description="User who last modified this rev org"
45
+ )
46
+ domain: str | None = Field(default=None, description="Domain")
47
+ external_ref: str | None = Field(default=None, description="External reference identifier")
48
+ external_refs: list[str] | None = Field(default=None, description="External references")
49
+ custom_fields: dict[str, Any] | None = Field(default=None, description="Custom fields")
50
+ sub_type: str | None = Field(default=None, description="Rev org subtype")
51
+ tags: list[TagWithValue] | None = Field(default=None, description="Tags")
52
+ tier: str | None = Field(default=None, description="Rev org tier")
53
+ artifacts: list[str] | None = Field(default=None, description="Associated artifact IDs")
54
+
55
+
56
+ class RevOrgSummary(DevRevResponseModel):
57
+ """Summary of a Rev Org for list/reference operations."""
58
+
59
+ id: str = Field(..., description="Rev org ID")
60
+ display_id: str | None = Field(default=None, description="Human-readable display ID")
61
+ display_name: str | None = Field(default=None, description="Rev org display name")
62
+
63
+
64
+ # Request Models
65
+
66
+
67
+ class RevOrgsGetRequest(DevRevBaseModel):
68
+ """Request to get a rev org."""
69
+
70
+ id: str | None = Field(default=None, description="Rev org ID")
71
+ account: str | None = Field(
72
+ default=None, description="Account ID to get the default rev org for"
73
+ )
74
+
75
+
76
+ class RevOrgsListRequest(DevRevBaseModel):
77
+ """Request to list rev orgs."""
78
+
79
+ account: list[str] | None = Field(default=None, description="Filter by account IDs")
80
+ created_by: list[str] | None = Field(default=None, description="Filter by creator user IDs")
81
+ created_date: DateFilter | None = Field(default=None, description="Filter by creation date")
82
+ cursor: str | None = Field(default=None, description="Pagination cursor")
83
+ display_name: list[str] | None = Field(default=None, description="Filter by display names")
84
+ domains: list[str] | None = Field(default=None, description="Filter by domains")
85
+ external_refs: list[str] | None = Field(default=None, description="Filter by external refs")
86
+ limit: int | None = Field(default=None, ge=1, le=100, description="Max results to return")
87
+ modified_date: DateFilter | None = Field(
88
+ default=None, description="Filter by modification date"
89
+ )
90
+ owned_by: list[str] | None = Field(default=None, description="Filter by owner user IDs")
91
+ tags: list[str] | None = Field(default=None, description="Filter by tag IDs")
92
+
93
+
94
+ class RevOrgsCreateRequest(DevRevBaseModel):
95
+ """Request to create a rev org."""
96
+
97
+ display_name: str = Field(..., description="Rev org display name", min_length=1, max_length=256)
98
+ account: str = Field(..., description="Parent account ID")
99
+ description: str | None = Field(default=None, description="Rev org description")
100
+ external_ref: str | None = Field(default=None, description="External reference identifier")
101
+ tier: str | None = Field(default=None, description="Rev org tier")
102
+ custom_fields: dict[str, Any] | None = Field(default=None, description="Custom fields")
103
+ custom_schema_spec: CustomSchemaSpec | None = Field(
104
+ default=None, description="Custom schema spec"
105
+ )
106
+
107
+
108
+ class RevOrgsUpdateRequest(DevRevBaseModel):
109
+ """Request to update a rev org."""
110
+
111
+ id: str = Field(..., description="Rev org ID")
112
+ display_name: str | None = Field(default=None, description="New display name")
113
+ description: str | None = Field(default=None, description="New description")
114
+ tier: str | None = Field(default=None, description="New tier")
115
+ custom_fields: dict[str, Any] | None = Field(
116
+ default=None, description="Custom fields to update"
117
+ )
118
+ artifacts: dict[str, Any] | None = Field(
119
+ default=None, description="Artifact set/remove operations"
120
+ )
121
+
122
+
123
+ class RevOrgsDeleteRequest(DevRevBaseModel):
124
+ """Request to delete a rev org."""
125
+
126
+ id: str = Field(..., description="Rev org ID to delete")
127
+
128
+
129
+ # Response Models
130
+
131
+
132
+ class RevOrgsGetResponse(DevRevResponseModel):
133
+ """Response from getting a rev org."""
134
+
135
+ rev_org: RevOrg = Field(..., description="Retrieved rev org")
136
+
137
+
138
+ class RevOrgsListResponse(PaginatedResponse):
139
+ """Response from listing rev orgs."""
140
+
141
+ rev_orgs: list[RevOrg] = Field(..., description="List of rev orgs")
142
+
143
+
144
+ class RevOrgsCreateResponse(DevRevResponseModel):
145
+ """Response from creating a rev org."""
146
+
147
+ rev_org: RevOrg = Field(..., description="Created rev org")
148
+
149
+
150
+ class RevOrgsUpdateResponse(DevRevResponseModel):
151
+ """Response from updating a rev org."""
152
+
153
+ rev_org: RevOrg = Field(..., description="Updated rev org")
154
+
155
+
156
+ class RevOrgsDeleteResponse(DevRevResponseModel):
157
+ """Response from deleting a rev org."""
158
+
159
+ pass # Empty response body
@@ -34,6 +34,7 @@ from devrev.services.recommendations import (
34
34
  AsyncRecommendationsService,
35
35
  RecommendationsService,
36
36
  )
37
+ from devrev.services.rev_orgs import AsyncRevOrgsService, RevOrgsService
37
38
  from devrev.services.rev_users import AsyncRevUsersService, RevUsersService
38
39
  from devrev.services.search import AsyncSearchService, SearchService
39
40
  from devrev.services.slas import AsyncSlasService, SlasService
@@ -99,6 +100,9 @@ __all__ = [
99
100
  # Recommendations
100
101
  "RecommendationsService",
101
102
  "AsyncRecommendationsService",
103
+ # Rev Orgs
104
+ "RevOrgsService",
105
+ "AsyncRevOrgsService",
102
106
  # Rev Users
103
107
  "RevUsersService",
104
108
  "AsyncRevUsersService",
@@ -0,0 +1,271 @@
1
+ """Rev Orgs service for DevRev SDK.
2
+
3
+ This module provides the RevOrgsService for managing DevRev Rev Orgs
4
+ (Revenue Organizations).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ from devrev.models.rev_orgs import (
12
+ RevOrg,
13
+ RevOrgsCreateRequest,
14
+ RevOrgsCreateResponse,
15
+ RevOrgsDeleteRequest,
16
+ RevOrgsDeleteResponse,
17
+ RevOrgsGetRequest,
18
+ RevOrgsGetResponse,
19
+ RevOrgsListRequest,
20
+ RevOrgsListResponse,
21
+ RevOrgsUpdateRequest,
22
+ RevOrgsUpdateResponse,
23
+ )
24
+ from devrev.services.base import AsyncBaseService, BaseService
25
+
26
+ if TYPE_CHECKING:
27
+ from devrev.utils.http import AsyncHTTPClient, HTTPClient
28
+
29
+
30
+ class RevOrgsService(BaseService):
31
+ """Synchronous service for managing DevRev Rev Orgs.
32
+
33
+ Provides methods for creating, reading, updating, and deleting
34
+ Rev Orgs (Revenue Organizations).
35
+
36
+ Example:
37
+ ```python
38
+ from devrev import DevRevClient
39
+
40
+ client = DevRevClient()
41
+ rev_orgs = client.rev_orgs.list()
42
+ ```
43
+ """
44
+
45
+ def __init__(self, http_client: HTTPClient) -> None:
46
+ """Initialize the RevOrgsService."""
47
+ super().__init__(http_client)
48
+
49
+ def create(
50
+ self,
51
+ display_name: str,
52
+ account: str,
53
+ *,
54
+ description: str | None = None,
55
+ external_ref: str | None = None,
56
+ tier: str | None = None,
57
+ custom_fields: dict[str, Any] | None = None,
58
+ ) -> RevOrg:
59
+ """Create a new rev org.
60
+
61
+ Args:
62
+ display_name: Rev org display name
63
+ account: Parent account ID
64
+ description: Rev org description
65
+ external_ref: External reference identifier
66
+ tier: Rev org tier
67
+ custom_fields: Custom fields
68
+
69
+ Returns:
70
+ The created RevOrg
71
+ """
72
+ request = RevOrgsCreateRequest(
73
+ display_name=display_name,
74
+ account=account,
75
+ description=description,
76
+ external_ref=external_ref,
77
+ tier=tier,
78
+ custom_fields=custom_fields,
79
+ )
80
+ response = self._post("/rev-orgs.create", request, RevOrgsCreateResponse)
81
+ return response.rev_org
82
+
83
+ def get(self, id: str) -> RevOrg:
84
+ """Get a rev org by ID.
85
+
86
+ Args:
87
+ id: Rev org ID
88
+
89
+ Returns:
90
+ The RevOrg
91
+ """
92
+ request = RevOrgsGetRequest(id=id)
93
+ response = self._post("/rev-orgs.get", request, RevOrgsGetResponse)
94
+ return response.rev_org
95
+
96
+ def list(
97
+ self,
98
+ *,
99
+ cursor: str | None = None,
100
+ limit: int | None = None,
101
+ account: list[str] | None = None,
102
+ display_name: list[str] | None = None,
103
+ domains: list[str] | None = None,
104
+ external_refs: list[str] | None = None,
105
+ owned_by: list[str] | None = None,
106
+ tags: list[str] | None = None,
107
+ ) -> RevOrgsListResponse:
108
+ """List rev orgs.
109
+
110
+ Args:
111
+ cursor: Pagination cursor
112
+ limit: Maximum number of results
113
+ account: Filter by account IDs
114
+ display_name: Filter by display names
115
+ domains: Filter by domains
116
+ external_refs: Filter by external refs
117
+ owned_by: Filter by owner user IDs
118
+ tags: Filter by tag IDs
119
+
120
+ Returns:
121
+ Paginated list of rev orgs
122
+ """
123
+ request = RevOrgsListRequest(
124
+ cursor=cursor,
125
+ limit=limit,
126
+ account=account,
127
+ display_name=display_name,
128
+ domains=domains,
129
+ external_refs=external_refs,
130
+ owned_by=owned_by,
131
+ tags=tags,
132
+ )
133
+ return self._post("/rev-orgs.list", request, RevOrgsListResponse)
134
+
135
+ def update(
136
+ self,
137
+ id: str,
138
+ *,
139
+ display_name: str | None = None,
140
+ description: str | None = None,
141
+ tier: str | None = None,
142
+ custom_fields: dict[str, Any] | None = None,
143
+ ) -> RevOrg:
144
+ """Update a rev org.
145
+
146
+ Args:
147
+ id: Rev org ID
148
+ display_name: New display name
149
+ description: New description
150
+ tier: New tier
151
+ custom_fields: Custom fields to update
152
+
153
+ Returns:
154
+ The updated RevOrg
155
+ """
156
+ request = RevOrgsUpdateRequest(
157
+ id=id,
158
+ display_name=display_name,
159
+ description=description,
160
+ tier=tier,
161
+ custom_fields=custom_fields,
162
+ )
163
+ response = self._post("/rev-orgs.update", request, RevOrgsUpdateResponse)
164
+ return response.rev_org
165
+
166
+ def delete(self, id: str) -> None:
167
+ """Delete a rev org.
168
+
169
+ Args:
170
+ id: Rev org ID to delete
171
+ """
172
+ request = RevOrgsDeleteRequest(id=id)
173
+ self._post("/rev-orgs.delete", request, RevOrgsDeleteResponse)
174
+
175
+
176
+ class AsyncRevOrgsService(AsyncBaseService):
177
+ """Asynchronous service for managing DevRev Rev Orgs.
178
+
179
+ Provides async methods for creating, reading, updating, and deleting
180
+ Rev Orgs (Revenue Organizations).
181
+
182
+ Example:
183
+ ```python
184
+ from devrev import AsyncDevRevClient
185
+
186
+ async with AsyncDevRevClient() as client:
187
+ rev_orgs = await client.rev_orgs.list()
188
+ ```
189
+ """
190
+
191
+ def __init__(self, http_client: AsyncHTTPClient) -> None:
192
+ """Initialize the AsyncRevOrgsService."""
193
+ super().__init__(http_client)
194
+
195
+ async def create(
196
+ self,
197
+ display_name: str,
198
+ account: str,
199
+ *,
200
+ description: str | None = None,
201
+ external_ref: str | None = None,
202
+ tier: str | None = None,
203
+ custom_fields: dict[str, Any] | None = None,
204
+ ) -> RevOrg:
205
+ """Create a new rev org."""
206
+ request = RevOrgsCreateRequest(
207
+ display_name=display_name,
208
+ account=account,
209
+ description=description,
210
+ external_ref=external_ref,
211
+ tier=tier,
212
+ custom_fields=custom_fields,
213
+ )
214
+ response = await self._post("/rev-orgs.create", request, RevOrgsCreateResponse)
215
+ return response.rev_org
216
+
217
+ async def get(self, id: str) -> RevOrg:
218
+ """Get a rev org by ID."""
219
+ request = RevOrgsGetRequest(id=id)
220
+ response = await self._post("/rev-orgs.get", request, RevOrgsGetResponse)
221
+ return response.rev_org
222
+
223
+ async def list(
224
+ self,
225
+ *,
226
+ cursor: str | None = None,
227
+ limit: int | None = None,
228
+ account: list[str] | None = None,
229
+ display_name: list[str] | None = None,
230
+ domains: list[str] | None = None,
231
+ external_refs: list[str] | None = None,
232
+ owned_by: list[str] | None = None,
233
+ tags: list[str] | None = None,
234
+ ) -> RevOrgsListResponse:
235
+ """List rev orgs."""
236
+ request = RevOrgsListRequest(
237
+ cursor=cursor,
238
+ limit=limit,
239
+ account=account,
240
+ display_name=display_name,
241
+ domains=domains,
242
+ external_refs=external_refs,
243
+ owned_by=owned_by,
244
+ tags=tags,
245
+ )
246
+ return await self._post("/rev-orgs.list", request, RevOrgsListResponse)
247
+
248
+ async def update(
249
+ self,
250
+ id: str,
251
+ *,
252
+ display_name: str | None = None,
253
+ description: str | None = None,
254
+ tier: str | None = None,
255
+ custom_fields: dict[str, Any] | None = None,
256
+ ) -> RevOrg:
257
+ """Update a rev org."""
258
+ request = RevOrgsUpdateRequest(
259
+ id=id,
260
+ display_name=display_name,
261
+ description=description,
262
+ tier=tier,
263
+ custom_fields=custom_fields,
264
+ )
265
+ response = await self._post("/rev-orgs.update", request, RevOrgsUpdateResponse)
266
+ return response.rev_org
267
+
268
+ async def delete(self, id: str) -> None:
269
+ """Delete a rev org."""
270
+ request = RevOrgsDeleteRequest(id=id)
271
+ await self._post("/rev-orgs.delete", request, RevOrgsDeleteResponse)
devrev_mcp/server.py CHANGED
@@ -243,6 +243,7 @@ from devrev_mcp.tools import groups as _groups_tools # noqa: E402, F401
243
243
  from devrev_mcp.tools import incidents as _incidents_tools # noqa: E402, F401
244
244
  from devrev_mcp.tools import links as _links_tools # noqa: E402, F401
245
245
  from devrev_mcp.tools import parts as _parts_tools # noqa: E402, F401
246
+ from devrev_mcp.tools import rev_orgs as _rev_orgs_tools # noqa: E402, F401
246
247
  from devrev_mcp.tools import server_info as _server_info_tools # noqa: E402, F401
247
248
  from devrev_mcp.tools import slas as _slas_tools # noqa: E402, F401
248
249
  from devrev_mcp.tools import tags as _tags_tools # noqa: E402, F401
@@ -9,6 +9,7 @@ from mcp.server.fastmcp import Context
9
9
 
10
10
  from devrev.exceptions import DevRevError
11
11
  from devrev_mcp.server import _config, mcp
12
+ from devrev_mcp.utils.don_id import validate_don_id
12
13
  from devrev_mcp.utils.errors import format_devrev_error
13
14
  from devrev_mcp.utils.formatting import serialize_model, serialize_models
14
15
  from devrev_mcp.utils.pagination import clamp_page_size, paginated_response
@@ -61,6 +62,7 @@ async def devrev_accounts_get(
61
62
  Args:
62
63
  id: The account ID.
63
64
  """
65
+ validate_don_id(id, "account", "devrev_accounts_get")
64
66
  app = ctx.request_context.lifespan_context
65
67
  try:
66
68
  account = await app.get_client().accounts.get(id)
@@ -124,6 +126,7 @@ if _config.enable_destructive_tools:
124
126
  description: New description.
125
127
  tier: New account tier.
126
128
  """
129
+ validate_don_id(id, "account", "devrev_accounts_update")
127
130
  app = ctx.request_context.lifespan_context
128
131
  try:
129
132
  account = await app.get_client().accounts.update(
@@ -146,6 +149,7 @@ if _config.enable_destructive_tools:
146
149
  Args:
147
150
  id: The account ID to delete.
148
151
  """
152
+ validate_don_id(id, "account", "devrev_accounts_delete")
149
153
  app = ctx.request_context.lifespan_context
150
154
  try:
151
155
  await app.get_client().accounts.delete(id)
@@ -167,6 +171,8 @@ if _config.enable_destructive_tools:
167
171
  primary_account: ID of the primary (surviving) account.
168
172
  secondary_account: ID of the secondary (merged) account.
169
173
  """
174
+ validate_don_id(primary_account, "account", "devrev_accounts_merge")
175
+ validate_don_id(secondary_account, "account", "devrev_accounts_merge")
170
176
  app = ctx.request_context.lifespan_context
171
177
  try:
172
178
  account = await app.get_client().accounts.merge(
@@ -22,6 +22,7 @@ from devrev.models.articles import (
22
22
  from devrev.models.base import SetTagWithValue
23
23
  from devrev.utils.content_converter import OutputFormat
24
24
  from devrev_mcp.server import _config, mcp
25
+ from devrev_mcp.utils.don_id import validate_don_id
25
26
  from devrev_mcp.utils.errors import format_devrev_error
26
27
  from devrev_mcp.utils.formatting import serialize_model, serialize_models
27
28
  from devrev_mcp.utils.pagination import clamp_page_size, paginated_response
@@ -89,6 +90,7 @@ async def devrev_articles_get(
89
90
  Raises:
90
91
  RuntimeError: If the DevRev API call fails.
91
92
  """
93
+ validate_don_id(id, "article", "devrev_articles_get")
92
94
  app = ctx.request_context.lifespan_context
93
95
  try:
94
96
  if include_content:
@@ -251,6 +253,7 @@ if _config.enable_destructive_tools:
251
253
  Raises:
252
254
  RuntimeError: If the DevRev API call fails.
253
255
  """
256
+ validate_don_id(id, "article", "devrev_articles_update")
254
257
  app = ctx.request_context.lifespan_context
255
258
  try:
256
259
  article_status = None
@@ -323,6 +326,7 @@ if _config.enable_destructive_tools:
323
326
  Raises:
324
327
  RuntimeError: If the DevRev API call fails.
325
328
  """
329
+ validate_don_id(id, "article", "devrev_articles_delete")
326
330
  app = ctx.request_context.lifespan_context
327
331
  try:
328
332
  request = ArticlesDeleteRequest(id=id)
@@ -16,6 +16,7 @@ from devrev.models.conversations import (
16
16
  ConversationsUpdateRequest,
17
17
  )
18
18
  from devrev_mcp.server import _config, mcp
19
+ from devrev_mcp.utils.don_id import validate_don_id
19
20
  from devrev_mcp.utils.errors import format_devrev_error
20
21
  from devrev_mcp.utils.formatting import serialize_model, serialize_models
21
22
  from devrev_mcp.utils.pagination import clamp_page_size, paginated_response
@@ -60,6 +61,7 @@ async def devrev_conversations_get(
60
61
  Args:
61
62
  id: Conversation ID (e.g., "don:core:dvrv-us-1:devo/1:conversation/123").
62
63
  """
64
+ validate_don_id(id, "conversation", "devrev_conversations_get")
63
65
  app = ctx.request_context.lifespan_context
64
66
  try:
65
67
  request = ConversationsGetRequest(id=id)
@@ -108,6 +110,7 @@ if _config.enable_destructive_tools:
108
110
  title: New conversation title.
109
111
  description: New conversation description.
110
112
  """
113
+ validate_don_id(id, "conversation", "devrev_conversations_update")
111
114
  app = ctx.request_context.lifespan_context
112
115
  try:
113
116
  request = ConversationsUpdateRequest(id=id, title=title, description=description)
@@ -126,6 +129,7 @@ if _config.enable_destructive_tools:
126
129
  Args:
127
130
  id: Conversation ID to delete.
128
131
  """
132
+ validate_don_id(id, "conversation", "devrev_conversations_delete")
129
133
  app = ctx.request_context.lifespan_context
130
134
  try:
131
135
  request = ConversationsDeleteRequest(id=id)