Skip to content

making/fetch-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fetch-server

An MCP (Model Context Protocol) server that exposes tools for retrieving web resources over HTTP and for reading the current date-time.

  • fetch — fetch one or more URLs in a single call. By default each HTML body is converted to Markdown; set markdown to false to receive the raw response body instead. URLs are fetched concurrently and the results are returned together, one entry per URL.
  • current_datetime — return the current date-time as an ISO-8601 string with an offset. Pass an IANA timezone (e.g. Asia/Tokyo) to convert it; when omitted, the server's default timezone is used.

Use this server when an MCP client (Claude Desktop, custom agents, etc.) needs to read web pages or call HTTP APIs as part of its workflow. The server speaks the MCP Streamable HTTP transport on POST /mcp.

Built with Spring Boot 4 + Spring AI 2.0. Supports GraalVM native image.

Requirements

  • JDK 25 (GraalVM CE 25 if you want to build a native image)
  • Maven Wrapper bundled in the repository (./mvnw)

Build & Run

JVM

./mvnw spring-boot:run

Native image

./mvnw -DskipTests native:compile
./target/fetch-server

The server listens on port 8090 by default (override with PORT).

fetch Parameters

name type required default
urls string array yes
markdown boolean no true
headers object (string→string) no none
timeoutSeconds integer no 30
maxBytes integer no 1 MB

headers, timeoutSeconds, and maxBytes apply to every URL in the call.

fetch Response

The tool returns a results array with one entry per requested URL, in the same order as urls:

field type description
url string the requested URL
status integer HTTP status code, or 0 when the request failed
contentType string response Content-Type (empty when absent or on failure)
title string HTML document title; null when markdown is false
content string Markdown when markdown is true, otherwise the raw body
truncated boolean true when the body exceeded maxBytes
error string failure message when this URL could not be fetched, else null

A failure of one URL does not abort the others; only that entry carries an error.

current_datetime Parameters

name type required default
timezone string no server's default

timezone is an IANA zone ID such as Asia/Tokyo or America/New_York. An unknown value results in an error response.

current_datetime Response

field type description
dateTime string current date-time, ISO-8601 with offset (e.g. 2026-05-29T14:30:00+09:00)

Testing with curl

The MCP Streamable HTTP transport requires a handshake before any tool call:

  1. POST /mcp with method initialize. The response carries an Mcp-Session-Id header that must be sent on every subsequent request.
  2. POST /mcp with method notifications/initialized to confirm the session.
  3. POST /mcp with method tools/list or tools/call.

The examples below assume the server is running on http://localhost:8090.

1. Initialize the session

curl -i -X POST http://localhost:8090/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "capabilities": {},
      "clientInfo": {"name": "curl", "version": "1"}
    }
  }'

Look for the response header Mcp-Session-Id: <uuid> and reuse the UUID below.

SESSION_ID=<paste-uuid-here>

2. Confirm initialization

curl -X POST http://localhost:8090/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc": "2.0", "method": "notifications/initialized"}'

This returns HTTP 202 with no body.

3. List the available tools

curl -X POST http://localhost:8090/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'

4. Call fetch (Markdown by default)

curl -X POST http://localhost:8090/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "fetch",
      "arguments": {"urls": ["https://example.com"]}
    }
  }'

5. Fetch multiple URLs and return the raw body

Pass several URLs in urls, and set markdown to false to skip the Markdown conversion. The response results array preserves the input order.

curl -X POST http://localhost:8090/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{
    "jsonrpc": "2.0",
    "id": 4,
    "method": "tools/call",
    "params": {
      "name": "fetch",
      "arguments": {
        "urls": ["https://example.com", "https://example.org"],
        "markdown": false,
        "maxBytes": 200
      }
    }
  }'

Custom headers and timeout

curl -X POST http://localhost:8090/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{
    "jsonrpc": "2.0",
    "id": 6,
    "method": "tools/call",
    "params": {
      "name": "fetch",
      "arguments": {
        "urls": ["https://httpbin.org/headers"],
        "headers": {"User-Agent": "fetch-server/0.0.1", "X-Trace-Id": "demo"},
        "timeoutSeconds": 5
      }
    }
  }'

Call current_datetime

Omit arguments (or pass an empty object) to use the server's default timezone, or pass a timezone to convert it.

curl -X POST http://localhost:8090/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{
    "jsonrpc": "2.0",
    "id": 7,
    "method": "tools/call",
    "params": {
      "name": "current_datetime",
      "arguments": {"timezone": "Asia/Tokyo"}
    }
  }'

One-shot script

The full handshake plus a tool call as a single script:

#!/usr/bin/env bash
set -euo pipefail
BASE=http://localhost:8090/mcp

INIT=$(curl -s -i -X POST "$BASE" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}')
SESSION_ID=$(printf '%s' "$INIT" | awk -F': ' 'tolower($1)=="mcp-session-id"{print $2}' | tr -d '\r\n')

curl -s -o /dev/null -X POST "$BASE" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'

curl -s -X POST "$BASE" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"fetch","arguments":{"urls":["https://example.com"]}}}'

Tests

./mvnw test

The unit tests spin up an in-process com.sun.net.httpserver.HttpServer and exercise the tools end-to-end, including header propagation, timeout, truncation, and charset decoding.

About

An MCP server that exposes tools for fetching web resources over HTTP

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages