Skip to content

Commit 0425d82

Browse files
committed
Merge remote-tracking branch 'origin/main' into 425-SECURITYFEATURE
2 parents 4c48203 + c0c12f4 commit 0425d82

File tree

8 files changed

+373
-146
lines changed

8 files changed

+373
-146
lines changed

.env.example

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,12 @@ CORS_ENABLED=true
134134
#####################################
135135

136136
RETRY_MAX_ATTEMPTS=3
137-
RETRY_BASE_DELAY=1.0 # seconds
138-
RETRY_MAX_DELAY=60.0 # seconds
139-
RETRY_JITTER_MAX=0.5 # fraction of delay
137+
# seconds
138+
RETRY_BASE_DELAY=1.0
139+
# seconds
140+
RETRY_MAX_DELAY=60.0
141+
# fraction of delay
142+
RETRY_JITTER_MAX=0.5
140143

141144
#####################################
142145
# Logging
@@ -256,9 +259,8 @@ UNHEALTHY_THRESHOLD=3
256259

257260
# This path is append with the system temp directory.
258261
# It is used to ensure that only one instance of the gateway health Check can run at a time.
259-
FILELOCK_NAME=gateway_healthcheck_init.lock # saved dir in /tmp/gateway_healthcheck_init.lock
260-
# FILELOCK_NAME=somefolder/gateway_healthcheck_init.lock # saved dir in /tmp/somefolder/gateway_healthcheck_init.lock#
261-
262+
# saved dir in /tmp/gateway_healthcheck_init.lock
263+
FILELOCK_NAME=gateway_healthcheck_init.lock
262264

263265
#####################################
264266
# Development Settings

Makefile

Lines changed: 103 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,10 @@ clean:
223223
## --- Automated checks --------------------------------------------------------
224224
smoketest:
225225
@echo "🚀 Running smoketest..."
226-
@./smoketest.py --verbose || { echo "❌ Smoketest failed!"; exit 1; }
227-
@echo "✅ Smoketest passed!"
226+
@bash -c '\
227+
./smoketest.py --verbose || { echo "❌ Smoketest failed!"; exit 1; }; \
228+
echo "✅ Smoketest passed!" \
229+
'
228230

229231
test:
230232
@echo "🧪 Running tests..."
@@ -1194,7 +1196,7 @@ endef
11941196

11951197
# Containerfile to use (can be overridden)
11961198
#CONTAINER_FILE ?= Containerfile
1197-
CONTAINER_FILE ?= $(shell [ -f "Containerfile" ] && echo "Containerfile" || echo "Dockerfile")
1199+
CONTAINER_FILE ?= $(shell [ -f "Containerfile.lite" ] && echo "Containerfile.lite" || echo "Dockerfile")
11981200

11991201

12001202
# Define COMMA for the conditional Z flag
@@ -1267,6 +1269,7 @@ container-run-ssl: certs container-check-image
12671269
-$(CONTAINER_RUNTIME) stop $(PROJECT_NAME) 2>/dev/null || true
12681270
-$(CONTAINER_RUNTIME) rm $(PROJECT_NAME) 2>/dev/null || true
12691271
$(CONTAINER_RUNTIME) run --name $(PROJECT_NAME) \
1272+
-u $(id -u):$(id -g) \
12701273
--env-file=.env \
12711274
-e SSL=true \
12721275
-e CERT_FILE=certs/cert.pem \
@@ -1287,6 +1290,7 @@ container-run-ssl-host: certs container-check-image
12871290
-$(CONTAINER_RUNTIME) stop $(PROJECT_NAME) 2>/dev/null || true
12881291
-$(CONTAINER_RUNTIME) rm $(PROJECT_NAME) 2>/dev/null || true
12891292
$(CONTAINER_RUNTIME) run --name $(PROJECT_NAME) \
1293+
-u $(id -u):$(id -g) \
12901294
--network=host \
12911295
--env-file=.env \
12921296
-e SSL=true \
@@ -2775,47 +2779,112 @@ shfmt-fix: shell-linters-install ## 🎨 Auto-format *.sh in place
27752779
# =============================================================================
27762780
# help: 🛢️ ALEMBIC DATABASE MIGRATIONS
27772781
# help: alembic-install - Install Alembic CLI (and SQLAlchemy) in the current env
2778-
# help: db-new - Create a new migration (override with MSG="your title")
2779-
# help: db-up - Upgrade DB to the latest revision (head)
2780-
# help: db-down - Downgrade one revision (override with REV=<id|steps>)
2781-
# help: db-current - Show the current head revision for the database
2782-
# help: db-history - Show the full migration graph / history
2783-
# help: db-revision-id - Echo just the current revision id (handy for scripting)
2782+
# help: db-init - Initialize alembic migrations
2783+
# help: db-migrate - Create a new migration
2784+
# help: db-upgrade - Upgrade database to latest migration
2785+
# help: db-downgrade - Downgrade database by one revision
2786+
# help: db-current - Show current database revision
2787+
# help: db-history - Show migration history
2788+
# help: db-heads - Show available heads
2789+
# help: db-show - Show a specific revision
2790+
# help: db-stamp - Stamp database with a specific revision
2791+
# help: db-reset - Reset database (CAUTION: drops all data)
2792+
# help: db-status - Show detailed database status
2793+
# help: db-check - Check if migrations are up to date
2794+
# help: db-fix-head - Fix multiple heads issue
27842795
# -----------------------------------------------------------------------------
27852796

