mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-11-10 21:32:43 +08:00
Combine RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS into ALLOW_ANY_HOST (#21523)
This commit is contained in:
1 parent
1a6a382a2f
commit
0b9ce6ddda
10 files changed
+37
-19
No files matched your search
@@ -77,10 +77,10 @@ RAGFlow keeps **Save** disabled until the current connection settings have been
|
||||
RAGFlow validates the endpoint before connecting:
|
||||
|
||||
- The URL must use `http://` or `https://` and contain a host. `stdio://` is not supported.
|
||||
- Every address returned by DNS must be publicly routable. Loopback, private, link-local, reserved, Docker-network, and other non-public addresses are rejected.
|
||||
- By default, every address returned by DNS must be publicly routable. Loopback, private, link-local, reserved, Docker-network, and other non-public addresses are rejected.
|
||||
- The Go MCP client connects to the validated address directly and does not use HTTP proxy environment variables.
|
||||
|
||||
Consequently, endpoints such as `localhost`, `127.0.0.1`, `::1`, `10.x.x.x`, `172.16.x.x` through `172.31.x.x`, and `192.168.x.x` cannot be added through this path. `ALLOW_ANY_HOST` does not disable this validation. Publish the MCP endpoint on a public address whose DNS records all resolve to public addresses.
|
||||
To connect to self-hosted MCP endpoints on private or Docker networks, set `ALLOW_ANY_HOST=true` in the RAGFlow backend environment and restart the backend. This shared setting also permits private database and connector hosts. Accepted true values are `1`, `true`, `yes`, and `on` (case-insensitive, with surrounding whitespace ignored). HTTP/HTTPS scheme validation, DNS resolution, and connection pinning remain enabled.
|
||||
|
||||
## Troubleshoot a failed connection
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@ import (
|
||||
// truthy value (1, true, yes, on), matching the Python host guard.
|
||||
//
|
||||
// The flag is the development opt-in documented in docker/.env. It applies
|
||||
// only to host-based database and connector dials (MySQL, PostgreSQL, IMAP,
|
||||
// test_db_connection, ExeSQL), including host.docker.internal. URL and Invoke
|
||||
// guards do not call this, so the flag cannot turn off DNS pinning for
|
||||
// user-controlled URLs. Default is off.
|
||||
// to host-based database and connector dials (MySQL, PostgreSQL, IMAP,
|
||||
// test_db_connection, ExeSQL), including host.docker.internal, and configured
|
||||
// MCP servers. Other URL and Invoke guards do not call this. DNS pinning
|
||||
// remains enabled. Default is off.
|
||||
func AllowConfiguredPrivateHost() bool {
|
||||
switch strings.ToLower(strings.TrimSpace(GetEnv(EnvAllowAnyHost))) {
|
||||
case "1", "true", "yes", "on":
|
||||
|
||||
@@ -84,7 +84,6 @@ const (
|
||||
EnvRAGFlowTTSCacheTTLSeconds = "RAGFLOW_TTS_CACHE_TTL_SECONDS"
|
||||
EnvRerankTokenLimitMode = "RERANK_TOKEN_LIMIT_MODE"
|
||||
EnvComponentExecTimeout = "COMPONENT_EXEC_TIMEOUT"
|
||||
EnvMCPAllowPrivateHosts = "RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS"
|
||||
EnvDocEngine = "DOC_ENGINE"
|
||||
EnvMaxFileNumPerUser = "MAX_FILE_NUM_PER_USER"
|
||||
EnvMaxContentLength = "MAX_CONTENT_LENGTH"
|
||||
|
||||
@@ -467,9 +467,9 @@ var LookupHost = net.LookupHost
|
||||
// a deployment mistake. The explicit "_ForTest" suffix is the
|
||||
// signal that production code must never touch it.
|
||||
//
|
||||
// Host-based database and connector dials are a separate opt-in.
|
||||
// AllowConfiguredPrivateHost reads ALLOW_ANY_HOST for those dials
|
||||
// only. This function stays limited to the in-memory test hook.
|
||||
// Host-based database and connector dials and configured MCP servers are a
|
||||
// separate opt-in. AllowConfiguredPrivateHost reads ALLOW_ANY_HOST for those
|
||||
// dials only. This function stays limited to the in-memory test hook.
|
||||
var AllowAnyHostForTest = false
|
||||
|
||||
// allowAnyHost reads the test-only override. Kept as a private
|
||||
|
||||
@@ -41,7 +41,7 @@ type CallOptions struct {
|
||||
HTTPClient *http.Client
|
||||
// AllowPrivateHosts relaxes the public-routability requirement so
|
||||
// self-hosted MCP servers on private/docker networks work. Callers source
|
||||
// it from the deployment flag (RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS); scheme
|
||||
// it from the deployment flag (ALLOW_ANY_HOST); scheme
|
||||
// validation, DNS resolution, and IP pinning still apply.
|
||||
AllowPrivateHosts bool
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ type FetchOptions struct {
|
||||
HTTPClient *http.Client
|
||||
// AllowPrivateHosts relaxes the public-routability requirement so
|
||||
// self-hosted MCP servers on private/docker networks work. Callers source
|
||||
// it from the deployment flag (RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS); scheme
|
||||
// it from the deployment flag (ALLOW_ANY_HOST); scheme
|
||||
// validation, DNS resolution, and IP pinning still apply.
|
||||
AllowPrivateHosts bool
|
||||
pinHostname string
|
||||
|
||||
@@ -51,7 +51,7 @@ func sameOrigin(a, b *url.URL) bool {
|
||||
// AssertMCPURLSafe validates an MCP server URL. It delegates to
|
||||
// common.AssertURLSafe by default. When allowPrivateHosts is true (a
|
||||
// deployment-level operator decision, sourced from
|
||||
// RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS at the call site), the
|
||||
// ALLOW_ANY_HOST at the call site), the
|
||||
// public-routability requirement is relaxed so self-hosted MCP servers on
|
||||
// private/docker networks work — scheme validation, DNS resolution, and
|
||||
// connection pinning to the resolved IP still apply.
|
||||
|
||||
@@ -170,7 +170,7 @@ func GetConfig() *config.Config {
|
||||
}
|
||||
|
||||
// MCPAllowPrivateHosts reports whether self-hosted MCP servers on private
|
||||
// networks are permitted (RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS). It is nil-safe:
|
||||
// networks are permitted (ALLOW_ANY_HOST). It is nil-safe:
|
||||
// an uninitialized global config yields false so callers fail closed instead
|
||||
// of panicking on a nil *config.Config.
|
||||
func MCPAllowPrivateHosts() bool {
|
||||
|
||||
@@ -111,7 +111,7 @@ type Environments struct {
|
||||
TavilyAPIKey string `mapstructure:"tavily_api_key"`
|
||||
QueritAPIKey string `mapstructure:"querit_api_key"`
|
||||
KeenableAPIURL string `mapstructure:"keenable_api_url"` // KEENABLE_API_URL
|
||||
MCPAllowPrivateHosts bool `mapstructure:"mcp_allow_private_hosts"` // RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS
|
||||
MCPAllowPrivateHosts bool `mapstructure:"mcp_allow_private_hosts"` // ALLOW_ANY_HOST
|
||||
}
|
||||
|
||||
type DefaultSuperUser struct {
|
||||
@@ -298,10 +298,7 @@ func (c *Config) GetEnvironments() error {
|
||||
c.environments.HomePath = homePath
|
||||
}
|
||||
|
||||
mcpAllowPrivateHosts := common.GetEnvSmall(common.EnvMCPAllowPrivateHosts)
|
||||
if mcpAllowPrivateHosts != "" {
|
||||
c.environments.MCPAllowPrivateHosts = mcpAllowPrivateHosts == "true" || mcpAllowPrivateHosts == "1" || mcpAllowPrivateHosts == "yes"
|
||||
}
|
||||
c.environments.MCPAllowPrivateHosts = common.AllowConfiguredPrivateHost()
|
||||
|
||||
userProfile := common.GetEnv(common.EnvUserProfile)
|
||||
if userProfile != "" {
|
||||
|
||||
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"ragflow/internal/common"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -20,6 +21,27 @@ func clearMCPEnv(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCPAllowPrivateHostsEnvironment(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
value string
|
||||
want bool
|
||||
}{
|
||||
{"", false}, {"0", false}, {"false", false}, {"no", false}, {"off", false}, {"invalid", false},
|
||||
{"1", true}, {"true", true}, {"yes", true}, {"on", true}, {" TRUE ", true},
|
||||
} {
|
||||
t.Run(tc.value, func(t *testing.T) {
|
||||
t.Setenv(common.EnvAllowAnyHost, tc.value)
|
||||
var cfg Config
|
||||
if err := cfg.GetEnvironments(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := cfg.GetMCPAllowPrivateHosts(); got != tc.want {
|
||||
t.Fatalf("ALLOW_ANY_HOST=%q: MCPAllowPrivateHosts = %v, want %v", tc.value, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func parseMCPYAML(t *testing.T, text string) (MCPConfig, error) {
|
||||
t.Helper()
|
||||
v := viper.New()
|
||||
|
||||
Reference in new issue
Block a user