codemie-mcp-datasources 0.1000.7__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,13 @@
1
+ Metadata-Version: 2.1
2
+ Name: codemie-mcp-datasources
3
+ Version: 0.1000.7
4
+ Summary: MCP server for connecting to CodeMie Datasources
5
+ Author: Nikita Levyankov
6
+ Author-email: nikita_levyankov@epam.com
7
+ Requires-Python: >=3.12,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Requires-Dist: certifi (>=2025.1.31,<2026.0.0)
11
+ Requires-Dist: codemie-sdk-python-az (==0.1000.7)
12
+ Requires-Dist: httpx (>=0.27.0,<0.28.0)
13
+ Requires-Dist: mcp (>=1.2.0,<2.0.0)
@@ -0,0 +1,39 @@
1
+ [project]
2
+ name = "codemie-mcp-datasources-az"
3
+ version = "0.1.2"
4
+ description = "MCP server for connecting to CodeMie Datasources"
5
+ #readme = "README.md"
6
+ packages = [
7
+ { include = "datasources_mcp", from = "src" }
8
+ ]
9
+
10
+ [tool.poetry]
11
+ name = "codemie-mcp-datasources"
12
+ version = "0.1000.7"
13
+ description = "MCP server for connecting to CodeMie Datasources"
14
+ authors = [
15
+ "Nikita Levyankov <nikita_levyankov@epam.com>",
16
+ ]
17
+ #readme = "README.md"
18
+ packages = [
19
+ { include = "datasources_mcp", from = "src" }
20
+ ]
21
+
22
+ [tool.poetry.dependencies]
23
+ python = "^3.12"
24
+ mcp = "^1.2.0"
25
+ httpx = "^0.27.0"
26
+ codemie-sdk-python-az = "0.1000.7"
27
+ certifi = "^2025.1.31"
28
+
29
+ [tool.poetry.group.dev.dependencies]
30
+ pytest = "^8.0.0"
31
+ black = "^24.1.0"
32
+ isort = "^5.13.2"
33
+
34
+ [build-system]
35
+ requires = ["poetry-core"]
36
+ build-backend = "poetry.core.masonry.api"
37
+
38
+ [tool.poetry.scripts]
39
+ codemie-mcp-assistant = "src.datasources_mcp:main"
@@ -0,0 +1,3 @@
1
+ """CodeMie MCP implementation for datasources."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,265 @@
1
+ """CodeMie MCP implementation for datasources."""
2
+
3
+ import os
4
+ from typing import Any, Dict, List, Optional, Literal
5
+
6
+ from codemie_sdk import CodeMieClient
7
+ from codemie_sdk.models.datasource import (
8
+ DataSourceType,
9
+ DataSourceStatus,
10
+ CodeDataSourceRequest,
11
+ UpdateCodeDataSourceRequest,
12
+ )
13
+ from mcp.server.fastmcp import FastMCP
14
+
15
+ DEFAULT_AUTH_CLIENT_ID = "codemie-sdk"
16
+ DEFAULT_AUTH_REALM_NAME = "codemie-prod"
17
+ DEFAULT_AUTH_SERVER_URL = (
18
+ "https://keycloak.eks-core.aws.main.edp.projects.epam.com/auth"
19
+ )
20
+ DEFAULT_CODEMIE_API_DOMAIN = "https://codemie.lab.epam.com/code-assistant-api"
21
+
22
+ # Initialize FastMCP server
23
+ mcp = FastMCP("codemie-datasources")
24
+
25
+ # Client instance
26
+ _client: Optional[CodeMieClient] = None
27
+
28
+
29
+ def get_client() -> CodeMieClient:
30
+ """Gets authenticated CodeMie client instance."""
31
+ username = os.getenv("CODEMIE_USERNAME")
32
+ password = os.getenv("CODEMIE_PASSWORD")
33
+ auth_client_id = os.getenv("CODEMIE_AUTH_CLIENT_ID", DEFAULT_AUTH_CLIENT_ID)
34
+ auth_realm_name = os.getenv("CODEMIE_AUTH_REALM_NAME", DEFAULT_AUTH_REALM_NAME)
35
+ auth_server_url = os.getenv("CODEMIE_AUTH_SERVER_URL", DEFAULT_AUTH_SERVER_URL)
36
+ codemie_api_domain = os.getenv("CODEMIE_API_DOMAIN", DEFAULT_CODEMIE_API_DOMAIN)
37
+
38
+ if not username or not password:
39
+ raise ValueError(
40
+ "Username and password must be set via environment variables: CODEMIE_USERNAME, CODEMIE_PASSWORD"
41
+ )
42
+
43
+ return CodeMieClient(
44
+ username=username,
45
+ password=password,
46
+ verify_ssl=False,
47
+ auth_client_id=auth_client_id,
48
+ auth_realm_name=auth_realm_name,
49
+ auth_server_url=auth_server_url,
50
+ codemie_api_domain=codemie_api_domain,
51
+ )
52
+
53
+
54
+ @mcp.tool()
55
+ async def list_datasources(
56
+ page: int = 0,
57
+ per_page: int = 10,
58
+ sort_key: Literal["date", "update_date"] = "update_date",
59
+ sort_order: Literal["asc", "desc"] = "desc",
60
+ datasource_types: List[DataSourceType] = None,
61
+ projects: List[str] = None,
62
+ owner: str = None,
63
+ status: DataSourceStatus = None,
64
+ ) -> List[Dict[str, Any]]:
65
+ """Get list of available datasources.
66
+
67
+ Args:
68
+ sort_key: sort results by params
69
+ sort_order: sort results in order
70
+ page: Page number (default: 0)
71
+ per_page: Items per page (default: 10)
72
+ projects: Filter by project name
73
+ datasource_types: Filter by datasource type
74
+ owner: Filter by owner
75
+ status: Filter by status
76
+ """
77
+ client = get_client()
78
+
79
+ datasources = client.datasources.list(
80
+ page=page,
81
+ per_page=per_page,
82
+ sort_key=sort_key,
83
+ sort_order=sort_order,
84
+ datasource_types=datasource_types,
85
+ projects=projects,
86
+ owner=owner,
87
+ status=status,
88
+ )
89
+
90
+ # Convert to simplified dict format
91
+ return [
92
+ {
93
+ "id": ds.id,
94
+ "name": ds.name,
95
+ "description": ds.description,
96
+ "type": ds.type.value,
97
+ "project": ds.project_name,
98
+ "status": ds.status.value,
99
+ "created_date": ds.created_date.isoformat() if ds.created_date else None,
100
+ "update_date": ds.update_date.isoformat() if ds.update_date else None,
101
+ "error_message": ds.error_message,
102
+ "processing_info": ds.processing_info.model_dump()
103
+ if ds.processing_info
104
+ else None,
105
+ }
106
+ for ds in datasources
107
+ ]
108
+
109
+
110
+ @mcp.tool()
111
+ async def get_datasource(datasource_id: str) -> Dict[str, Any]:
112
+ """Get datasource details by ID.
113
+
114
+ Args:
115
+ datasource_id: ID of the datasource to retrieve
116
+ """
117
+ client = get_client()
118
+ datasource = client.datasources.get(datasource_id)
119
+
120
+ return {
121
+ "id": datasource.id,
122
+ "name": datasource.name,
123
+ "description": datasource.description,
124
+ "type": datasource.type.value,
125
+ "project": datasource.project_name,
126
+ "status": datasource.status.value,
127
+ "created_date": datasource.created_date.isoformat()
128
+ if datasource.created_date
129
+ else None,
130
+ "update_date": datasource.update_date.isoformat()
131
+ if datasource.update_date
132
+ else None,
133
+ "error_message": datasource.error_message,
134
+ "processing_info": datasource.processing_info.model_dump()
135
+ if datasource.processing_info
136
+ else None,
137
+ "code": datasource.code.model_dump() if datasource.code else None,
138
+ "jira": datasource.jira.model_dump() if datasource.jira else None,
139
+ "confluence": datasource.confluence.model_dump()
140
+ if datasource.confluence
141
+ else None,
142
+ }
143
+
144
+
145
+ @mcp.tool()
146
+ async def create_code_datasource(
147
+ name: str,
148
+ description: str,
149
+ project_name: str,
150
+ repository_link: str,
151
+ branch: str,
152
+ index_type: str = "code",
153
+ files_filter: str = "",
154
+ embeddings_model: Optional[str] = None,
155
+ shared_with_project: bool = False,
156
+ ) -> Dict[str, Any]:
157
+ """Create a new code datasource.
158
+
159
+ Args:
160
+ name: Datasource name (lowercase letters and underscores only)
161
+ description: Datasource description
162
+ project_name: Project name
163
+ repository_link: Git repository URL
164
+ branch: Git branch name
165
+ index_type: Type of indexing (code, summary, chunk-summary)
166
+ files_filter: File patterns to include/exclude
167
+ embeddings_model: Model for embeddings generation
168
+ shared_with_project: Whether datasource is shared with project
169
+ """
170
+ client = get_client()
171
+
172
+ request = CodeDataSourceRequest(
173
+ name=name,
174
+ description=description,
175
+ project_name=project_name,
176
+ link=repository_link,
177
+ branch=branch,
178
+ index_type=index_type,
179
+ files_filter=files_filter,
180
+ embeddings_model=embeddings_model,
181
+ shared_with_project=shared_with_project,
182
+ )
183
+
184
+ datasource = client.datasources.create(request)
185
+ return get_datasource(datasource.id)
186
+
187
+
188
+ @mcp.tool()
189
+ async def delete_datasource(datasource_id: str) -> Dict[str, Any]:
190
+ """Delete a datasource.
191
+
192
+ Args:
193
+ datasource_id: ID of the datasource to delete
194
+ """
195
+ client = get_client()
196
+ return client.datasources.delete(datasource_id)
197
+
198
+
199
+ @mcp.tool()
200
+ async def update_code_datasource(
201
+ datasource_id: str,
202
+ name: Optional[str] = None,
203
+ description: Optional[str] = None,
204
+ branch: Optional[str] = None,
205
+ files_filter: Optional[str] = None,
206
+ full_reindex: Optional[bool] = None,
207
+ skip_reindex: Optional[bool] = None,
208
+ resume_indexing: Optional[bool] = None,
209
+ ) -> Dict[str, Any]:
210
+ """Update a code datasource.
211
+
212
+ Args:
213
+ datasource_id: ID of the datasource to update
214
+ name: New name (optional)
215
+ description: New description (optional)
216
+ branch: New branch (optional)
217
+ files_filter: New files filter (optional)
218
+ full_reindex: Whether to perform full reindex
219
+ skip_reindex: Whether to skip reindex
220
+ resume_indexing: Whether to resume indexing
221
+ """
222
+ client = get_client()
223
+
224
+ # First get current datasource
225
+ current = client.datasources.get(datasource_id)
226
+
227
+ # Prepare update request
228
+ request = UpdateCodeDataSourceRequest(
229
+ name=name or current.name,
230
+ description=description or current.description,
231
+ project_name=current.project_name,
232
+ branch=branch or current.code.branch if current.code else None,
233
+ files_filter=files_filter or current.code.files_filter
234
+ if current.code
235
+ else None,
236
+ full_reindex=full_reindex,
237
+ skip_reindex=skip_reindex,
238
+ resume_indexing=resume_indexing,
239
+ )
240
+
241
+ datasource = client.datasources.update(datasource_id, request)
242
+ return get_datasource(datasource.id)
243
+
244
+
245
+ @mcp.tool()
246
+ async def get_datasource_processing_info(datasource_id: str) -> Dict[str, Any]:
247
+ """Get datasource processing information.
248
+
249
+ Args:
250
+ datasource_id: ID of the datasource to get info for
251
+ """
252
+ client = get_client()
253
+ info = client.datasources.get_processing_info(datasource_id)
254
+ return {
255
+ "status": info.status.value if info.status else None,
256
+ "total_files": info.total_files,
257
+ "processed_files": info.processed_files,
258
+ "progress": info.progress,
259
+ "error_message": info.error_message,
260
+ }
261
+
262
+
263
+ if __name__ == "__main__":
264
+ # Initialize and run the server
265
+ mcp.run(transport="stdio")