2
2
3
3
from __future__ import annotations
4
4
5
+ import os
6
+ import threading
7
+
8
+ import uvicorn
9
+ from fastapi import FastAPI
10
+ from fastapi .middleware .cors import CORSMiddleware
11
+ from fastapi .responses import JSONResponse
5
12
from mcp .server .fastmcp import FastMCP # pylint: disable=import-error
13
+ from prometheus_client import Counter
6
14
7
15
from gitingest .entrypoint import ingest_async
8
16
from gitingest .utils .logging_config import get_logger
17
+ from server .metrics_server import start_metrics_server
9
18
10
19
# Initialize logger for this module
11
20
logger = get_logger (__name__ )
12
21
22
+ # Create Prometheus metrics
23
+ fastmcp_ingest_counter = Counter ("gitingest_fastmcp_ingest_total" , "Number of FastMCP ingests" , ["status" ])
24
+ fastmcp_tool_calls_counter = Counter (
25
+ "gitingest_fastmcp_tool_calls_total" ,
26
+ "Number of FastMCP tool calls" ,
27
+ ["tool_name" , "status" ],
28
+ )
29
+
13
30
# Create the FastMCP server instance
14
31
mcp = FastMCP ("gitingest" )
15
32
@@ -40,6 +57,7 @@ async def ingest_repository(
40
57
41
58
"""
42
59
try :
60
+ fastmcp_tool_calls_counter .labels (tool_name = "ingest_repository" , status = "started" ).inc ()
43
61
logger .info ("Starting MCP ingestion" , extra = {"source" : source })
44
62
45
63
# Convert patterns to sets if provided
@@ -58,8 +76,14 @@ async def ingest_repository(
58
76
token = token ,
59
77
output = None , # Don't write to file, return content instead
60
78
)
79
+
80
+ fastmcp_ingest_counter .labels (status = "success" ).inc ()
81
+ fastmcp_tool_calls_counter .labels (tool_name = "ingest_repository" , status = "success" ).inc ()
82
+
61
83
except Exception :
62
84
logger .exception ("Error during ingestion" )
85
+ fastmcp_ingest_counter .labels (status = "error" ).inc ()
86
+ fastmcp_tool_calls_counter .labels (tool_name = "ingest_repository" , status = "error" ).inc ()
63
87
return "Error ingesting repository: An internal error occurred"
64
88
65
89
# Create a structured response and return directly
@@ -85,10 +109,17 @@ async def start_mcp_server_tcp(host: str = "127.0.0.1", port: int = 8001) -> Non
85
109
"""Start the MCP server with HTTP transport using SSE."""
86
110
logger .info ("Starting Gitingest MCP server with HTTP/SSE transport on %s:%s" , host , port )
87
111
88
- import uvicorn # noqa: PLC0415 # pylint: disable=import-outside-toplevel
89
- from fastapi import FastAPI # noqa: PLC0415 # pylint: disable=import-outside-toplevel
90
- from fastapi .middleware .cors import CORSMiddleware # noqa: PLC0415 # pylint: disable=import-outside-toplevel
91
- from fastapi .responses import JSONResponse # noqa: PLC0415 # pylint: disable=import-outside-toplevel
112
+ # Start metrics server in a separate thread if enabled
113
+ if os .getenv ("GITINGEST_METRICS_ENABLED" ) is not None :
114
+ metrics_host = os .getenv ("GITINGEST_METRICS_HOST" , "127.0.0.1" )
115
+ metrics_port = int (os .getenv ("GITINGEST_METRICS_PORT" , "9090" ))
116
+ metrics_thread = threading .Thread (
117
+ target = start_metrics_server ,
118
+ args = (metrics_host , metrics_port ),
119
+ daemon = True ,
120
+ )
121
+ metrics_thread .start ()
122
+ logger .info ("Started metrics server on %s:%s" , metrics_host , metrics_port )
92
123
93
124
tcp_app = FastAPI (title = "Gitingest MCP Server" , description = "MCP server over HTTP/SSE" )
94
125
0 commit comments