diff --git a/AGENTS.md b/AGENTS.md
index e38eb3f0b..967e7ea1e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -282,21 +282,28 @@ make agent-finished
 ```go
 import "github.com/github/gh-aw-mcpg/internal/logger"
 
-// Create a logger with namespace following pkg:filename convention
-var log = logger.New("pkg:filename")
+// Create a logger with namespace auto-derived from the calling file (PREFERRED)
+var logComponent = logger.ForFile()
 
 // Log debug messages
 // - Writes to stderr with colors and time diffs (when DEBUG matches namespace)
 // - Also writes to file logger as text-only (always, when logger is enabled)
-log.Printf("Processing %d items", count)
-log.Print("Simple debug message")
+logComponent.Printf("Processing %d items", count)
+logComponent.Print("Simple debug message")
 
 // Check if logging is enabled before expensive operations
-if log.Enabled() {
-    log.Printf("Expensive debug info: %+v", expensiveOperation())
+if logComponent.Enabled() {
+    logComponent.Printf("Expensive debug info: %+v", expensiveOperation())
 }
 ```
 
+`logger.ForFile()` automatically derives the namespace as `"package:filename"` from the calling
+file path (e.g., a call in `internal/server/unified.go` yields `"server:unified"`). This
+eliminates manually maintained namespace strings and prevents namespace drift.
+
+Use `logger.New("pkg:component")` only when a custom namespace is intentionally different from
+the file name (e.g., a file that maintains backward-compatible debug namespace for users).
+
 **For operational/file logging, use the file logger directly:**
 
 ```go
@@ -311,7 +318,7 @@ logger.LogError("category", "Operation failed: %v", err)
 logger.LogDebug("category", "Debug details: %+v", details)
 ```
 
-**Note:** Debug loggers created with `logger.New()` now write to both stderr (with colors/time diffs) and the file logger (text-only). This provides real-time colored output during development while ensuring all debug logs are captured to file for production troubleshooting.
+**Note:** Debug loggers created with `logger.ForFile()` and `logger.New()` write to both stderr (with colors/time diffs) and the file logger (text-only). This provides real-time colored output during development while ensuring all debug logs are captured to file for production troubleshooting.
 
 **Logging Categories:**
 - `startup` - Gateway initialization and configuration
@@ -326,26 +333,23 @@ logger.LogDebug("category", "Debug details: %+v", details)
 - Be consistent with existing loggers in the codebase
 
 **Logger Variable Naming Convention:**
-- **Use descriptive names** that match the component: `var log<Component> = logger.New("pkg:component")`
-- Examples: `var logLauncher = logger.New("launcher:launcher")`, `var logConfig = logger.New("config:config")`
+- **Use descriptive names** that match the component: `var log<Component> = logger.ForFile()`
+- Examples: `var logLauncher = logger.ForFile()`, `var logHandlers = logger.ForFile()`
 - **Avoid generic `log` name** when it might conflict with standard library or when the file already imports `log` package
 - Capitalize the component part after 'log' (e.g., `logAuth` with capital 'A', `logLauncher` with capital 'L')
 - This convention makes it clear which logger is being used and reduces naming collisions
-- For components with very short files or temporary code, generic `log` is acceptable but descriptive is preferred
 
-**Examples of good logger naming:**
+**Examples of good logger declarations:**
 ```go
-// Descriptive - clearly indicates the component (RECOMMENDED)
-var logLauncher = logger.New("launcher:launcher")
-var logPool = logger.New("launcher:pool")
-var logConfig = logger.New("config:config")
-var logValidation = logger.New("config:validation")
-var logUnified = logger.New("server:unified")
-var logRouted = logger.New("server:routed")
-
-// Generic - acceptable for simple cases but less clear
-var log = logger.New("auth:header")
-var log = logger.New("sys:sys")
+// Using ForFile() - namespace is auto-derived from file path (RECOMMENDED)
+var logLauncher = logger.ForFile()   // in launcher/launcher.go → "launcher:launcher"
+var logValidation = logger.ForFile() // in config/validation.go → "config:validation"
+var logUnified = logger.ForFile()    // in server/unified.go    → "server:unified"
+var logRouted = logger.ForFile()     // in server/routed.go     → "server:routed"
+
+// Using New() - only for intentionally custom namespaces
+var logPool = logger.New("launcher:pool")   // in connection_pool.go, custom shorter name
+var logConfig = logger.New("config:config") // in config_core.go, intentional short name
 ```
 
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5b6cbfe6d..6ddcb8a03 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -430,9 +430,9 @@ Use the logger package for debug logging:
 ```go
 import "github.com/github/gh-aw-mcpg/internal/logger"
 
-// Create a logger with namespace following pkg:filename convention
+// Create a logger with namespace auto-derived from the calling file (PREFERRED)
 // Use descriptive variable names (e.g., logLauncher, logConfig) for clarity
-var logComponent = logger.New("pkg:filename")
+var logComponent = logger.ForFile()
 
 // Log debug messages (only shown when DEBUG environment variable matches)
 logComponent.Printf("Processing %d items", count)
@@ -443,9 +443,15 @@ if logComponent.Enabled() {
 }
 ```
 
+`logger.ForFile()` automatically derives the namespace as `"package:filename"` from the calling
+file path, eliminating manually maintained namespace strings and preventing drift.
+
+Use `logger.New("pkg:component")` only when a custom namespace is intentionally different from
+the file name (e.g., preserving a short backward-compatible debug namespace).
+
 **Logger Variable Naming Convention:**
