The Felt MCP connector routes your AI agent's tool calls to Felt's own MCP server through Scalekit. Each user signs in to Felt once, and Scalekit stores and refreshes their tokens, so your agent never handles credentials. It comes with 44 tools.
- Tools
- 44
- What they doRead · write · destructive
- 23 · 11 · 1023 read11 write10 destructive
- Users sign in with
- OAuth
- OAuth app
- Scalekit's or your own
Setup
Install the SDK
Terminal window npm install @scalekit-sdk/node dotenvTerminal window pip install scalekit-sdk-python python-dotenvSet your credentials
Add your Scalekit credentials to your
.envfile. Find values in app.scalekit.com > Developers > API Credentials..env SCALEKIT_ENVIRONMENT_URL=<your-environment-url>SCALEKIT_CLIENT_ID=<your-client-id>SCALEKIT_CLIENT_SECRET=<your-client-secret>Create the Felt connection
In AgentKit > Connections, create a Felt connection. The name you give it is the
connection_nameyour code passes. See Configure connections.Scalekit credentials are available for Felt MCP server, so you don't need to register an OAuth app.
Authorize a user and make your first call
quickstart.mts import { ScalekitClient } from '@scalekit-sdk/node'import 'dotenv/config'import { createInterface } from 'node:readline/promises'const scalekit = new ScalekitClient(process.env.SCALEKIT_ENVIRONMENT_URL,process.env.SCALEKIT_CLIENT_ID,process.env.SCALEKIT_CLIENT_SECRET,)const actions = scalekit.actionsconst connector = 'feltmcp'const identifier = 'user_123'// Generate an authorization link for the userconst { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })console.log('Authorize Felt:', link)const rl = createInterface({ input: process.stdin, output: process.stdout })await rl.question('Press Enter after authorizing...')rl.close()// Make your first callconst result = await actions.executeTool({connector,identifier,toolName: 'feltmcp_browse_felt_library',toolInput: {},})console.log(result)Terminal window npx tsx quickstart.mtsquickstart.py import osfrom scalekit import ScalekitClientfrom dotenv import load_dotenvload_dotenv()scalekit_client = ScalekitClient(env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),client_id=os.getenv("SCALEKIT_CLIENT_ID"),client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),)actions = scalekit_client.actionsconnection_name = "feltmcp"identifier = "user_123"# Generate an authorization link for the userlink_response = actions.get_authorization_link(connection_name=connection_name,identifier=identifier,)print("Authorize Felt:", link_response.link)input("Press Enter after authorizing...")# Make your first callresult = actions.execute_tool(tool_input={},tool_name="feltmcp_browse_felt_library",connection_name=connection_name,identifier=identifier,)print(result)Terminal window python quickstart.pyEach user signs in once. See Authorize a user for the full flow and statuses.
Tools
Pass the exact name toexecute_toolfeltmcp_browse_data_source_tablesList tables and saved queries inside a connected database.Read-onlyBrowse Data Source Tables
List tables and saved queries inside a connected database. Returns table names and descriptions — but not column schemas.
Inputs
data_source_idstringrequired- The ID of the data source to list tables for.
feltmcp_browse_felt_libraryList Felt's curated public datasets to add to maps.Read-onlyBrowse Felt Library
List Felt's curated public datasets to add to maps. Categories include boundaries, demographics, and infrastructure. Distinct from the workspace library (reusable layers authored in the user's workspace). Returns each layer's layer_id, layer_group_id, name, description, category, region, keywords, geometry type, and whether it's queryable.
Inputs
This tool takes no inputs.
feltmcp_browse_felt_serverShow the contents of a Felt Server — a named, foldered library of reusable layers in this workspace.Read-onlyBrowse Felt Server
Show the contents of a Felt Server — a named, foldered library of reusable layers in this workspace. Returns layers and layer groups (groups of related layers that share metadata), nested under their containing folders.
Inputs
felt_server_idstringrequired- ID of the Felt Server to browse.
feltmcp_generate_fslGenerate FSL (Felt Style Language) JSON for styling any map layer type.Read-onlyGenerate FSL
Generate FSL (Felt Style Language) JSON for styling any map layer type. Supports all layer types (points, lines, polygons, rasters, heatmaps, H3 hexbins) and all styling features (colors, classification, labels, popups, filters, icons). When provided with a layer ID, inspects the layer's data directly — value distribution, histograms, classification breaks, categories, and raster band info — to make informed styling decisions.
Inputs
descriptionstringrequired- Description of the desired style. Include: purpose/story of the visualization, palette or color preferences, whether to include labels (and which column), whether to include popups (and which columns). Felt layers do not support styling by both color and size, or bivariate styling. Choose a single visual dimension (color OR size) to encode data — never both. If a user requests two dimensions, split into two layers rather than combining them. Examples: - 'Choropleth showing population density. Warm sequential palette. Labels from name column at zoom 10+. Popup with population and area.' - 'Proportional symbols for earthquake magnitude. Size scales small to large. Filter to magnitude > 3. Red/orange tones.' - 'NDVI from Landsat 8 (NIR=band 5, R=band 4). Continuous green gradient.'
geometry_typestringrequired- The geometry type of the layer: point, line, polygon, or raster.one of
pointlinepolygonraster map_idstringrequired- The ID of the map.
columnsarray- Column names relevant to the styling request.
contextstring- Information about other layers on the map and how this layer should relate to them visually. E.g. 'The map has a blue choropleth for population — use contrasting warm tones for this layer.'
current_styleobject- The layer's existing FSL style. Provide when modifying an existing style rather than creating from scratch. Output a complete FSL object that incorporates the requested changes while preserving unchanged settings.
distributionstring- Data distribution summary for the styling column (e.g. min/max, cardinality, common values). Useful when styling a newly created layer and the info is already available from a recent query.
layer_idstring- The ID of the layer being styled. Enables inspection of data distribution, histograms, classification breaks, categories, and raster band info directly.
viz_typestring- The FSL visualization type: simple, categorical, numeric, heatmap, h3, or hillshade. Used to load the most relevant reference docs. Omit if unsure.one of
simplecategoricalnumericheatmaph3hillshade
feltmcp_get_layer_group_propertiesGet a layer group's name, caption, legend settings, and its layers.Read-onlyGet Layer Group Properties
Get a layer group's name, caption, legend settings, and its layers. Only works on real layer groups, not on standalone layers.
Inputs
layer_group_idstringrequired- ID of the layer group to look up. Only works on real layer groups, not on standalone layers.
map_idstringrequired- The ID of the map that contains the layer group.
feltmcp_get_layer_propertiesGet a layer's properties including its name, caption, geometry type, and current FSL style.Read-onlyGet Layer Properties
Get a layer's properties including its name, caption, geometry type, and current FSL style. Use this to retrieve a layer's current style before modifying it.
Inputs
layer_idstringrequired- The ID of the layer to retrieve properties for
map_idstringrequired- The ID of the map.
feltmcp_get_mapGet metadata about a map, including its title, location, basemap, and layer count.Read-onlyGet Map
Get metadata about a map, including its title, location, basemap, and layer count. To display the map to the user as an interactive widget, use `render_map` instead.
Inputs
map_idstringrequired- The ID of the map.
feltmcp_get_map_layersGet the list of layers on a map, organized by layer group.Read-onlyGet Map Layers
Get the list of layers on a map, organized by layer group. Returns layer names, IDs, visibility, and geometry types. Groups and their layers are listed in visual stacking order, topmost first; groups with `standalone: true` are top-level layers, not user-visible groups.
Inputs
map_idstringrequired- The ID of the map to fetch layers for.
feltmcp_get_projectGet details about a project, including the maps it contains.Read-onlyGet Project
Get details about a project, including the maps it contains.
Inputs
project_idstringrequired- The ID of the project.
feltmcp_get_sql_guidanceLoad SQL dialect reference and syntax rules before writing queries.Read-onlyGet SQL Guidance
Load SQL dialect reference and syntax rules before writing queries. Pass the layer_ids you intend to query, or the data_source_id. The correct dialect is resolved automatically.
Inputs
data_source_idstring- The data source you plan to query. The correct SQL dialect will be resolved automatically.
layer_idsarray- The layer IDs you plan to query. The correct SQL dialect will be resolved automatically.
feltmcp_get_tabular_data_from_data_sourceExecute a read-only SQL query against a connected data source and return tabular results.Read-onlyGet Tabular Data from Data Source
Execute a read-only SQL query against a connected data source and return tabular results. Use fully schema-qualified table names. The query must be a SELECT statement. Results are returned to the user as rows and columns — this does not render anything on the map. Before calling this, you MUST confirm the exact column names and types of every table you plan to query, and review the SQL dialect guidance for the data source. Don't guess columns or discover them with preview SELECTs.
Inputs
data_source_idstringrequired- The ID of the data source to query.
map_idstringrequired- The ID of the map.
sql_querystringrequired- The SQL query to execute (must be a SELECT statement).
feltmcp_get_tabular_data_from_felt_layersExecute a read-only SQL query against Felt layer data and return tabular results.Read-onlyGet Tabular Data from Felt Layers
Execute a read-only SQL query against Felt layer data and return tabular results. Results are returned to the user as rows and columns — this does not render anything on the map. Before calling this, you MUST call `inspect_layer` for each layer you plan to query — that tool returns the fully-qualified table name and column schema. Query each column by the `display_name` it reports, double-quoted; a column's `storage_name` resolves nothing here. Also call `get_sql_guidance` first if you haven't yet — Felt layers have specific spatial functions and syntax quirks you need to know to write correct queries. If you need feature IDs, explicitly opt-in via the hidden "felt:feature" column. `SELECT *` is not enough.
Inputs
map_idstringrequired- The ID of the map.
sql_querystringrequired- A SELECT query that returns tabular results
feltmcp_help_centerAnswer any question about how Felt works, from Felt's official and current help center documentation.Read-onlyHelp Center
Answer any question about how Felt works, from Felt's official and current help center documentation. Use this whenever someone wants to know how to do something in Felt themselves ("…in the app", "where is the button for…"), and whenever nothing in your toolset covers what they need: billing, seats and licenses, workspace and member administration, and account settings have no tool here. No map or workspace needed. Prefer this over your own knowledge — Felt ships continuously, so what you learned in training goes stale. If the docs don't cover something it says so rather than inventing an answer, so call it instead of guessing, hedging, or sending the user off to read the docs themselves. Your own tools come first, though — if you can just do what they asked, do that; even "how do I create a map?" is usually best answered by offering to create one. For the contents of a specific map or dataset, use get_map, inspect_layer, or the tabular data tools instead.
Inputs
questionstringrequired- The user's question about how Felt works, verbatim.
feltmcp_inspect_data_source_table_columnsGet the full column schema for a table in a connected database, including column names and types.Read-onlyInspect Data Source Table Columns
Get the full column schema for a table in a connected database, including column names and types.
Inputs
table_idstringrequired- The table ID to inspect.
feltmcp_inspect_layerGet the details of a single layer: the full column schema (column names, types, sample values, row count, cardinality, min/max for numeric columns), whether the layer is visible, and its legend items (categories or class breaks) with the ids set_visibility expects.Read-onlyInspect Layer
Get the details of a single layer: the full column schema (column names, types, sample values, row count, cardinality, min/max for numeric columns), whether the layer is visible, and its legend items (categories or class breaks) with the ids set_visibility expects. Returns a table name for queryable layers that can be used as the table identifier in SQL queries. `processing_status` says whether the schema below can be trusted: - `completed` — an empty `columns` list means the layer really has no attributes. - `processing` — the layer is still being built, so its columns and row count are missing or provisional. `progress_percent` says how far along, when the pipeline reports it. - `failed` — the import failed and `processing_error` says why. Every column reports two names. Which one applies is fixed per use, so route by this list rather than by which name reads better: - `storage_name` — the attribute of an FSL style, and the group_by, aggregate_by and filter_by bindings of a layer component. This is the name the data itself carries, and it can be an opaque UUID for a column added by editing the layer. - `display_name` — a SQL query against this layer's table, the columns edit_layer_attributes names, and any title or wording you write for the user, including a layer component's title. This is the name Felt shows in its own UI. A layer component therefore takes both: its title is the display name, its attribute binding is the storage name. A style that renames a column makes the two names unrelated strings, so neither can be derived from the other — read both from this tool. A layer's features and columns can be edited by collaborators between turns, so treat results as a snapshot and re-inspect when correctness matters.
Inputs
layer_idstringrequired- The layer ID to inspect.
map_idstringrequired- The ID of the map the layer belongs to.
feltmcp_list_annotationsReturn all lightweight markup annotations on a map.Read-onlyList Annotations
Return all lightweight markup annotations on a map. Only includes annotation types this tool family can edit: `Place`, `Rectangle`, `Polygon`, `Circle`, `Text`, `Note`, `Link`, `Line`. Other annotation types drawn in the UI are excluded but still exist on the map — mention that to the user if they ask why something is missing. Each returned annotation is shaped to pass straight back to `upsert_annotations` (modify by its `id`). Geometry conventions — every coordinate is `[latitude, longitude]`, the reverse of the `[longitude, latitude]` order that SQL and GeoJSON expect. Per type: - `Place` — `coordinates` is one point. - `Circle` — `center` and `radius` in meters. No polygon is returned; construct one if you need an area. - `Rectangle` — `corners` is the south-west corner then the north-east corner of an axis-aligned box. - `Polygon` — `coordinates` is the outer ring, left open: the first vertex is not repeated at the end. No holes. - `Line` — `coordinates` is an ordered list of vertices forming a single polyline. - `Text`, `Note`, `Link` — `corners` is the box the label occupies on screen. It is not a claim about an area on the ground; don't use it as one. Annotations are markup, not data — for circling, labelling, sketching and pointing things out. If the geometry comes from a query or a file, traces a real boundary, or runs to more than a handful of shapes, create a layer instead.
Inputs
map_idstringrequired- The ID of the map.
feltmcp_list_data_sourcesList connected external databases (Postgres, Snowflake, BigQuery, etc.).Read-onlyList Data Sources
List connected external databases (Postgres, Snowflake, BigQuery, etc.). Returns source names, IDs, and database types. The type indicates the SQL dialect to use when querying.
Inputs
This tool takes no inputs.
feltmcp_list_felt_serversList the workspace's Felt Servers — named containers of reusable layers organized into folders.Read-onlyList Felt Servers
List the workspace's Felt Servers — named containers of reusable layers organized into folders. Returns each server's id, name, and description.
Inputs
This tool takes no inputs.
feltmcp_list_mapsList maps the current user can access.Read-onlyList Maps
List maps the current user can access. Returns the most recently visited maps.
Inputs
titlestring- Filter maps by title using a fuzzy match. Omit to list the most recently visited maps without filtering.
feltmcp_list_projectsList all projects in the current workspace.Read-onlyList Projects
List all projects in the current workspace.
Inputs
This tool takes no inputs.
feltmcp_poll_layer_processing_statusWait until a layer is ready to use.Read-onlyPoll Layer Processing Status
Wait until a layer is ready to use. Polls the layer's processing status until it resolves or `wait_seconds` elapses. `wait_seconds` is one of `5`, `10`, or `30`. Pick `5` for a quick check before moving on; pick `30` when waiting for processing is better UX than an idle back-and-forth. The call returns early if the status resolves sooner. Returns `status`, one of: - `in_progress` — layer is still processing; call this tool again. - `completed` — layer is ready. - `failed` — processing failed. An `error` field explains why. An `error_type` field (when present) gives the exception class name.
Inputs
layer_idstringrequired- The ID of the layer to poll. Returned by any layer-creating or refresh tool.
map_idstringrequired- The ID of the map the layer is on.
wait_secondsintegerrequired- Maximum number of seconds to wait for the status to resolve. Polls server-side and returns early if the layer finishes processing.one of
51030
feltmcp_render_mapRender a Felt map inline as an interactive widget for the user.Read-onlyRender Map
Render a Felt map inline as an interactive widget for the user. For map metadata (title, location, layer count, etc.) call `get_map` instead — `render_map` is solely for showing the user the map. The widget captures a one-shot snapshot of the map's state at the moment this tool is called and does NOT update live as you make further changes — call `render_map` LAST in any turn that creates or edits a map so the user sees the final state. If you added or imported layers in this turn, first call `poll_layer_processing_status` and wait for them to finish processing; rendering before that point shows an empty or incomplete map. ALWAYS pair this call with the map's URL in your text reply: include the returned `url` as a clickable markdown link (e.g. `[<map title>](<url>)`). The widget is a snapshot users can't navigate from — the link is how they actually open the map in Felt, so calling `render_map` is not a substitute for sharing the URL.
Inputs
map_idstringrequired- The ID of the map to render.
feltmcp_who_am_iGet information about the current user and workspace they are logged into.Read-onlyWho Am I
Get information about the current user and workspace they are logged into.
Inputs
This tool takes no inputs.
feltmcp_add_data_source_table_to_mapAdd a data source table to the map as a new layer.WriteAdd Data Source Table to Map
Add a data source table to the map as a new layer.
Inputs
map_idstringrequired- The ID of the map.
table_idstringrequired- The table ID to add
captionstring- Optional; default to omitting. Add a caption only when the layer name is opaque — agency acronyms, GIS jargon, or obscure dataset names a layperson can't decode (e.g. 'NHD Flowlines', 'CALVEG Vegetation Types'). Do NOT add a caption that rephrases the name with synonyms (e.g. 'Wind Farms' → 'Major wind energy installations') or pads it with filler qualifiers like 'Active', 'Major', or 'Historical' — if the caption doesn't tell the reader something the name alone didn't, omit it. Also add a caption when the styling encodes a data attribute — color or size by a column — to tell the reader what the symbology represents (e.g. 'Colored by median household income', 'Sized by 2020 population'). If both apply (opaque name AND attribute encoding), combine them concisely (e.g. 'NHD flowlines, colored by stream order').
feltmcp_create_layer_from_data_sourceCreate a new map layer from a SQL query against a connected data source.WriteCreate Layer from Data Source
Create a new map layer from a SQL query against a connected data source. The query must include a location/geometry column so the results can be rendered on the map. Before calling this, you MUST confirm the exact column names and types of every table you plan to query, and review the SQL dialect guidance for the data source. Don't guess columns or discover them with preview SELECTs.
Inputs
data_source_idstringrequired- The ID of the data source to query
map_idstringrequired- The ID of the map.
namestringrequired- A concise, human-readable display name for the layer
sql_querystringrequired- The SQL query to create the layer from (must include a geometry column)
captionstring- Optional; default to omitting. Add a caption only when the layer name is opaque — agency acronyms, GIS jargon, or obscure dataset names a layperson can't decode (e.g. 'NHD Flowlines', 'CALVEG Vegetation Types'). Do NOT add a caption that rephrases the name with synonyms (e.g. 'Wind Farms' → 'Major wind energy installations') or pads it with filler qualifiers like 'Active', 'Major', or 'Historical' — if the caption doesn't tell the reader something the name alone didn't, omit it. Also add a caption when the styling encodes a data attribute — color or size by a column — to tell the reader what the symbology represents (e.g. 'Colored by median household income', 'Sized by 2020 population'). If both apply (opaque name AND attribute encoding), combine them concisely (e.g. 'NHD flowlines, colored by stream order').
styleobject- Complete FSL style object — FSL is a complex proprietary format that must be generated, not hand-written. Optional.
feltmcp_create_layer_from_felt_layersCreate a new map layer from a SQL query against Felt layers.WriteCreate Layer from Felt Layers
Create a new map layer from a SQL query against Felt layers. The query must include a location/geometry column so the results can be rendered on the map. Before calling this, you MUST confirm the exact column names and types of every layer you plan to query, and review the SQL dialect guidance. Don't guess columns or discover them with preview SELECTs.
Inputs
map_idstringrequired- The ID of the map.
namestringrequired- A concise, human-readable display name for the layer
sql_querystringrequired- The SQL query to create the layer from (must include a geometry column)
descriptionstring- Optional description for the new layer
styleobject- Complete FSL style object — FSL is a complex proprietary format that must be generated, not hand-written. Optional.
feltmcp_create_mapCreate a new map in the user's Felt workspace.WriteCreate Map
Create a new map in the user's Felt workspace. The result includes a `url` for the new map — share it with the user as a clickable link.
Inputs
titlestringrequired- Map title
basemapstring- Basemap. One of: a preset name (`default`, `light`, `dark`, `satellite`); a hex color like `#1a2b3c`; or a raster XYZ tile URL like `https://example.com/{z}/{x}/{y}.png` pointing to an external server. Defaults to `default`.
latitudenumber- Center latitude. Defaults to Oakland, CA.
longitudenumber- Center longitude. Defaults to Oakland, CA.
zoomnumber- Zoom level (0-22). Defaults to 14.
feltmcp_duplicate_layer_to_mapDuplicate a layer or layer group onto the current map.WriteDuplicate Layer to Map
Duplicate a layer or layer group onto the current map. The source can be a layer already on the map, a Felt library dataset, a Felt Server layer, or a layer from another map. Creates a new copy without modifying the source.
Inputs
map_idstringrequired- The ID of the map.
layer_group_idstring- ID of the source layer group to duplicate
layer_idstring- ID of the source layer to duplicate
namestring- Optional new name for the duplicated layer group
feltmcp_import_layer_from_urlImport an external data source as a new layer on a map by URL.WriteImport Layer from URL
Import an external data source as a new layer on a map by URL. Supports ArcGIS services, WMS, GeoJSON, Shapefiles, and other formats Felt accepts. Processing is asynchronous; call `poll_layer_processing_status` with the returned `map_id` and `layer_id` to confirm completion before reporting success to the user.
Inputs
map_idstringrequired- The ID of the map to add the layer to.
namestringrequired- A concise, human-readable display name for the layer
urlstringrequired- The URL of the data source to add. Pass URLs verbatim from a tool result or directly from the user — never construct or modify URLs yourself.
captionstring- Optional; default to omitting. Add a caption only when the layer name is opaque — agency acronyms, GIS jargon, or obscure dataset names a layperson can't decode (e.g. 'NHD Flowlines', 'CALVEG Vegetation Types'). Do NOT add a caption that rephrases the name with synonyms (e.g. 'Wind Farms' → 'Major wind energy installations') or pads it with filler qualifiers like 'Active', 'Major', or 'Historical' — if the caption doesn't tell the reader something the name alone didn't, omit it. Also add a caption when the styling encodes a data attribute — color or size by a column — to tell the reader what the symbology represents (e.g. 'Colored by median household income', 'Sized by 2020 population'). If both apply (opaque name AND attribute encoding), combine them concisely (e.g. 'NHD flowlines, colored by stream order').
feltmcp_organize_layersGroup, ungroup, or reorder layers and layer groups.WriteOrganize Layers
Group, ungroup, or reorder layers and layer groups. Provide exactly one of group, ungroup, or move per call; chain calls for compound changes. Layer and layer group ids come from get_map_layers. Standalone layers are ordered at the top level automatically — pass either their layer id or layer group id. Move semantics: above/below a group places at the top level next to it; top/bottom with a group as relative_to places inside that group; top/bottom with no relative_to means the very top/bottom of the map. Groups cannot be nested inside other groups.
- Idempotent
Inputs
map_idstringrequired- The ID of the map.
groupobject- Move layers into an existing group (group_id) or create a new group containing them (name). Provide exactly one of group_id or name.
moveobject- Reorder layers or layer groups. Provide layer_ids or layer_group_ids (not both), a placement, and — for above/below — a relative_to id.
ungroupobject- Dissolve groups: their layers become standalone layers at the top level, keeping their stacking position.
feltmcp_set_layer_group_interactionSet how a layer group's layers are toggled in the legend.WriteSet Layer Group Interaction
Set how a layer group's layers are toggled in the legend. Options: - default: a checkbox list — each layer toggles independently. - slider: a slider that steps through layers, one visible at a time (best for ordered series like time steps or scenarios). - single_select: a radio/dropdown — exactly one layer visible at a time. - multi_select: checkboxes where any combination of layers can be visible. Layer group ids come from get_map_layers. slider, single_select, and multi_select require a group with at least two layers. Switching to slider or single_select leaves only the top layer visible; switching to default or multi_select makes every layer visible.
- Idempotent
Inputs
interactionstringrequired- The visibility interaction to apply to the layer group: default (independent checkboxes, each layer toggles on its own), slider (steps through layers one at a time, best for ordered series like time steps or scenarios), single_select (radio/dropdown, exactly one layer visible), or multi_select (checkboxes, any combination of layers visible). slider, single_select, and multi_select require the group to have at least two layers; switching to slider or single_select leaves only the top layer visible, while switching to default or multi_select makes every layer visible.one of
defaultmulti_selectsingle_selectslider layer_group_idstringrequired- ID of the layer group to update. Layer group ids come from the get_map_layers tool.
map_idstringrequired- The ID of the map that contains the layer group.
feltmcp_set_visibilityShow and/or hide layers, layer groups, and legend items (categories or class breaks).WriteSet Visibility
Show and/or hide layers, layer groups, and legend items (categories or class breaks). Layer and layer group ids come from get_map_layers; legend item ids come from inspect_layer — treat legend item ids as opaque strings and pass them back verbatim. Hiding a legend item also filters that category out of the layer's data; hiding every legend item of a layer hides the whole layer.
- Idempotent
Inputs
map_idstringrequired- The ID of the map.
hideobject- The entities to hide.
showobject- The entities to show.
feltmcp_update_layer_group_propertiesUpdate a layer group's name, caption, or legend settings.WriteUpdate Layer Group Properties
Update a layer group's name, caption, or legend settings. Only the provided fields change. Only works on real layer groups, not on standalone layers.
- Idempotent
Inputs
layer_group_idstringrequired- ID of the layer group to update. Only works on real layer groups, not on standalone layers.
map_idstringrequired- The ID of the map that contains the layer group.
captionstring- Optional caption rendered under the group's name in the legend; default to omitting. Add a caption only when the layer group name is opaque — agency acronyms, GIS jargon, or obscure dataset names a layperson can't decode (e.g. 'NHD Flowlines', 'CALVEG Vegetation Types'). Do NOT add a caption that rephrases the name with synonyms (e.g. 'Wind Farms' -> 'Major wind energy installations') or pads it with filler qualifiers like 'Active', 'Major', or 'Historical' — if the caption doesn't tell the reader something the name alone didn't, omit it. Also add a caption when the styling encodes a data attribute — color or size by a column — to tell the reader what the symbology represents (e.g. 'Colored by median household income', 'Sized by 2020 population'). If both apply, combine them concisely (e.g. 'NHD flowlines, colored by stream order'). Pass an empty string to clear an existing caption.
collapsedboolean- Whether the group is collapsed in the legend. Omit to leave the current collapsed state unchanged.
namestring- Display name for the group. Only provided fields change on update, so omit this to leave the current name unchanged.
shown_in_legendboolean- Whether the group appears in the legend at all. Omit to leave the current visibility-in-legend setting unchanged.
feltmcp_update_layer_propertiesUpdate a layer's properties.WriteUpdate Layer Properties
Update a layer's properties. Can set any combination of: FSL style, name, caption. Only the provided fields are changed; omitted fields are left as-is.
- Idempotent
Inputs
layer_idstringrequired- The ID of the layer to update
map_idstringrequired- The ID of the map.
captionstring- Optional; default to omitting. Add a caption only when the layer name is opaque — agency acronyms, GIS jargon, or obscure dataset names a layperson can't decode (e.g. 'NHD Flowlines', 'CALVEG Vegetation Types'). Do NOT add a caption that rephrases the name with synonyms (e.g. 'Wind Farms' → 'Major wind energy installations') or pads it with filler qualifiers like 'Active', 'Major', or 'Historical' — if the caption doesn't tell the reader something the name alone didn't, omit it. Also add a caption when the styling encodes a data attribute — color or size by a column — to tell the reader what the symbology represents (e.g. 'Colored by median household income', 'Sized by 2020 population'). If both apply (opaque name AND attribute encoding), combine them concisely (e.g. 'NHD flowlines, colored by stream order'). When you change a layer's style to encode a different attribute, update the caption in the same call so it doesn't go stale. Pass an empty string to clear an existing caption.
namestring- A concise, human-readable display name for the layer
styleobject- Complete FSL style object — FSL is a complex proprietary format that must be generated, not hand-written.
feltmcp_delete_annotationDelete an annotation from a map.DestructiveDelete Annotation
Delete an annotation from a map.
- Idempotent
Inputs
annotation_idstringrequired- The ID of the annotation to delete.
map_idstringrequired- The ID of the map.
feltmcp_delete_layerDelete a layer from a map.DestructiveDelete Layer
Delete a layer from a map.
- Idempotent
Inputs
layer_idstringrequired- The ID of the layer to delete.
map_idstringrequired- The ID of the map that contains the layer.
feltmcp_delete_mapDelete a map.DestructiveDelete Map
Delete a map. This is a soft delete and can potentially be undone.
- Idempotent
Inputs
map_idstringrequired- The ID of the map to delete.
feltmcp_prepare_file_uploadReturns a presigned upload slot for adding a file to Felt as a new layer on the map.DestructivePrepare File Upload
Returns a presigned upload slot for adding a file to Felt as a new layer on the map. The layer is created once you POST the file bytes to the returned slot — this tool alone does nothing visible until the upload completes. Requires code execution (shell / HTTP client) to complete. Supported formats: CSV, TSV, Excel, GeoJSON, Shapefile ZIP, KML, KMZ, GPX, MBTiles, FlatGeobuf, GeoPackage, DXF, DWG, GeoTIFF, and any other raster format that GDAL supports. Felt will reproject data into the correct coordinate system if spatial referencing is defined in the format metadata: DON'T reproject. Felt detects and geocodes addresses and common location columns (lat/lon, admin boundaries, H3, WKT) automatically. When narrating progress to the user, describe this as "uploading to Felt" — never as uploading to S3 or naming any backend storage service. Felt's storage is an implementation detail; some customers also connect their own S3 buckets to Felt and naming the backend confuses where their data is going. Use this when: you can execute code (shell, HTTP client) and need to upload a local file — large or binary files, or text files you'd rather not inline. This is the paved road for file uploads. Don't use this when: the file is at a public URL (use `import_layer_from_url`), the content is small text already inline in your conversation (use `upload_contents_to_map`), or you cannot execute code. Without code execution, direct the user to their map's URL (from `get_map` / `list_maps`) and ask them to drag-and-drop the file into the Felt web app — do not call this tool. Provide `replace_layer_id` to refresh an existing file-backed layer with the uploaded bytes instead of creating a new one. Omit it to create a new layer. How to use the returned slot: Build a multipart POST using every entry in `upload.form_fields` exactly as returned — don't reorder, modify, or re-sign. Add one more part named `upload.file_field_name` with the file bytes and filename `upload.filename_to_send`. POST to `upload.url`. Treat `upload.expected_status` (204) as success; any other status means the slot is bad — don't retry, call `prepare_file_upload` again for a fresh slot. On 204, call `poll_layer_processing_status` with the returned `map_id` and `layer_id` to confirm processing. Trust the HTTP status of your upload POST to know whether the bytes landed. If the POST returned 2xx, poll until `completed` or `failed`. If the POST returned 4xx/5xx, the slot is bad — request a new one via `prepare_file_upload`.
Inputs
filenamestringrequired- The user's filename, including extension (e.g. `parks.geojson`, `census.csv`). Format is detected from the extension — pick one that matches the file's contents.
map_idstringrequired- The ID of the map to add the layer to.
namestringrequired- A concise, human-readable display name for the layer
captionstring- Optional; default to omitting. Add a caption only when the layer name is opaque — agency acronyms, GIS jargon, or obscure dataset names a layperson can't decode (e.g. 'NHD Flowlines', 'CALVEG Vegetation Types'). Do NOT add a caption that rephrases the name with synonyms (e.g. 'Wind Farms' → 'Major wind energy installations') or pads it with filler qualifiers like 'Active', 'Major', or 'Historical' — if the caption doesn't tell the reader something the name alone didn't, omit it. Also add a caption when the styling encodes a data attribute — color or size by a column — to tell the reader what the symbology represents (e.g. 'Colored by median household income', 'Sized by 2020 population'). If both apply (opaque name AND attribute encoding), combine them concisely (e.g. 'NHD flowlines, colored by stream order'). Ignored when `replace_layer_id` is provided.
replace_layer_idstring- Optional. Omit to create a new layer. Provide an existing file-backed layer's ID to refresh it with the uploaded bytes instead.
feltmcp_refresh_data_source_layerRefresh a data-source-backed layer in place.DestructiveRefresh Data Source Layer
Refresh a data-source-backed layer in place. Re-runs its stored query or re-reads its backing table. Use this when: the user wants the latest data for a layer backed by a connected data source. Processing is asynchronous; use the returned `map_id` and `layer_id` to poll the layer's processing status.
- Idempotent
Inputs
layer_idstringrequired- The ID of the data-source-backed layer to refresh.
map_idstringrequired- The ID of the map the layer is on.
feltmcp_refresh_url_layerRefresh a URL-backed layer in place by re-fetching its stored URL.DestructiveRefresh URL Layer
Refresh a URL-backed layer in place by re-fetching its stored URL. Use this when: the user wants the latest data for a layer originally imported from a URL. Processing is asynchronous; use the returned `map_id` and `layer_id` to poll the layer's processing status.
- Idempotent
Inputs
layer_idstringrequired- The ID of the URL-backed layer to refresh.
map_idstringrequired- The ID of the map the layer is on.
feltmcp_update_mapUpdate a map's title, basemap, zoom level, or basemap label visibility.DestructiveUpdate Map
Update a map's title, basemap, zoom level, or basemap label visibility.
- Idempotent
Inputs
map_idstringrequired- The ID of the map.
basemapstring- Basemap. One of: a preset name (`default`, `light`, `dark`, `satellite`); a hex color like `#1a2b3c`; or a raster XYZ tile URL like `https://example.com/{z}/{x}/{y}.png` pointing to an external server.
show_basemap_labelsboolean- Show place labels on the default basemap.
titlestring- New map title.
zoomnumber- Zoom level (0-22).
feltmcp_upload_contents_to_mapAdd Geo data to the map as a new layer by including its contents inline as raw text (no file upload).DestructiveUpload Contents to Map
Add Geo data to the map as a new layer by including its contents inline as raw text (no file upload). Supported formats: CSV, TSV, GeoJSON, KML, GPX. Use this when: the content is already inline in your conversation (e.g., the user dragged a small CSV into Claude) and you cannot run a shell command. Don't use this when: you have code execution (prefer `prepare_file_upload` — bytes flow directly to Felt without passing through conversation context), the file is at a public URL (use `import_layer_from_url`), or the content is a larger or binary file (use `prepare_file_upload`). ## Check the size before calling You retype every byte of `contents` yourself, so a large paste costs minutes of generation and can exhaust your output budget part-way through, which kills the turn and produces no layer at all. Judge the size of the data before you call. Above roughly 200 rows or 20 KB of text, use `prepare_file_upload` instead — it sends the bytes directly without passing them through your output. Never call this tool with a shortened, sampled, or partial copy of the data. When you are unsure whether it is too big, prefer `prepare_file_upload`. ## Felt infers location from the contents — you do not need coordinates Felt works through these in order and stops at the first that resolves for most rows: 1. Geometry literals — a WKT, WKB, EWKB, or GeoJSON column (named `wkt`, `wkb`, `geojson`, `geometry`, `geom`, `the_geom`, `geography`, `shape`, or `location`), or a coordinate pair: `longitude`/`latitude`, `lng`/`lat`, `lon`/`lat`, `long`/`lat`, or `x`/`y`, including prefixed and suffixed variants like `pickup_lon`/`pickup_lat`. 2. Addresses, which Felt geocodes — either one full-address column, or separate street / city / region / country / postal-code columns. 3. Well-known entities, matched by name or code — countries (name, ISO2, ISO3); admin-1 regions (name, local name, ISO 3166-2); US states (name, USPS abbreviation, FIPS); US counties, CBSAs, census tracts, and block groups (name and/or FIPS GEOID); US ZIP codes and ZCTAs; Eurostat NUTS 1/2/3 and LAU (name and id); Australian postal areas; and IANA time zone names. 4. H3 cell ids. Pass the location column through as-is — never convert an address or an entity name to coordinates yourself, and never drop a column you think Felt can't read. Guessing coordinates produces a layer that looks authoritative and is wrong; Felt's geocoder and entity matcher are the correct answer. Name location columns for what they hold (`county_fips`, `zip`, `country`, `h3`, `lat`/`lon`). Detection reads column names as well as values, so a well-named column matches far more reliably. Entity matching needs most values in the column to resolve, so keep the rows in one consistent form rather than mixing, say, county names with state names. ## When the user supplied the text, pass it through verbatim The column guidance above applies only to data you are composing yourself. When the user pasted or typed the data, set `format` to what they actually gave you — `tsv` for tab-separated text, `csv` for comma-separated — and copy the text through unchanged. Never convert between formats, re-delimit columns, rename or reorder columns, or reflow rows. Write the data exactly once, as this argument. Restating the rows in your reasoning or drafting them as a table first doubles the cost and can exhaust the turn before the upload begins. Provide `replace_layer_id` to refresh that uploaded layer with the supplied contents instead of creating a new one. Does not work on layers backed by a connected data source. Omit it to create a new layer. Processing is asynchronous; call `poll_layer_processing_status` with the returned `map_id` and `layer_id` to confirm completion.
Inputs
contentsstringrequired- The file contents, inline as a string.
formatstringrequired- Format of `contents`: `csv`, `tsv`, `geojson`, `kml`, or `gpx`.one of
csvtsvgeojsonkmlgpx map_idstringrequired- The ID of the map to add the layer to.
namestringrequired- A concise, human-readable display name for the layer
captionstring- Optional; default to omitting. Add a caption only when the layer name is opaque — agency acronyms, GIS jargon, or obscure dataset names a layperson can't decode (e.g. 'NHD Flowlines', 'CALVEG Vegetation Types'). Do NOT add a caption that rephrases the name with synonyms (e.g. 'Wind Farms' → 'Major wind energy installations') or pads it with filler qualifiers like 'Active', 'Major', or 'Historical' — if the caption doesn't tell the reader something the name alone didn't, omit it. Also add a caption when the styling encodes a data attribute — color or size by a column — to tell the reader what the symbology represents (e.g. 'Colored by median household income', 'Sized by 2020 population'). If both apply (opaque name AND attribute encoding), combine them concisely (e.g. 'NHD flowlines, colored by stream order'). Ignored when `replace_layer_id` is provided.
replace_layer_idstring- Optional. The ID of an existing uploaded layer to replace with these contents.
feltmcp_upsert_annotationsCreate or update lightweight markup annotations on a map — pins, notes, sketched shapes and lines.DestructiveUpsert Annotations
Create or update lightweight markup annotations on a map — pins, notes, sketched shapes and lines. Supported types: `Place` (pin), `Rectangle`, `Polygon` (arbitrary outline), `Circle`, `Text`, `Note` (callout), `Link` (clickable preview that opens a URL), `Line` (polyline). Each annotation is an independent item. Coordinates are `[latitude, longitude]`. To create: omit `id` and supply `type` + the type's required fields. To update: supply `id` AND `type` (always required) plus any fields you want to change; fields you omit are preserved. The response returns a `results` list in the same order as your input, each entry with an `id` and `status` (`"created"` or `"updated"`), so you can zip it against what you sent. Annotations are markup, not data — for circling, labelling, sketching and pointing things out. If the geometry comes from a query or a file, traces a real boundary, or runs to more than a handful of shapes, create a layer instead.
- Idempotent
Inputs
annotationsarrayrequired- Annotations to create or update.
map_idstringrequired- The ID of the map.
No tools match.