Skip to content

feat(http): enforce static CLI flags as upper bound for per-request filtering#2208

Open
SamMorrowDrums wants to merge 1 commit intomainfrom
http-static-flags-support
Open

feat(http): enforce static CLI flags as upper bound for per-request filtering#2208
SamMorrowDrums wants to merge 1 commit intomainfrom
http-static-flags-support

Conversation

@SamMorrowDrums
Copy link
Collaborator

Summary

The HTTP server now respects the same static CLI flags as the stdio server: --toolsets, --tools, --exclude-tools, --read-only, --dynamic-toolsets, and --insiders.

A static inventory is built once at startup from these flags, producing a pre-filtered tool/resource/prompt universe. Per-request headers (X-MCP-Toolsets, X-MCP-Tools, etc.) can only narrow within these bounds, never expand beyond them. When no static flags are set, existing behavior is preserved — headers have full access to all toolsets.

Problem

Users deploying the HTTP server expected --read-only, --toolsets, and other CLI flags to work the same as in stdio mode. Instead, these flags were ignored entirely — any request header could access any tool regardless of server configuration.

Approach

Layer What it does
Static inventory (startup) Built once from CLI flags. Pre-filters tools/resources/prompts to create the allowed universe.
Per-request builder (each request) Starts from the static universe. Headers can narrow (e.g., select a toolset subset) but cannot expand.
Graceful degradation If a request header asks for a tool not in the static universe, it's silently dropped rather than returning an error.

Key design decisions

  • Static tools as upper bound: SetTools(staticTools) means per-request builders physically cannot see tools outside the static set
  • Backward compatible: No static flags → full tool universe (existing HTTP behavior unchanged)
  • Per-request defaults: When static flags are set, per-request builder defaults to WithToolsets(["all"]) within the static bounds, so all statically-allowed tools are visible unless headers narrow further
  • No exported API changes: New fields added to ServerConfig; DefaultInventoryFactory now uses the previously-ignored *ServerConfig parameter

Changes

  • pkg/http/server.go — Added ReadOnly, EnabledToolsets, EnabledTools, DynamicToolsets, ExcludeTools, InsidersMode to ServerConfig
  • pkg/http/handler.gobuildStaticInventory() pre-filters at startup; DefaultInventoryFactory captures static tools in closure; filterRequestTools() gracefully drops unknown tool names from request headers
  • cmd/github-mcp-server/main.go — Wired CLI flags to HTTP ServerConfig (matching stdio pattern)
  • pkg/http/handler_test.go — 13 new test cases covering static enforcement, non-overridability, narrowing, combinations, and backward compat

Relevant issues

Testing

$ script/lint   → 0 issues
$ script/test   → all packages pass

…iltering

The HTTP server now respects the same static CLI flags as the stdio
server: --toolsets, --tools, --exclude-tools, --read-only,
--dynamic-toolsets, and --insiders.

A static inventory is built once at startup from these flags, producing
a pre-filtered tool/resource/prompt universe. Per-request headers
(X-MCP-Toolsets, X-MCP-Tools, etc.) can only narrow within these
bounds, never expand beyond them. When no static flags are set, the
existing behavior is preserved — headers have full access to all
toolsets.

Fixes #2156

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@SamMorrowDrums SamMorrowDrums requested a review from a team as a code owner March 13, 2026 09:38
Copilot AI review requested due to automatic review settings March 13, 2026 09:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes #2156 by wiring the static CLI flags (--read-only, --toolsets, --tools, --exclude-tools, --dynamic-toolsets, --insiders) into the HTTP server, ensuring they act as an upper bound on per-request header-based filtering.

Changes:

  • Added static filtering fields to ServerConfig and wired CLI flags in main.go
  • Built a startup-time static inventory in DefaultInventoryFactory that constrains per-request tool visibility
  • Added 13 table-driven tests covering static enforcement, non-overridability, narrowing, and backward compatibility

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
pkg/http/server.go Added 6 new fields to ServerConfig for static filtering; enhanced startup log
pkg/http/handler.go Implemented buildStaticInventory, hasStaticConfig, filterRequestTools; updated DefaultInventoryFactory to use static bounds
cmd/github-mcp-server/main.go Wired CLI flags to HTTP ServerConfig matching stdio pattern
pkg/http/handler_test.go Added mockToolFull helper and TestStaticConfigEnforcement with 13 test cases

You can also share your feedback on Copilot code review. Take the survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--read-only flag fails to restrict write tools when using the new http command

2 participants