88#include < cstdlib>
99
1010using namespace duckdb_yyjson ;
11+ #ifndef __EMSCRIPTEN__
1112#include " mcpfs/mcp_file_system.hpp"
1213#include " client/mcp_storage_extension.hpp"
1314#include " protocol/mcp_connection.hpp"
15+ #endif
1416#include " protocol/mcp_message.hpp"
1517#include " protocol/mcp_template.hpp"
1618#include " protocol/mcp_pagination.hpp"
@@ -33,6 +35,8 @@ using namespace duckdb_yyjson;
3335
3436namespace duckdb {
3537
38+ #ifndef __EMSCRIPTEN__
39+
3640// Get MCP resource content
3741static void MCPGetResourceFunction (DataChunk &args, ExpressionState &state, Vector &result) {
3842 auto &server_vector = args.data [0 ];
@@ -455,6 +459,8 @@ static void MCPServerHealthFunction(DataChunk &args, ExpressionState &state, Vec
455459 }
456460}
457461
462+ #endif // !__EMSCRIPTEN__
463+
458464// MCPStatus struct type definition
459465static LogicalType GetMCPStatusType () {
460466 child_list_t <LogicalType> members;
@@ -596,7 +602,19 @@ static Value MCPServerStartImpl(ExpressionState &state, const string &transport,
596602 }
597603
598604 // Handle different transport types
599- if (transport == " stdio" ) {
605+ if (transport == " memory" ) {
606+ // Memory transport is always background mode (for testing with mcp_server_send_request)
607+ // The server doesn't do I/O - it just waits for requests via ProcessRequest()
608+ server_config.background = true ;
609+ if (server_manager.StartServer (server_config)) {
610+ return CreateMCPStatus (true , true , " MCP server started on memory transport (background mode)" ,
611+ transport, bind_address, port, true );
612+ } else {
613+ return CreateMCPStatus (false , false , " Failed to start MCP server" , transport, bind_address, port, true );
614+ }
615+ }
616+ #ifndef __EMSCRIPTEN__
617+ else if (transport == " stdio" ) {
600618 if (server_config.background ) {
601619 // Background mode: use server manager (non-blocking, starts thread)
602620 if (server_manager.StartServer (server_config)) {
@@ -626,16 +644,6 @@ static Value MCPServerStartImpl(ExpressionState &state, const string &transport,
626644 server.GetErrorsReturned ());
627645 }
628646 }
629- } else if (transport == " memory" ) {
630- // Memory transport is always background mode (for testing with mcp_server_send_request)
631- // The server doesn't do I/O - it just waits for requests via ProcessRequest()
632- server_config.background = true ;
633- if (server_manager.StartServer (server_config)) {
634- return CreateMCPStatus (true , true , " MCP server started on memory transport (background mode)" ,
635- transport, bind_address, port, true );
636- } else {
637- return CreateMCPStatus (false , false , " Failed to start MCP server" , transport, bind_address, port, true );
638- }
639647 } else if (transport == " http" || transport == " https" ) {
640648 // HTTP/HTTPS transport
641649 if (server_config.background ) {
@@ -667,14 +675,22 @@ static Value MCPServerStartImpl(ExpressionState &state, const string &transport,
667675 server.GetErrorsReturned ());
668676 }
669677 }
670- } else {
678+ }
679+ #endif // !__EMSCRIPTEN__
680+ else {
681+ // Unknown transport (or non-memory transport in WASM)
682+ #ifdef __EMSCRIPTEN__
683+ return CreateMCPStatus (false , false , " Only 'memory' transport is available in WASM" , transport,
684+ bind_address, port, false );
685+ #else
671686 // For other transports (TCP/WebSocket), use background thread
672687 if (server_manager.StartServer (server_config)) {
673688 return CreateMCPStatus (true , true , " MCP server started on " + transport, transport, bind_address, port,
674689 true );
675690 } else {
676691 return CreateMCPStatus (false , false , " Failed to start MCP server" , transport, bind_address, port, true );
677692 }
693+ #endif
678694 }
679695
680696 } catch (const std::exception &e) {
@@ -1300,10 +1316,12 @@ static void MCPGetDiagnosticsFunction(DataChunk &args, ExpressionState &state, V
13001316}
13011317
13021318// Callback functions for MCP configuration settings
1319+ #ifndef __EMSCRIPTEN__
13031320static void SetAllowedMCPCommands (ClientContext &context, SetScope scope, Value ¶meter) {
13041321 auto &security = MCPSecurityConfig::GetInstance ();
13051322 security.SetAllowedCommands (parameter.ToString ());
13061323}
1324+ #endif
13071325
13081326static void SetMCPLogLevel (ClientContext &context, SetScope scope, Value ¶meter) {
13091327 auto level_str = parameter.ToString ();
@@ -1325,14 +1343,17 @@ static void SetMCPLogLevel(ClientContext &context, SetScope scope, Value ¶me
13251343 MCPLogger::GetInstance ().SetLogLevel (level);
13261344}
13271345
1346+ #ifndef __EMSCRIPTEN__
13281347static void SetMCPLogFile (ClientContext &context, SetScope scope, Value ¶meter) {
13291348 MCPLogger::GetInstance ().SetLogFile (parameter.ToString ());
13301349}
1350+ #endif
13311351
13321352static void SetMCPConsoleLogging (ClientContext &context, SetScope scope, Value ¶meter) {
13331353 MCPLogger::GetInstance ().EnableConsoleLogging (parameter.GetValue <bool >());
13341354}
13351355
1356+ #ifndef __EMSCRIPTEN__
13361357static void SetAllowedMCPUrls (ClientContext &context, SetScope scope, Value ¶meter) {
13371358 auto &security = MCPSecurityConfig::GetInstance ();
13381359 security.SetAllowedUrls (parameter.ToString ());
@@ -1348,13 +1369,16 @@ static void SetMCPLockServers(ClientContext &context, SetScope scope, Value &par
13481369 bool lock = parameter.GetValue <bool >();
13491370 security.LockServers (lock);
13501371}
1372+ #endif
13511373
13521374static void SetMCPDisableServing (ClientContext &context, SetScope scope, Value ¶meter) {
13531375 auto &security = MCPSecurityConfig::GetInstance ();
13541376 bool disable = parameter.GetValue <bool >();
13551377 security.SetServingDisabled (disable);
13561378}
13571379
1380+ #ifndef __EMSCRIPTEN__
1381+
13581382// MCP-Compliant Pagination Functions
13591383
13601384// List resources with optional cursor (MCP-compliant)
@@ -1489,6 +1513,8 @@ static void MCPListPromptsWithCursorFunction(DataChunk &args, ExpressionState &s
14891513 }
14901514}
14911515
1516+ #endif // !__EMSCRIPTEN__
1517+
14921518// MCP Template Functions
14931519
14941520static void MCPRegisterPromptTemplateFunction (DataChunk &args, ExpressionState &state, Vector &result) {
@@ -1619,20 +1645,21 @@ static void MCPRenderPromptTemplateFunction(DataChunk &args, ExpressionState &st
16191645
16201646static void LoadInternal (ExtensionLoader &loader) {
16211647 auto &db = loader.GetDatabaseInstance ();
1648+ auto &config = DBConfig::GetConfig (db);
16221649
1650+ #ifndef __EMSCRIPTEN__
16231651 // Register MCPFS file system
16241652 auto &fs = FileSystem::GetFileSystem (db);
16251653 fs.RegisterSubSystem (make_uniq<MCPFileSystem>());
16261654
16271655 // Register MCP storage extension for ATTACH support
1628- auto &config = DBConfig::GetConfig (db);
16291656#ifdef DUCKDB_V15
16301657 StorageExtension::Register (config, " mcp" , MCPStorageExtension::Create ());
16311658#else
16321659 config.storage_extensions [" mcp" ] = MCPStorageExtension::Create ();
16331660#endif
16341661
1635- // Register MCP configuration options
1662+ // Register native-only MCP configuration options
16361663 config.AddExtensionOption (" allowed_mcp_commands" ,
16371664 " Colon-delimited list of executable paths allowed for MCP servers (security: executable "
16381665 " paths only, no arguments)" ,
@@ -1648,45 +1675,38 @@ static void LoadInternal(ExtensionLoader &loader) {
16481675 " Lock MCP server configuration to prevent runtime changes (security feature)" ,
16491676 LogicalType::BOOLEAN, Value (false ), SetMCPLockServers);
16501677
1651- config.AddExtensionOption (" mcp_disable_serving" , " Disable MCP server functionality entirely (client-only mode)" ,
1652- LogicalType::BOOLEAN, Value (false ), SetMCPDisableServing);
1653-
1654- // Register MCP logging configuration options
1655- config.AddExtensionOption (" mcp_log_level" , " MCP logging level (trace, debug, info, warn, error, off)" ,
1656- LogicalType::VARCHAR, Value (" warn" ), SetMCPLogLevel);
1657-
16581678 config.AddExtensionOption (" mcp_log_file" , " Path to MCP log file (empty for no file logging)" , LogicalType::VARCHAR,
16591679 Value (" " ), SetMCPLogFile);
16601680
1661- config.AddExtensionOption (" mcp_console_logging" , " Enable MCP logging to console/stderr" , LogicalType::BOOLEAN,
1662- Value (false ), SetMCPConsoleLogging);
1663-
16641681 // Initialize default security settings only if not already configured.
1665- // The singleton may already be locked from a previous LoadInternal call
1666- // (e.g., multiple database instances) or from user SET commands.
1667- // Avoid resetting locked state — doing so could widen permissions.
16681682 auto &security = MCPSecurityConfig::GetInstance ();
16691683 if (!security.AreCommandsLocked ()) {
1670- // Set defaults for URL and server file (these don't lock).
1671- // Do NOT call SetAllowedCommands("") here — the constructor defaults
1672- // (empty + unlocked) are sufficient. The user's first explicit
1673- // SET allowed_mcp_commands will lock commands.
16741684 security.SetAllowedUrls (" " );
16751685 security.SetServerFile (" ./.mcp.json" );
16761686 security.LockServers (false );
16771687 }
1688+ #endif // !__EMSCRIPTEN__
1689+
1690+ // Configuration options available on all platforms (including WASM)
1691+ config.AddExtensionOption (" mcp_disable_serving" , " Disable MCP server functionality entirely (client-only mode)" ,
1692+ LogicalType::BOOLEAN, Value (false ), SetMCPDisableServing);
1693+
1694+ config.AddExtensionOption (" mcp_log_level" , " MCP logging level (trace, debug, info, warn, error, off)" ,
1695+ LogicalType::VARCHAR, Value (" warn" ), SetMCPLogLevel);
1696+
1697+ config.AddExtensionOption (" mcp_console_logging" , " Enable MCP logging to console/stderr" , LogicalType::BOOLEAN,
1698+ Value (false ), SetMCPConsoleLogging);
16781699
1679- // Register MCP resource functions
1700+ #ifndef __EMSCRIPTEN__
1701+ // Register client-side MCP functions (require MCPConnectionRegistry)
16801702 auto get_resource_func = ScalarFunction (" mcp_get_resource" , {LogicalType::VARCHAR, LogicalType::VARCHAR},
16811703 LogicalType::JSON (), MCPGetResourceFunction);
16821704 loader.RegisterFunction (get_resource_func);
16831705
1684- // Create overloaded versions for list_resources (with and without cursor)
16851706 auto list_resources_func_simple =
16861707 ScalarFunction (" mcp_list_resources" , {LogicalType::VARCHAR}, LogicalType::JSON (), MCPListResourcesFunction);
16871708 auto list_resources_func_cursor = ScalarFunction (" mcp_list_resources" , {LogicalType::VARCHAR, LogicalType::VARCHAR},
16881709 LogicalType::JSON (), MCPListResourcesWithCursorFunction);
1689-
16901710 loader.RegisterFunction (list_resources_func_simple);
16911711 loader.RegisterFunction (list_resources_func_cursor);
16921712
@@ -1695,15 +1715,13 @@ static void LoadInternal(ExtensionLoader &loader) {
16951715 LogicalType::JSON (), MCPCallToolFunction);
16961716 loader.RegisterFunction (call_tool_func);
16971717
1698- // Register MCP tool functions (with and without cursor)
16991718 auto list_tools_func_simple =
17001719 ScalarFunction (" mcp_list_tools" , {LogicalType::VARCHAR}, LogicalType::JSON (), MCPListToolsFunction);
17011720 auto list_tools_func_cursor = ScalarFunction (" mcp_list_tools" , {LogicalType::VARCHAR, LogicalType::VARCHAR},
17021721 LogicalType::JSON (), MCPListToolsWithCursorFunction);
17031722 loader.RegisterFunction (list_tools_func_simple);
17041723 loader.RegisterFunction (list_tools_func_cursor);
17051724
1706- // Register MCP prompt functions (with and without cursor)
17071725 auto list_prompts_func_simple =
17081726 ScalarFunction (" mcp_list_prompts" , {LogicalType::VARCHAR}, LogicalType::JSON (), MCPListPromptsFunction);
17091727 auto list_prompts_func_cursor = ScalarFunction (" mcp_list_prompts" , {LogicalType::VARCHAR, LogicalType::VARCHAR},
@@ -1716,17 +1734,16 @@ static void LoadInternal(ExtensionLoader &loader) {
17161734 LogicalType::JSON (), MCPGetPromptFunction);
17171735 loader.RegisterFunction (get_prompt_func);
17181736
1719- // Register MCP connection management functions
17201737 auto reconnect_func = ScalarFunction (" mcp_reconnect_server" , {LogicalType::VARCHAR}, LogicalType::VARCHAR,
17211738 MCPReconnectServerFunction);
17221739 loader.RegisterFunction (reconnect_func);
17231740
17241741 auto health_func =
17251742 ScalarFunction (" mcp_server_health" , {LogicalType::VARCHAR}, LogicalType::VARCHAR, MCPServerHealthFunction);
17261743 loader.RegisterFunction (health_func);
1744+ #endif // !__EMSCRIPTEN__
17271745
1728- // Register MCP server functions (multiple overloads for convenience)
1729- // All server management functions return MCPStatus struct type
1746+ // Server-side functions (work via memory transport in WASM)
17301747 LogicalType mcp_status_type = GetMCPStatusType ();
17311748
17321749 // mcp_server_start(transport) - simplest form for stdio
0 commit comments