3
3
from typing import Annotated , Any
4
4
5
5
from dotenv import load_dotenv
6
-
7
- # Remove FastAPI and HTTPException imports as they are no longer directly used
8
- # from fastapi import FastAPI, HTTPException
9
6
from mcp .server .fastmcp import FastMCP
10
7
from pydantic import Field
11
8
12
- # Use direct import as files are now in the same directory
13
- # from src.esa_client import EsaClient
14
9
from esa_client import EsaClient
15
10
16
11
# Load environment variables from .env file
20
15
logging .basicConfig (level = logging .INFO )
21
16
logger = logging .getLogger (__name__ )
22
17
23
- # Remove FastAPI app initialization
24
- # app = FastAPI()
25
-
26
18
# Create MCP instance
27
19
mcp = FastMCP ("esa-mcp-server" )
28
20
29
21
# Get environment variables
30
22
esa_token = os .getenv ("ESA_TOKEN" )
31
23
esa_team_name = os .getenv ("ESA_TEAM_NAME" )
32
24
33
- # 追加: 環境変数の値をログに出力
34
25
logger .info ("Attempting to initialize EsaClient." )
35
26
logger .info (f"ESA_TOKEN from env: { esa_token } " )
36
27
logger .info (f"ESA_TEAM_NAME from env: { esa_team_name } " )
41
32
esa_client = None
42
33
else :
43
34
try :
44
- # Initialize EsaClient without arguments, let it read env vars internally
45
- # esa_client = EsaClient(api_token=esa_token, team_name=esa_team_name)
46
35
esa_client = EsaClient ()
47
36
logger .info ("EsaClient initialized successfully." )
48
37
except ValueError as e : # Catch potential ValueError from EsaClient init
@@ -143,32 +132,27 @@ def posts_create(
143
132
"""
144
133
if esa_client is None :
145
134
logger .error ("EsaClient is not initialized. Cannot create post." )
146
- raise RuntimeError ("EsaClient not initialized" ) # Changed from HTTPException
135
+ raise RuntimeError ("EsaClient not initialized" )
147
136
try :
148
137
logger .info (f"Creating post with name: { name } " )
149
138
150
- # MODIFIED SECTION: Handle empty string category as None
151
- # This ensures that if category is an empty string (default or explicitly passed),
152
- # it's treated as 'no category' and will be removed from the payload if None.
153
- effective_category = category if category else None
154
-
155
139
payload = {
156
140
"name" : name ,
157
141
"body_md" : body_md ,
158
142
"tags" : tags or [],
159
- "category" : effective_category ,
143
+ "category" : category ,
160
144
"wip" : wip ,
161
145
"message" : message ,
162
146
}
163
147
# Remove None values from payload
164
148
payload = {k : v for k , v in payload .items () if v is not None }
165
149
166
- new_post = esa_client .create_post (payload = payload ) # Removed await
150
+ new_post = esa_client .create_post (payload = payload )
167
151
logger .info (f"Successfully created post: { new_post .get ('url' )} " )
168
152
return new_post
169
153
except Exception as e :
170
154
logger .error (f"Error creating post: { e } " , exc_info = True )
171
- raise RuntimeError (f"Error creating post: { e } " ) from e # Changed from HTTPException
155
+ raise RuntimeError (f"Error creating post: { e } " ) from e
172
156
173
157
174
158
@mcp .tool ()
@@ -194,7 +178,7 @@ def posts_update(
194
178
"""
195
179
if esa_client is None :
196
180
logger .error ("EsaClient is not initialized. Cannot update post." )
197
- raise RuntimeError ("EsaClient not initialized" ) # Changed from HTTPException
181
+ raise RuntimeError ("EsaClient not initialized" )
198
182
try :
199
183
logger .info (f"Updating post number: { post_number } " )
200
184
payload = {
@@ -211,15 +195,14 @@ def posts_update(
211
195
if not payload :
212
196
logger .warning (f"No update parameters provided for post { post_number } ." )
213
197
# Consider returning current post details or raising a more specific error
214
- # For now, returning a message indicating no action was taken.
215
198
return {"message" : f"No update parameters provided for post { post_number } . Nothing changed." }
216
199
217
200
updated_post = esa_client .update_post (post_number = post_number , payload = payload )
218
201
logger .info (f"Successfully updated post: { updated_post .get ('url' )} " )
219
202
return updated_post
220
203
except Exception as e :
221
204
logger .error (f"Error updating post { post_number } : { e } " , exc_info = True )
222
- raise RuntimeError (f"Error updating post: { e } " ) from e # Changed from HTTPException
205
+ raise RuntimeError (f"Error updating post: { e } " ) from e
223
206
224
207
225
208
@mcp .tool ()
@@ -231,34 +214,18 @@ def posts_delete(post_number: int) -> dict[str, Any]:
231
214
"""
232
215
if esa_client is None :
233
216
logger .error ("EsaClient is not initialized. Cannot delete post." )
234
- raise RuntimeError ("EsaClient not initialized" ) # Changed from HTTPException
217
+ raise RuntimeError ("EsaClient not initialized" )
235
218
try :
236
- logger .info (f"Deleting post number: { post_number } " )
237
- esa_client .delete_post (post_number ) # Removed await
219
+ esa_client .delete_post (post_number )
238
220
logger .info (f"Successfully deleted post { post_number } ." )
239
221
# Return empty dict upon successful deletion as per esa.io API
240
- # (204 No Content)
241
222
return {}
242
223
except Exception as e :
243
224
logger .error (f"Error deleting post { post_number } : { e } " , exc_info = True )
244
- raise RuntimeError (f"Error deleting post: { e } " ) from e # Changed from HTTPException
245
-
246
-
247
- # Mount MCP router using sse_app
248
- # app.include_router(mcp.router)
249
- # app.mount("/mcp", app=mcp.sse_app())
250
- # @app.get("/")
251
- # async def root():
252
- # return {"message": "MCP Server for esa.io is running"}
253
-
225
+ raise RuntimeError (f"Error deleting post: { e } " ) from e
254
226
255
- # TODO: Add MCP tools based on EsaClient methods
256
- # TODO: Add error handling for EsaClient initialization failures
257
227
258
228
# Use mcp.run() to start the server when script is executed directly
259
229
if __name__ == "__main__" :
260
- # Remove uvicorn import and run
261
- # import uvicorn
262
- # uvicorn.run(app, host="0.0.0.0", port=8000)
263
230
logger .info ("Starting MCP server..." )
264
231
mcp .run ()
0 commit comments