2786-
# ──────────────────────────
2787-
# Internals & defaults
2788-
# ──────────────────────────
2789-
ALEMBIC ?= alembic # Override to e.g. `poetry run alembic`
2790-
MSG ?= "auto migration"
2791-
REV ?= -1 # Default: one step down; can be hash, -n, +n, etc.
2797+
# Database migration commands
2798+
ALEMBIC_CONFIG = mcpgateway/alembic.ini
27922799

2793-
.PHONY: alembic-install db-new db-up db-down db-current db-history db-revision-id
2800+
.PHONY: alembic-install db-init db-migrate db-upgrade db-downgrade db-current db-history db-heads db-show db-stamp db-reset db-status db-check db-fix-head
27942801

27952802
alembic-install:
27962803
@echo "➜ Installing Alembic ..."
27972804
pip install --quiet alembic sqlalchemy
27982805

2799-
db-new:
2800-
@echo "➜ Generating revision: $(MSG)"
2801-
$(ALEMBIC) -c mcpgateway/alembic.ini revision --autogenerate -m $(MSG)
2802-
2803-
db-up:
2804-
@echo "➜ Upgrading database to head ..."
2805-
$(ALEMBIC) -c mcpgateway/alembic.ini upgrade head
2806-
2807-
db-down:
2808-
@echo "➜ Downgrading database → $(REV) ..."
2809-
$(ALEMBIC) -c mcpgateway/alembic.ini downgrade $(REV)
2810-
2811-
db-current:
2812-
$(ALEMBIC) -c mcpgateway/alembic.ini current
2806+
.PHONY: db-init
2807+
db-init: ## Initialize alembic migrations
2808+
@echo "🗄️ Initializing database migrations..."
2809+
alembic -c $(ALEMBIC_CONFIG) init alembic
2810+
2811+
.PHONY: db-migrate
2812+
db-migrate: ## Create a new migration
2813+
@echo "�️ Creating new migration..."
2814+
@read -p "Enter migration message: " msg; \
2815+
alembic -c $(ALEMBIC_CONFIG) revision --autogenerate -m "$$msg"
2816+
2817+
.PHONY: db-upgrade
2818+
db-upgrade: ## Upgrade database to latest migration
2819+
@echo "🗄️ Upgrading database..."
2820+
alembic -c $(ALEMBIC_CONFIG) upgrade head
2821+
2822+
.PHONY: db-downgrade
2823+
db-downgrade: ## Downgrade database by one revision
2824+
@echo "�️ Downgrading database..."
2825+
alembic -c $(ALEMBIC_CONFIG) downgrade -1
2826+
2827+
.PHONY: db-current
2828+
db-current: ## Show current database revision
2829+
@echo "🗄️ Current database revision:"
2830+
@alembic -c $(ALEMBIC_CONFIG) current
2831+
2832+
.PHONY: db-history
2833+
db-history: ## Show migration history
2834+
@echo "🗄️ Migration history:"
2835+
@alembic -c $(ALEMBIC_CONFIG) history
2836+
2837+
.PHONY: db-heads
2838+
db-heads: ## Show available heads
2839+
@echo "�️ Available heads:"
2840+
@alembic -c $(ALEMBIC_CONFIG) heads
2841+
2842+
.PHONY: db-show
2843+
db-show: ## Show a specific revision
2844+
@read -p "Enter revision ID: " rev; \
2845+
alembic -c $(ALEMBIC_CONFIG) show $$rev
2846+
2847+
.PHONY: db-stamp
2848+
db-stamp: ## Stamp database with a specific revision
2849+
@read -p "Enter revision to stamp: " rev; \
2850+
alembic -c $(ALEMBIC_CONFIG) stamp $$rev
2851+
2852+
.PHONY: db-reset
2853+
db-reset: ## Reset database (CAUTION: drops all data)
2854+
@echo "⚠️ WARNING: This will drop all data!"
2855+
@read -p "Are you sure? (y/N): " confirm; \
2856+
if [ "$$confirm" = "y" ]; then \
2857+
alembic -c $(ALEMBIC_CONFIG) downgrade base && \
2858+
alembic -c $(ALEMBIC_CONFIG) upgrade head; \
2859+
echo "✅ Database reset complete"; \
2860+
else \
2861+
echo "❌ Database reset cancelled"; \
2862+
fi
28132863