-- **Prefer descriptive names**: `var log<Component> = logger.New("pkg:component")`
-- Examples: `var logLauncher = logger.New("launcher:launcher")`
+- **Prefer descriptive names**: `var log<Component> = logger.ForFile()`
+- Examples: `var logLauncher = logger.ForFile()`, `var logHandlers = logger.ForFile()`
 - Avoid generic `log` when it might conflict with standard library
 - Capitalize the component part after 'log' (e.g., `logAuth` with capital 'A', `logLauncher` with capital 'L')
 
diff --git a/internal/auth/header.go b/internal/auth/header.go
index bcfbe860c..590664412 100644
--- a/internal/auth/header.go
+++ b/internal/auth/header.go
@@ -44,7 +44,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logAuth = logger.New("auth:header")
+var logAuth = logger.ForFile()
 var logAPIKey = logger.New("auth:apikey")
 
 var (
diff --git a/internal/cmd/proxy.go b/internal/cmd/proxy.go
index 62fa3bc5e..dbcdd45da 100644
--- a/internal/cmd/proxy.go
+++ b/internal/cmd/proxy.go
@@ -22,7 +22,7 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var logProxyCmd = logger.New("cmd:proxy")
+var logProxyCmd = logger.ForFile()
 
 // Proxy subcommand flag variables
 var (
diff --git a/internal/cmd/root.go b/internal/cmd/root.go
index 81736fc4e..d87ba7df0 100644
--- a/internal/cmd/root.go
+++ b/internal/cmd/root.go
@@ -33,7 +33,7 @@ const (
 
 // Package-level variables that don't belong to a specific feature
 var (
-	debugLog = logger.New("cmd:root")
+	debugLog = logger.ForFile()
 	// cliVersion stores the version string for Cobra's CLI version display.
 	// This is kept separate from version.Get() because rootCmd.Version must be
 	// set at initialization time (before SetVersion is called). We sync both
diff --git a/internal/config/config_stdin.go b/internal/config/config_stdin.go
index ebf6ab226..b19c14ec8 100644
--- a/internal/config/config_stdin.go
+++ b/internal/config/config_stdin.go
@@ -14,7 +14,7 @@ import (
 	"github.com/santhosh-tekuri/jsonschema/v6"
 )
 
-var logStdin = logger.New("config:config_stdin")
+var logStdin = logger.ForFile()
 
 // StdinConfig represents the JSON configuration format read from stdin.
 type StdinConfig struct {
diff --git a/internal/config/config_tracing.go b/internal/config/config_tracing.go
index d70840782..a80e01230 100644
--- a/internal/config/config_tracing.go
+++ b/internal/config/config_tracing.go
@@ -4,7 +4,7 @@ package config
 
 import "github.com/github/gh-aw-mcpg/internal/logger"
 
-var logTracingCfg = logger.New("config:config_tracing")
+var logTracingCfg = logger.ForFile()
 
 // DefaultTracingSampleRate is the default sample rate for tracing (100% sampling).
 const DefaultTracingSampleRate = 1.0
diff --git a/internal/config/guard_policy.go b/internal/config/guard_policy.go
index faf7c9b40..0838a8b90 100644
--- a/internal/config/guard_policy.go
+++ b/internal/config/guard_policy.go
@@ -9,7 +9,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logGuardPolicy = logger.New("config:guard_policy")
+var logGuardPolicy = logger.ForFile()
 
 const (
 	IntegrityNone       = "none"
diff --git a/internal/config/validation_env.go b/internal/config/validation_env.go
index 4fcfa3b0c..9f768e8f1 100644
--- a/internal/config/validation_env.go
+++ b/internal/config/validation_env.go
@@ -9,7 +9,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/sys"
 )
 
-var logEnv = logger.New("config:validation_env")
+var logEnv = logger.ForFile()
 
 // RequiredEnvVars lists the environment variables that must be set for the gateway to operate
 var RequiredEnvVars = []string{
diff --git a/internal/config/validation_schema.go b/internal/config/validation_schema.go
index 988865f7c..e66eb44ff 100644
--- a/internal/config/validation_schema.go
+++ b/internal/config/validation_schema.go
@@ -61,7 +61,7 @@ var schemaErrPrinter = message.NewPrinter(language.English)
 
 var (
 	// logSchema is the debug logger for schema validation
-	logSchema = logger.New("config:validation_schema")
+	logSchema = logger.ForFile()
 
 	// Schema caching to avoid recompiling the JSON schema on every validation.
 	// This improves performance by compiling the schema once and reusing it.
diff --git a/internal/config/validation_shared.go b/internal/config/validation_shared.go
index 84582b8da..d76cc1b59 100644
--- a/internal/config/validation_shared.go
+++ b/internal/config/validation_shared.go
@@ -6,7 +6,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logValidation = logger.New("config:validation_shared")
+var logValidation = logger.ForFile()
 
 // customSchemaCache stores compiled custom schemas by schema URL to avoid
 // repeated fetch + compile work across validations.
diff --git a/internal/difc/agent.go b/internal/difc/agent.go
index 7db93c72d..f926519ef 100644
--- a/internal/difc/agent.go
+++ b/internal/difc/agent.go
@@ -7,7 +7,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/syncutil"
 )
 
-var logAgent = logger.New("difc:agent")
+var logAgent = logger.ForFile()
 
 // AgentLabels associates each agent with their DIFC labels
 // Tracks what secrecy and integrity tags an agent has accumulated
diff --git a/internal/difc/capabilities.go b/internal/difc/capabilities.go
index 46fab6de4..101b854d1 100644
--- a/internal/difc/capabilities.go
+++ b/internal/difc/capabilities.go
@@ -2,7 +2,7 @@ package difc
 
 import "github.com/github/gh-aw-mcpg/internal/logger"
 
-var logCapabilities = logger.New("difc:capabilities")
+var logCapabilities = logger.ForFile()
 
 // Capabilities represents the global set of tags available in the system
 // This is used to validate and discover available DIFC tags
diff --git a/internal/difc/evaluator.go b/internal/difc/evaluator.go
index 6b55bb953..a39b96419 100644
--- a/internal/difc/evaluator.go
+++ b/internal/difc/evaluator.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logEvaluator = logger.New("difc:evaluator")
+var logEvaluator = logger.ForFile()
 
 // DIFC mode string constants - use these for consistent mode references
 const (
diff --git a/internal/difc/labels.go b/internal/difc/labels.go
index 5392b7be4..3ca8229b8 100644
--- a/internal/difc/labels.go
+++ b/internal/difc/labels.go
@@ -6,7 +6,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logLabels = logger.New("difc:labels")
+var logLabels = logger.ForFile()
 
 // Tag represents a single DIFC tag (e.g., "repo:owner/name", "agent:demo-agent")
 type Tag string
diff --git a/internal/difc/path_labels.go b/internal/difc/path_labels.go
index 44d76e3ca..117bec1f6 100644
--- a/internal/difc/path_labels.go
+++ b/internal/difc/path_labels.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/mcpresult"
 )
 
-var logPathLabels = logger.New("difc:path_labels")
+var logPathLabels = logger.ForFile()
 
 // PathLabels represents a collection of labeled paths in a JSON response.
 // Guards return this structure to indicate which elements in the response
diff --git a/internal/difc/pipeline_decisions.go b/internal/difc/pipeline_decisions.go
index 1d6450446..d260bcd68 100644
--- a/internal/difc/pipeline_decisions.go
+++ b/internal/difc/pipeline_decisions.go
@@ -2,7 +2,7 @@ package difc
 
 import "github.com/github/gh-aw-mcpg/internal/logger"
 
-var logPipeline = logger.New("difc:pipeline_decisions")
+var logPipeline = logger.ForFile()
 
 // CoarseCheckOutcome is the typed result of a Phase 2 coarse-grained access check.
 type CoarseCheckOutcome int
diff --git a/internal/difc/reflect.go b/internal/difc/reflect.go
index 10759685d..4f40f91e3 100644
--- a/internal/difc/reflect.go
+++ b/internal/difc/reflect.go
@@ -7,7 +7,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logReflect = logger.New("difc:reflect")
+var logReflect = logger.ForFile()
 
 // ReflectedAgentLabels is the JSON shape for an agent's current DIFC labels.
 type ReflectedAgentLabels struct {
diff --git a/internal/difc/resource.go b/internal/difc/resource.go
index 062baa1fd..9529782aa 100644
--- a/internal/difc/resource.go
+++ b/internal/difc/resource.go
@@ -2,7 +2,7 @@ package difc
 
 import "github.com/github/gh-aw-mcpg/internal/logger"
 
-var logResource = logger.New("difc:resource")
+var logResource = logger.ForFile()
 
 // Resource represents an external system with label requirements (deprecated - use LabeledResource)
 type Resource struct {
diff --git a/internal/difc/sink_server_ids.go b/internal/difc/sink_server_ids.go
index e9cfbccd7..f31df8e3e 100644
--- a/internal/difc/sink_server_ids.go
+++ b/internal/difc/sink_server_ids.go
@@ -9,7 +9,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logSink = logger.New("difc:sink_server_ids")
+var logSink = logger.ForFile()
 
 var (
 	sinkServerIDsMu sync.RWMutex
diff --git a/internal/envutil/envfile.go b/internal/envutil/envfile.go
index c04ba6fbc..286ee7238 100644
--- a/internal/envutil/envfile.go
+++ b/internal/envutil/envfile.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/sanitize"
 )
 
-var logEnvFile = logger.New("envutil:envfile")
+var logEnvFile = logger.ForFile()
 
 // LoadEnvFile reads a .env file and sets environment variables.
 // Lines beginning with '#' and blank lines are ignored.
diff --git a/internal/envutil/envutil.go b/internal/envutil/envutil.go
index c4896d9b4..cc4cc3022 100644
--- a/internal/envutil/envutil.go
+++ b/internal/envutil/envutil.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/sanitize"
 )
 
-var logEnvUtil = logger.New("envutil:envutil")
+var logEnvUtil = logger.ForFile()
 
 // HasEnvVar reports whether the named environment variable is present in the
 // process environment, regardless of whether its value is empty.
diff --git a/internal/envutil/github.go b/internal/envutil/github.go
index 19c3e2ca4..e67748878 100644
--- a/internal/envutil/github.go
+++ b/internal/envutil/github.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/sanitize"
 )
 
-var logGitHub = logger.New("envutil:github")
+var logGitHub = logger.ForFile()
 
 // DefaultGitHubAPIBaseURL is the default GitHub API base URL.
 const DefaultGitHubAPIBaseURL = "https://api.github.com"
diff --git a/internal/githubhttp/client.go b/internal/githubhttp/client.go
index 74052ebb0..ce24905f4 100644
--- a/internal/githubhttp/client.go
+++ b/internal/githubhttp/client.go
@@ -11,7 +11,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logHTTP = logger.New("githubhttp:client")
+var logHTTP = logger.ForFile()
 
 // GitHubUserAgent is the User-Agent header value sent on all GitHub API requests.
 const GitHubUserAgent = "awmg/1.0"
diff --git a/internal/githubhttp/collaborator.go b/internal/githubhttp/collaborator.go
index 7d60acdd4..d01bcadc6 100644
--- a/internal/githubhttp/collaborator.go
+++ b/internal/githubhttp/collaborator.go
@@ -12,7 +12,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logCollab = logger.New("githubhttp:collaborator")
+var logCollab = logger.ForFile()
 
 // ParseCollaboratorPermissionArgs extracts and validates the owner, repo, and
 // username fields from an args map for a get_collaborator_permission call.
diff --git a/internal/githubhttp/visibility.go b/internal/githubhttp/visibility.go
index 3b1ba15aa..62ed3b74d 100644
--- a/internal/githubhttp/visibility.go
+++ b/internal/githubhttp/visibility.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logVisibility = logger.New("githubhttp:visibility")
+var logVisibility = logger.ForFile()
 
 // RepoVisibility represents the visibility of a GitHub repository.
 type RepoVisibility string
diff --git a/internal/guard/context.go b/internal/guard/context.go
index b46535cf2..450b47ce7 100644
--- a/internal/guard/context.go
+++ b/internal/guard/context.go
@@ -26,7 +26,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logContext = logger.New("guard:context")
+var logContext = logger.ForFile()
 
 // ContextKey is used for storing values in context
 type ContextKey string
diff --git a/internal/guard/label_agent.go b/internal/guard/label_agent.go
index 964b496d2..491932e91 100644
--- a/internal/guard/label_agent.go
+++ b/internal/guard/label_agent.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logLabelAgent = logger.New("guard:label_agent")
+var logLabelAgent = logger.ForFile()
 
 // RunLabelAgentForAgent is a convenience wrapper around RunLabelAgent that resolves
 // agent labels from the registry instead of requiring the caller to do so. It calls
diff --git a/internal/guard/noop.go b/internal/guard/noop.go
index 1cd5de882..d834570fd 100644
--- a/internal/guard/noop.go
+++ b/internal/guard/noop.go
@@ -7,7 +7,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logNoop = logger.New("guard:noop")
+var logNoop = logger.ForFile()
 
 // NoopGuard is the default guard that performs no DIFC labeling
 // It allows all operations by returning empty labels (no restrictions)
diff --git a/internal/guard/pipeline.go b/internal/guard/pipeline.go
index 6a480b6d6..d249fa74e 100644
--- a/internal/guard/pipeline.go
+++ b/internal/guard/pipeline.go
@@ -9,7 +9,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logPipeline = logger.New("guard:pipeline")
+var logPipeline = logger.ForFile()
 
 // PipelineInput holds the shared inputs used across DIFC pipeline phases 0–2, 4, and 6.
 // Both the HTTP proxy and the MCP unified server populate this struct and pass it to
diff --git a/internal/guard/registry.go b/internal/guard/registry.go
index 6a4b3f710..563d09369 100644
--- a/internal/guard/registry.go
+++ b/internal/guard/registry.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logRegistry = logger.New("guard:registry")
+var logRegistry = logger.ForFile()
 
 // Registry manages guard instances for different MCP servers
 type Registry struct {
diff --git a/internal/httputil/httputil.go b/internal/httputil/httputil.go
index 6c3f33453..03acbbf55 100644
--- a/internal/httputil/httputil.go
+++ b/internal/httputil/httputil.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logHTTP = logger.New("httputil:httputil")
+var logHTTP = logger.ForFile()
 
 // WriteJSONResponse sets the Content-Type header, writes the status code, and encodes
 // body as JSON. It centralises the three-line pattern used across HTTP handlers.
diff --git a/internal/httputil/tls.go b/internal/httputil/tls.go
index fc908e1b9..15967a97f 100644
--- a/internal/httputil/tls.go
+++ b/internal/httputil/tls.go
@@ -22,7 +22,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logTLS = logger.New("httputil:tls")
+var logTLS = logger.ForFile()
 
 // MinTLSVersion is the minimum TLS version enforced across all gateway listeners
 // and clients. Centralizing this constant ensures a single point of change if
diff --git a/internal/launcher/launcher.go b/internal/launcher/launcher.go
index 48ee64280..afe75100b 100644
--- a/internal/launcher/launcher.go
+++ b/internal/launcher/launcher.go
@@ -18,7 +18,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/sys"
 )
 
-var logLauncher = logger.New("launcher:launcher")
+var logLauncher = logger.ForFile()
 
 // ErrServerNotFound is returned by getServerConfig when the requested server ID
 // is not present in the gateway configuration.
diff --git a/internal/logger/logger.go b/internal/logger/logger.go
index c5f461dea..0c55aaf4f 100644
--- a/internal/logger/logger.go
+++ b/internal/logger/logger.go
@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"hash/fnv"
 	"os"
+	"path/filepath"
+	"runtime"
 	"strings"
 	"sync"
 	"time"
@@ -80,6 +82,22 @@ func New(namespace string) *Logger {
 	}
 }
 
+// ForFile creates a new Logger with a namespace automatically derived from the calling
+// file's path. The namespace follows the "package:filename" convention where package is
+// the last directory component of the file path and filename is the Go source file name
+// without the .go extension. This eliminates manually maintained namespace strings.
+//
+// Example: a call from internal/server/unified.go yields namespace "server:unified".
+func ForFile() *Logger {
+	_, file, _, ok := runtime.Caller(1)
+	if !ok {
+		return New("error:caller-not-found")
+	}
+	pkg := filepath.Base(filepath.Dir(file))
+	filename := strings.TrimSuffix(filepath.Base(file), ".go")
+	return New(pkg + ":" + filename)
+}
+
 // selectColor selects a color for the namespace based on its hash.
 func selectColor(namespace string) string {
 	if !debugColors || !isTTY {
diff --git a/internal/logger/logger_namespace_test.go b/internal/logger/logger_namespace_test.go
index ec114e0cd..120d80d06 100644
--- a/internal/logger/logger_namespace_test.go
+++ b/internal/logger/logger_namespace_test.go
@@ -25,19 +25,35 @@ func TestLoggerNamespacesMatchFileConventions(t *testing.T) {
 	internalRoot := filepath.Join(repoRoot, "internal")
 
 	exceptionNamespaces := map[string][]string{
-		"internal/auth/header.go":                {"auth:header", "auth:apikey"},
-		"internal/config/config_core.go":         {"config:config"},
-		"internal/config/config_feature.go":      {"config:feature"},
-		"internal/envutil/expand_env_args.go":    {"envutil:expand"},
-		"internal/guard/wasm_lifecycle.go":       {"guard:wasm"},
-		"internal/guard/write_sink.go":           {"guard:write-sink"},
-		"internal/launcher/connection_pool.go":   {"launcher:pool"},
-		"internal/launcher/health_monitor.go":    {"launcher:health"},
-		"internal/server/http_helpers.go":        {"server:helpers"},
-		"internal/server/http_server.go":         {"server:http_server", "server:transport"},
-		"internal/server/middleware_auth.go":     {"server:auth"},
-		"internal/server/sdk_logging.go":         {"server:sdk-frontend"},
-		"internal/server/session_auto_init.go":   {"server:auto-init"},
+		// header.go defines two loggers: one for general auth (auto-derived via ForFile as
+		// "auth:header") and one for API-key auth which uses the custom namespace "auth:apikey"
+		// so callers can filter API-key debug logs independently with DEBUG=auth:apikey.
+		"internal/auth/header.go": {"auth:apikey"},
+
+		// The following files use intentionally shorter or semantically clearer namespaces
+		// instead of the full file-name-derived form. These are preserved for backward
+		// compatibility with existing DEBUG filter configurations.
+		"internal/config/config_core.go":       {"config:config"},
+		"internal/config/config_feature.go":    {"config:feature"},
+		"internal/envutil/expand_env_args.go":  {"envutil:expand"},
+		"internal/guard/wasm_lifecycle.go":     {"guard:wasm"},
+		"internal/guard/write_sink.go":         {"guard:write-sink"},
+		"internal/launcher/connection_pool.go": {"launcher:pool"},
+		"internal/launcher/health_monitor.go":  {"launcher:health"},
+		"internal/server/http_helpers.go":      {"server:helpers"},
+
+		// http_server.go defines two loggers: the primary one for the HTTP server itself
+		// (auto-derived via ForFile as "server:http_server") and a second one with the custom
+		// namespace "server:transport" for transport-layer events, allowing independent filtering.
+		"internal/server/http_server.go": {"server:transport"},
+
+		"internal/server/middleware_auth.go":   {"server:auth"},
+		"internal/server/sdk_logging.go":       {"server:sdk-frontend"},
+		"internal/server/session_auto_init.go": {"server:auto-init"},
+
+		// testutil/mcptest/server.go uses "testutil:mcptest" (package/feature oriented) rather
+		// than the file-derived "mcptest:server". testutil/mcptest/validator.go similarly uses
+		// "testutil:validator" to group all testutil helpers under a common DEBUG prefix.
 		"internal/testutil/mcptest/server.go":    {"testutil:mcptest"},
 		"internal/testutil/mcptest/validator.go": {"testutil:validator"},
 	}
diff --git a/internal/logger/logger_test.go b/internal/logger/logger_test.go
index 8fc8ec782..f38cf9541 100644
--- a/internal/logger/logger_test.go
+++ b/internal/logger/logger_test.go
@@ -724,3 +724,20 @@ func TestLogger_Print_WithColors(t *testing.T) {
 	assert.Contains(t, output, "\033[", "Print() output should contain ANSI color codes when colors enabled")
 	assert.Contains(t, output, colorReset, "Print() output should contain color reset code")
 }
+
+// TestForFile verifies that ForFile derives the correct namespace from the calling file.
+func TestForFile(t *testing.T) {
+	t.Parallel()
+
+	// ForFile() is called from logger_test.go in the "logger" package.
+	// Expected namespace: "logger:logger_test"
+	log := ForFile()
+	assert.Equal(t, "logger:logger_test", log.namespace)
+}
+
+// TestForFile_Enabled verifies that ForFile respects the DEBUG environment variable.
+func TestForFile_Enabled(t *testing.T) {
+	t.Setenv("DEBUG", "logger:*")
+	log := ForFile()
+	assert.True(t, log.Enabled(), "ForFile logger should be enabled when DEBUG matches its derived namespace")
+}
diff --git a/internal/mcp/connection.go b/internal/mcp/connection.go
index 1ec5986e0..1278c3615 100644
--- a/internal/mcp/connection.go
+++ b/internal/mcp/connection.go
@@ -22,7 +22,7 @@ import (
 	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
 )
 
-var logConn = logger.New("mcp:connection")
+var logConn = logger.ForFile()
 
 // defaultConnectTimeout is the fallback connect timeout used when the configured timeout
 // is non-positive or otherwise invalid.
diff --git a/internal/mcp/connection_logging.go b/internal/mcp/connection_logging.go
index 2c44385fc..a77f12b13 100644
--- a/internal/mcp/connection_logging.go
+++ b/internal/mcp/connection_logging.go
@@ -6,7 +6,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logConnLogging = logger.New("mcp:connection_logging")
+var logConnLogging = logger.ForFile()
 
 // logReconnectStart emits the structured log warning that is common to all reconnect paths.
 func (c *Connection) logReconnectStart() {
diff --git a/internal/mcp/helpers.go b/internal/mcp/helpers.go
index 32fff4ddd..6ab57566f 100644
--- a/internal/mcp/helpers.go
+++ b/internal/mcp/helpers.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logMCPHelpers = logger.New("mcp:helpers")
+var logMCPHelpers = logger.ForFile()
 
 // marshalToResponse marshals an SDK result into a Response object.
 // This helper reduces code duplication across all MCP method wrappers.
diff --git a/internal/mcp/http_transport.go b/internal/mcp/http_transport.go
index dc4f1c545..10f460756 100644
--- a/internal/mcp/http_transport.go
+++ b/internal/mcp/http_transport.go
@@ -51,7 +51,7 @@ const streamableMaxRetries = -1
 // requestIDCounter is used to generate unique request IDs for HTTP requests
 var requestIDCounter uint64
 
-var logHTTP = logger.New("mcp:http_transport")
+var logHTTP = logger.ForFile()
 
 // httpRequestResult contains the result of an HTTP request execution
 type httpRequestResult struct {
diff --git a/internal/mcp/pagination.go b/internal/mcp/pagination.go
index 320b09908..bf80a9ed8 100644
--- a/internal/mcp/pagination.go
+++ b/internal/mcp/pagination.go
@@ -6,7 +6,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logPagination = logger.New("mcp:pagination")
+var logPagination = logger.ForFile()
 
 // paginatedPage holds a single page of results from a paginated SDK list call.
 type paginatedPage[T any] struct {
diff --git a/internal/mcp/schema.go b/internal/mcp/schema.go
index 656a96a80..5a9a6ce4c 100644
--- a/internal/mcp/schema.go
+++ b/internal/mcp/schema.go
@@ -4,7 +4,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logSchema = logger.New("mcp:schema")
+var logSchema = logger.ForFile()
 
 // NormalizeInputSchema ensures tool input schemas are valid for the MCP SDK
 // The MCP SDK requires that object type schemas have a "properties" field,
diff --git a/internal/mcp/tool_result.go b/internal/mcp/tool_result.go
index dbfa8c700..0e56875e5 100644
--- a/internal/mcp/tool_result.go
+++ b/internal/mcp/tool_result.go
@@ -9,7 +9,7 @@ import (
 	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
 )
 
-var logToolResult = logger.New("mcp:tool_result")
+var logToolResult = logger.ForFile()
 
 func marshalValueToTextContentResult(value interface{}) (*sdk.CallToolResult, error) {
 	dataBytes, err := json.Marshal(value)
diff --git a/internal/mcpresult/mcpresult.go b/internal/mcpresult/mcpresult.go
index 20972734c..69099c9e2 100644
--- a/internal/mcpresult/mcpresult.go
+++ b/internal/mcpresult/mcpresult.go
@@ -6,7 +6,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logMCPResult = logger.New("mcpresult:mcpresult")
+var logMCPResult = logger.ForFile()
 
 // NormalizeContentItems normalizes an MCP "content" field into a slice of item
 // maps. It supports both []interface{} values produced by json.Unmarshal and
diff --git a/internal/middleware/jqschema.go b/internal/middleware/jqschema.go
index 26d4a54f4..0c4d2460b 100644
--- a/internal/middleware/jqschema.go
+++ b/internal/middleware/jqschema.go
@@ -24,7 +24,7 @@ import (
 	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
 )
 
-var logMiddleware = logger.New("middleware:jqschema")
+var logMiddleware = logger.ForFile()
 
 // DefaultJqTimeout is the default timeout for jq query execution (5 seconds)
 // This prevents malformed queries or large payloads from causing hangs
diff --git a/internal/oidc/provider.go b/internal/oidc/provider.go
index a9a872324..06b61fb08 100644
--- a/internal/oidc/provider.go
+++ b/internal/oidc/provider.go
@@ -21,7 +21,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logOIDC = logger.New("oidc:provider")
+var logOIDC = logger.ForFile()
 
 // tokenRefreshMargin is how far before expiry we proactively refresh a cached token.
 const tokenRefreshMargin = 60 * time.Second
diff --git a/internal/proxy/graphql.go b/internal/proxy/graphql.go
index b9cb6eba7..19ff978f8 100644
--- a/internal/proxy/graphql.go
+++ b/internal/proxy/graphql.go
@@ -9,7 +9,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logGraphQL = logger.New("proxy:graphql")
+var logGraphQL = logger.ForFile()
 
 // GraphQLRequest represents a parsed GraphQL request body.
 type GraphQLRequest struct {
diff --git a/internal/proxy/graphql_rewrite.go b/internal/proxy/graphql_rewrite.go
index 1b0d7d608..853417833 100644
--- a/internal/proxy/graphql_rewrite.go
+++ b/internal/proxy/graphql_rewrite.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logGraphQLRewrite = logger.New("proxy:graphql_rewrite")
+var logGraphQLRewrite = logger.ForFile()
 
 // Pre-compiled patterns used in injectFieldsIntoQuery.
 // Compiling these once at package init avoids repeated regexp compilation on
diff --git a/internal/proxy/handler.go b/internal/proxy/handler.go
index c28ab0eb7..950154184 100644
--- a/internal/proxy/handler.go
+++ b/internal/proxy/handler.go
@@ -23,7 +23,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logHandler = logger.New("proxy:handler")
+var logHandler = logger.ForFile()
 
 // writeDIFCForbidden writes a 403 JSON response for DIFC policy violations.
 // Uses the shared WriteErrorResponse helper so that the response shape is consistent
diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go
index 86b0584eb..6f5b4624a 100644
--- a/internal/proxy/proxy.go
+++ b/internal/proxy/proxy.go
@@ -24,7 +24,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/tracing"
 )
 
-var logProxy = logger.New("proxy:proxy")
+var logProxy = logger.ForFile()
 
 const (
 	// DefaultGitHubAPIBase is the upstream GitHub API URL.
diff --git a/internal/proxy/response_transform.go b/internal/proxy/response_transform.go
index ba2d61567..baba678b2 100644
--- a/internal/proxy/response_transform.go
+++ b/internal/proxy/response_transform.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logTransform = logger.New("proxy:response_transform")
+var logTransform = logger.ForFile()
 
 // rewrapSearchResponse re-wraps filtered items into the original search response
 // envelope. GitHub search endpoints return {"total_count": N, "items": [...]};
diff --git a/internal/proxy/router.go b/internal/proxy/router.go
index e8ebfc642..6ac0fe5b8 100644
--- a/internal/proxy/router.go
+++ b/internal/proxy/router.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logRouter = logger.New("proxy:router")
+var logRouter = logger.ForFile()
 
 // Argument key constants used when building route args maps.
 // Centralising these strings avoids typo-prone bare literals scattered across the file.
diff --git a/internal/proxy/tls.go b/internal/proxy/tls.go
index 97407f562..638308f8a 100644
--- a/internal/proxy/tls.go
+++ b/internal/proxy/tls.go
@@ -38,7 +38,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logTLS = logger.New("proxy:tls")
+var logTLS = logger.ForFile()
 
 // TLSConfig holds the paths to the generated certificate files.
 type TLSConfig struct {
diff --git a/internal/server/circuit_breaker.go b/internal/server/circuit_breaker.go
index d1795b78a..fc3172277 100644
--- a/internal/server/circuit_breaker.go
+++ b/internal/server/circuit_breaker.go
@@ -43,7 +43,7 @@ const DefaultRateLimitThreshold = 3
 // before transitioning to HALF-OPEN to probe one request.
 const DefaultRateLimitCooldown = 60 * time.Second
 
-var logCircuitBreaker = logger.New("server:circuit_breaker")
+var logCircuitBreaker = logger.ForFile()
 
 // circuitBreaker implements a per-backend rate-limit circuit breaker.
 //
diff --git a/internal/server/difc_log.go b/internal/server/difc_log.go
index 758743d8b..1d0fc4e1a 100644
--- a/internal/server/difc_log.go
+++ b/internal/server/difc_log.go
@@ -11,7 +11,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logDifcLog = logger.New("server:difc_log")
+var logDifcLog = logger.ForFile()
 
 // logFilteredItems logs structured details for every item removed by DIFC filtering.
 // Each item is written as a [DIFC-FILTERED] JSON entry to both the unified and
diff --git a/internal/server/guard_init.go b/internal/server/guard_init.go
index ea4637bea..f6dfd7042 100644
--- a/internal/server/guard_init.go
+++ b/internal/server/guard_init.go
@@ -14,7 +14,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logGuardInit = logger.New("server:guard_init")
+var logGuardInit = logger.ForFile()
 
 // legacyPolicySource is returned by resolveGuardPolicy when no explicit policy
 // is configured and the caller should fall back to legacy session-label semantics.
diff --git a/internal/server/handlers.go b/internal/server/handlers.go
index f7162c914..91f30229e 100644
--- a/internal/server/handlers.go
+++ b/internal/server/handlers.go
@@ -11,7 +11,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logHandlers = logger.New("server:handlers")
+var logHandlers = logger.ForFile()
 
 // HandleReflect returns an http.HandlerFunc that handles the /reflect endpoint.
 func HandleReflect(unifiedServer *UnifiedServer) http.HandlerFunc {
diff --git a/internal/server/health.go b/internal/server/health.go
index c2039113a..2796f2426 100644
--- a/internal/server/health.go
+++ b/internal/server/health.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/version"
 )
 
-var logHealth = logger.New("server:health")
+var logHealth = logger.ForFile()
 
 // HealthResponse represents the JSON structure for the /health endpoint response
 // as defined in MCP Gateway Specification section 8.1.1
diff --git a/internal/server/hmac.go b/internal/server/hmac.go
index f37529cc5..92b6875c2 100644
--- a/internal/server/hmac.go
+++ b/internal/server/hmac.go
@@ -31,7 +31,7 @@ const (
 	nonceTTL = 2 * hmacMaxAgeSecs * time.Second
 )
 
-var logHMAC = logger.New("server:hmac")
+var logHMAC = logger.ForFile()
 
 // nonceCache tracks recently-seen nonces to detect replay attacks.
 // Nonces are held for nonceTTL seconds after first use, then evicted.
diff --git a/internal/server/http_server.go b/internal/server/http_server.go
index 6835612c8..94829d24a 100644
--- a/internal/server/http_server.go
+++ b/internal/server/http_server.go
@@ -13,7 +13,7 @@ import (
 	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
 )
 
-var logHTTPServer = logger.New("server:http_server")
+var logHTTPServer = logger.ForFile()
 var logTransport = logger.New("server:transport")
 
 // newSDKServer creates a new MCP SDK server with the given implementation name and debug logger.
diff --git a/internal/server/response_writer.go b/internal/server/response_writer.go
index 6243cc9b9..ce46d753f 100644
--- a/internal/server/response_writer.go
+++ b/internal/server/response_writer.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logResponseWriter = logger.New("server:response_writer")
+var logResponseWriter = logger.ForFile()
 
 // responseWriter wraps http.ResponseWriter to capture response body and status code.
 // It embeds httputil.BaseResponseWriter for shared status-code capture logic, and
diff --git a/internal/server/routed.go b/internal/server/routed.go
index e4dbae44a..566db0ca3 100644
--- a/internal/server/routed.go
+++ b/internal/server/routed.go
@@ -11,7 +11,7 @@ import (
 	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
 )
 
-var logRouted = logger.New("server:routed")
+var logRouted = logger.ForFile()
 
 // rejectIfShutdown is a middleware that rejects requests with HTTP 503 when gateway is shutting down
 // Per spec 5.1.3: "Immediately reject any new RPC requests to /mcp/{server-name} endpoints with HTTP 503"
diff --git a/internal/server/session.go b/internal/server/session.go
index cc48bcf9a..66b50f03f 100644
--- a/internal/server/session.go
+++ b/internal/server/session.go
@@ -17,7 +17,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logSession = logger.New("server:session")
+var logSession = logger.ForFile()
 
 // extractSessionIDFromRequest extracts the session ID from X-Agent-ID and
 // Authorization headers. Returns "" if neither header is present or valid.
diff --git a/internal/server/system_tools.go b/internal/server/system_tools.go
index 15084d943..dc95a685a 100644
--- a/internal/server/system_tools.go
+++ b/internal/server/system_tools.go
@@ -10,7 +10,7 @@ import (
 	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
 )
 
-var logSys = logger.New("server:system_tools")
+var logSys = logger.ForFile()
 
 // SysServer implements the MCPG system tools
 type SysServer struct {
diff --git a/internal/server/tool_registry_helpers.go b/internal/server/tool_registry_helpers.go
index a34c169f9..04a06fc78 100644
--- a/internal/server/tool_registry_helpers.go
+++ b/internal/server/tool_registry_helpers.go
@@ -12,7 +12,7 @@ import (
 	sdk "github.com/modelcontextprotocol/go-sdk/mcp"
 )
 
-var logToolRegistryHelpers = logger.New("server:tool_registry_helpers")
+var logToolRegistryHelpers = logger.ForFile()
 
 // launchResult stores the result of a backend server launch.
 type launchResult struct {
diff --git a/internal/server/unified.go b/internal/server/unified.go
index 9ea19bdd4..d96101dc4 100644
--- a/internal/server/unified.go
+++ b/internal/server/unified.go
@@ -23,7 +23,7 @@ import (
 	oteltrace "go.opentelemetry.io/otel/trace"
 )
 
-var logUnified = logger.New("server:unified")
+var logUnified = logger.ForFile()
 
 const rateLimitExceededStatus = "rate limit exceeded"
 
diff --git a/internal/sys/container.go b/internal/sys/container.go
index 3259fdc61..673bf651f 100644
--- a/internal/sys/container.go
+++ b/internal/sys/container.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logSys = logger.New("sys:container")
+var logSys = logger.ForFile()
 
 // containerIndicators lists the cgroup path substrings that indicate a container environment.
 var containerIndicators = []string{"docker", "containerd", "kubepods", "lxc"}
diff --git a/internal/sys/docker.go b/internal/sys/docker.go
index 804583879..8466575e4 100644
--- a/internal/sys/docker.go
+++ b/internal/sys/docker.go
@@ -10,7 +10,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logDocker = logger.New("sys:docker")
+var logDocker = logger.ForFile()
 
 // containerIDPattern validates that a container ID only contains valid characters (hex digits).
 // Container IDs are 64 character hex strings, but short form (12 chars) is also valid.
diff --git a/internal/testutil/mcptest/driver.go b/internal/testutil/mcptest/driver.go
index bb3229414..2b9819572 100644
--- a/internal/testutil/mcptest/driver.go
+++ b/internal/testutil/mcptest/driver.go
@@ -12,7 +12,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/server"
 )
 
-var logDriver = logger.New("mcptest:driver")
+var logDriver = logger.ForFile()
 
 // TestDriver manages test servers and the gateway for integration testing
 type TestDriver struct {
diff --git a/internal/tracing/provider.go b/internal/tracing/provider.go
index df285e2af..4d3bf3528 100644
--- a/internal/tracing/provider.go
+++ b/internal/tracing/provider.go
@@ -40,7 +40,7 @@ import (
 
 const instrumentationName = "github.com/github/gh-aw-mcpg"
 
-var logTracing = logger.New("tracing:provider")
+var logTracing = logger.ForFile()
 
 // Provider wraps an OpenTelemetry TracerProvider and provides a Shutdown method.
 type Provider struct {
diff --git a/internal/urlutil/domains.go b/internal/urlutil/domains.go
index b8cd45430..e1ed62356 100644
--- a/internal/urlutil/domains.go
+++ b/internal/urlutil/domains.go
@@ -9,7 +9,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/util"
 )
 
-var logDomains = logger.New("urlutil:domains")
+var logDomains = logger.ForFile()
 
 // urlPattern requires a non-empty hostname candidate and then captures the rest
 // of the URL until common delimiter characters. The (?i) flag makes the scheme
diff --git a/internal/version/version.go b/internal/version/version.go
index 30efb8a30..d60b7d0ca 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -8,7 +8,7 @@ import (
 	"github.com/github/gh-aw-mcpg/internal/logger"
 )
 
-var logVersion = logger.New("version:version")
+var logVersion = logger.ForFile()
 
 // readBuildInfo is a package-level variable wrapping debug.ReadBuildInfo to
 // allow test injection without changing the public API.
