http_request
Send HTTP requests using GET, POST, PUT, PATCH, or DELETE methods with custom headers and parameters. Returns full response data including status, headers, and body for API integration and web communication tasks.
Instructions
Execute an HTTP request with the specified method
Function/Features:
Sends HTTP requests using any standard method (GET, POST, PUT, PATCH, DELETE)
Allows custom HTTP headers
Returns complete HTTP response including status, headers, and body
Notes:
'data' and 'json' parameters are mutually exclusive - use only one
When using 'json', the Content-Type header is automatically set to 'application/json'
When using 'data', you may need to set appropriate Content-Type header manually
Query parameters are URL-encoded automatically and appended to the URL
The response includes the full HTTP response with status line, all headers, and body
Args: url (str): Target URL for the HTTP request. method ('GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'], optional): HTTP method to use. Defaults to "GET". query ({ [string]: string | number }, optional): Query parameters to append to the URL. Values are automatically converted to strings. Example: {'key1': 'value1', 'key2': 2}, becomes "key1=value1&key2=2" appended to the URL. headers ({ [string]: string }, optional): Custom HTTP request headers. data (str, optional): Text data to send in the request body. Cannot be used with 'json'. json (Any JSON, optional): Data to serialize as JSON and send in the request body. Cannot be used with 'data'.
Examples: // GET request (default method) http_request({url: "https://api.example.com/data"})
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | (require) Target URL for the HTTP request | |
| method | Yes | (optional, Defaults to "GET") HTTP method to use for the request | |
| query | Yes | ||
| headers | Yes | ||
| data | Yes | ||
| json | Yes |
Implementation Reference
- mcp_server_requests/server.py:393-451 (handler)Primary MCP tool handler for 'http_request'. Includes registration via @mcp.tool(), input schema via Annotated types, and execution logic calling mcp_http_request with user-agent and formatting.@mcp.tool() def http_request( url: Annotated[str, "(require) Target URL for the HTTP request"], *, method: Annotated[Literal['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], "(optional, Defaults to \"GET\") HTTP method to use for the request"] = "GET", query: Annotated[Optional[Dict[str, str | int | float]], "(optional) Query parameters to append to the URL"] = None, headers: Annotated[Optional[Dict[str, str]], "(optional) Custom HTTP request headers"] = None, data: Annotated[Optional[str], "(optional) Text data to send in the request body. Cannot be used with 'json'"] = None, json: Annotated[Optional[Any], "(optional) JSON to send in the request body. Cannot be used with 'data'"] = None, ) -> str: """Execute an HTTP request with the specified method Function/Features: - Sends HTTP requests using any standard method (GET, POST, PUT, PATCH, DELETE) - Allows custom HTTP headers - Returns **complete** HTTP response including status, headers, and body Notes: - 'data' and 'json' parameters are mutually exclusive - use only one - When using 'json', the Content-Type header is automatically set to 'application/json' - When using 'data', you may need to set appropriate Content-Type header manually - Query parameters are URL-encoded automatically and appended to the URL - The response includes the full HTTP response with status line, all headers, and body Args: url (str): Target URL for the HTTP request. method ('GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'], optional): HTTP method to use. Defaults to "GET". query ({ [string]: string | number }, optional): Query parameters to append to the URL. Values are automatically converted to strings. Example: {'key1': 'value1', 'key2': 2}, becomes "key1=value1&key2=2" appended to the URL. headers ({ [string]: string }, optional): Custom HTTP request headers. data (str, optional): Text data to send in the request body. Cannot be used with 'json'. json (Any JSON, optional): Data to serialize as JSON and send in the request body. Cannot be used with 'data'. Examples: // GET request (default method) http_request({url: "https://api.example.com/data"}) // GET request with query parameters http_request({url: "https://api.example.com/search", query: {"q": "test", "limit": 10}}) // POST request with JSON data http_request({url: "https://api.example.com/users", method: "POST", json: {"name": "John", "age": 30}}) // POST request with raw text data http_request({url: "https://api.example.com/log", method: "POST", data: "This is a log message"}) // PUT request http_request({url: "https://api.example.com/users/123", method: "PUT", json: {"name": "John Updated", "age": 31}}) // PATCH request http_request({url: "https://api.example.com/users/123", method: "PATCH", json: {"age": 31, "email": "new@example.com"}}) // DELETE request http_request({url: "https://api.example.com/users/123", method: "DELETE"}) // Request with custom headers http_request({url: "https://api.example.com/secure", method: "POST", headers: {"Authorization": "Bearer token"}, json: {"key": "value"}}) """ return mcp_http_request(method, url, query=query, data=data, json=json, headers=headers, user_agent=ua, force_user_agnet=ua_force)
- Intermediate wrapper mcp_http_request: adds User-Agent header, calls core http_request, formats response or error.def mcp_http_request( method: str, url: str, *, query: Optional[dict] = None, data: Optional[str | bytes | bytearray] = None, json: Optional[dict] = None, headers: Optional[dict] = None, user_agent: Optional[str] = None, force_user_agnet: Optional[bool] = None, format_status: bool = True, format_headers: bool = True, return_content: Literal['raw', 'basic_clean', 'strict_clean', 'markdown'] = "raw", ) -> str: hs = {} if headers: hs.update(headers) if force_user_agnet: if user_agent: hs["User-Agent"] = user_agent else: if "User-Agent" not in hs and user_agent: hs["User-Agent"] = user_agent try: response = http_request( method, url, query=query, headers=hs, data=data, json_=json ) return format_response_result( response, format_status=format_status, format_headers=format_headers, return_content=return_content ) except Exception as e: return format_error_result(e)
- Core low-level http_request implementation using Python's urllib.request. Handles URL/query, data/json body, headers, returns Response object. Includes error cases.def http_request( method: str, url: str, *, query: Optional[dict] = None, data: Optional[Union[str, bytes, bytearray]] = None, json_: Optional[dict] = None, headers: Optional[dict] = None ) -> Response: if headers is None: headers = {} if not isinstance(method, str): raise ArgumentError(f"http method must be a string, and must be one of {str(HTTP_METHODS)}") m, method = method, method.upper() if method not in HTTP_METHODS: raise ArgumentError(f"Invalid HTTP method: {m}, must be one of {str(HTTP_METHODS)}") if not isinstance(url, str): raise ArgumentError("URL must be a string") if data is not None and json_ is not None: raise ArgumentError("Both data and json cannot be provided at the same time") try: if query is not None: url = merge_query_to_url(url, query) except ArgumentError as e: raise e from e except Exception as e: raise ArgumentError("Failed to splicing URL and query") from e data_bytes = None if data is not None: if not isinstance(data, (str, bytes, bytearray)): raise ArgumentError("Data must be a string, bytes, or bytearray") elif isinstance(data, str): data_bytes = data.encode(encoding="utf-8") elif isinstance(data, bytearray): data_bytes = bytes(data) else: data_bytes = data elif json_ is not None: try: data_bytes = json.dumps(json_).encode(encoding="utf-8") except Exception as e: raise ArgumentError("Failed to serialize JSON data") from e if not url.startswith("http://") and not url.startswith("https://"): url = "https://" + url try: url = quote(url, safe=";/?:@&=+$,", encoding="utf-8") request = urllib.request.Request(url, method=method, headers=headers, data=data_bytes) response: http.client.HTTPResponse = urllib.request.urlopen(request) version = VERSION_MAP.get(response.version, "HTTP/1.1") status_code = response.status reason = response.reason response_headers = response.getheaders() content = response.read() result = Response(url, version, status_code, reason, response_headers, content) except urllib.error.HTTPError as e: if e.status is None: raise RequestError(f"Failed to send request, unknown error") from e version = "HTTP/1.1" status_code = e.status reason = e.reason response_headers = e.headers.items() content = e.read() result = Response(url, version, status_code, reason, response_headers, content) except urllib.error.URLError as e: raise RequestError(f"Failed to send request, {e.reason}") from e except Exception as e: raise RequestError(f"Failed to send request, {e}") from e return result
- mcp_server_requests/request.py:22-44 (schema)Response dataclass schema defining the structure of HTTP response objects used throughout the tool.@dataclass class Response: url: str version: str status_code: int reason: str headers: list[tuple[str, str]] content: str | bytes | bytearray _content_type: str | None = None @property def content_type(self) -> str: if self._content_type is None: for k, v in self.headers: if k.lower() == "content-type": self._content_type = v if self._content_type is None: self._content_type = "application/octet-stream" return self._content_type
- mcp_server_requests/server.py:44-99 (helper)Helper to format the final response string: handles content decoding, HTML cleaning/markdown conversion, assembles status/headers/body.def format_response_result( response: Response, *, format_status: bool | None = None, format_headers: bool | None = None, return_content: Literal["raw", "basic_clean", "strict_clean", "markdown"] = "raw", ) -> str: http_version = response.version status = response.status_code reason = response.reason headers = response.headers content = response.content content_type = response.content_type if not isinstance(content_type, str): content_type = 'application/octet-stream' if content_type.startswith("text/") or content_type.startswith("application/json"): try: if isinstance(content, (bytes, bytearray)): content = content.decode('utf-8') else: content = str(content) except UnicodeDecodeError as e: err_message = f"response content type is \"{content_type}\", but not utf-8 encoded'" raise ResponseError(response, err_message) from e except Exception as e: err_message = f"response content type is \"{content_type}\", but cannot be converted to a string" raise ResponseError(response, err_message) from e else: err_message = f'response content type is "{content_type}", cannot be converted to a string' raise ResponseError(response, err_message) if content_type.startswith("text/html"): if return_content == "raw": pass elif return_content == "basic_clean": content = clean_html(content, allowed_attrs=True) elif return_content == "strict_clean": content = clean_html(content, allowed_attrs=("id", "src", "href")) elif return_content == "markdown": content = html_to_markdown(content) strs = [] if format_status: strs.append(f"{http_version} {status} {reason}\r\n") if format_headers: response_header_str = "\r\n".join(f"{k}: {v}" for k, v in headers) strs.append(response_header_str) if len(strs) > 0: strs.append("\r\n\r\n") strs.append(content) return "\r\n".join(strs)