Repository: envoyproxy/envoy
File: source/extensions/filters/http/mcp_router/mcp_router.cc (C++)

Code before:
}

} // namespace

// Static map for MCP method string lookup.
using McpMethodMap = absl::flat_hash_map<absl::string_view, McpMethod>;

const McpMethodMap& mcpMethodMap() {
  // TODO(botengyao): Add support for more MCP methods:
  // - completion/complete
  // - logging/setLevel
  CONSTRUCT_ON_FIRST_USE(
      McpMethodMap,
      {{"initialize", McpMethod::Initialize},
       {"tools/list", McpMethod::ToolsList},
       {"tools/call", McpMethod::ToolsCall},
       {"resources/list", McpMethod::ResourcesList},
       {"resources/read", McpMethod::ResourcesRead},
       {"resources/subscribe", McpMethod::ResourcesSubscribe},
       {"resources/unsubscribe", McpMethod::ResourcesUnsubscribe},
       {"prompts/list", McpMethod::PromptsList},
       {"prompts/get", McpMethod::PromptsGet},
       {"ping", McpMethod::Ping},
       // Notifications (client -> server).
       {"notifications/initialized", McpMethod::NotificationInitialized},
       {"notifications/cancelled", McpMethod::NotificationCancelled},
       {"notifications/progress", McpMethod::NotificationProgress},
       {"notifications/roots/list_changed", McpMethod::NotificationRootsListChanged},
       {"notifications/resources/list_changed", McpMethod::NotificationResourcesListChanged},
       {"notifications/resources/updated", McpMethod::NotificationResourcesUpdated},
       {"notifications/tools/list_changed", McpMethod::NotificationToolsListChanged},
       {"notifications/prompts/list_changed", McpMethod::NotificationPromptsListChanged}});
}

McpMethod parseMethodString(absl::string_view method_str) {
  auto it = mcpMethodMap().find(method_str);
  return it != mcpMethodMap().end() ? it->second : McpMethod::Unknown;
}

BackendStreamCallbacks::BackendStreamCallbacks(const std::string& backend_name,
                                               std::function<void(BackendResponse)> on_complete)
    : backend_name_(backend_name), on_complete_(std::move(on_complete)) {
  response_.backend_name = backend_name;
}

void BackendStreamCallbacks::onHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) {
  if (headers && headers->Status()) {
    response_.status_code = Http::Utility::getResponseStatus(*headers);
    response_.success = (response_.status_code >= 200 && response_.status_code < 300);

    // Extract session ID from response header

Review comment (suggestion):
This should also be a targeted cancelled, and this is an [optional](https://modelcontextprotocol.io/specification/2025-03-26/basic/utilities/cancellation) feature. One way to solve it is to rewrite request id but this is from client, we need to maintain some map to backend here, which is not scaleable, I think it can be out of scope now.

Edit: think it more, this can also fan-out to all backends with limitations.

Code after:
}

} // namespace

// Static map for MCP method string lookup.
using McpMethodMap = absl::flat_hash_map<absl::string_view, McpMethod>;

const McpMethodMap& mcpMethodMap() {
  // TODO(botengyao): Add support for more MCP methods:
  // - completion/complete
  // - logging/setLevel
  CONSTRUCT_ON_FIRST_USE(
      McpMethodMap,
      {{"initialize", McpMethod::Initialize},
       {"tools/list", McpMethod::ToolsList},
       {"tools/call", McpMethod::ToolsCall},
       {"resources/list", McpMethod::ResourcesList},
       {"resources/read", McpMethod::ResourcesRead},
       {"resources/subscribe", McpMethod::ResourcesSubscribe},
       {"resources/unsubscribe", McpMethod::ResourcesUnsubscribe},
       {"prompts/list", McpMethod::PromptsList},
       {"prompts/get", McpMethod::PromptsGet},
       {"ping", McpMethod::Ping},
       // Notifications (client -> server).
       {"notifications/initialized", McpMethod::NotificationInitialized},
       {"notifications/cancelled", McpMethod::NotificationCancelled},
       {"notifications/roots/list_changed", McpMethod::NotificationRootsListChanged}});
}

McpMethod parseMethodString(absl::string_view method_str) {
  auto it = mcpMethodMap().find(method_str);
  return it != mcpMethodMap().end() ? it->second : McpMethod::Unknown;
}

BackendStreamCallbacks::BackendStreamCallbacks(const std::string& backend_name,
                                               std::function<void(BackendResponse)> on_complete)
    : backend_name_(backend_name), on_complete_(std::move(on_complete)) {
  response_.backend_name = backend_name;
}

void BackendStreamCallbacks::onHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) {
  if (headers && headers->Status()) {
    response_.status_code = Http::Utility::getResponseStatus(*headers);
    response_.success = (response_.status_code >= 200 && response_.status_code < 300);

    // Extract session ID from response header
    auto session_header = headers->get(Http::LowerCaseString(std::string(kSessionIdHeader)));
    if (!session_header.empty()) {
      response_.session_id = std::string(session_header[0]->value().getStringView());
    }
  }