feat: API endpoint is served under the /v1 prefix#4403
feat: API endpoint is served under the /v1 prefix#4403Lang-Akshay wants to merge 14 commits intomainfrom
/v1 prefix#4403Conversation
c8e7d17 to
77af9dd
Compare
cfeb057 to
d190e69
Compare
msureshkumar88
left a comment
There was a problem hiding this comment.
Request Changes - PR #4403
Summary
This PR implements API versioning under /v1 prefix with excellent architecture and comprehensive test coverage. However, there are 1 CRITICAL and 2 MEDIUM priority issues that must be addressed before merging.
🚨 CRITICAL Issues (Must Fix)
1. Breaking Change Without Backward Compatibility
Location: mcpgateway/main.py:11544
Problem: This PR introduces an immediate breaking change for all external API consumers. Any client using unversioned endpoints (e.g., /tools, /servers, /gateways) will break immediately upon deployment.
Required Action: Implement a backward compatibility layer with deprecation warnings:
# In main.py after line 11544
# Mount v1_router at both /v1 (new) and root (deprecated)
app.include_router(v1_router) # /v1/* (new canonical path)
# Temporary compatibility layer - remove in v2.0.0
app.include_router(v1_router, prefix="") # /* (deprecated, for backward compatibility)
# Add deprecation warning middleware for unversioned paths
# Log warnings when clients use deprecated unversioned endpointsAdditional Requirements:
- Add
MIGRATION.mddocumenting the breaking change and migration path - Update
CHANGELOG.mdwith breaking change notice - Add deprecation timeline (e.g., "unversioned endpoints deprecated, will be removed in v2.0.0")
- Ensure all security middleware applies to both
/v1/*and/*paths
⚠️ MEDIUM Issues (Should Fix)
2. Duplicated Path Normalization Logic
Location: mcpgateway/middleware/token_scoping.py:243-250 and 345-352
Problem: Path normalization logic for stripping /v1 prefix is duplicated in two functions (_normalize_llm_api_prefix() and _normalize_path_for_matching()), creating maintenance burden and potential inconsistencies.
Required Action: Consolidate into a single shared utility function:
def _normalize_api_path(path: str) -> str:
"""Strip /v1 prefix for consistent pattern matching across middleware."""
if path.startswith("/v1/"):
return path[3:]
if path == "/v1":
return "/"
return path
# Then update both functions to use this shared utility3. Missing API Version Discovery Endpoint
Location: mcpgateway/api/v1/__init__.py:273
Problem: No endpoint exists for clients to programmatically discover the API version, making it difficult for clients to adapt to versioning changes.
Required Action: Add version discovery endpoint:
# In build_v1_router() after creating v1_router (line 73)
@v1_router.get("/version", tags=["Version"])
async def get_api_version():
"""Return current API version information."""
return {
"version": "v1",
"deprecated": False,
"deprecation_date": None,
"sunset_date": None
}📋 Additional Recommendations (Optional)
Test Coverage Gap
Add explicit test verifying unversioned routes remain unversioned:
def test_unversioned_routes_remain_unversioned():
"""Verify RFC well-known, OAuth, health remain at root."""
assert client.get("/.well-known/openid-configuration").status_code != 404
assert client.get("/oauth/authorize").status_code != 404
assert client.get("/health").status_code == 200Documentation
- Update OpenAPI schema to reflect
/v1prefix in all endpoint paths - Add API versioning policy to project documentation
✅ What's Working Well
- Excellent centralized router architecture
- Comprehensive test coverage (194 files updated)
- Proper security middleware updates
- Clean separation of versioned vs unversioned routes
- No security regressions identified
🎯 Merge Criteria
Cannot merge until:
- ✅ Backward compatibility layer implemented
- ✅ Migration documentation added (
MIGRATION.md,CHANGELOG.md) - ✅ Path normalization logic consolidated
- ✅ Version discovery endpoint added
Estimated effort: 2-4 hours to address all issues
Review Status: 🔴 REQUEST CHANGES
Risk Level: 🟡 MEDIUM (Technical: LOW, Business: MEDIUM due to breaking change)
msureshkumar88
left a comment
There was a problem hiding this comment.
As mentioned in the comments
…pace package Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
- Updated test cases in to change API paths from and to and . - Modified pagination tests in to reflect new API paths with versioning. - Adjusted proxy authentication tests in to use and . - Changed credential verification tests in to redirect to . Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
- Updated all instances of /v1/servers/{id}/mcp to /servers/{id}/mcp in test cases.
- Ensured consistency across tests for authentication and authorization checks.
- Adjusted related test assertions to reflect the new endpoint structure.
Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
- Updated various service and router files to remove the /v1 prefix from API paths. - Adjusted tests to reflect the new endpoint structure without versioning. - Ensured that all references to admin routes are updated to include the new path format. - Modified the metrics endpoint to return data without the version prefix. - Cleaned up related tests to ensure they align with the new routing structure. Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…baseline refactor: reorder logging import in alembic env.py fix: add comment for first-party import in audit_trail_service.py cleanup: remove merge conflict markers in resource_service.py refactor: add first-party comment in context.py refactor: add blank line after import in streamablehttp_transport.py docs: enhance API endpoint organization documentation in plan.md chmod: update permissions for update_test_paths.py script Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…API paths to include versioning in tests Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…rage - Implement tests for legacy /admin/* paths to ensure they trigger admin auth checks. - Ensure /admin/login remains exempt from authentication. - Add tests for browser and HTMX request redirects when unauthenticated admin is enabled. - Introduce tests for token scoping and cancellation router functionalities. - Enhance audit trail service tests to handle identity extraction failures gracefully. - Add email auth service tests for forgot and reset password URL constructions. - Introduce comprehensive tests for the v1 API router, covering various feature flags and import errors. - Remove obsolete cancellation router tests to streamline the codebase. Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…aseline; add noqa comment for import in main.py Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…ioning Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…fix in tests Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
- Changed all admin-related fetch and form action URLs in observability templates to include the new versioning scheme (v1). - Updated paths in performance, prompts, resources, tools, and user management templates to reflect the new API structure. - Adjusted Playwright tests to align with the updated URL structure for admin routes. Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…ion in logout tests Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
Summary
This PR introduces API versioning for ContextForge by serving all resource management and business-logic endpoints under a
/v1URL prefix. A newmcpgateway/api/v1/__init__.pymodule centralizes router assembly through abuild_v1_router()factory, keepingmain.pyclean and making future version additions (/v2, etc.) straightforward.Protocol-level routes (MCP transports, OAuth, well-known URIs, health probes) intentionally remain unversioned at the root — these follow external standards or must stay stable for infrastructure compatibility.
Changes
mcpgateway/api/v1/__init__.py— newbuild_v1_router()factory that assembles all versioned routers under/v1; feature-flagged routers are conditionally included heremcpgateway/api/__init__.py— new namespace packagemcpgateway/main.py— router registration refactored; versioned routers delegated tobuild_v1_router(); unversioned routers mounted directly onappmcpgateway/admin.py— admin redirect paths updated to/v1/admin/*mcpgateway/middleware/— path references updated (path_filter.py,rbac.py,token_scoping.py)/v1prefixed pathsscripts/update_test_paths.py— utility script for migrating test path referencesEndpoint Classification
Versioned — served under
/v1/v1/protocol/**/v1/tools/**/v1/resources/**/v1/prompts/**/v1/gateways/**/v1/roots/**/v1/servers/**/v1/metrics/**/v1/tags/**/v1/export,/v1/import/v1/tools/plugin_bindings/**/v1/admin/**MCPGATEWAY_ADMIN_API_ENABLED/v1/admin/runtime/**MCPGATEWAY_ADMIN_API_ENABLED/v1/admin/llm/**MCPGATEWAY_LLMCHAT_ENABLED/v1/a2a/**MCPGATEWAY_A2A_ENABLED/v1/observability/**OBSERVABILITY_ENABLED/v1/reverse-proxy/**MCPGATEWAY_REVERSE_PROXY_ENABLED/v1/cancellation/**MCPGATEWAY_TOOL_CANCELLATION_ENABLED/v1/toolops/**TOOLOPS_ENABLED/v1/auth/**EMAIL_AUTH_ENABLED/v1/auth/email/**EMAIL_AUTH_ENABLED/v1/auth/sso/**EMAIL_AUTH_ENABLED+SSO_ENABLED/v1/teams/**EMAIL_AUTH_ENABLED/v1/tokens/**EMAIL_AUTH_ENABLED/v1/rbac/**EMAIL_AUTH_ENABLED/v1/llmchat/**MCPGATEWAY_LLMCHAT_ENABLED/v1/llm/**MCPGATEWAY_LLMCHAT_ENABLEDNot versioned — mounted at root
/health,/ready,/health/security/mcp/_internal/mcp/transport/oauth/**/.well-known/**/servers/{id}/.well-known/**/version/static/**//favicon.ico/api/logs/**{llm_api_prefix}(default/v1)LLM_API_PREFIX; cannot be nested inside the gateway's own/v1Breaking Change
All previously unversioned API paths (
/tools,/resources,/prompts,/gateways,/servers,/roots,/metrics,/tags,/a2a,/admin,/auth,/teams,/tokens,/rbac,/observability,/cancellation,/toolops,/reverse-proxy,/export,/import) are now served exclusively under/v1. Clients must update base URLs accordingly.The MCP transports (
/mcp), OAuth endpoints (/oauth), health probes, and well-known URIs are unchanged.