spring-ai-playground

description: Default Tools - 85 ready-to-call JavaScript tools across 5 source bundles, exposed through the built-in MCP server, OS-agnostic by design.

Default Tools

Where: top navigation → Tool Studio - the default tools ship pre-loaded; tune the exposed subset in the Built-in MCP Server Native Tools drawer.

Spring AI Playground ships with 85 default tools spread across six JSON source bundles. They are ready to call the moment a model provider is connected - you do not need to author anything yourself to see agentic workflows work end-to-end. They also serve as editable references when you start writing your own tools.

Tools that reach an external API read their keys from environment variables - each tool’s card below lists the variables it needs. How to supply env vars (desktop launcher, Docker -e, or a source run) is covered once in the Configuration reference.

Every tool is Local-Passed (published to the built-in MCP server) out of the box - except any that are still missing a required ${ENV_VAR}, which stay as drafts until you supply it. A preset decides something separate: which of the Local-Passed tools the server actually exposes to agents at boot (the default is Starter 5), with per-tool include / exclude rules layering on top. That preference lives in <home>/spring-ai-playground/tool/save/default-tools-preference.json and is chosen at setup - the desktop launcher’s Default MCP Tools card, or CLI / yaml (full breakdown in Tool Studio → Where preset choices live). Tool Studio’s Built-in MCP Server Native Tools drawer then selects which Local-Passed tools the MCP server exposes. Applying a chat-side prompt preset that declares tools writes this same preference, resetting the exposed set to that preset’s key-less tools - so it persists across restarts and the chat, Tool Studio, and the server stay in agreement.

