feat(mcp-server): implement all 19 MCP 2026-07-28 SEPs - #75
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Pratistha Singh <pratisin@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Pratistha Singh <pratisin@redhat.com>
375ecb3 to
fb9ae6b
Compare
Signed-off-by: Pratistha Singh <pratisin@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
||
| def _get_issuer() -> str: | ||
| safe_default = "http://localhost:5001" | ||
| endpoint = getattr(settings, "MCP_HOST_ENDPOINT", None) or safe_default |
There was a problem hiding this comment.
This is not defined in the settings.
Signed-off-by: Pratistha Singh <pratisin@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…d test coverage Signed-off-by: Pratistha Singh <pratisin@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
b3eca3d to
e40c0a4
Compare
Signed-off-by: Pratistha Singh <pratisin@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Pratistha Singh <pratisin@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Pratistha Singh <pratisin@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Pratistha Singh <pratisin@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Description
Implements all 19 SEPs from the MCP 2026-07-28 specification, removes SSE transport, adds stdio transport, adds
ToolAnnotationson all tools, and brings test coverage to 741 tests at 100% across 29 source files (1885 statements, 0 missed).SEP Implementations
Transport & Protocol
Mcp-Session-Idheader, no session tracking, noLast-Event-IDresumability.stateless_http=Trueby default, configurable viaMCP_STATELESS_HTTP.server/discoverreplaces the initialize handshake. Removed methods (ping,logging/setLevel,notifications/roots/list_changed,tasks/list) return-32023 METHOD_NOT_SUPPORTED. Per-request_meta.logLevelreplaces stateful logging config.mrtr.pymodule (23 stmts) withInputRequestmodel,input_required_result()/complete_result()builders, andget_response_value()lookup. Middleware intercepts MRTR-enabled tools (e.g.,send_email) — first call returnsresultType: "input_required"withinputRequestsasking for confirmation; client retries withinputResponses; confirmed calls execute the tool and returnresultType: "complete". Non-MRTR tools still getresultType: "complete"injected via_inject_result_type().server/discoveradvertisesmultiRoundTrip: truein tools capability. Configurable viaMCP_MRTR_ENABLED.Observability
tracing.pymodule (60 stmts) — parsestraceparent/tracestate/baggagefrom HTTP headers and MCP_metafields, generates server span IDs, injectstrace_id/span_idinto structlog via contextvars. Middleware binds trace context per request and returnstraceparentin response headers.OAuth & Security
_infer_application_type()classifies redirect URIs — loopback/custom-scheme →"native", HTTPS →"web". Stored inoauth_clientstable and returned in registration response.GET /auth/client-metadata/{client_id}serves read-only client metadata.POST /auth/registerreturnsDeprecation: trueheader. Well-known metadata advertisesregistration_endpoint_is_deprecated: true.SCOPES_SUPPORTEDexcludesoffline_accesswith a module-level validation guard. Refresh tokens controlled viagrant_types_supported.OAuthServicetakesissuerparam; auth code and refresh token grant handlers reject tokens from different issuers.PRIMARY KEY (issuer, client_id).handle_callback()includesissin redirect params (RFC 9207). AS metadata returnsauthorization_response_iss_parameter_supported: true.Schema & Tools
SEP-2106 (JSON Schema 2020-12): New
schema.pymodule (60 stmts) — validatesinputSchema(roottype: "object"),outputSchema, and$refresolution within$defs. All 4 tools defineOUTPUT_SCHEMAwithstructuredContent.SEP-2549 (Deterministic tools/list + cache metadata):
_ensure_deterministic_tool_order()sorts tools by name for client-side caching and LLM prompt cache hits.TOOL_CACHE_TTL_MSandTOOL_CACHE_SCOPEconfigurable.SEP-2243 (Mcp-Method / Mcp-Name header validation): Middleware validates headers match JSON-RPC body. Returns
-32020 HEADER_MISMATCHon mismatch. Response includesx-mcp-methodandx-mcp-name.Tool Annotations: All 4 tools registered with
ToolAnnotationsbehavioral hints viamcp.tool(annotations=...):calculate_bmitruefalsetruefalsesearch_webtruefalsetruetruesend_emailfalsetruefalsetruevalidate_emailtruefalsetruefalseExtensions
extensions.py(20 stmts) —ExtensionRegistrywith reverse-DNS identifiers. Capabilities advertised inserver/discover.apps.py(35 stmts) —AppRegistrywith register/unregister/get/list. RPC handlers:apps/list,apps/get. Default "health-dashboard" app registered.tasks.py(73 stmts) —TaskStorewith full lifecycle (pending→running→completed/failed/cancelled). RPC handlers:tasks/get,tasks/update,tasks/cancel. Progress clamped to [0,1], terminal tasks reject updates.Deprecation & Lifecycle
server/discover(roots → tool params, sampling → direct LLM APIs, logging → per-request_meta.logLevel).deprecation.py(43 stmts) —DeprecationRegistrywithactive/deprecated/removedstates. 15 entries pre-registered from the 2026-07-28 spec.Error Codes
errors.py(27 stmts) — code ranges per spec (-32000to-32019implementation-defined,-32020to-32099MCP-reserved).HeaderMismatchError(-32020),MethodNotSupportedError(-32023),ResourceNotFoundError(-32602).Transport Changes
api.py— Streamable HTTP is now the only HTTP transportmain.pyusingFastMCP.run_stdio_async()with lazy imports"http"to"streamable-http"in settingsHardcoded Value Removal
handler.py: SSO scopes and introspection timeout fromsettings.SSO_SCOPES/settings.SSO_INTROSPECTION_TIMEOUTemail_tool.py:RESEND_FROM_EMAILnow required (no hardcoded fallback)settings.py: AddedOAUTH_ISSUER,ACCESS_TOKEN_EXPIRY,SESSION_COOKIE_HTTPS_ONLY,SESSION_COOKIE_SAME_SITE,SESSION_COOKIE_MAX_AGE,SSO_SCOPES,SSO_INTROSPECTION_TIMEOUT,MCP_TRACE_CONTEXT_ENABLED,MCP_EXTENSIONS_ENABLED,MCP_STATELESS_HTTP,MCP_PROTOCOL_VERSION,TOOL_CACHE_TTL_MS,TOOL_CACHE_SCOPE,MCP_MRTR_ENABLEDDead Code Removal
service.py: Removed 14 backward-compat wrapper functionsmodels.py: Removed 5 unused Pydantic modelsconftest.py: Removed 11 unused test fixturestest_utils.py: Removed 3 duplicate test casestest_oauth_controller.py: Removed placeholder test classCode Reuse
controller.py: Extracted_validate_client_credentials()helper (3 duplicated blocks → 1)api.py:get_host()checksOAUTH_ISSUERfirst, matchingget_current_issuer()logicpylogger.py: Addedstructlog.contextvars.merge_contextvarsfor trace context propagationBreaking Changes
OAuthService.__init__()requiresissuerparameterstorage_service.get_client()/get_client_by_name_and_redirect_uris()requireissuerparameterservice.pyRESEND_FROM_EMAILnow required (no hardcoded fallback)SSO_SCOPESdefault changed to["email", "openid", "profile"](configurable)Type of Change
Checklist
make test)make pre-commit)make coverage)CHANGELOG.md(if applicable)Testing
741 tests passing, 100% coverage across 29 source files (1885 statements, 0 missed).
Key test coverage by SEP:
test_tracing.py,test_api.pytest_oauth_service.py,test_oauth_controller.pytest_oauth_routes.py,test_api.pytest_schema.py,test_mcp.pytest_extensions.py,test_api.pytest_api.pytest_api.pytest_api.pytest_mrtr.py,test_api.pytest_oauth_service.py,test_oauth_controller.py,test_storage_service.pytest_oauth_controller.py,test_api.pytest_mcp.pytest_settings.py,test_api.pytest_api.pytest_deprecation.py,test_api.pytest_deprecation.pytest_apps.py,test_api.pytest_tasks.py,test_api.pytest_errors.pytest_mcp.py