restapi-mcp-server 0.0.1__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.
Files changed (84) hide show
  1. restapi_mcp_server-0.0.1/PKG-INFO +96 -0
  2. restapi_mcp_server-0.0.1/README.md +80 -0
  3. restapi_mcp_server-0.0.1/pyproject.toml +35 -0
  4. restapi_mcp_server-0.0.1/restapi_mcp_server/__init__.py +4 -0
  5. restapi_mcp_server-0.0.1/restapi_mcp_server/__main__.py +328 -0
  6. restapi_mcp_server-0.0.1/restapi_mcp_server/src/__init__.py +0 -0
  7. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/__init__.py +0 -0
  8. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/router.py +17 -0
  9. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/__init__.py +7 -0
  10. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/__init__.py +0 -0
  11. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/bas64interpolationRoute.py +57 -0
  12. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/healthRouter.py +7 -0
  13. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/jqRoute.py +29 -0
  14. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/restapiRoute.py +252 -0
  15. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/sessionRoute.py +25 -0
  16. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/transactionRoute.py +46 -0
  17. restapi_mcp_server-0.0.1/restapi_mcp_server/src/api/v0_0_1/routes/variablesRoute.py +87 -0
  18. restapi_mcp_server-0.0.1/restapi_mcp_server/src/constants/COMMON.py +25 -0
  19. restapi_mcp_server-0.0.1/restapi_mcp_server/src/constants/RESTAPI.py +7 -0
  20. restapi_mcp_server-0.0.1/restapi_mcp_server/src/constants/__init__.py +4 -0
  21. restapi_mcp_server-0.0.1/restapi_mcp_server/src/models/__init__.py +9 -0
  22. restapi_mcp_server-0.0.1/restapi_mcp_server/src/models/bas64interpolationSchema.py +35 -0
  23. restapi_mcp_server-0.0.1/restapi_mcp_server/src/models/jqSchema.py +25 -0
  24. restapi_mcp_server-0.0.1/restapi_mcp_server/src/models/restapiSchema.py +101 -0
  25. restapi_mcp_server-0.0.1/restapi_mcp_server/src/models/sessionSchema.py +7 -0
  26. restapi_mcp_server-0.0.1/restapi_mcp_server/src/models/transacationSchema.py +42 -0
  27. restapi_mcp_server-0.0.1/restapi_mcp_server/src/models/variablesSchema.py +65 -0
  28. restapi_mcp_server-0.0.1/restapi_mcp_server/src/services/__init__.py +0 -0
  29. restapi_mcp_server-0.0.1/restapi_mcp_server/src/services/restapi.py +499 -0
  30. restapi_mcp_server-0.0.1/restapi_mcp_server/src/services/transactions.py +142 -0
  31. restapi_mcp_server-0.0.1/restapi_mcp_server/src/services/variablesInterpolation.py +112 -0
  32. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/__init__.py +0 -0
  33. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/__init__.py +0 -0
  34. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/router.py +17 -0
  35. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/__init__.py +7 -0
  36. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/__init__.py +0 -0
  37. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/bas64interpolationRoute.py +57 -0
  38. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/healthRouter.py +7 -0
  39. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/jqRoute.py +29 -0
  40. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/restapiRoute.py +34 -0
  41. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/sessionRoute.py +25 -0
  42. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/transactionRoute.py +46 -0
  43. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/api/v0_0_1/routes/variablesRoute.py +87 -0
  44. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/constants/COMMON.py +25 -0
  45. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/constants/RESTAPI.py +7 -0
  46. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/constants/__init__.py +4 -0
  47. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/models/__init__.py +9 -0
  48. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/models/bas64interpolationSchema.py +35 -0
  49. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/models/jqSchema.py +25 -0
  50. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/models/restapiSchema.py +54 -0
  51. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/models/sessionSchema.py +7 -0
  52. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/models/transacationSchema.py +42 -0
  53. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/models/variablesSchema.py +65 -0
  54. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/services/__init__.py +0 -0
  55. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/services/restapi.py +385 -0
  56. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/services/transactions.py +142 -0
  57. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/services/variablesInterpolation.py +112 -0
  58. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/__init__.py +0 -0
  59. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/bas64interpolation.py +111 -0
  60. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/env.py +93 -0
  61. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/idgen.py +23 -0
  62. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/interpolation.py +60 -0
  63. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/jqinterpolation.py +70 -0
  64. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/jsoncodec.py +77 -0
  65. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/logger.py +38 -0
  66. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/persist.py +146 -0
  67. restapi_mcp_server-0.0.1/restapi_mcp_server/src/src/utils/restapi.py +233 -0
  68. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/__init__.py +0 -0
  69. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/bas64interpolation.py +111 -0
  70. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/env.py +93 -0
  71. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/idgen.py +23 -0
  72. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/interpolation.py +60 -0
  73. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/jqinterpolation.py +70 -0
  74. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/jsoncodec.py +77 -0
  75. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/logger.py +38 -0
  76. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/persist.py +146 -0
  77. restapi_mcp_server-0.0.1/restapi_mcp_server/src/utils/restapi.py +269 -0
  78. restapi_mcp_server-0.0.1/restapi_mcp_server.egg-info/PKG-INFO +96 -0
  79. restapi_mcp_server-0.0.1/restapi_mcp_server.egg-info/SOURCES.txt +82 -0
  80. restapi_mcp_server-0.0.1/restapi_mcp_server.egg-info/dependency_links.txt +1 -0
  81. restapi_mcp_server-0.0.1/restapi_mcp_server.egg-info/entry_points.txt +2 -0
  82. restapi_mcp_server-0.0.1/restapi_mcp_server.egg-info/requires.txt +9 -0
  83. restapi_mcp_server-0.0.1/restapi_mcp_server.egg-info/top_level.txt +1 -0
  84. restapi_mcp_server-0.0.1/setup.cfg +4 -0
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.4
2
+ Name: restapi-mcp-server
3
+ Version: 0.0.1
4
+ Summary: RestAPI MCP Server - SSE
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: fastapi>=0.128.0
8
+ Requires-Dist: httpx>=0.28.1
9
+ Requires-Dist: jq>=1.10.0
10
+ Requires-Dist: mcp>=1.25.0
11
+ Requires-Dist: pandas>=2.3.3
12
+ Requires-Dist: pydantic>=2.12.5
13
+ Requires-Dist: python-multipart>=0.0.20
14
+ Requires-Dist: pyyaml>=6.0.3
15
+ Requires-Dist: uvicorn>=0.40.0
16
+
17
+ # RestAPI MCP Server
18
+
19
+ ## Overview
20
+ - This project will install `MCP - Model Context Protocol Server`, that provides configured REST API's as context to LLM's.
21
+ - Using this we can enable LLMs to do RestAPI's using prompts.
22
+ - Currently we support HTTP API Call's `GET/PUT/POST/PATCH/DELETE`.
23
+
24
+ ## Installation
25
+ - Install package
26
+ ```bash
27
+ source start.sh
28
+ ```
29
+
30
+ ## Claud Desktop
31
+ - Configuration details for Claud Desktop
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "restapi_mcp_server":{
36
+ "command": "npx",
37
+ "args": ["mcp-remote","<<IP:765/sse>>","--allow-http"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+ - Cline
43
+ ```json
44
+ "DEMO": {
45
+ "autoApprove": [
46
+ "createSession",
47
+ "createEnviromentVariables",
48
+ "listAllEnviromentVariables",
49
+ "listSpecificEnvironmentVariable",
50
+ "createRestAPICall"
51
+ ],
52
+ "disabled": false,
53
+ "timeout": 60,
54
+ "type": "stdio",
55
+ "command": "npx",
56
+ "args": [
57
+ "mcp-remote",
58
+ "http://<<IP>>:8765/sse",
59
+ "--allow-http"
60
+ ]
61
+ }
62
+ ```
63
+
64
+ ### Configuration
65
+ - List of available environment variables
66
+ - `DEBUG`: Enable debug logging (optional default is False)
67
+
68
+ ## Contributing
69
+ Contributions are welcome.
70
+ Please feel free to submit a Pull Request.
71
+
72
+ ## License
73
+ This project is licensed under the terms of the MIT license.
74
+
75
+ ## Github Stars
76
+ [![Star History Chart](https://api.star-history.com/svg?repos=rahgadda/restapi_mcp_server=Date)](https://star-history.com/#rahgadda/restapi_mcp_server&Date)
77
+
78
+ ## Appendix
79
+ ### UV
80
+ ```bash
81
+ mkdir -m777 restapi_mcp_server
82
+ cd restapi_mcp_server
83
+ uv init
84
+ uv add mcp[cli] pydantic python-dotenv requests
85
+ uv add --dev twine setuptools
86
+ uv sync
87
+ uv run restapi_mcp_server
88
+ uv build
89
+ pip install --force-reinstall --no-deps .\dist\restapi_mcp_server-*fileversion*.whl
90
+ export TWINE_USERNAME="rahgadda"
91
+ export TWINE_USERNAME="<<API Key>>"
92
+ uv run twine upload --verbose dist/*
93
+ ```
94
+
95
+ ## Reference
96
+ - [UV Overview](https://www.youtube.com/watch?v=WKc2BdgmGZE)
@@ -0,0 +1,80 @@
1
+ # RestAPI MCP Server
2
+
3
+ ## Overview
4
+ - This project will install `MCP - Model Context Protocol Server`, that provides configured REST API's as context to LLM's.
5
+ - Using this we can enable LLMs to do RestAPI's using prompts.
6
+ - Currently we support HTTP API Call's `GET/PUT/POST/PATCH/DELETE`.
7
+
8
+ ## Installation
9
+ - Install package
10
+ ```bash
11
+ source start.sh
12
+ ```
13
+
14
+ ## Claud Desktop
15
+ - Configuration details for Claud Desktop
16
+ ```json
17
+ {
18
+ "mcpServers": {
19
+ "restapi_mcp_server":{
20
+ "command": "npx",
21
+ "args": ["mcp-remote","<<IP:765/sse>>","--allow-http"]
22
+ }
23
+ }
24
+ }
25
+ ```
26
+ - Cline
27
+ ```json
28
+ "DEMO": {
29
+ "autoApprove": [
30
+ "createSession",
31
+ "createEnviromentVariables",
32
+ "listAllEnviromentVariables",
33
+ "listSpecificEnvironmentVariable",
34
+ "createRestAPICall"
35
+ ],
36
+ "disabled": false,
37
+ "timeout": 60,
38
+ "type": "stdio",
39
+ "command": "npx",
40
+ "args": [
41
+ "mcp-remote",
42
+ "http://<<IP>>:8765/sse",
43
+ "--allow-http"
44
+ ]
45
+ }
46
+ ```
47
+
48
+ ### Configuration
49
+ - List of available environment variables
50
+ - `DEBUG`: Enable debug logging (optional default is False)
51
+
52
+ ## Contributing
53
+ Contributions are welcome.
54
+ Please feel free to submit a Pull Request.
55
+
56
+ ## License
57
+ This project is licensed under the terms of the MIT license.
58
+
59
+ ## Github Stars
60
+ [![Star History Chart](https://api.star-history.com/svg?repos=rahgadda/restapi_mcp_server=Date)](https://star-history.com/#rahgadda/restapi_mcp_server&Date)
61
+
62
+ ## Appendix
63
+ ### UV
64
+ ```bash
65
+ mkdir -m777 restapi_mcp_server
66
+ cd restapi_mcp_server
67
+ uv init
68
+ uv add mcp[cli] pydantic python-dotenv requests
69
+ uv add --dev twine setuptools
70
+ uv sync
71
+ uv run restapi_mcp_server
72
+ uv build
73
+ pip install --force-reinstall --no-deps .\dist\restapi_mcp_server-*fileversion*.whl
74
+ export TWINE_USERNAME="rahgadda"
75
+ export TWINE_USERNAME="<<API Key>>"
76
+ uv run twine upload --verbose dist/*
77
+ ```
78
+
79
+ ## Reference
80
+ - [UV Overview](https://www.youtube.com/watch?v=WKc2BdgmGZE)
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "restapi-mcp-server"
3
+ version = "0.0.1"
4
+ description = "RestAPI MCP Server - SSE"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "fastapi>=0.128.0",
9
+ "httpx>=0.28.1",
10
+ "jq>=1.10.0",
11
+ "mcp>=1.25.0",
12
+ "pandas>=2.3.3",
13
+ "pydantic>=2.12.5",
14
+ "python-multipart>=0.0.20",
15
+ "pyyaml>=6.0.3",
16
+ "uvicorn>=0.40.0",
17
+ ]
18
+
19
+ [dependency-groups]
20
+ dev = [
21
+ "setuptools>=80.9.0",
22
+ "twine>=6.2.0",
23
+ ]
24
+
25
+ [project.scripts]
26
+ restapi_mcp_server = "restapi_mcp_server.__main__:main"
27
+
28
+ [build-system]
29
+ requires = ["setuptools>=42", "wheel"]
30
+ build-backend = "setuptools.build_meta"
31
+
32
+ [tool.setuptools.packages.find]
33
+ # Explicitly include only our package and exclude the storage folder
34
+ include = ["restapi_mcp_server*"]
35
+ exclude = ["storage*"]
@@ -0,0 +1,4 @@
1
+ """
2
+ RestAPI MCP Server package.
3
+ """
4
+ __version__ = "0.0.1"
@@ -0,0 +1,328 @@
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.exceptions import RequestValidationError
4
+ from .src.api.router import api_v001
5
+ from .src.constants import COMMON
6
+ import uvicorn
7
+ import os
8
+ from .src.utils.logger import setup_logging
9
+ from fastapi import Request
10
+ from mcp.server.fastmcp import FastMCP
11
+ from typing import Dict, List, Any
12
+ import httpx
13
+ import asyncio
14
+ import threading
15
+ from .src.utils.env import load_common_from_env
16
+ from pathlib import Path
17
+ from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
18
+
19
+ logger = setup_logging()
20
+
21
+ # Create the ASGI app at module scope so Uvicorn can import it via string path
22
+ app = FastAPI(
23
+ title="Rest API Orchestrator",
24
+ version="0.0.1",
25
+ docs_url="/api/docs",
26
+ redoc_url="/api/redoc",
27
+ openapi_url="/api/openapi.json",
28
+ )
29
+
30
+ # CORS: allow requests from any origin (any IP/host and any port) for all routes.
31
+ #
32
+ # Notes:
33
+ # - allow_origins=["*"] is sufficient to allow all hosts/ports.
34
+ # - If allow_credentials=True, FastAPI/starlette will NOT allow "*"; it must be
35
+ # an explicit list. We default credentials off for a true allow-all stance.
36
+ # - We also allow all methods/headers and expose all headers.
37
+ app.add_middleware(
38
+ CORSMiddleware,
39
+ allow_origins=["*"],
40
+ allow_credentials=False,
41
+ allow_methods=["*"],
42
+ allow_headers=["*"],
43
+ expose_headers=["*"],
44
+ max_age=86400,
45
+ )
46
+ app.include_router(api_v001)
47
+
48
+ # Guard error logging middleware to avoid double-send issues under certain ASGI flows
49
+ if os.getenv("ENABLE_ERROR_LOG_MW", "0").lower() in ("1", "true", "yes", "on"):
50
+ @app.middleware("http")
51
+ async def error_logging_middleware(request: Request, call_next):
52
+ try:
53
+ response = await call_next(request)
54
+ except Exception:
55
+ logger.exception("Unhandled exception: %s %s", request.method, request.url.path)
56
+ raise
57
+ if response.status_code >= 400:
58
+ logger.error("Request failed: %s %s -> %d", request.method, request.url.path, response.status_code)
59
+ return response
60
+
61
+ def startAppServer():
62
+ host = COMMON.HOST
63
+ port = COMMON.API_PORT
64
+ log_level = COMMON.log_level
65
+
66
+ # Use an import string that points to this module's app object
67
+ import_string = "restapi_mcp_server.__main__:app"
68
+
69
+ # Disable reload by default in container to avoid multi-process duplication issues
70
+ # Enable via UVICORN_RELOAD=1 if needed for local dev
71
+ reload_flag = os.getenv("UVICORN_RELOAD", "0").lower() in ("1", "true", "yes", "on")
72
+
73
+ uvicorn.run(
74
+ import_string,
75
+ host=host,
76
+ port=port,
77
+ log_level=log_level,
78
+ reload=reload_flag,
79
+ reload_dirs=["."] if reload_flag else None,
80
+ proxy_headers=False,
81
+ workers=1,
82
+ )
83
+
84
+
85
+ def startStaticIndexServer():
86
+ """Serve only index.html on a dedicated port (default :5500).
87
+
88
+ This keeps the FastAPI/Uvicorn port unchanged while allowing a simple UI server
89
+ suitable for local use and Docker.
90
+ """
91
+
92
+ ui_host = os.getenv("UI_HOST", "0.0.0.0")
93
+ ui_port = int(os.getenv("UI_PORT", "5500"))
94
+
95
+ index_path = Path(__file__).resolve().parent / "static" / "index.html"
96
+ if not index_path.exists():
97
+ logger.warning("[UI] index.html not found at %s; UI server will not start", index_path)
98
+ return
99
+
100
+ index_bytes = index_path.read_bytes()
101
+
102
+ class _IndexOnlyHandler(BaseHTTPRequestHandler):
103
+ def do_GET(self): # noqa: N802 (stdlib naming)
104
+ # Serve index for / or /index.html; 404 for everything else.
105
+ if self.path in ("/", "/index.html"):
106
+ self.send_response(200)
107
+ self.send_header("Content-Type", "text/html; charset=utf-8")
108
+ self.send_header("Content-Length", str(len(index_bytes)))
109
+ self.end_headers()
110
+ self.wfile.write(index_bytes)
111
+ return
112
+
113
+ self.send_response(404)
114
+ self.send_header("Content-Type", "text/plain; charset=utf-8")
115
+ self.end_headers()
116
+ self.wfile.write(b"Not Found")
117
+
118
+ def log_message(self, format, *args): # noqa: N802 (stdlib naming)
119
+ # Route http.server logs through our logger (info level)
120
+ logger.info("[UI] %s - %s", self.address_string(), format % args)
121
+
122
+ def _run():
123
+ try:
124
+ httpd = ThreadingHTTPServer((ui_host, ui_port), _IndexOnlyHandler)
125
+ logger.info("[UI] Serving %s on http://%s:%d", index_path, ui_host, ui_port)
126
+ httpd.serve_forever()
127
+ except OSError as e:
128
+ logger.error("[UI] Failed to start UI server on %s:%d: %s", ui_host, ui_port, e)
129
+ except Exception:
130
+ logger.exception("[UI] UI server crashed")
131
+
132
+ threading.Thread(target=_run, name="ui-5500", daemon=True).start()
133
+
134
+ def createMCPServerWithTools():
135
+
136
+ mcp_host: str = COMMON.HOST
137
+ mcp_port: int = COMMON.MCP_API_PORT
138
+ # Allow overriding the orchestrator base URL (default stays local for dev)
139
+ # Set env var RESTAPI_ORCHESTRATOR_BASE (or ORCHESTRATOR_BASE) to target a remote host
140
+ API_BASE: str = os.getenv("RESTAPI_ORCHESTRATOR_BASE") or f"http://127.0.0.1:{COMMON.API_PORT}"
141
+ logger.info(f"[MCP] Orchestrator base: {API_BASE}")
142
+ mcp = FastMCP("restapi_orchestrator_tools", host=mcp_host, port=mcp_port)
143
+
144
+ @mcp.tool()
145
+ def createSession() -> Dict[str, Any]:
146
+ """Create a new session id.
147
+ Returns: { "session": string }
148
+ """
149
+ with httpx.Client(timeout=30.0) as client:
150
+ r = client.post(f"{API_BASE}/api/v001/session/createSession")
151
+ r.raise_for_status()
152
+ return r.json()
153
+
154
+ @mcp.tool()
155
+ def createEnvironmentVariables(items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
156
+ """Upsert environment variables via REST API.
157
+
158
+ Endpoint: PUT /api/v001/variables/upsertEnvironmentVariable
159
+ Input: items: list of { "environment": str, "variable": str, "value": Any }
160
+ Returns: list of upserted items (echoed from API)
161
+ """
162
+ results: List[Dict[str, Any]] = []
163
+ with httpx.Client(timeout=30.0) as client:
164
+ for it in items:
165
+ r = client.put(f"{API_BASE}/api/v001/variables/upsertEnvironmentVariable", json=it)
166
+ r.raise_for_status()
167
+ results.append(r.json())
168
+ return results
169
+
170
+ @mcp.tool()
171
+ def upsertEnvironmentVariable(environment: str, variable: str, value: Any) -> Dict[str, Any]:
172
+ """Upsert a single environment variable via REST API.
173
+
174
+ Endpoint: PUT /api/v001/variables/upsertEnvironmentVariable
175
+ Inputs:
176
+ - environment: target environment name
177
+ - variable: variable name
178
+ - value: variable value (any JSON-serializable type)
179
+ Returns: { environment, variable, value }
180
+ """
181
+ payload: Dict[str, Any] = {
182
+ "environment": environment,
183
+ "variable": variable,
184
+ "value": value,
185
+ }
186
+ with httpx.Client(timeout=30.0) as client:
187
+ r = client.put(
188
+ f"{API_BASE}/api/v001/variables/upsertEnvironmentVariable",
189
+ json=payload,
190
+ )
191
+ r.raise_for_status()
192
+ return r.json()
193
+
194
+ @mcp.tool()
195
+ def listAllEnvironmentVariables(environment: str) -> List[Dict[str, Any]]:
196
+ """List all variables for the given environment.
197
+ Returns: array of { environment, variable, value }
198
+ """
199
+ with httpx.Client(timeout=30.0) as client:
200
+ r = client.get(
201
+ f"{API_BASE}/api/v001/variables/listAllEnvironmentVariables", params={"environment": environment}
202
+ )
203
+ r.raise_for_status()
204
+ return r.json()
205
+
206
+ @mcp.tool()
207
+ def listSpecificEnvironmentVariable(environment: str, variable: str) -> List[Dict[str, Any]]:
208
+ """Get a specific environment variable.
209
+ Returns: { environment, variable, value }
210
+ """
211
+ with httpx.Client(timeout=30.0) as client:
212
+ r = client.get(
213
+ f"{API_BASE}/api/v001/variables/listSpecificVariableByEnvironment",
214
+ params={"environment": environment, "variable": variable},
215
+ )
216
+ r.raise_for_status()
217
+ return r.json()
218
+
219
+ @mcp.tool()
220
+ def deleteAllByEnvironment(environment: str) -> Dict[str, Any]:
221
+ """Delete all variables for the given environment via REST API.
222
+
223
+ Endpoint: DELETE /api/v001/variables/deleteAllByEnvironment
224
+ Returns: { environment, deletedCount }
225
+ """
226
+ with httpx.Client(timeout=30.0) as client:
227
+ r = client.delete(
228
+ f"{API_BASE}/api/v001/variables/deleteAllByEnvironment",
229
+ params={"environment": environment},
230
+ )
231
+ r.raise_for_status()
232
+ return r.json()
233
+
234
+ @mcp.tool()
235
+ def health() -> Dict[str, Any]:
236
+ """Check API health.
237
+
238
+ Endpoint: GET /api/v001/health
239
+ Returns: {"status": "ok"} on healthy server.
240
+ """
241
+ with httpx.Client(timeout=10.0) as client:
242
+ r = client.get(f"{API_BASE}/api/v001/health")
243
+ r.raise_for_status()
244
+ return r.json()
245
+
246
+ @mcp.tool()
247
+ def createRestAPICall(
248
+ method: str,
249
+ url: str,
250
+ action: str,
251
+ environment: str,
252
+ session: str,
253
+ request_headers: Dict[str, Any] | None = None,
254
+ request_body: Any | None = None,
255
+ request_form_data: Dict[str, Any] | None = None,
256
+ request_files: List[Dict[str, Any]] | None = None,
257
+ pre_script: Any | None = None,
258
+ post_script: Any | None = None,
259
+ debug: bool | None = None,
260
+ ) -> Dict[str, Any]:
261
+ """Call the RestAPI Orchestrator HTTP endpoint.
262
+
263
+ Endpoint: POST /api/v001/restapi/call
264
+
265
+ Inputs:
266
+ - method: HTTP method (GET, POST, PUT, PATCH, DELETE)
267
+ - url: Target URL (supports variable/base64/jq interpolation server-side)
268
+ - action: Logical action name for transaction logging
269
+ - environment: Environment name
270
+ - session: Session identifier
271
+ - request_headers: Optional headers map (values may use interpolation syntax)
272
+ - request_body: Optional JSON body (values may use interpolation syntax)
273
+ - request_form_data: Optional form fields map for x-www-form-urlencoded or multipart requests
274
+ - request_files: Optional list of file parts. Each item: {field_name, filename, content_type?, content}
275
+ - pre_script: Reserved (not used currently)
276
+ - post_script: Optional dict of {"{{VARIABLE_NAME}}": "expression"}; evaluated on 2xx/3xx status
277
+ - debug: Optional flag
278
+
279
+ Returns: { response_status, response_headers, response_body }
280
+ """
281
+ payload: Dict[str, Any] = {
282
+ "method": method,
283
+ "url": url,
284
+ "action": action,
285
+ "environment": environment,
286
+ "session": session,
287
+ }
288
+ if request_headers is not None:
289
+ payload["request_headers"] = request_headers
290
+ if request_body is not None:
291
+ payload["request_body"] = request_body
292
+ if request_form_data is not None:
293
+ payload["request_form_data"] = request_form_data
294
+ if request_files is not None:
295
+ payload["request_files"] = request_files
296
+ if pre_script is not None:
297
+ payload["pre_script"] = pre_script
298
+ if post_script is not None:
299
+ payload["post_script"] = post_script
300
+ if debug is not None:
301
+ payload["debug"] = bool(debug)
302
+
303
+ with httpx.Client(timeout=60.0) as client:
304
+ r = client.post(f"{API_BASE}/api/v001/restapi/call", json=payload)
305
+ r.raise_for_status()
306
+ return r.json()
307
+
308
+ def _run_mcp_in_thread():
309
+ try:
310
+ loop = asyncio.new_event_loop()
311
+ asyncio.set_event_loop(loop)
312
+ mcp.run(transport="sse")
313
+ except Exception as e:
314
+ print(f"[MCP] MCP server thread exited: {e}")
315
+
316
+ thread = threading.Thread(target=_run_mcp_in_thread, name="mcp-sse", daemon=True)
317
+ thread.start()
318
+
319
+ def main():
320
+ load_common_from_env()
321
+ global logger
322
+ logger = setup_logging()
323
+ startStaticIndexServer()
324
+ createMCPServerWithTools()
325
+ startAppServer()
326
+
327
+ if __name__ == "__main__":
328
+ main()
@@ -0,0 +1,17 @@
1
+ from fastapi import APIRouter
2
+ from .v0_0_1.routes.bas64interpolationRoute import router as b64_router
3
+ from .v0_0_1.routes.sessionRoute import router as session_router
4
+ from .v0_0_1.routes.jqRoute import router as jq_router
5
+ from .v0_0_1.routes.variablesRoute import router as variable_router
6
+ from .v0_0_1.routes.transactionRoute import router as transaction_router
7
+ from .v0_0_1.routes.restapiRoute import router as restapi_router
8
+ from .v0_0_1.routes.healthRouter import router as health_router
9
+
10
+ api_v001 = APIRouter(prefix="/api/v001")
11
+ api_v001.include_router(health_router)
12
+ api_v001.include_router(b64_router)
13
+ api_v001.include_router(session_router)
14
+ api_v001.include_router(jq_router)
15
+ api_v001.include_router(variable_router)
16
+ api_v001.include_router(transaction_router)
17
+ api_v001.include_router(restapi_router)
@@ -0,0 +1,7 @@
1
+ """
2
+ API version 0.0.1 (import-safe package v0_0_1)
3
+
4
+ This file marks the directory as a Python package to ensure reliable imports:
5
+ from .v0_0_1.routes.bas64interpolationRoute import router
6
+ """
7
+ __all__ = []
@@ -0,0 +1,57 @@
1
+ """
2
+ Base64 encode/decode routes.
3
+
4
+ Endpoints:
5
+ - POST /base64/encode
6
+ Encode plain text to Base64.
7
+
8
+ - POST /base64/decode
9
+ Decode a Base64-encoded string to plain text.
10
+ """
11
+ from fastapi import APIRouter, HTTPException
12
+ from ....models.bas64interpolationSchema import (
13
+ Base64EncodeIn,
14
+ Base64EncodeOut,
15
+ Base64DecodeIn,
16
+ Base64DecodeOut,
17
+ )
18
+ from ....utils.bas64interpolation import encode_base64, decode_base64
19
+
20
+ # Router for Base64 operations
21
+ router = APIRouter(prefix="/base64", tags=["Base64"])
22
+
23
+ @router.post("/encode", response_model=Base64EncodeOut)
24
+ def base64_encode(payload: Base64EncodeIn):
25
+ """
26
+ Encode plain text to a Base64 string.
27
+
28
+ Request body (Base64EncodeIn):
29
+ - text: Plain text to encode.
30
+
31
+ Returns:
32
+ Base64EncodeOut with 'encoded' containing the Base64 string.
33
+ """
34
+ try:
35
+ base64_encoded_str = encode_base64(text=payload.text)
36
+ response_payload = Base64EncodeOut(encoded=base64_encoded_str)
37
+ return response_payload
38
+ except Exception as e:
39
+ raise HTTPException(status_code=400, detail=str(e))
40
+
41
+ @router.post("/decode", response_model=Base64DecodeOut)
42
+ def base64_decode(payload: Base64DecodeIn):
43
+ """
44
+ Decode a Base64 string to plain text.
45
+
46
+ Request body (Base64DecodeIn):
47
+ - encodedString: Base64-encoded string to decode.
48
+
49
+ Returns:
50
+ Base64DecodeOut with 'text' containing the decoded plain text.
51
+ """
52
+ try:
53
+ base64_decoded_str = decode_base64(b64_text=payload.encodedString)
54
+ response_payload = Base64DecodeOut(text=base64_decoded_str)
55
+ return response_payload
56
+ except Exception as e:
57
+ raise HTTPException(status_code=400, detail=str(e))
@@ -0,0 +1,7 @@
1
+ from fastapi import APIRouter
2
+
3
+ router = APIRouter(tags=["Health"])
4
+
5
+ @router.get("/health")
6
+ def health_env():
7
+ return {"status": "ok"}
@@ -0,0 +1,29 @@
1
+ """
2
+ JQ expression evaluation routes.
3
+
4
+ Endpoints:
5
+ - POST /jq/eval
6
+ Evaluate a JQ expression against supplied JSON input.
7
+ """
8
+ from fastapi import APIRouter, HTTPException
9
+ from ....utils import jqinterpolation
10
+ from ....models.jqSchema import JQExpressionIn, JQExpressionOut
11
+
12
+ router = APIRouter(prefix="/jq", tags=["JQ"])
13
+
14
+ @router.post("/eval", response_model=JQExpressionOut)
15
+ def jq_expression_evaluation(payload: JQExpressionIn):
16
+ """
17
+ Evaluate a JQ expression against provided JSON input.
18
+
19
+ Request body (JQExpressionIn):
20
+ - expression: JQ expression string to evaluate.
21
+ - data: JSON input object/array the expression applies to.
22
+
23
+ Returns:
24
+ JQExpressionOut: Pydantic model with 'result' containing the evaluation output.
25
+ """
26
+ try:
27
+ return JQExpressionOut(result=jqinterpolation.jqinterpolate(expression=payload.expression,json_input=payload.data))
28
+ except Exception as e:
29
+ raise HTTPException(status_code=400, detail=str(e))