codemie-mcp-assistants 0.1.4__tar.gz → 0.1.5__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.

Potentially problematic release.


This version of codemie-mcp-assistants might be problematic. Click here for more details.

@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.1
2
+ Name: codemie-mcp-assistants
3
+ Version: 0.1.5
4
+ Summary: MCP server for connecting to CodeMie Assistants API
5
+ Author: Vadym Vlasenko
6
+ Author-email: vadym_vlasenko@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 (==0.1.5)
12
+ Requires-Dist: httpx (>=0.27.0,<0.28.0)
13
+ Requires-Dist: mcp (>=1.6.0,<2.0.0)
14
+ Requires-Dist: pydantic (>=2.11.2,<3.0.0)
15
+ Description-Content-Type: text/markdown
16
+
17
+ # CodeMie Assistants MCP Server
18
+
19
+ Python server implementing Model Context Protocol (MCP) for CodeMie Assistants operations.
20
+
21
+ ## Features
22
+ - Chat with AI/Run CodeMie assistant
23
+
24
+ Note: The server requires authentication credentials via environment variables.
25
+
26
+ ## API
27
+
28
+ ### Tools
29
+
30
+ #### chat
31
+ Chat with a specific AI assistant
32
+ Inputs:
33
+ - `message (string)`: Message to send to assistant
34
+ - `conversation_id (string)`: Identifier of current conversation. It should be always passed if present in current communication thread.
35
+ - `history (array, optional)`: Previous conversation messages in format:
36
+ [{"role": "user|assistant", "message": "text"}]
37
+
38
+ Returns generated assistant response as text
39
+
40
+ ## Installation
41
+
42
+ Ensure you have `Python 3.12` or later installed.
43
+
44
+ ### Using uv (recommended)
45
+
46
+ When using [`uv`](https://docs.astral.sh/uv/) no specific installation is needed. We will
47
+ use [`uvx`](https://docs.astral.sh/uv/guides/tools/) to directly run *codemie-mcp-assistants*.
48
+
49
+ ```bash
50
+ uvx codemie-mcp-assistants
51
+ ```
52
+
53
+ ### Using Poetry
54
+
55
+ Alternatively you can install via Poetry:
56
+
57
+ ```bash
58
+ poetry install codemie-mcp-assistants
59
+ ```
60
+
61
+ After installation, you can run it as a script using:
62
+
63
+ ```bash
64
+ poetry run codemie-mcp-assistants
65
+ ```
66
+
67
+ ## Configuration
68
+
69
+ ### Configure for Claude.app
70
+
71
+ Add to your Claude settings:
72
+
73
+ <details>
74
+ <summary>Using uvx</summary>
75
+
76
+ ```json
77
+ "mcpServers": {
78
+ "codemie": {
79
+ "command": "uvx",
80
+ "args": ["codemie-mcp-assistants"],
81
+ "env": {
82
+ "CODEMIE_ASSISTANT_ID": "your-assistant-id"
83
+ "CODEMIE_USERNAME": "your-username",
84
+ "CODEMIE_PASSWORD": "your-password"
85
+ }
86
+ }
87
+ }
88
+ ```
89
+ </details>
90
+
91
+ <details>
92
+ <summary>Using poetry installation</summary>
93
+
94
+ ```json
95
+ "mcpServers": {
96
+ "codemie": {
97
+ "command": "poetry",
98
+ "args": ["run", "codemie-mcp-assistants"],
99
+ "env": {
100
+ "CODEMIE_ASSISTANT_ID": "your-assistant-id"
101
+ "CODEMIE_USERNAME": "your-username",
102
+ "CODEMIE_PASSWORD": "your-password"
103
+ }
104
+ }
105
+ }
106
+ ```
107
+ </details>
108
+
109
+ ### Environment Variables
110
+
111
+ - `CODEMIE_ASSISTANT_ID`: "AI/Run CodeMie assistant UID"
112
+
113
+ The following environment variables are required for authentication:
114
+
115
+ - `CODEMIE_USERNAME`: Your CodeMie username
116
+ - `CODEMIE_PASSWORD`: Your CodeMie password
117
+
118
+ Optional configuration:
119
+ - `CODEMIE_AUTH_CLIENT_ID`: Auth client ID (default: "codemie-sdk")
120
+ - `CODEMIE_AUTH_REALM_NAME`: Auth realm name (default: "codemie-prod")
121
+
122
+ ## Build
123
+
124
+ ### Make build:
125
+ ```bash
126
+ make build
127
+ ```
128
+
@@ -0,0 +1,111 @@
1
+ # CodeMie Assistants MCP Server
2
+
3
+ Python server implementing Model Context Protocol (MCP) for CodeMie Assistants operations.
4
+
5
+ ## Features
6
+ - Chat with AI/Run CodeMie assistant
7
+
8
+ Note: The server requires authentication credentials via environment variables.
9
+
10
+ ## API
11
+
12
+ ### Tools
13
+
14
+ #### chat
15
+ Chat with a specific AI assistant
16
+ Inputs:
17
+ - `message (string)`: Message to send to assistant
18
+ - `conversation_id (string)`: Identifier of current conversation. It should be always passed if present in current communication thread.
19
+ - `history (array, optional)`: Previous conversation messages in format:
20
+ [{"role": "user|assistant", "message": "text"}]
21
+
22
+ Returns generated assistant response as text
23
+
24
+ ## Installation
25
+
26
+ Ensure you have `Python 3.12` or later installed.
27
+
28
+ ### Using uv (recommended)
29
+
30
+ When using [`uv`](https://docs.astral.sh/uv/) no specific installation is needed. We will
31
+ use [`uvx`](https://docs.astral.sh/uv/guides/tools/) to directly run *codemie-mcp-assistants*.
32
+
33
+ ```bash
34
+ uvx codemie-mcp-assistants
35
+ ```
36
+
37
+ ### Using Poetry
38
+
39
+ Alternatively you can install via Poetry:
40
+
41
+ ```bash
42
+ poetry install codemie-mcp-assistants
43
+ ```
44
+
45
+ After installation, you can run it as a script using:
46
+
47
+ ```bash
48
+ poetry run codemie-mcp-assistants
49
+ ```
50
+
51
+ ## Configuration
52
+
53
+ ### Configure for Claude.app
54
+
55
+ Add to your Claude settings:
56
+
57
+ <details>
58
+ <summary>Using uvx</summary>
59
+
60
+ ```json
61
+ "mcpServers": {
62
+ "codemie": {
63
+ "command": "uvx",
64
+ "args": ["codemie-mcp-assistants"],
65
+ "env": {
66
+ "CODEMIE_ASSISTANT_ID": "your-assistant-id"
67
+ "CODEMIE_USERNAME": "your-username",
68
+ "CODEMIE_PASSWORD": "your-password"
69
+ }
70
+ }
71
+ }
72
+ ```
73
+ </details>
74
+
75
+ <details>
76
+ <summary>Using poetry installation</summary>
77
+
78
+ ```json
79
+ "mcpServers": {
80
+ "codemie": {
81
+ "command": "poetry",
82
+ "args": ["run", "codemie-mcp-assistants"],
83
+ "env": {
84
+ "CODEMIE_ASSISTANT_ID": "your-assistant-id"
85
+ "CODEMIE_USERNAME": "your-username",
86
+ "CODEMIE_PASSWORD": "your-password"
87
+ }
88
+ }
89
+ }
90
+ ```
91
+ </details>
92
+
93
+ ### Environment Variables
94
+
95
+ - `CODEMIE_ASSISTANT_ID`: "AI/Run CodeMie assistant UID"
96
+
97
+ The following environment variables are required for authentication:
98
+
99
+ - `CODEMIE_USERNAME`: Your CodeMie username
100
+ - `CODEMIE_PASSWORD`: Your CodeMie password
101
+
102
+ Optional configuration:
103
+ - `CODEMIE_AUTH_CLIENT_ID`: Auth client ID (default: "codemie-sdk")
104
+ - `CODEMIE_AUTH_REALM_NAME`: Auth realm name (default: "codemie-prod")
105
+
106
+ ## Build
107
+
108
+ ### Make build:
109
+ ```bash
110
+ make build
111
+ ```
@@ -2,38 +2,41 @@
2
2
  name = "codemie-mcp-assistants"
3
3
  version = "0.1.2"
4
4
  description = "MCP server for connecting to CodeMie Assistants API"
5
- #readme = "README.md"
5
+ readme = "README.md"
6
6
  packages = [
7
- { include = "assistants_mcp", from = "src" }
7
+ { include = "src"}
8
8
  ]
9
9
 
10
10
  [tool.poetry]
11
11
  name = "codemie-mcp-assistants"
12
- version = "0.1.4"
12
+ version = "0.1.5"
13
13
  description = "MCP server for connecting to CodeMie Assistants API"
14
14
  authors = [
15
+ "Vadym Vlasenko <vadym_vlasenko@epam.com>",
15
16
  "Nikita Levyankov <nikita_levyankov@epam.com>",
16
17
  ]
17
- #readme = "README.md"
18
+ readme = "README.md"
18
19
  packages = [
19
- { include = "assistants_mcp", from = "src" }
20
+ { include = "src"}
20
21
  ]
21
22
 
22
23
  [tool.poetry.dependencies]
23
24
  python = "^3.12"
24
- mcp = "^1.2.0"
25
+ mcp = "^1.6.0"
25
26
  httpx = "^0.27.0"
26
- codemie-sdk-python = "0.1.4"
27
+ codemie-sdk-python = "0.1.5"
27
28
  certifi = "^2025.1.31"
29
+ pydantic = "^2.11.2"
28
30
 
29
31
  [tool.poetry.group.dev.dependencies]
30
32
  pytest = "^8.0.0"
31
33
  black = "^24.1.0"
32
34
  isort = "^5.13.2"
35
+ ruff = "^0.11.3"
33
36
 
34
37
  [build-system]
35
38
  requires = ["poetry-core"]
36
39
  build-backend = "poetry.core.masonry.api"
37
40
 
38
41
  [tool.poetry.scripts]
39
- codemie-mcp-assistant = "src.assistants_mcp:main"
42
+ codemie-mcp-assistants = "src.assistants_mcp:main"
@@ -0,0 +1,114 @@
1
+ import os
2
+ from typing import Optional
3
+
4
+ from pydantic import BaseModel, Field, model_validator
5
+
6
+
7
+ class AssistantInfo(BaseModel):
8
+ """Model representing assistant information from the MCP API"""
9
+
10
+ id: str = Field(..., description="Unique identifier of the assistant")
11
+ name: str = Field(..., description="Name of the assistant")
12
+ slug: Optional[str] = Field(None, description="Slug of the assistant")
13
+ description: str = Field(..., description="Description of the assistant")
14
+ project: Optional[str] = Field(None, description="Associated project name")
15
+
16
+
17
+ class AssistantNotFoundError(Exception):
18
+ """Exception raised when an assistant is not found"""
19
+
20
+ def __init__(self, assistant_id: str):
21
+ self.assistant_id = assistant_id
22
+ self.message = f"Assistant with ID {assistant_id} not found"
23
+ super().__init__(self.message)
24
+
25
+
26
+ class AuthConfig(BaseModel):
27
+ """Authentication configuration with support for multiple auth methods."""
28
+
29
+ username: Optional[str] = Field(
30
+ default=None, description="Username for password-based authentication"
31
+ )
32
+ password: Optional[str] = Field(
33
+ default=None, description="Password for password-based authentication"
34
+ )
35
+ client_id: str = Field(
36
+ default="codemie-sdk",
37
+ description="Client ID for client credentials authentication",
38
+ )
39
+ client_secret: Optional[str] = Field(
40
+ default=None, description="Client secret for client credentials authentication"
41
+ )
42
+
43
+ @model_validator(mode="after")
44
+ def validate_auth_method(self) -> "AuthConfig":
45
+ has_user_pass = bool(self.username and self.password)
46
+ has_client_creds = bool(self.client_id and self.client_secret)
47
+
48
+ if not (has_user_pass or has_client_creds):
49
+ raise ValueError(
50
+ "Authentication configuration missing. Please provide either:\n"
51
+ "- CODEMIE_USERNAME and CODEMIE_PASSWORD for password authentication\n"
52
+ "- CODEMIE_AUTH_CLIENT_ID and CODEMIE_AUTH_CLIENT_SECRET for client credentials\n"
53
+ )
54
+
55
+ if has_user_pass and has_client_creds:
56
+ import warnings
57
+
58
+ warnings.warn(
59
+ "Both authentication methods provided. Using client credentials authentication.",
60
+ UserWarning,
61
+ )
62
+
63
+ return self
64
+
65
+
66
+ class Settings:
67
+ """Application settings configured via environment variables."""
68
+
69
+ # Default values
70
+ DEFAULT_AUTH_CLIENT_ID = "codemie-sdk"
71
+ DEFAULT_AUTH_REALM_NAME = "codemie-prod"
72
+ DEFAULT_AUTH_SERVER_URL = (
73
+ "https://keycloak.eks-core.aws.main.edp.projects.epam.com/auth"
74
+ )
75
+ DEFAULT_CODEMIE_API_DOMAIN = "https://codemie.lab.epam.com/code-assistant-api"
76
+
77
+ def __init__(self):
78
+ # Authentication settings
79
+ self.auth = AuthConfig(
80
+ username=os.environ.get("CODEMIE_USERNAME"),
81
+ password=os.environ.get("CODEMIE_PASSWORD"),
82
+ client_id=os.environ.get(
83
+ "CODEMIE_AUTH_CLIENT_ID", self.DEFAULT_AUTH_CLIENT_ID
84
+ ),
85
+ client_secret=os.environ.get("CODEMIE_AUTH_CLIENT_SECRET"),
86
+ )
87
+
88
+ # Server configuration
89
+ self.auth_client_id = os.environ.get(
90
+ "CODEMIE_AUTH_CLIENT_ID", self.DEFAULT_AUTH_CLIENT_ID
91
+ )
92
+ self.auth_realm_name = os.environ.get(
93
+ "CODEMIE_AUTH_REALM_NAME", self.DEFAULT_AUTH_REALM_NAME
94
+ )
95
+ self.auth_server_url = os.environ.get(
96
+ "CODEMIE_AUTH_SERVER_URL", self.DEFAULT_AUTH_SERVER_URL
97
+ )
98
+ self.api_domain = os.environ.get(
99
+ "CODEMIE_API_DOMAIN", self.DEFAULT_CODEMIE_API_DOMAIN
100
+ )
101
+ self.assistant_id = os.environ.get("CODEMIE_ASSISTANT_ID")
102
+ self.verify_ssl = os.environ.get("CODEMIE_VERIFY_SSL", "true").lower() == "true"
103
+
104
+ def __str__(self):
105
+ """String representation of the settings (excluding sensitive data)."""
106
+ return (
107
+ f"Settings:\n"
108
+ f" Auth Client ID: {self.auth_client_id}\n"
109
+ f" Auth Realm Name: {self.auth_realm_name}\n"
110
+ f" Auth Server URL: {self.auth_server_url}\n"
111
+ f" API Domain: {self.api_domain}\n"
112
+ f" Assistant ID: {self.assistant_id}\n"
113
+ f" Verify SSL: {self.verify_ssl}\n"
114
+ )
@@ -0,0 +1,195 @@
1
+ import sys
2
+ import uuid
3
+ from typing import Dict, List
4
+
5
+ from codemie_sdk import CodeMieClient
6
+ from codemie_sdk.models.assistant import (
7
+ AssistantChatRequest,
8
+ ChatMessage,
9
+ ChatRole,
10
+ )
11
+ from model import AssistantInfo, AssistantNotFoundError, Settings
12
+
13
+ from mcp.server.fastmcp import FastMCP
14
+
15
+ # Initialize settings at module level
16
+ try:
17
+ settings = Settings()
18
+ except Exception as e:
19
+ print(f"Error initializing settings: {str(e)}", file=sys.stderr)
20
+ sys.exit(1)
21
+
22
+
23
+ def get_client() -> CodeMieClient:
24
+ """Gets authenticated CodeMie client instance."""
25
+ try:
26
+ client = CodeMieClient(
27
+ username=settings.auth.username,
28
+ password=settings.auth.password,
29
+ auth_client_id=settings.auth.client_id,
30
+ auth_client_secret=settings.auth.client_secret,
31
+ verify_ssl=settings.verify_ssl,
32
+ auth_realm_name=settings.auth_realm_name,
33
+ auth_server_url=settings.auth_server_url,
34
+ codemie_api_domain=settings.api_domain,
35
+ )
36
+
37
+ if not client.token:
38
+ print("Failed to obtain authentication token", file=sys.stderr)
39
+ raise ValueError("Failed to obtain authentication token")
40
+
41
+ print("Successfully initialized CodeMie client", file=sys.stdout)
42
+ return client
43
+ except Exception as e:
44
+ print(f"Error initializing client: {str(e)}", file=sys.stderr)
45
+ raise
46
+
47
+
48
+ def get_assistant_info(assistant_id: str) -> AssistantInfo:
49
+ """
50
+ Retrieve and validate assistant information.
51
+
52
+ Args:
53
+ assistant_id: The ID of the assistant to retrieve
54
+
55
+ Returns:
56
+ AssistantInfo: Validated assistant information
57
+
58
+ Raises:
59
+ AssistantNotFoundError: If the assistant doesn't exist
60
+ ValueError: If there are validation errors
61
+ """
62
+ try:
63
+ assistant = get_client().assistants.get(assistant_id)
64
+ if not assistant:
65
+ raise AssistantNotFoundError(assistant_id)
66
+
67
+ return AssistantInfo(
68
+ id=assistant.id,
69
+ name=assistant.name,
70
+ description=assistant.description,
71
+ project=assistant.project,
72
+ slug=assistant.slug,
73
+ )
74
+ except AssistantNotFoundError:
75
+ print(f"Assistant not found: {assistant_id}", file=sys.stderr)
76
+ raise
77
+ except Exception as e:
78
+ print(f"Error retrieving assistant {assistant_id}: {str(e)}", file=sys.stderr)
79
+ raise
80
+
81
+
82
+ # Initialize FastMCP server
83
+ mcp = FastMCP("codemie-assistants")
84
+ # Get and validate assistant by identifier.
85
+ codemie_assistant = get_assistant_info(settings.assistant_id)
86
+
87
+ chat_tool_name = "ask_" + codemie_assistant.name.lower().replace(" ", "_")
88
+ chat_assistant_tool_description = (
89
+ f"""
90
+ This tool allows to ask and communicate with '{codemie_assistant.name}'.
91
+ Call this tool when '{codemie_assistant.slug}' or '{codemie_assistant.name} is present in message'
92
+ Purpose of '{codemie_assistant.name}' is: {codemie_assistant.description}.
93
+ You MUST always call this tool when '{codemie_assistant.name}' is tagged or referenced.
94
+ """
95
+ + """
96
+ Tool accepts the following parameters:
97
+ - message - required. User message to send to assistant
98
+ - conversation_id - string. Identifier of current conversation. if context or history contains Conversation_Id, this ID must be passed as parameter
99
+ must not be passed with the first call, only if returned previously
100
+ - history. List[Dict[str, str]]. MUST always be passed to assistant
101
+ Example of the given param [{"role": "User", "message": "show my tools"}, {"role": "Assistant", "message": "Here are the tools available for use: **functions.generic_jira_tool**}]
102
+ This parameter must always be filled when conversation is in progress
103
+
104
+ Returns assistant response. IMPORTANT: response must never be formatter or summarized.
105
+ """
106
+ )
107
+
108
+
109
+ @mcp.tool(
110
+ name=chat_tool_name,
111
+ description=chat_assistant_tool_description,
112
+ )
113
+ async def chat_with_assistant(
114
+ message: str,
115
+ history: List[Dict[str, str]] = None,
116
+ conversation_id: str = None,
117
+ ) -> str:
118
+ """
119
+ Chat with a specific assistant.
120
+ :param str message: required. User request to send to assistant
121
+ :param List[Dict[str, str]] history: Must be passed to assistant if user proceeds current conversation
122
+ :param str conversation_id: Identifier of current conversation
123
+ Example of the given param [{'role': 'User', 'message': 'show my tools'}, {'role': 'Assistant', 'message': 'Here are the tools available for use: **functions.generic_jira_tool**'}]
124
+ This parameter must always be filled when conversation is in progress
125
+
126
+ :return response from assistant.
127
+ """
128
+ try:
129
+ client = get_client()
130
+ if not message or not message.strip():
131
+ print("Empty message provided", file=sys.stderr)
132
+ raise ValueError("Empty message provided")
133
+
134
+ # Convert history to ChatMessage objects if provided
135
+ chat_history = []
136
+ if history:
137
+ try:
138
+ for msg in history:
139
+ if (
140
+ not isinstance(msg, dict)
141
+ or "role" not in msg
142
+ or "message" not in msg
143
+ ):
144
+ print(f"Invalid history format: {msg}", file=sys.stderr)
145
+ raise ValueError(f"Invalid history format: {msg}")
146
+ chat_history.append(
147
+ ChatMessage(role=ChatRole(msg["role"]), message=msg["message"])
148
+ )
149
+ except Exception as e:
150
+ print(f"Error processing chat history: {str(e)}", file=sys.stderr)
151
+ raise
152
+
153
+ # Create chat request
154
+ if not conversation_id:
155
+ conversation_id = str(uuid.uuid4())
156
+ print(f"Starting chat with assistant {settings.assistant_id} ", file=sys.stdout)
157
+
158
+ request = AssistantChatRequest(
159
+ text=message,
160
+ conversation_id=conversation_id,
161
+ history=chat_history,
162
+ stream=False,
163
+ )
164
+
165
+ # Send chat request
166
+ response = client.assistants.chat(
167
+ assistant_id=settings.assistant_id, request=request
168
+ )
169
+
170
+ if not response or not response.generated:
171
+ print(
172
+ f"Received empty response from {codemie_assistant.name}",
173
+ file=sys.stderr,
174
+ )
175
+ raise ValueError("Received empty response from assistant")
176
+
177
+ print(
178
+ f"Successfully received response from {codemie_assistant.name} for conversation {conversation_id}",
179
+ file=sys.stdout,
180
+ )
181
+ return f"Response: {response.generated}. Conversation_Id: {conversation_id}"
182
+
183
+ except Exception as e:
184
+ print(f"Error in chat_with_assistant: {str(e)}", file=sys.stderr)
185
+ raise
186
+
187
+
188
+ if __name__ == "__main__":
189
+ try:
190
+ print("Starting CodeMie Assistants MCP server", file=sys.stdout)
191
+ # Initialize and run the server
192
+ mcp.run(transport="stdio")
193
+ except Exception as e:
194
+ print(f"Error starting MCP server: {str(e)}", file=sys.stderr)
195
+ sys.exit(1)
@@ -1,13 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: codemie-mcp-assistants
3
- Version: 0.1.4
4
- Summary: MCP server for connecting to CodeMie Assistants API
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 (==0.1.4)
12
- Requires-Dist: httpx (>=0.27.0,<0.28.0)
13
- Requires-Dist: mcp (>=1.2.0,<2.0.0)
@@ -1,151 +0,0 @@
1
- import os
2
- import uuid
3
- from typing import Any, Dict, List, Optional
4
-
5
- from codemie_sdk import CodeMieClient
6
- from codemie_sdk.models.assistant import (
7
- AssistantChatRequest,
8
- ChatMessage,
9
- ChatRole,
10
- )
11
- from mcp.server.fastmcp import FastMCP
12
-
13
- DEFAULT_AUTH_CLIENT_ID = "codemie-sdk"
14
- DEFAULT_AUTH_REALM_NAME = "codemie-prod"
15
- DEFAULT_AUTH_SERVER_URL = (
16
- "https://keycloak.eks-core.aws.main.edp.projects.epam.com/auth"
17
- )
18
- DEFAULT_CODEMIE_API_DOMAIN = "https://codemie.lab.epam.com/code-assistant-api"
19
-
20
- # Initialize FastMCP server
21
- mcp = FastMCP("codemie-assistants")
22
-
23
- # Client instance
24
- _client: Optional[CodeMieClient] = None
25
-
26
-
27
- def get_client() -> CodeMieClient:
28
- """Gets authenticated CodeMie client instance."""
29
- username = os.getenv("CODEMIE_USERNAME")
30
- password = os.getenv("CODEMIE_PASSWORD")
31
- auth_client_id = os.getenv("CODEMIE_AUTH_CLIENT_ID", DEFAULT_AUTH_CLIENT_ID)
32
- auth_realm_name = os.getenv("CODEMIE_AUTH_REALM_NAME", DEFAULT_AUTH_REALM_NAME)
33
- auth_server_url = os.getenv("CODEMIE_AUTH_SERVER_URL", DEFAULT_AUTH_SERVER_URL)
34
- codemie_api_domain = os.getenv("CODEMIE_API_DOMAIN", DEFAULT_CODEMIE_API_DOMAIN)
35
-
36
- if not username or not password:
37
- raise ValueError(
38
- "Username and password must be set via environment variables: CODEMIE_USERNAME, CODEMIE_PASSWORD"
39
- )
40
-
41
- return CodeMieClient(
42
- username=username,
43
- password=password,
44
- verify_ssl=False,
45
- auth_client_id=auth_client_id,
46
- auth_realm_name=auth_realm_name,
47
- auth_server_url=auth_server_url,
48
- codemie_api_domain=codemie_api_domain,
49
- )
50
-
51
-
52
- @mcp.tool()
53
- async def get_tools() -> List[Dict[str, Any]]:
54
- """Get available tools for assistants."""
55
- try:
56
- print("Getting tools")
57
- client = get_client()
58
- if client.token is None:
59
- raise ValueError("Client not initialized")
60
- toolkits = client.assistants.get_tools()
61
-
62
- # Convert to dict format for better visualization
63
- tools_list = []
64
- for toolkit in toolkits:
65
- tools_list.extend(
66
- [
67
- {
68
- "toolkit": toolkit.toolkit,
69
- "tool": tool.name,
70
- "label": tool.label or tool.name,
71
- "settings_required": tool.settings_config,
72
- }
73
- for tool in toolkit.tools
74
- ]
75
- )
76
-
77
- return tools_list
78
- except Exception as e:
79
- print(f"Error getting tools: {str(e)}")
80
- raise e
81
-
82
-
83
- @mcp.tool()
84
- async def get_assistants(
85
- minimal: bool = True, project: Optional[str] = None
86
- ) -> List[Dict[str, Any]]:
87
- """Get list of available assistants.
88
-
89
- Args:
90
- minimal: Return minimal info (default: True)
91
- project: Filter by project name
92
- """
93
- client = get_client()
94
- filters = {"project": project} if project else None
95
-
96
- assistants = client.assistants.list(minimal_response=minimal, filters=filters)
97
-
98
- # Convert to dict format
99
- return [
100
- {
101
- "id": asst.id,
102
- "name": asst.name,
103
- "description": asst.description,
104
- "project": getattr(asst, "project", None) if not minimal else None,
105
- }
106
- for asst in assistants
107
- ]
108
-
109
-
110
- @mcp.tool()
111
- async def chat_with_assistant(
112
- message: str,
113
- assistant_id: str,
114
- conversation_id: Optional[str] = None,
115
- history: Optional[List[Dict[str, str]]] = None,
116
- ) -> str:
117
- """Chat with a specific assistant.
118
-
119
- Args:
120
- message: User message
121
- assistant_id: ID of the assistant to chat with
122
- conversation_id: Optional conversation ID
123
- history: Optional chat history as list of dicts with role and message
124
- """
125
- client = get_client()
126
-
127
- # Convert history to ChatMessage objects if provided
128
- chat_history = []
129
- if history:
130
- for msg in history:
131
- chat_history.append(
132
- ChatMessage(role=ChatRole(msg["role"]), message=msg["message"])
133
- )
134
-
135
- # Create chat request
136
- request = AssistantChatRequest(
137
- text=message,
138
- conversation_id=conversation_id if conversation_id else str(uuid.uuid4()),
139
- history=chat_history,
140
- stream=False, # For now using non-streaming responses
141
- )
142
-
143
- # Send chat request
144
- response = client.assistants.chat(assistant_id=assistant_id, request=request)
145
-
146
- return response.generated
147
-
148
-
149
- if __name__ == "__main__":
150
- # Initialize and run the server
151
- mcp.run(transport="stdio")