2814-
db-history:
2815-
$(ALEMBIC) -c mcpgateway/alembic.ini history --verbose
2864+
.PHONY: db-status
2865+
db-status: ## Show detailed database status
2866+
@echo "�️ Database Status:"
2867+
@echo "Current revision:"
2868+
@alembic -c $(ALEMBIC_CONFIG) current
2869+
@echo ""
2870+
@echo "Pending migrations:"
2871+
@alembic -c $(ALEMBIC_CONFIG) history -r current:head
2872+
2873+
.PHONY: db-check
2874+
db-check: ## Check if migrations are up to date
2875+
@echo "🗄️ Checking migration status..."
2876+
@if alembic -c $(ALEMBIC_CONFIG) current | grep -q "(head)"; then \
2877+
echo "✅ Database is up to date"; \
2878+
else \
2879+
echo "⚠️ Database needs migration"; \
2880+
echo "Run 'make db-upgrade' to apply pending migrations"; \
2881+
exit 1; \
2882+
fi
28162883

2817-
db-revision-id:
2818-
@$(ALEMBIC) -c mcpgateway/alembic.ini current --verbose | awk '/Current revision/ {print $$3}'
2884+
.PHONY: db-fix-head
2885+
db-fix-head: ## Fix multiple heads issue
2886+
@echo "�️ Fixing multiple heads..."
2887+
alembic -c $(ALEMBIC_CONFIG) merge -m "merge heads"
28192888

28202889