Risk Level { #risk-level }

Every tool carries a Risk Level (L0-L5) - the sandbox posture the Safe Tool Specification computes from the tool’s declared capabilities (sandboxOverrides). Lower = more sandboxed. Each tool’s reference card shows its level; the same chip appears in Tool Studio’s Sandbox & Capabilities pane.

!!! note “Two L0-L5 scales” This is the sandbox rubric (how far a JavaScript tool widens the local sandbox). External MCP servers reuse the same enum for a different question - see MCP Server Safety. The two never mix.

Level What it means for a tool What ships here
L0 - Safest Pure compute - no declared network or filesystem widening helper / utility tools with no I/O
L3 - Scoped widening Allowlisted-host fetch, strict egress, or file read the network, Korea, and most filesystem tools
L4 - Broad access File write, * allowlist / open egress, or reflection class added the file-write filesystem tool
L5 - Unsandboxed System / Runtime / Process re-enabled, or raw file-write class none ship by default

Levels are derived from each tool’s declared sandboxOverrides (by SandboxPostureCalculator); the full bullet-by-bullet rule set is in AI Agent Tool Safety → Risk Level decision matrix. Across the 85 default tools: 28 are L0, 56 are L3 (allowlisted-host fetch or file read), and 1 is L4 (file write) - none ship at L5.

!!! question “Why no L1 or L2 here?” The sandbox rubric only ever produces L0 / L3 / L4 / L5 - the calculator jumps from the L0 baseline straight to L3 the moment a tool declares any widening (network, file, or class change), so a tool is never L1 or L2. L1 (Safe) and L2 (Low) exist only in the MCP server rubric, which scores a different thing (connecting to an external server) on the same L0-L5 enum.

Browse all 85 tools { #browse-all-tools }

Click a card to jump to its full reference (with the JS source pre-expanded) on the right sub-page - same UX as the Built-in MCP Server Native Tools drawer in Tool Studio. Five reference pages organise the catalog by source bundle and concern: Examples · Utilities · Filesystem · Global · Korea.

Filter modes: pick a Preset for an exclusive view (just the tools in that preset, all other filters cleared); or combine a search keyword with one or more Tag / Category chips - search is AND, tag and category are OR (a card is shown when it matches any selected tag OR category and also matches the search keyword).

Preset
Tag
Category
Showing 85 of 85 tools
extractPageContent
extractPageContent 🆓
:material-language-html5:
web · example L3
Fetches a web page and extracts its main readable content + outbound links. Uses the host-injected fetch (SSRF-defended in `strict` mode) and safety.parser.html for parsing.
**Params**   `pageUrl`
**Env**       -
→ Examples
getCurrentTime
getCurrentTime 🆓
:material-clock-outline:
datetime · example · util L0
Returns the current time in ISO 8601 format. If the user specifies a city, country, or location, the agent should first map it to an IANA time zone and supply it via the timeZone parameter. If no time zone is provided, UTC is used.
**Params**   `timeZone`
**Env**       -
→ Examples
buildGoogleCalendarCreateLink
buildGoogleCalendarCreateLink 🆓
:simple-googlecalendar:
productivity · example · util L0
Builds a Google Calendar "Add Event" URL with prefilled fields.
**Params**   `title` · `start` · `end` · `details` · `location` · `timeZone`
**Env**       -
→ Examples
getWeather
getWeather 🆓
:material-weather-partly-cloudy:
web · example · weather L3
Free public weather lookup via wttr.in (no API key). Returns a small JSON summary: { location, tempC, humidity, windSpeed, windDirection }.
**Params**   `location`
**Env**       -
→ Examples
googlePseSearch
googlePseSearch 🔑 × 2
:simple-google:
web · example · search L3
Google Programmable Search Engine query (Custom Search API). Requires `GOOGLE_API_KEY` and `GOOGLE_PSE_ID` env vars.
**Params**   `query` · `resultNum` · `startPage`
**Env**       `GOOGLE_API_KEY` · `GOOGLE_PSE_ID`
→ Examples
openaiResponseGenerator
openaiResponseGenerator 🔑 × 1
:material-creation:
ai · example L3
Calls OpenAI's Responses API. Requires `OPENAI_API_KEY` env var.
**Params**   `prompt` · `model`
**Env**       `OPENAI_API_KEY`
→ Examples
sendSlackMessage
sendSlackMessage 🔑 × 1
:material-pound-box-outline:
messaging · example L3
Posts a text message to a Slack channel via Incoming Webhook. Requires `SLACK_WEBHOOK_URL` env var (the full https://hooks.slack.com/services/... URL).
**Params**   `text`
**Env**       `SLACK_WEBHOOK_URL`
→ Examples
timezoneConvert
timezoneConvert 🆓
:material-clock-alert-outline:
datetime · util L0
Converts a moment in time between IANA time zones. Returns the same instant rendered in the target zone (ISO with offset).
**Params**   `text` · `toTimeZone`
**Env**       -
→ Utilities
dateDiff
dateDiff 🆓
:material-calendar-arrow-right:
datetime · util L0
Computes b - a in the requested unit (days|hours|minutes|seconds|milliseconds). Returns a number which may be fractional.
**Params**   `a` · `b` · `unit`
**Env**       -
→ Utilities
urlEncode
urlEncode 🆓
:material-link-variant:
text · util L0
Percent-encodes a string for use in a URL component. Equivalent to encodeURIComponent.
**Params**   `text`
**Env**       -
→ Utilities
dateMath
dateMath 🆓
:material-calendar-clock:
datetime · util L0
Adds (or subtracts) a duration to a date and returns the resulting ISO timestamp. Unit: years|months|weeks|days|hours|minutes|seconds|milliseconds.
**Params**   `text` · `amount` · `unit`
**Env**       -
→ Utilities
parseDate
parseDate 🆓
:material-calendar-import:
datetime · util L0
Parses a date/time string (ISO 8601 or RFC 2822) and returns its components plus epochMillis.
**Params**   `text` · `timeZone`
**Env**       -
→ Utilities
cronNext
cronNext 🆓
:material-timer-cog-outline:
datetime · util L0
Computes the next datetime matching a standard 5-field cron expression (minute hour day month weekday). Supports * , - / and ? (treated as *). Returns ISO timestamp in UTC.
**Params**   `expression` · `from` · `count`
**Env**       -
→ Utilities
diffText
diffText 🆓
:material-file-compare:
text · util L0
Returns a line-by-line diff between two texts. Each entry is {op, line} where op is one of '=' (unchanged), '-' (only in a), '+' (only in b).
**Params**   `a` · `b`
**Env**       -
→ Utilities
sortLines
sortLines 🆓
:material-sort-alphabetical-ascending:
text · util L0
Sorts lines of text alphabetically. Supports reverse and case-insensitive options.
**Params**   `text` · `reverse` · `caseInsensitive`
**Env**       -
→ Utilities
piiDetect
piiDetect 🆓
:material-shield-account-outline:
security · util L0
Scans text for personally identifiable information patterns (email, US SSN, US phone, credit card, IPv4). Returns an array of {type, masked, index}.
**Params**   `text`
**Env**       -
→ Utilities
regexExtract
regexExtract 🆓
:material-regex:
text · util L0
Returns all regex matches in the input. With the 'g' flag every match is returned; without it the first match (with capture groups) is returned.
**Params**   `text` · `pattern` · `flags`
**Env**       -
→ Utilities
formatDate
formatDate 🆓
:material-calendar-text-outline:
datetime · util L0
Formats a date (ISO string or epoch ms) using a pattern with tokens yyyy/MM/dd HH:mm:ss SSS. Time zone aware.
**Params**   `text` · `pattern` · `timeZone`
**Env**       -
→ Utilities
stats
stats 🆓
:material-sigma:
math · util L0
Returns summary statistics (count, sum, min, max, mean, median, stddev) for an array of numbers.
**Params**   `numbers`
**Env**       -
→ Utilities
secretPatternDetect
secretPatternDetect 🆓
:material-key-alert-outline:
security · util L0
Scans text for well-known secret patterns (AWS keys, GitHub tokens, Slack tokens, OpenAI keys, Stripe keys, private keys). Returns an array of {type, masked, index}.
**Params**   `text`
**Env**       -
→ Utilities
regexReplace
regexReplace 🆓
:material-find-replace:
text · util L0
Replaces regex matches in the input with the given replacement string. Supports $1, $2 group back-references.
**Params**   `text` · `pattern` · `replacement` · `flags`
**Env**       -
→ Utilities
evalExpression
evalExpression 🆓
:material-calculator-variant-outline:
math · util L0
Evaluates a safe arithmetic/logical expression (no eval, no host access). Supports + - * / % ** parens, &&, ||, !, ==, !=, <, <=, >, >=, and numeric/string/boolean literals plus variables from the variables object.
**Params**   `expression` · `variables`
**Env**       -
→ Utilities
formatCsv
formatCsv 🆓
:material-file-table-outline:
data · util L0
Serialises an array of rows into CSV text. Rows may be arrays (use header param) or objects (keys become the header). RFC 4180 quoting.
**Params**   `rows` · `header` · `delimiter`
**Env**       -
→ Utilities
base64
base64 🆓
:material-code-tags:
encoding · util L0
Encodes UTF-8 text to base64, or decodes base64 back to UTF-8 text. Use mode='encode' (default) or 'decode'. URL-safe variant via urlSafe=true.
**Params**   `text` · `mode` · `urlSafe`
**Env**       -
→ Utilities
hex
hex 🆓
:material-numeric:
encoding · util L0
Encodes UTF-8 text to hex string, or decodes hex back to UTF-8 text. Use mode='encode' (default) or 'decode'.
**Params**   `text` · `mode` · `upperCase`
**Env**       -
→ Utilities
uuid
uuid 🆓
:material-identifier:
crypto · util L0
Generates a cryptographically random UUID v4 string.
**Params**   -
**Env**       -
→ Utilities
hash
hash 🆓
:material-pound:
crypto · util L0
Computes the cryptographic hash of UTF-8 text. Algorithms: SHA-256 (default), SHA-384, SHA-512. Returns lowercase hex.
**Params**   `text` · `algorithm`
**Env**       -
→ Utilities
hmac
hmac 🆓
:material-key-variant:
crypto · util L0
Computes an HMAC signature over UTF-8 text using a secret. Algorithms: SHA-256 (default), SHA-384, SHA-512. Returns lowercase hex.
**Params**   `secret` · `text` · `algorithm`
**Env**       -
→ Utilities
secureRandom
secureRandom 🆓
:material-dice-6-outline:
crypto · util L0
Generates cryptographically secure random bytes. encoding: 'hex' (default), 'base64', or 'base64url'.
**Params**   `bytes` · `encoding`
**Env**       -
→ Utilities
passwordGenerate
passwordGenerate 🆓
:material-form-textbox-password:
crypto · util L0
Generates a strong random password from selected character classes. Uses crypto.getRandomValues for unbiased selection.
**Params**   `length` · `includeLowercase` · `includeUppercase` · `includeDigits` · `includeSymbols`
**Env**       -
→ Utilities
jwtDecode
jwtDecode 🆓
:material-shield-key-outline:
crypto · util L0
Decodes a JWT without verifying its signature. Returns the header and payload as JSON, plus signaturePresent.
**Params**   `token`
**Env**       -
→ Utilities
jwtVerify
jwtVerify 🆓
:material-shield-check-outline:
crypto · util L0
Verifies a HS256/HS384/HS512 JWT signature using a shared secret and returns the decoded payload on success. Also checks exp and nbf claims when present.
**Params**   `token` · `secret`
**Env**       -
→ Utilities
parseCsv
parseCsv 🆓
:material-file-import-outline:
data · util L0
Parses CSV text into an array of rows. If header=true, each row is an object keyed by the first row.
**Params**   `text` · `header` · `delimiter`
**Env**       -
→ Utilities
readTextFile
readTextFile 🆓
:material-file-document-outline:
file · pipeline L3
Reads a UTF-8 text file from disk and returns its contents as a single string.
**Params**   `path`
**Env**       -
→ Filesystem
listDir
listDir 🆓
:material-folder-outline:
file · pipeline L3
Lists the immediate entries (files and subdirectories) of a directory under the FS base path. Returns an array of relative names (not full paths). Uses safety.fs.list().
**Params**   `dir`
**Env**       -
→ Filesystem
statFile
statFile 🆓
:material-information-outline:
file · pipeline L3
Returns size, last-modified timestamp, and a directory flag for a path inside the FS base. Uses safety.fs.stat().
**Params**   `path`
**Env**       -
→ Filesystem
lineCount
lineCount 🆓
:material-counter:
file · pipeline L3
Counts the lines in a UTF-8 text file. Uses safety.fs.lineCount().
**Params**   `path`
**Env**       -
→ Filesystem
sliceFile
sliceFile 🆓
:material-content-cut:
file · pipeline L3
Returns a slice of lines from a UTF-8 text file (head / tail / range). `start` is 0-based inclusive, `end` is 0-based exclusive (Python-style slice). Negative values count from the end of the file. Uses safety.fs.slice().
**Params**   `path` · `start` · `end`
**Env**       -
→ Filesystem
sortFile
sortFile 🆓
:material-sort:
file · pipeline L3
Sorts the lines of a UTF-8 text file and returns the sorted lines as an array. Options: reverse / numeric / caseInsensitive / unique. Uses safety.fs.sort().
**Params**   `path` · `reverse` · `numeric` · `caseInsensitive` · `unique`
**Env**       -
→ Filesystem
grepFile
grepFile 🆓
:material-file-find-outline:
file · pipeline L3
Searches a UTF-8 text file for lines matching a JavaScript regex. Returns an array of matching lines (optionally numbered). Uses safety.fs.grep().
**Params**   `pattern` · `path` · `caseInsensitive` · `numbered` · `limit`
**Env**       -
→ Filesystem
findFiles
findFiles 🆓
:material-folder-search-outline:
file · pipeline L3
Recursively finds files matching a glob inside a directory. Glob supports `*` and `?`. Optional max recursion depth and type filter ('file' or 'dir'). Uses safety.fs.find().
**Params**   `dir` · `glob` · `maxDepth` · `type`
**Env**       -
→ Filesystem
cutFileFields
cutFileFields 🆓
:material-table-column:
file · pipeline L3
Extracts selected fields from each line of a delimited file (CSV/TSV/etc.). Uses safety.fs.cut(). 1-based field numbers, comma-separated alternatives via the array.
**Params**   `path` · `fields` · `delimiter` · `regex`
**Env**       -
→ Filesystem
writeTextFile
writeTextFile 🆓
:material-file-edit-outline:
file · pipeline L4
Writes a UTF-8 text file inside the FS base path (creating parent directories as needed). Overwrites any existing file. Requires `fileWrite` permission on the sandbox.
**Params**   `path` · `content`
**Env**       -
→ Filesystem
getGithubRepo
getGithubRepo 🆓
:simple-github:
web · github L3
Fetches public metadata for a GitHub repository (no authentication needed; subject to GitHub's 60 requests/hour anonymous rate limit).
**Params**   `owner` · `repo`
**Env**       -
→ Global
searchWikipedia
searchWikipedia 🆓
:simple-wikipedia:
web · search L3
Looks up a Wikipedia page summary by title. No authentication required. Uses the public REST API at en.wikipedia.org/api/rest_v1/page/summary.
**Params**   `title` · `lang`
**Env**       -
→ Global
searchHackerNews
searchHackerNews 🆓
:simple-ycombinator:
web · search L3
Searches Hacker News stories via the public Algolia HN Search API (no auth needed).
**Params**   `query` · `hits` · `tag`
**Env**       -
→ Global
searchStackOverflow
searchStackOverflow 🆓
:simple-stackoverflow:
web · search L3
Searches Stack Overflow questions via the public Stack Exchange API (anonymous, capped at 300 requests / IP / day).
**Params**   `query` · `pageSize` · `sort` · `tags`
**Env**       -
→ Global
getGithubUser
getGithubUser 🆓
:simple-github:
web · github L3
Fetches public profile information for a GitHub user or organisation (no auth - 60 req/h anonymous).
**Params**   `login`
**Env**       -
→ Global
listGithubRepoIssues
listGithubRepoIssues 🆓
:simple-github:
web · github L3
Lists issues on a public GitHub repository (no auth). Excludes pull requests by default. Anonymous quota 60 req/h.
**Params**   `owner` · `repo` · `state` · `perPage` · `page`
**Env**       -
→ Global
listGithubRepoReleases
listGithubRepoReleases 🆓
:simple-github:
web · github L3
Lists releases on a public GitHub repository (no auth).
**Params**   `owner` · `repo` · `perPage`
**Env**       -
→ Global
getGithubLatestRelease
getGithubLatestRelease 🆓
:simple-github:
web · github L3
Fetches the latest non-draft, non-prerelease release of a public GitHub repository (no auth).
**Params**   `owner` · `repo`
**Env**       -
→ Global
getGithubFileContent
getGithubFileContent 🆓
:simple-github:
web · github L3
Fetches the raw text content of a file from a public GitHub repository (no auth).
**Params**   `owner` · `repo` · `path` · `ref`
**Env**       -
→ Global
searchGithubRepos
searchGithubRepos 🆓
:simple-github:
web · github · search L3
Searches public GitHub repositories by query (no auth - anonymous limit 10 requests/minute).
**Params**   `query` · `sort` · `perPage`
**Env**       -
→ Global
listGithubRepoContributors
listGithubRepoContributors 🆓
:simple-github:
web · github L3
Lists top contributors to a public GitHub repository (no auth).
**Params**   `owner` · `repo` · `perPage`
**Env**       -
→ Global
getCryptoPrice
getCryptoPrice 🆓
:material-currency-btc:
web · finance L3
Fetches current crypto prices from CoinGecko's public Simple Price API (no auth, generous rate limit). Pass coin ids like 'bitcoin,ethereum' and currency ids like 'usd,krw'.
**Params**   `ids` · `currencies`
**Env**       -
→ Global
convertCurrency
convertCurrency 🆓
:material-currency-usd:
web · finance L3
Converts between fiat currencies using open.er-api.com daily reference rates (no key).
**Params**   `from` · `to` · `amount`
**Env**       -
→ Global
getIpInfo
getIpInfo 🆓
:material-ip-network-outline:
web · geo L3
Returns geolocation and ASN info for an IP address (or the caller's IP if `ip` is omitted) via ipapi.co (no auth, 1000 req/day).
**Params**   `ip`
**Env**       -
→ Global
getCountryInfo
getCountryInfo 🆓
:material-earth:
web · geo L3
Fetches country information from the open mledoze/countries dataset (via the jsDelivr CDN, no key) by partial or full name.
**Params**   `name`
**Env**       -
→ Global
searchArxiv
searchArxiv 🆓
:simple-arxiv:
web · search L3
Searches arXiv preprints via the public Atom-feed API (no auth). Results are parsed from XML.
**Params**   `query` · `max` · `sortBy`
**Env**       -
→ Global
getPublicHolidays
getPublicHolidays 🆓
:material-calendar-star-outline:
web L3
Returns public holidays for a given country and year via Nager.Date (no auth).
**Params**   `year` · `countryCode`
**Env**       -
→ Global
getOpenMeteoForecast
getOpenMeteoForecast 🆓
:material-weather-cloudy-clock:
web · weather L3
Fetches a multi-day weather forecast from Open-Meteo (no auth, 10k req/day for non-commercial). Open-Meteo serves official ECMWF/GFS/ICON model output - far richer than wttr.in but requires lat/lon (use `geocodeAddress` first if you only have a city name).
**Params**   `latitude` · `longitude` · `days` · `timezone`
**Env**       -
→ Global
geocodeAddress
geocodeAddress 🆓
:simple-openstreetmap:
web · geo L3
Forward-geocodes a free-form address to coordinates via OpenStreetMap Nominatim (no key). Nominatim's usage policy requires a descriptive User-Agent and at most 1 req/s - we set both.
**Params**   `address` · `limit`
**Env**       -
→ Global
getSunriseSunset
getSunriseSunset 🆓
:material-weather-sunset:
web · geo L3
Returns sunrise / sunset / twilight times for a given lat-lon and date via sunrise-sunset.org (no auth).
**Params**   `latitude` · `longitude` · `date` · `timezone`
**Env**       -
→ Global
getRecentEarthquakes
getRecentEarthquakes 🆓
:material-vibrate:
web · geo L3
Fetches recent earthquakes from the USGS public catalog (no auth).
**Params**   `minMagnitude` · `lookbackHours` · `limit`
**Env**       -
→ Global
getUpbitTicker
getUpbitTicker 🆓
:material-currency-btc:
web · korea · finance L3
Fetches the current KRW ticker(s) from Upbit, a major Korean crypto exchange (no auth). `markets` is comma-separated, e.g. 'KRW-BTC,KRW-ETH'. Returns an array of { market, tradePrice, openingPrice, highPrice, lowPrice, change, changeRate, accTradeVolume24h, timestamp }.
**Params**   `markets`
**Env**       -
→ Korea
getUpbitOrderbook
getUpbitOrderbook 🆓
:material-chart-box-outline:
web · korea · finance L3
Fetches Upbit live orderbook (bids/asks) for one or more KRW markets (no auth). `markets` is comma-separated like 'KRW-BTC,KRW-ETH'. Optional `level` controls price aggregation upstream. Returns an array of { market, timestamp, totalAskSize, totalBidSize, units:[{askPrice,bidPrice,askSize,bidSize}] }.
**Params**   `markets` · `level`
**Env**       -
→ Korea
getUpbitCandles
getUpbitCandles 🆓
:material-chart-line:
web · korea · finance L3
Fetches Upbit OHLCV candles for a market (no auth). `interval` accepts 'days' (default), 'weeks', 'months', or 'minutes/N' where N is one of 1, 3, 5, 10, 15, 30, 60, 240. `count` is capped at 200 upstream. Returns an array (most recent first) of { market, candleDateTimeKst, candleDateTimeUtc, openingPrice, highPrice, lowPrice, tradePrice, candleAccTradeVolume, candleAccTradePrice }.
**Params**   `market` · `interval` · `count`
**Env**       -
→ Korea
listUpbitMarkets
listUpbitMarkets 🆓
:material-format-list-bulleted:
web · korea · finance L3
Lists all tradable markets on Upbit (no auth). Pass `quote` (e.g. 'KRW', 'BTC', 'USDT') to filter by quote currency. Returns { count, markets: [{ market, koreanName, englishName }] }.
**Params**   `quote`
**Env**       -
→ Korea
getBithumbTicker
getBithumbTicker 🆓
:material-currency-btc:
web · korea · finance L3
Fetches the current KRW ticker for a symbol from Bithumb (no auth). Used as an Upbit alternative or for cross-exchange checks. Returns: { symbol, openingPrice, closingPrice, minPrice, maxPrice, unitsTraded24h, accTradeValue24h, change24h, changeRate24h, fluctate24h, fluctateRate24h }.
**Params**   `symbol`
**Env**       -
→ Korea
getBithumbOrderbook
getBithumbOrderbook 🆓
:material-chart-box-outline:
web · korea · finance L3
Fetches Bithumb public orderbook depth for a KRW pair (no auth). `count` defaults to 5, max 30. Returns { symbol, paymentCurrency, orderCurrency, timestamp, bids:[{price,quantity}], asks:[{price,quantity}] }.
**Params**   `symbol` · `count`
**Env**       -
→ Korea
searchNaver
searchNaver 🔑 × 2
:simple-naver:
web · korea · search L3
Naver Search API (KR; key required). Searches across blog, news, webkr, encyc, book, image, shop, kin, or cafearticle. Issue Client-Id + Client-Secret at https://developers.naver.com/apps/ and set NAVER_CLIENT_ID + NAVER_CLIENT_SECRET on the tool's staticVariables, or inject as env vars. Returns: { type, total, start, display, items:[{title, description, link, pubDate, bloggerName, author}] }.
**Params**   `query` · `type` · `display` · `start`
**Env**       `NAVER_CLIENT_ID` · `NAVER_CLIENT_SECRET`
→ Korea
searchKakaoLocal
searchKakaoLocal 🔑 × 1
:simple-kakaotalk:
web · korea · geo L3
Kakao Local keyword search - finds places/POIs and returns WGS84 coordinates (KR; key required). Issue a REST API key at https://developers.kakao.com/ and set KAKAO_REST_API_KEY on the tool's staticVariables, or inject as env var. Optionally pass (longitude, latitude, radius) to search around a point. Returns: { totalCount, pageableCount, isEnd, places:[{ name, category, categoryGroup, phone, address, roadAddress, latitude, longitude, placeUrl, distance }] }.
**Params**   `query` · `size` · `page` · `longitude` · `latitude` · `radius`
**Env**       `KAKAO_REST_API_KEY`
→ Korea
getAirKoreaPm
getAirKoreaPm 🔑 × 1
:material-air-filter:
web · korea · weather L3
AirKorea (data.go.kr) real-time air quality readings by Korean province (KR; data.go.kr key required). Issue the air-quality serviceKey at https://www.data.go.kr/data/15073861/openapi.do and set DATA_GO_KR_AIR_KEY on the tool's staticVariables, or inject as env var. Returns: { sidoName, totalCount, stations:[{ stationName, sidoName, dataTime, pm10, pm25, o3, no2, co, so2, khaiValue, khaiGrade }] }. On auth error: { success:false, status, message }.
**Params**   `sidoName` · `numOfRows`
**Env**       `DATA_GO_KR_AIR_KEY`
→ Korea
searchKpopOnItunes
searchKpopOnItunes 🆓
:simple-applemusic:
web · korea L3
iTunes Search API - Korean music catalog including K-pop (no auth). Default country=kr biases results to the Korean iTunes storefront. Suitable for song / musicArtist / album / musicVideo lookups. Each result includes a 30s preview URL and album artwork URL. Catalog metadata is in the storefront language (Korean for kr). `entity`: musicArtist | song | album | musicVideo | mix. `country`: ISO-2 storefront code (kr/us/jp/...). Default kr. Returns: { country, entity, resultCount, results:[{ kind, artistName, trackName, collection, releaseDate, primaryGenre, previewUrl, trackViewUrl, artworkUrl, ... }] }.
**Params**   `term` · `entity` · `country` · `limit`
**Env**       -
→ Korea
searchKBeautyProducts
searchKBeautyProducts 🆓
:material-flower-tulip-outline:
web · korea · search L3
K-beauty cosmetics product search via Open Beauty Facts (no auth). Default country=south-korea biases the lookup to Korean brand catalogs (Innisfree / Laneige / COSRX / ...). Returns ingredients, allergens, packaging, and product image URLs. For a global search pass country='', or other slugs like country='japan'. Note: localized product names may appear in Korean. Pass a barcode (e.g. '8809610706106') as `query` for single-product lookup - useful for ingredient checks. Returns: { country, count, page, pageSize, products:[{ code, productName, brands, countries, categories, allergens, ingredients, packaging, imageUrl, openBeautyFactsUrl }] }.
**Params**   `query` · `country` · `pageSize`
**Env**       -
→ Korea
searchKoreaTour
searchKoreaTour 🔑 × 1
:material-bag-suitcase-outline:
web · korea · search L3
Korea Tourism Organization TourAPI 4.0 keyword search - tourist spots, cultural facilities, festivals, lodging, restaurants by Korean keyword (KR; data.go.kr key required, separate from the air-quality key). Issue the Korean tourism serviceKey at https://www.data.go.kr/data/15101578/openapi.do and set DATA_GO_KR_TOUR_KEY on the tool's staticVariables, or inject as env var. Filters: `areaCode` (province) + `sigunguCode` (city/county) + `contentTypeId` (content type). Examples: Jeonju = areaCode 37 + sigunguCode 12, Gyeongju = 35+2, Jeju City = 39+4, Seogwipo = 39+5. Metropolitan cities (Busan=6, Daegu=4, ...) do not require sigunguCode. Returns: { keyword, totalCount, pageNo, numOfRows, items:[{ contentId, contentTypeId, title, addr1, addr2, areaCode, sigunguCode, firstImage, mapX, mapY, tel, ... }] }.
**Params**   `keyword` · `areaCode` · `sigunguCode` · `contentTypeId` · `pageNo` · `numOfRows`
**Env**       `DATA_GO_KR_TOUR_KEY`
→ Korea
searchSeoulCulturalEvents
searchSeoulCulturalEvents 🔑 × 1
:material-theater:
web · korea · search L3
Seoul Open Data Plaza (data.seoul.go.kr) cultural events search (KR; separate key required). This API is operated directly by the Seoul city government and is separate from the data.go.kr keychain. Issue a free key at https://data.seoul.go.kr/together/apikey.do (1,000 req/day) and set SEOUL_OPEN_API_KEY on the tool's staticVariables, or inject as env var. Optional filters: `codename` (category: musical / exhibition / Korean classical music / concert / ...), `titleSearch` (partial title match), `eventDate` ('YYYY-MM-DD'; events active on that date only). Returns: { totalCount, events:[{ category, gu, title, period, startDate, endDate, place, organizer, audience, fee, isFree, program, imageUrl, latitude, longitude, ... }] }.
**Params**   `startIndex` · `endIndex` · `codename` · `titleSearch` · `eventDate`
**Env**       `SEOUL_OPEN_API_KEY`
→ Korea
getKamisAgriPrice
getKamisAgriPrice 🔑 × 2
:material-leaf:
web · korea · finance L3
KAMIS agricultural product wholesale/retail prices - daily price data operated by aT (Korea Agro-Fisheries & Food Trade Corp). KR; cert_id + cert_key required, free. Issue credentials at https://www.kamis.or.kr/customer/reference/openapi_list.do and set KAMIS_CERT_ID + KAMIS_CERT_KEY on the tool's staticVariables, or inject as env vars. `productClsCode`: 01=retail, 02=wholesale (default). `itemCode` is the KAMIS product code (rice=111, apple=411, napa cabbage=211, pork belly=515, ...). Returns: { productClass, itemCode, startDay, endDay, count, rows:[{ itemName, kindName, county, market, year, date, price, unit }] }.
**Params**   `itemCode` · `startDay` · `endDay` · `productClsCode` · `itemCategoryCode` · `kindCode`
**Env**       `KAMIS_CERT_ID` · `KAMIS_CERT_KEY`
→ Korea
getKoficBoxOffice
getKoficBoxOffice 🔑 × 1
:material-movie-outline:
web · korea L3
KOFIC (Korean Film Council) daily box-office ranking (KR; single API key required, free instant issuance). Issue the key at https://www.kobis.or.kr/kobisopenapi/ and set KOFIC_API_KEY on the tool's staticVariables, or inject as env var. `targetDate` is typically yesterday's date (same-day totals are tallied after market close). Both YYYYMMDD and YYYY-MM-DD are accepted. Optional filters: `multiMovieYn` (Y=diversity films only / N=commercial films only), `repNationCd` (K=Korean / F=foreign), `wideAreaCd` (screening region). Returns: { type, showRange, count, movies:[{ rank, rankChange, isNew, movieCode, title, openDate, salesAmount, salesShare, salesAccumulated, audience, audienceAccumulated, screens, shows }] }.
**Params**   `targetDate` · `multiMovieYn` · `repNationCd` · `wideAreaCd`
**Env**       `KOFIC_API_KEY`
→ Korea
getKrxStockPrice
getKrxStockPrice 🔑 × 1
:material-chart-line:
web · korea · finance L3
KRX Korea Exchange daily stock quotes (data.go.kr) - KOSPI/KOSDAQ/KONEX daily open/close/change/volume/market cap. KR; data.go.kr serviceKey required, separate service application from other dgk keys. Register the `Financial Services Commission stock quote info` service at data.go.kr (https://www.data.go.kr/data/15094808/openapi.do), receive a serviceKey, and set DATA_GO_KR_STOCK_KEY on the tool's staticVariables, or inject as env var. Note: the KIS API (Korea Investment & Securities) is a two-step token → Bearer flow that is inefficient for stateless tools (token consumed per call). This tool uses the KRX-official channel that exposes the same data behind a single key. Filters: `basDt` (business day YYYYMMDD), `itmsNm` (exact stock name), `likeItmsNm` (partial name match), `srtnCd` (short code e.g. 005930), `mrktCls` (KOSPI/KOSDAQ/KONEX). Returns: { totalCount, pageNo, numOfRows, items:[{ baseDate, shortCode, isinCode, name, market, close, diff, changePct, open, high, low, volume, tradeValue, listedShares, marketCap }] }.
**Params**   `basDt` · `itmsNm` · `likeItmsNm` · `srtnCd` · `mrktCls` · `numOfRows` · `pageNo`
**Env**       `DATA_GO_KR_STOCK_KEY`
→ Korea
callDataGoKrOpenApi
callDataGoKrOpenApi 🔑 × 1
:material-database:
web · korea L3
data.go.kr generic dispatcher - calls arbitrary data.go.kr services not covered by dedicated tools in this catalog. High-frequency services (air quality / tourism / stocks / ...) have their own tools; use this dispatcher for the 7,000+ other services (real-estate transactions / postal codes / road-name addresses / drug-safety agency / national statistics / ...). Most responses are in Korean. Set the data.go.kr serviceKey on the tool's staticVariables as DATA_GO_KR_KEY, or inject as env var. NOTE: each data.go.kr dataset requires its own service registration (the key value can be the same, but each OpenAPI service is approved separately). Inputs: { servicePath: 'B551011/KorService2/...' (the path after apis.data.go.kr/), query: { pageNo:1, numOfRows:10, ... } (extra query parameters) }. On success: { ok:true, totalCount, pageNo, numOfRows, items, raw }. On failure: { ok:false, status, message } (HTTP error or OpenAPI_ServiceResponse.cmmMsgHeader error).
**Params**   `servicePath` · `query`
**Env**       `DATA_GO_KR_KEY`
→ Korea
getKmaShortTermForecast
getKmaShortTermForecast 🔑 × 1
:material-weather-cloudy:
web · korea · weather L3
KMA short-term weather forecast - hourly forecast for the next ~72 hours by lat/lon or KMA grid coordinates (nx,ny). KR; data.go.kr serviceKey required, separate KMA service registration. Register the `KMA short-term forecast service` at data.go.kr, receive a serviceKey, and set DATA_GO_KR_KMA_KEY on the tool's staticVariables, or inject as env var. Coordinates: pass either (latitude, longitude) or (nx, ny). Lat/lon are converted internally to KMA Lambert grid. baseDate/baseTime default to today's 0500 release (KMA releases at 02/05/08/11/14/17/20/23). Response is pivoted to 1-hour slots: { fcstDate, fcstTime, temp(℃), humidity(%), precipProbability(%), precipType, precipAmount, skyCondition, windSpeed(m/s), windDirection(deg) }.
**Params**   `latitude` · `longitude` · `nx` · `ny` · `baseDate` · `baseTime`
**Env**       `DATA_GO_KR_KMA_KEY`
→ Korea
getApartmentTradePrice
getApartmentTradePrice 🔑 × 1
:material-home-city-outline:
web · korea · finance L3
MOLIT (Ministry of Land, Infrastructure & Transport) apartment sale transactions (KR; data.go.kr serviceKey required). Register the MOLIT apartment-trade data service at data.go.kr, receive a serviceKey, and set DATA_GO_KR_APT_KEY on the tool's staticVariables, or inject as env var. `lawdCode` is the 5-digit legal-dong city/county code (not the road-name address). Examples: Gangnam=11680, Seocho=11650, Songpa=11710, Haeundae=26350, Bundang(Seongnam)=41135, Jeju City=50110. `dealYmd` is the transaction month as YYYYMM. Returns: { lawdCode, dealYmd, totalCount, pageNo, numOfRows, items:[{ aptName, dealYear, dealMonth, dealDay, dealAmount(10K KRW), excluUseAr(sqm), floor, buildYear, umdNm(legal dong), jibun(lot), roadName, dealingType }] }.
**Params**   `lawdCode` · `dealYmd` · `numOfRows` · `pageNo`
**Env**       `DATA_GO_KR_APT_KEY`
→ Korea
searchKoreaDrugInfo
searchKoreaDrugInfo 🔑 × 1
:material-pill:
web · korea · search L3
MFDS (Ministry of Food & Drug Safety) drug product approval search (KR; data.go.kr serviceKey required). Register the `MFDS drug product approval info` service at data.go.kr, receive a serviceKey, and set DATA_GO_KR_DRUG_KEY on the tool's staticVariables, or inject as env var. At least one of `itemName` (partial product name), `entpName` (company name), or `itemSeq` (product sequence) is required. Returns: { totalCount, pageNo, numOfRows, items:[{ itemSeq, itemName, entpName, itemPermitDate, className, storageMethod, packUnit, validTerm, cancelDate, cancelName, chart }] }.
**Params**   `itemName` · `entpName` · `itemSeq` · `numOfRows` · `pageNo`
**Env**       `DATA_GO_KR_DRUG_KEY`
→ Korea
getKoreaEmergencyAlerts
getKoreaEmergencyAlerts 🔑 × 1
:material-alert-octagon-outline:
web · korea L3
MOIS (Ministry of the Interior & Safety) emergency disaster-alert SMS history (KR; data.go.kr serviceKey required). Register the `MOIS emergency disaster alerts` service at data.go.kr, receive a serviceKey, and set DATA_GO_KR_DISASTER_KEY on the tool's staticVariables, or inject as env var. `area` matches the dispatch region name partially (Korean string). `fromDate`/`toDate` accept YYYYMMDD or YYYY-MM-DD. Returns: { totalCount, pageNo, numOfRows, items:[{ serialNo, createDate, message, emergencyStep, disasterType, location }] }.
**Params**   `area` · `fromDate` · `toDate` · `numOfRows` · `pageNo`
**Env**       `DATA_GO_KR_DISASTER_KEY`
→ Korea

Two ways to use these tools

Expose and call

The simplest mode - pick a preset (or layer rules on top) and the built-in MCP server publishes that subset. The same tool inventory ends up reachable, but the two transports the server can run with serve different audiences:

Before exposing to an external client, the in-app MCP Inspector is the practical place to verify each tool’s contract - run the tool, look at its schema, prompts, and resources, all isolated from chat.

No JS authoring is required for any of this mode - pick a preset, expose, call.

Author and compose

The deeper mode - each default tool’s JS source is a working reference for the cross-bridged helpers (fetch, safety.fs.*, safety.parser.*, crypto.subtle, console.log). Open one in Tool Studio, use Copy And New Tool to fork it, tweak the action, hit Test & Publish. The moment Local Pass succeeds, your tweaked tool joins the same built-in MCP server - Agentic Chat and external clients see it without a restart.

End-to-end flow

[ Default tool · Custom tool ]
            │
            ▼
   [ Author in Tool Studio ]
            │
            ▼
   [ Local Pass test  ✅ ] ──── No pass, no run - the gate
            │
            ▼
   [ Built-in MCP server ]
            │
            ├── Streamable HTTP  ·  http://localhost:8282/mcp
            │   server runs independently; clients connect by URL
            │       │
            │       ├──▶  [ MCP Inspector ]  (in-app - verify the contract)
            │       ├──▶  [ Agentic Chat ]   (in-app)
            │       └──▶  External HTTP clients - Claude Code · Cursor ·
            │             Claude Desktop (via mcp-remote) · any Streamable HTTP MCP client
            │
            └── STDIO  ·  process stdin/stdout JSON-RPC
                client spawns the playground as its child process;
                its lifetime is tied to the client - when the client exits, the server exits with it
                (opt-in: mcp-stdio profile - Docker -e SPRING_PROFILES_INCLUDE=mcp-stdio,
                 or java -jar with the same env var)
                     │
                     └──▶  External STDIO clients - Claude Desktop · Claude Code
                           configured to spawn the process · any other STDIO MCP client

The two transports differ in who owns the server’s lifetime: in Streamable HTTP mode the playground is a long-running daemon and clients come and go by URL; in STDIO mode the MCP client launches the playground as a child process and the server dies with the client. The in-app Inspector and Agentic Chat always reach the server over Streamable HTTP - STDIO is purely for external clients that want to host the process themselves. The same flow applies whether you expose a default tool unchanged or compose new tools from default-tool patterns, and the Inspector is where you exercise each tool against its schema before pointing an external client at it.

Why these are different from other MCP tools

Most MCP server implementations ship one native binary per OS (Python wheels, Node binaries, Go / Rust executables) and require the user to install a platform-matching build, often plus a toolchain (Python, Node, Cargo) to author new tools.

Spring AI Playground’s tool runtime is OS-agnostic by design. One JVM artifact - distributed as a JAR, a Docker image, or an Electron-packaged desktop launcher - runs identically on macOS, Windows, and Linux. All 85 default tools are pure JavaScript executed through GraalVM Polyglot, and so is every tool you author. There is no per-OS build step, no native dependency, no toolchain on the user’s machine.

Full mechanics - including how every cross-bridged helper rides on JVM stdlib so / vs \, TLS, parsers, and crypto behave identically across OSes - in Tool Studio → Cross-platform by design.

Composition recipes

The reference pages list what’s available; composition recipes show how to chain them into a useful new tool. Three walk-throughs are in Tutorial 8: Default Tool Recipes:

Environment variables - short list

Some default tools depend on environment-backed secrets and stay inert until those are set. The full per-tool breakdown lives on each reference page; the most common are:

Env var Used by Why
OPENAI_API_KEY openaiResponseGenerator OpenAI Responses API
GOOGLE_API_KEY + GOOGLE_PSE_ID googlePseSearch Google Programmable Search Engine
SLACK_WEBHOOK_URL sendSlackMessage Incoming Webhook
TOOL_STUDIO_FS_BASE All Filesystem tools Per-app safety.fs root (defaults to ${user.home}/spring-ai-playground/fs-tool-workspace)
Various Korean provider keys KR network tools - Naver, Kakao, KMA, data.go.kr Provider-specific (per-page)

Secrets are masked from console.log output by substring replacement when the full resolved value appears, and they are not committed to the tool spec - they resolve at runtime from the JVM environment.

Tool Studio: Key Tool Studio Capabilities - Static Variables, secret masking, and how env-backed values reach the JS action.