Repository: hahwul/dalfox

Issue:
Add MCP Server mode


Discussion:

Solution patch:
diff --git a/cmd/server.go b/cmd/server.go
index 35bb510..ae72f4f 100644
--- a/cmd/server.go
+++ b/cmd/server.go
@@ -7,7 +7,7 @@ import (
 )
 
 var port int
-var host string
+var host, server_type string
 
 // serverCmd represents the server command
 var serverCmd = &cobra.Command{
@@ -18,15 +18,24 @@ var serverCmd = &cobra.Command{
 
 func runServerCmd(cmd *cobra.Command, args []string) {
 	printing.Banner(options)
-	printing.DalLog("SYSTEM", "Starting API Server", options)
 	options.ServerHost = host
 	options.ServerPort = port
-	printing.Summary(options, "REST API Mode")
-	server.RunAPIServer(options)
+
+	switch server_type {
+	case "mcp":
+		printing.DalLog("SYSTEM", "Starting MCP Server", options)
+		printing.Summary(options, "MCP Server Mode")
+		server.RunMCPServer(options)
+	default:
+		printing.DalLog("SYSTEM", "Starting REST API Server", options)
+		printing.Summary(options, "REST API Mode")
+		server.RunAPIServer(options)
+	}
 }
 
 func init() {
 	rootCmd.AddCommand(serverCmd)
 	serverCmd.Flags().IntVar(&port, "port", 6664, "Specify the port to bind the server to. Example: --port 6664")
 	serverCmd.Flags().StringVar(&host, "host", "0.0.0.0", "Specify the address to bind the server to. Example: --host '0.0.0.0'")
+	serverCmd.Flags().StringVar(&server_type, "type", "rest", "Specify the server type. Example: --type 'rest' or --type 'mcp'")
 }
diff --git a/docs/images/page/running/mcp-claude.jpg b/docs/images/page/running/mcp-claude.jpg
new file mode 100644
index 0000000..1dcfc24
Binary files /dev/null and b/docs/images/page/running/mcp-claude.jpg differ
diff --git a/docs/images/page/running/mcp-vscode.jpg b/docs/images/page/running/mcp-vscode.jpg
new file mode 100644
index 0000000..89aec45
Binary files /dev/null and b/docs/images/page/running/mcp-vscode.jpg differ
diff --git a/docs/page/modes/server-mode.md b/docs/page/modes/server-mode.md
index 5c2f9a3..42090b7 100644
--- a/docs/page/modes/server-mode.md
+++ b/docs/page/modes/server-mode.md
@@ -1,5 +1,5 @@
 ---
-title: Server Mode (REST API)
+title: Server Mode
 redirect_from: /docs/modes/server-mode/
 has_children: false
 parent: Usage
@@ -8,30 +8,48 @@ toc: true
 layout: page
 ---
 
-# Server Mode (REST API)
+# Server Mode
 
 ## Overview
 
-Server mode transforms Dalfox into a REST API service, enabling integration with other security tools, automation workflows, and continuous security pipelines. When running in server mode, Dalfox listens on a specified IP address and port, accepting scan requests via HTTP endpoints.
+Server mode transforms Dalfox into a service that can be used in different ways. By default, Dalfox runs as a REST API service, but it can also operate as an MCP (Model Context Protocol) server using the `--type` flag.
 
-This mode is particularly valuable for:
+### Server Types
+
+1. **REST API Mode (Default)**: Enables integration with other security tools, automation workflows, and continuous security pipelines through HTTP endpoints.
+
+2. **MCP Mode**: Allows Dalfox to operate as a Model Context Protocol server, making it compatible with advanced AI assistants and development environments like Visual Studio Code.
+
+These modes are particularly valuable for:
 - Security operations centers (SOCs) looking to build centralized scanning infrastructure
 - DevSecOps teams integrating security scanning into CI/CD pipelines
 - Bug bounty hunters automating large-scale testing
 - Creating custom security dashboards with XSS scanning capabilities
+- AI-assisted security testing workflows (MCP mode)
 
 ## Starting the Server
 
 To start Dalfox in server mode, use the `server` command:
 
 ```bash
-# Start with default settings (listening on 0.0.0.0:6664)
+# Start with default settings (listening on 0.0.0.0:6664 in REST API mode)
 dalfox server
 
 # Specify custom host and port
 dalfox server --host 127.0.0.1 --port 8090
+
+# Start as an MCP server
+dalfox server --type mcp
 ```
 
+### Server Mode Flags
+
+| Flag       | Description                                                     | Default     |
+|------------|-----------------------------------------------------------------|-------------|
+| `--host`   | Specify the address to bind the server to                       | `0.0.0.0`   |
+| `--port`   | Specify the port to bind the server to                          | `6664`      |
+| `--type`   | Specify the server type (`rest` or `mcp`)                       | `rest`      |
+
 ### Example Output
 
 ```bash
@@ -273,3 +291,51 @@ When deploying Dalfox in server mode, consider the following security practices:
 - Use a proper API key mechanism for authenticating clients
 - Consider implementing rate limiting for public-facing instances
 - Regularly update your Dalfox installation to get the latest security checks and bug fixes
+
+## MCP Server Mode
+{: .d-inline-block }
+
+Not released (v2.11.0) 
+{: .label .label-blue }
+
+Dalfox can function as a Model Context Protocol (MCP) server, enabling direct integration with AI-powered development environments like Visual Studio Code and compatible AI assistants.
+
+### What is MCP?
+
+Model Context Protocol (MCP) is a protocol designed to enable AI assistants to execute specialized tools in a controlled environment. By running Dalfox as an MCP server, AI coding assistants can directly leverage Dalfox's XSS scanning capabilities within your development workflow.
+
+### Setting Up MCP Integration with VS Code
+
+To use Dalfox as an MCP server with Visual Studio Code:
+
+1. Start Dalfox in MCP server mode:
+   ```bash
+   dalfox server --type mcp
+   ```
+
+2. Configure VS Code to use Dalfox as an MCP server by adding the following to your `settings.json`:
+   ```json
+   {
+     "mcp": {
+       "servers": {
+         "dalfox": {
+           "type": "stdio",
+           "command": "dalfox",
+           "args": [
+             "server",
+             "--type=mcp"
+           ]
+         }
+       }
+     }
+   }
+   ```
+
+3. With this configuration, compatible AI coding assistants can now use Dalfox to perform XSS vulnerability scanning directly within your IDE.
+
+### Benefits of MCP Mode
+
+- **AI-Driven Security Testing**: AI assistants can suggest and execute security tests directly within your development environment
+- **Interactive Scanning**: Have conversations with AI about possible XSS vulnerabilities in your code
+- **Seamless Workflow Integration**: Eliminates the need to switch between your development environment and security tools
+- **Guided Remediation**: AI can not only find vulnerabilities but help explain and fix them in context
diff --git a/docs/page/running/mcp.md b/docs/page/running/mcp.md
new file mode 100644
index 0000000..6fa4a8b
--- /dev/null
+++ b/docs/page/running/mcp.md
@@ -0,0 +1,183 @@
+---
+title: MCP Mode
+parent: Running
+has_children: false
+nav_order: 4
+layout: page
+---
+
+# Dalfox MCP Mode
+{: .d-inline-block }
+
+Not released (v2.11.0) 
+{: .label .label-blue }
+
+## Overview
+
+Model Context Protocol (MCP) mode allows Dalfox to operate as an MCP server, enabling direct integration with AI assistants and language models (LLMs). This integration provides a seamless experience for security testing, allowing AI tools to directly leverage Dalfox's XSS scanning capabilities.
+
+## What is Model Context Protocol (MCP)?
+
+Model Context Protocol is a specification that allows AI language models to interact with external tools. By running Dalfox as an MCP server, AI coding assistants can:
+
+- Initiate XSS vulnerability scans
+- Process scan results within the AI conversation
+- Help interpret security findings
+- Suggest remediation steps
+
+## Starting Dalfox in MCP Mode
+
+To run Dalfox as an MCP server:
+
+```bash
+dalfox server --type mcp
+```
+
+## Client Integrations
+
+### Visual Studio Code
+
+VS Code provides robust support for MCP tools when used with AI coding assistants like GitHub Copilot or other MCP-compatible extensions.
+
+#### Configuration Steps
+
+1. **Install Dalfox** (if not already installed)
+   ```bash
+   # From source
+   go install github.com/hahwul/dalfox/v2@latest
+
+   # Homebrew
+   brew install dalfox
+
+   # Snapcraft
+   snap install dalfox
+   ```
+
+   *[Installation](/page/installation/)*
+
+2. **Configure VS Code settings**
+   
+   To enable the dalfox server in VS Code, update your `settings.json` file with the following configuration:
+   
+   ```json
+   {
+     "mcp": {
+       "servers": {
+         "dalfox": {
+           "type": "stdio",
+           "command": "dalfox",
+           "args": [
+             "server",
+             "--type=mcp"
+           ]
+         }
+       }
+     }
+   }
+   ```
+
+   This setup defines a server named dalfox that uses standard input/output (stdio) and runs the command `dalfox server --type=mcp`. You can manually add the server by pressing `⌘` + `⇧` + `p`, selecting MCP: Add Server, choosing `Command (stdio)`, and entering `dalfox server --type=mcp` in the input field. This ensures seamless integration of the dalfox server with your VS Code environment.
+
+3. **Use with AI assistant**
+   
+   Now your AI coding assistant can directly use Dalfox to scan for XSS vulnerabilities. For example, you can ask:
+   
+   ```
+   "Can you scan this URL for XSS vulnerabilities using Dalfox?"
+   ```
+
+#### Example VS Code Usage
+
+![](/images/page/running/mcp-vscode.jpg)
+
+### Claude Desktop
+
+Claude Desktop is Anthropic's standalone application that can integrate with external tools using the MCP protocol.
+
+#### Configuration Steps
+
+1. **Install Dalfox** (if not already installed)
+   ```bash
+   # From source
+   go install github.com/hahwul/dalfox/v2@latest
+
+   # Homebrew
+   brew install dalfox
+
+   # Snapcraft
+   snap install dalfox
+   ```
+
+   *[Installation](/page/installation/)*
+
+2. **Configure Claude Desktop settings**
+
+   ```json
+    {
+        "mcpServers": {
+            "filesystem": {
+                "command": "dalfox",
+                "args": [
+                "server",
+                "--type",
+                "mcp"
+                ]
+            }
+        }
+    }
+   ```
+
+3. **Use with Claude**
+   
+   You can now use Dalfox directly through Claude's interface:
+   
+   ```
+   "Can you scan https://xss-game.appspot.com/level1/frame  for XSS vulnerabilities"
+   ```
+
+#### Example Claude Desktop Usage
+
+![](/images/page/running/mcp-claude.jpg)
+
+## Advanced MCP Integration
+
+### Custom Scan Options
+
+When using Dalfox through MCP, you can specify various scan options by providing them in your request:
+
+```
+"Scan https://example.com with Dalfox using the following options:
+- Custom headers with an authorization token
+- Cookie-based authentication
+- A blind XSS callback URL"
+```
+
+The AI assistant will translate these requests into the appropriate Dalfox commands.
+
+## Use Cases
+
+### Security Code Review
+
+Ask your AI assistant to review code and then scan endpoints for vulnerabilities:
+
+```
+"Review this controller code and identify any potential XSS vulnerabilities. 
+Then use Dalfox to scan the corresponding endpoints."
+```
+
+### Vulnerability Research
+
+Have the AI assistant help with targeted testing:
+
+```
+"I found a potential XSS vulnerability in the search parameter. 
+Can you use Dalfox to verify if it's exploitable?"
+```
+
+## Best Practices
+
+1. **Keep Dalfox Updated**: Ensure you're using the latest version for the most current security checks
+2. **Validate Results**: Always verify AI-interpreted scan results manually for critical systems  
+3. **Rate Limiting**: Be mindful of scan frequency to avoid overwhelming target systems
+4. **Context Matters**: Provide AI assistants with sufficient context about targets for more effective scanning
+5. **Security Awareness**: Remember that scan results might contain sensitive information
diff --git a/go.mod b/go.mod
index c553fc9..5461902 100644
--- a/go.mod
+++ b/go.mod
@@ -41,10 +41,12 @@ require (
 	github.com/gobwas/httphead v0.1.0 // indirect
 	github.com/gobwas/pool v0.2.1 // indirect
 	github.com/gobwas/ws v1.4.0 // indirect
+	github.com/google/uuid v1.6.0 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/labstack/gommon v0.4.2 // indirect
 	github.com/mailru/easyjson v0.9.0 // indirect
+	github.com/mark3labs/mcp-go v0.20.0 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-runewidth v0.0.9 // indirect
@@ -56,6 +58,7 @@ require (
 	github.com/tidwall/pretty v1.2.0 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/valyala/fasttemplate v1.2.2 // indirect
+	github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
 	golang.org/x/crypto v0.37.0 // indirect
 	golang.org/x/net v0.39.0 // indirect
 	golang.org/x/sys v0.32.0 // indirect
diff --git a/go.sum b/go.sum
index 45e96a8..c62c611 100644
--- a/go.sum
+++ b/go.sum
@@ -48,6 +48,8 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm
 github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
 github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/hahwul/volt v1.0.7 h1:8D3Qbmt82I4r0M/JfLog2VmR5FUIaiboqgx06PWXAbA=
 github.com/hahwul/volt v1.0.7/go.mod h1:Zt5vhIno5O8ZrknLUY5mAssK4N15laDvnaS9NIsrpPA=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -72,6 +74,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
 github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
+github.com/mark3labs/mcp-go v0.20.0 h1:NYZDZ10GBKHVz4SdQ2tPFSDFQFKCTrTZJLn4wj6jAaw=
+github.com/mark3labs/mcp-go v0.20.0/go.mod h1:KmJndYv7GIgcPVwEKJjNcbhVQ+hJGJhrCCB/9xITzpE=
 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@@ -123,6 +127,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
 github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
+github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
diff --git a/pkg/server/mcp.go b/pkg/server/mcp.go
new file mode 100644
index 0000000..4f038e5
--- /dev/null
+++ b/pkg/server/mcp.go
@@ -0,0 +1,257 @@
+package server
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	dalfox "github.com/hahwul/dalfox/v2/lib"
+	"github.com/hahwul/dalfox/v2/pkg/model"
+	vlogger "github.com/hahwul/volt/logger"
+	"github.com/mark3labs/mcp-go/mcp"
+	mcpserver "github.com/mark3labs/mcp-go/server"
+)
+
+// RunMCPServer starts the MCP server for Dalfox
+func RunMCPServer(options model.Options) {
+	vLog := vlogger.GetLogger(options.Debug)
+	vLog.Info("Starting MCP Server")
+
+	// Create a new MCP server
+	s := mcpserver.NewMCPServer(
+		"Dalfox XSS Scanner",
+		"2.0.0",
+		mcpserver.WithResourceCapabilities(true, true),
+		mcpserver.WithLogging(),
+		mcpserver.WithRecovery(),
+	)
+
+	// Add scan tool for standard URL scanning
+	scanTool := mcp.NewTool("scan_with_dalfox",
+		mcp.WithDescription("Scan for XSS vulnerabilities in a web application"),
+		mcp.WithString("url",
+			mcp.Required(),
+			mcp.Description("The URL to scan for XSS vulnerabilities"),
+		),
+		mcp.WithString("method",
+			mcp.Description("HTTP method to use (GET, POST, etc.)"),
+			mcp.DefaultString("GET"),
+		),
+		mcp.WithString("headers",
+			mcp.Description("Custom HTTP headers as a JSON string"),
+		),
+		mcp.WithString("cookie",
+			mcp.Description("Cookies to include in the request"),
+		),
+		mcp.WithString("data",
+			mcp.Description("HTTP request body for POST requests"),
+		),
+		mcp.WithBoolean("follow-redirects",
+			mcp.Description("Whether to follow HTTP redirects"),
+			mcp.DefaultBool(false),
+		),
+		mcp.WithString("proxy",
+			mcp.Description("Proxy URL to route requests through"),
+		),
+		mcp.WithNumber("worker",
+			mcp.Description("Number of concurrent worker threads"),
+			mcp.DefaultNumber(100),
+		),
+		mcp.WithNumber("delay",
+			mcp.Description("Delay between requests in milliseconds"),
+			mcp.DefaultNumber(0),
+		),
+		mcp.WithBoolean("deep-domxss",
+			mcp.Description("Enable deep DOM XSS testing"),
+			mcp.DefaultBool(false),
+		),
+		mcp.WithBoolean("skip-discovery",
+			mcp.Description("Skip the entire discovery phase, proceeding directly to XSS scanning"),
+			mcp.DefaultBool(false),
+		),
+		mcp.WithBoolean("skip-mining-all",
+			mcp.Description("Skip all parameter mining"),
+			mcp.DefaultBool(false),
+		),
+		mcp.WithBoolean("skip-mining-dict",
+			mcp.Description("Skip dictionary-based parameter mining"),
+			mcp.DefaultBool(false),
+		),
+		mcp.WithBoolean("skip-mining-dom",
+			mcp.Description("Skip DOM-based parameter mining"),
+			mcp.DefaultBool(false),
+		),
+	)
+
+	// Handler for the scan tool
+	s.AddTool(scanTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
+		url := request.Params.Arguments["url"].(string)
+		if url == "" {
+			return nil, fmt.Errorf("URL is required")
+		}
+
+		// Create a unique scan ID
+		sid := generateScanID(url)
+		vLog.WithField("scan_id", sid).Info("Starting scan for URL: " + url)
+
+		// Set up scan options
+		rqOptions := model.Options{}
+
+		// Parse optional parameters
+		if method, ok := request.Params.Arguments["method"].(string); ok && method != "" {
+			rqOptions.Method = method
+		}
+
+		if headers, ok := request.Params.Arguments["headers"].(string); ok && headers != "" {
+			rqOptions.Header = strings.Split(headers, "|")
+		}
+
+		if cookie, ok := request.Params.Arguments["cookie"].(string); ok && cookie != "" {
+			rqOptions.Cookie = cookie
+		}
+
+		if data, ok := request.Params.Arguments["data"].(string); ok && data != "" {
+			rqOptions.Data = data
+		}
+
+		if followRedirect, ok := request.Params.Arguments["follow-redirects"].(bool); ok {
+			rqOptions.FollowRedirect = followRedirect
+		}
+
+		if proxy, ok := request.Params.Arguments["proxy"].(string); ok && proxy != "" {
+			rqOptions.ProxyAddress = proxy
+		}
+
+		if worker, ok := request.Params.Arguments["worker"].(float64); ok {
+			rqOptions.Concurrence = int(worker)
+		}
+
+		if delay, ok := request.Params.Arguments["delay"].(float64); ok {
+			rqOptions.Delay = int(delay)
+		}
+
+		if deepDomXSS, ok := request.Params.Arguments["deep-domxss"].(bool); ok {
+			rqOptions.UseDeepDXSS = deepDomXSS
+		}
+
+		if skipDiscovery, ok := request.Params.Arguments["skip-discovery"].(bool); ok {
+			rqOptions.SkipDiscovery = skipDiscovery
+		}
+
+		if skipMiningAll, ok := request.Params.Arguments["skip-mining-all"].(bool); ok {
+			if skipMiningAll {
+				rqOptions.Mining = false
+				rqOptions.FindingDOM = false
+			}
+		}
+
+		if skipMiningDict, ok := request.Params.Arguments["skip-mining-dict"].(bool); ok {
+			if skipMiningDict {
+				rqOptions.Mining = false
+			}
+		}
+
+		if skipMiningDOM, ok := request.Params.Arguments["skip-mining-dom"].(bool); ok {
+			if skipMiningDOM {
+				rqOptions.FindingDOM = false
+			}
+		}
+
+		// Create a goroutine to run the scan
+		go func() {
+			// Set up the target
+			target := dalfox.Target{
+				URL:     url,
+				Method:  rqOptions.Method,
+				Options: dalfox.Options{},
+			}
+
+			// Initialize options
+			newOptions := dalfox.Initialize(target, target.Options)
+			newOptions.Scan = options.Scan
+
+			// Set method
+			if rqOptions.Method != "" {
+				newOptions.Method = rqOptions.Method
+			} else {
+				newOptions.Method = "GET"
+			}
+
+			// Clean URL
+			escapedURL := url
+			vLog.WithField("data1", sid).Debug(escapedURL)
+			vLog.WithField("data1", sid).Debug(newOptions)
+
+			// Run scan
+			ScanFromAPI(url, newOptions, options, sid)
+			vLog.WithField("data1", sid).Info("Scan completed successfully")
+		}()
+
+		// Return immediate response while scan runs in background
+		return mcp.NewToolResultText(fmt.Sprintf("Scan started with ID: %s. The scan is running in the background.", sid)), nil
+	})
+
+	// Add results tool to get scan results
+	resultsTool := mcp.NewTool("get_results_dalfox",
+		mcp.WithDescription("Get results of a previously started scan"),
+		mcp.WithString("scan_id",
+			mcp.Required(),
+			mcp.Description("The scan ID returned from the scan tool"),
+		),
+	)
+
+	// Handler for the results tool
+	s.AddTool(resultsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
+		scanID := request.Params.Arguments["scan_id"].(string)
+		if scanID == "" {
+			return nil, fmt.Errorf("scan_id is required")
+		}
+
+		scan := GetScan(scanID, options)
+
+		if len(scan.URL) == 0 {
+			return mcp.NewToolResultText("Scan is still in progress. Please check again later."), nil
+		}
+
+		// Format results
+		var resultText strings.Builder
+		resultText.WriteString(fmt.Sprintf("Scan results for %s\n\n", scan.URL))
+
+		if scan.Results == nil || len(scan.Results) == 0 {
+			resultText.WriteString("No vulnerabilities found.")
+		} else {
+			resultText.WriteString("Vulnerabilities found:\n")
+			for i, result := range scan.Results {
+				resultText.WriteString(fmt.Sprintf("%d. {%s %s %s %s %s param:%s payload:%s evidence:%s %s %s %d %s}\n",
+					i+1,
+					result.Type,
+					result.InjectType,
+					result.PoCType,
+					result.Method,
+					result.Data,
+					result.Param,
+					result.Payload,
+					result.Evidence,
+					result.CWE,
+					result.Severity,
+					result.MessageID,
+					result.MessageStr))
+			}
+		}
+
+		return mcp.NewToolResultText(resultText.String()), nil
+	})
+
+	// Start the MCP server over stdin/stdout
+	if err := mcpserver.ServeStdio(s); err != nil {
+		vLog.Error("MCP Server error:", err)
+	}
+}
+
+// generateScanID creates a unique scan ID for MCP scans
+func generateScanID(url string) string {
+	return fmt.Sprintf("mcp-%s", strings.Replace(
+		strings.Replace(url, "://", "-", -1),
+		"/", "-", -1,
+	))
+}



Test patch:
diff --git a/pkg/server/mcp_test.go b/pkg/server/mcp_test.go
new file mode 100644
index 0000000..e946b83
--- /dev/null
+++ b/pkg/server/mcp_test.go
@@ -0,0 +1,55 @@
+package server
+
+import (
+	"testing"
+
+	"github.com/hahwul/dalfox/v2/pkg/model"
+)
+
+func TestRunMCPServer(t *testing.T) {
+	type args struct {
+		options model.Options
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "Test with default options",
+			args: args{
+				options: model.Options{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			RunMCPServer(tt.args.options)
+		})
+	}
+}
+
+func Test_generateScanID(t *testing.T) {
+	type args struct {
+		url string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "Test with valid URL",
+			args: args{
+				url: "http://example.com",
+			},
+			want: "mcp-http-example.com",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := generateScanID(tt.args.url); got != tt.want {
+				t.Errorf("generateScanID() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}