28212890
# =============================================================================

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,20 @@ You can get started by copying the provided [.env.example](.env.example) to `.en
10941094

10951095
> 🧠 `none` disables caching entirely. Use `memory` for dev, `database` for persistence, or `redis` for distributed caching.
10961096

1097+
### Database Management
1098+
1099+
MCP Gateway uses Alembic for database migrations. Common commands:
1100+
1101+
- `make db-current` - Show current database version
1102+
- `make db-upgrade` - Apply pending migrations
1103+
- `make db-migrate` - Create new migration
1104+
- `make db-history` - Show migration history
1105+
- `make db-status` - Detailed migration status
1106+
1107+
#### Troubleshooting
1108+
1109+
If you see "No 'script_location' key found", ensure you're running from the project root directory.
1110+
10971111
### Development
10981112

10991113
| Setting | Description | Default | Options |

mcpgateway/static/admin.js

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3022,50 +3022,73 @@ function updateEditToolRequestTypes(selectedMethod = null) {
30223022
// TOOL SELECT FUNCTIONALITY
30233023
// ===================================================================
30243024

3025-
function initToolSelect(selectId, pillsId, warnId, max = 6) {
3026-
const select = safeGetElement(selectId);
3027-
const pillsBox = safeGetElement(pillsId);
3028-
const warnBox = safeGetElement(warnId);
3025+
function initToolSelect(
3026+
selectId,
3027+
pillsId,
3028+
warnId,
3029+
max = 6,
3030+
selectBtnId = null,
3031+
clearBtnId = null,
3032+
) {
3033+
const container = document.getElementById(selectId);
3034+
const pillsBox = document.getElementById(pillsId);
3035+
const warnBox = document.getElementById(warnId);
3036+
const clearBtn = clearBtnId ? document.getElementById(clearBtnId) : null;
3037+
const selectBtn = selectBtnId ? document.getElementById(selectBtnId) : null;
30293038

3030-
if (!select || !pillsBox || !warnBox) {
3039+
if (!container || !pillsBox || !warnBox) {
30313040
console.warn(
30323041
`Tool select elements not found: ${selectId}, ${pillsId}, ${warnId}`,
30333042
);
30343043
return;
30353044
}
30363045

3046+
const checkboxes = container.querySelectorAll('input[type="checkbox"]');
30373047
const pillClasses =
3038-
"inline-block px-2 py-1 text-xs font-medium text-blue-800 bg-blue-100 rounded";
3048+
"inline-block px-3 py-1 text-xs font-semibold text-indigo-700 bg-indigo-100 rounded-full shadow";
30393049

30403050
function update() {
30413051
try {
3042-
const chosen = Array.from(select.selectedOptions);
3043-
const count = chosen.length;
3052+
const checked = Array.from(checkboxes).filter((cb) => cb.checked);
3053+
const count = checked.length;
30443054

30453055
// Rebuild pills safely
30463056
pillsBox.innerHTML = "";
3047-
chosen.forEach((opt) => {
3057+
checked.forEach((cb) => {
30483058
const span = document.createElement("span");
30493059
span.className = pillClasses;
3050-
span.textContent = opt.text; // Safe text content
3060+
span.textContent =
3061+
cb.nextElementSibling?.textContent?.trim() || "Unnamed";
30513062
pillsBox.appendChild(span);
30523063
});
30533064

30543065
// Warning when > max
30553066
if (count > max) {
30563067
warnBox.textContent = `Selected ${count} tools. Selecting more than ${max} tools can degrade agent performance with the server.`;
3057-
warnBox.className = "text-yellow-600 text-sm mt-2";
30583068
} else {
30593069
warnBox.textContent = "";
3060-
warnBox.className = "";
30613070
}
30623071
} catch (error) {
30633072
console.error("Error updating tool select:", error);
30643073
}
30653074
}
30663075

3076+
if (clearBtn) {
3077+
clearBtn.addEventListener("click", () => {
3078+
checkboxes.forEach((cb) => (cb.checked = false));
3079+
update();
3080+
});
3081+
}
3082+
3083+
if (selectBtn) {
3084+
selectBtn.addEventListener("click", () => {
3085+
checkboxes.forEach((cb) => (cb.checked = true));
3086+
update();
3087+
});
3088+
}
3089+
30673090
update(); // Initial render
3068-
select.addEventListener("change", update);
3091+
checkboxes.forEach((cb) => cb.addEventListener("change", update));
30693092
}
30703093

30713094
// ===================================================================
@@ -4415,8 +4438,12 @@ async function handleEditToolFormSubmit(event) {
44154438

44164439
// // Save CodeMirror editors' contents if present
44174440

4418-
if (window.editToolHeadersEditor) window.editToolHeadersEditor.save();
4419-
if (window.editToolSchemaEditor) window.editToolSchemaEditor.save();
4441+
if (window.editToolHeadersEditor) {
4442+
window.editToolHeadersEditor.save();
4443+
}
4444+
if (window.editToolSchemaEditor) {
4445+
window.editToolSchemaEditor.save();
4446+
}
44204447

44214448
const isInactiveCheckedBool = isInactiveChecked("tools");
44224449
formData.append("is_inactive_checked", isInactiveCheckedBool);
@@ -4428,7 +4455,7 @@ async function handleEditToolFormSubmit(event) {
44284455
headers: { "X-Requested-With": "XMLHttpRequest" },
44294456
});
44304457
console.log("response:", response);
4431-
result = await response.json();
4458+
const result = await response.json();
44324459
console.log("result edit tool form:", result);
44334460
if (!result.success) {
44344461
throw new Error(result.message || "An error occurred");
@@ -4838,12 +4865,16 @@ function initializeToolSelects() {
48384865
"selectedToolsPills",
48394866
"selectedToolsWarning",
48404867
6,
4868+
"selectAllToolsBtn",
4869+
"clearAllToolsBtn",
48414870
);
48424871
initToolSelect(
48434872
"edit-server-tools",
48444873
"selectedEditToolsPills",
48454874
"selectedEditToolsWarning",
48464875
6,
4876+
"selectAllEditToolsBtn",
4877+
"clearAllEditToolsBtn",
48474878
);
48484879
}
48494880

0 commit comments

Comments
 (0)