MDM MCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| MDM_DATA_DIR | No | Override the data directory. By default, local (non-Docker) runs store data in ./data; the Docker setup uses the mdm-data volume mounted at /data. | ./data |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| create_datasetA | Create a new dataset (a table) with user-defined typed columns. Use this whenever the user wants to start tracking something new - candidates, inventory, payments, a health log. Columns behave like spreadsheet headers with Google-Forms-style validation. Always propose the column list to the user and get their confirmation before calling this tool. Args: name: Unique dataset name, e.g. "Candidates" (case-insensitive uniqueness). columns: One or more column definitions. description: Optional short description of what this dataset tracks. Column types: string, text, boolean, integer, float, phone, date, enum. Column attributes: required, default, min_value/max_value (numeric columns), pattern (string/text columns), options (enum columns, at least one value). Returns: {"ok": true, "dataset": "", "columns": [{"name", "type"}]} on success, {"ok": false, "error": ""} on failure. Example: create_dataset(name="Candidates", description="Applicants for the Java JD", columns=[ {"name": "name", "type": "string", "required": true}, {"name": "phone", "type": "phone"}, {"name": "experience", "type": "float", "min_value": 0}, {"name": "stage", "type": "enum", "options": ["Applied", "Screened", "Rejected"]}, {"name": "applied_on", "type": "date"} ]) |
| list_datasetsA | List all datasets with row counts and a name:type column summary. Use this to discover what the user is already tracking before creating or querying a dataset. Results are paginated: use next_offset from the response to fetch the next page instead of raising the limit. Args: limit: Page size (1-100, default 20). offset: Number of datasets to skip (default 0). Returns: {"ok": true, "datasets": [{"name", "description", "row_count", "columns"}], "total": , "count": , "next_offset": }. Example: list_datasets(limit=50) |
| describe_datasetA | Show a dataset's full column definitions (types and constraints) and row count. Use this before adding or searching rows so you know the exact column names, types, and constraints. Optionally include a few sample rows (capped at 5) to see what the data looks like. Args: name: Exact dataset name, e.g. "Candidates". sample_rows: Optional number of first rows to include, 0-5 (default 0). Returns: {"ok": true, "dataset", "description", "row_count", "columns": [{"name", "type", "required", "default?", "options?", ...}], "samples": [{"id", ...}]} on success, {"ok": false, "error": ""} when the dataset does not exist. Example: describe_dataset(name="Candidates", sample_rows=3) |
| add_columnA | Add a new typed column to an existing dataset. Existing rows are backfilled with the column's default value, or null when no default is set. Use this when the user wants to start tracking something new in an existing dataset ("also note each candidate's expected salary"). Args: dataset: Exact dataset name, e.g. "Candidates". column: The new column definition (same shape as in create_dataset). Returns: {"ok": true, "dataset", "column", "type", "backfilled_rows": } on success, {"ok": false, "error": ""} when the column already exists or the definition is invalid (e.g. enum without options). Example: add_column(dataset="Candidates", column={"name": "expected_salary", "type": "float", "min_value": 0}) |
| update_columnA | Change a column's name, type, or constraints on an existing dataset. Only the fields you explicitly provide are changed. After the change every stored row is revalidated: rows that no longer satisfy the new definition are reported with their row ids and errors, and their values are preserved so the user can decide how to fix them. Renaming a column moves the values under the new name in all rows. Args: dataset: Exact dataset name, e.g. "Candidates". column: Current column name to change. changes: Fields to change, e.g. {"max_value": 10} or {"name": "full_name"}. Returns: {"ok": true, "dataset", "column", "renamed_from": , "rows_checked": , "invalid_rows": {"": [""]}} on success, {"ok": false, "error": ""} for unknown columns or invalid changes. Example: update_column(dataset="Candidates", column="experience", changes={"max_value": 20}) |
| remove_columnA | Remove a column from a dataset after explicit confirmation. Destructive: without confirm=true the tool only returns a preview of what would be dropped. Call it with confirm=false first, tell the user what will be lost, and only re-invoke with confirm=true after they agree. Args: dataset: Exact dataset name, e.g. "Candidates". column: Column name to remove. confirm: Must be true to actually remove (default false = preview only). Returns: {"ok": true, "dataset", "removed", "rows_updated"} after confirmation, {"ok": true, "requires_confirmation": true, "preview": {...}} without, {"ok": false, "error": ""} for unknown columns. Example: remove_column(dataset="Candidates", column="temporary_note", confirm=false) |
| delete_datasetA | Delete an entire dataset and all of its rows after explicit confirmation. Destructive: without confirm=true the tool only returns a preview (row count, column count). Call it with confirm=false first, tell the user what will be lost, and only re-invoke with confirm=true after they agree. Args: name: Exact dataset name to delete. confirm: Must be true to actually delete (default false = preview only). Returns: {"ok": true, "deleted": "", "rows_removed": } after confirmation, {"ok": true, "requires_confirmation": true, "preview": {...}} without. Example: delete_dataset(name="Old JD", confirm=false) |
| add_rowsA | Add one or more rows to a dataset with per-row validation. Use this to capture records the user dictates in conversation. Each row is an object mapping column names to values; every row is validated against the dataset schema and valid rows are saved while invalid rows are reported back with plain-language reasons. At most 100 rows per call - split larger batches. Check describe_dataset first so column names, types, and constraints match exactly. Args: dataset: Exact dataset name, e.g. "Candidates". rows: List of row objects, e.g. [{"name": "Asha", "phone": "9876543210"}]. Returns: {"ok": true, "dataset", "added": , "rejected": , "results": [{"row": , "status": "added", "row_id": ""} | {"row": , "status": "rejected", "errors": ["..."]}]} Relay every rejected row's errors to the user in plain language. Example: add_rows(dataset="Candidates", rows=[ {"name": "Asha Verma", "phone": "9876543210", "stage": "Applied", "applied_on": "2026-08-30"} ]) |
| get_rowA | Fetch a single row by id, optionally limited to specific columns. Use this when the user asks about one record ("show me row 12", "what is Asha's phone number?"). Ask for only the columns you need to keep the response small. Args: dataset: Exact dataset name, e.g. "Candidates". row_id: The row id, e.g. "12". columns: Optional list of column names to project, e.g. ["name", "stage"]. Returns: {"ok": true, "dataset", "row": {"id", ...requested columns}} on success, {"ok": false, "error": ""} for unknown ids or columns. Example: get_row(dataset="Candidates", row_id="12", columns=["name", "phone"]) |
| update_rowsA | Update rows by explicit ids, or in bulk for every row matching a filter. Only the provided columns change; everything else stays as-is. New values are validated together with the rest of each row, so an invalid change leaves that row untouched and is reported with plain-language errors. Bulk mode (conditions): defaults to a dry-run preview. Review the preview with the user, then re-invoke with dry_run=false to apply. Never set dry_run=false on the first call when a filter may match many rows. Args: dataset: Exact dataset name, e.g. "Candidates". values: Column values to set, e.g. {"stage": "Rejected"}. row_ids: Explicit row ids to update, e.g. ["3", "7"]. Mutually exclusive with conditions. conditions: Filter selecting rows to update, e.g. [{"column": "stage", "op": "eq", "value": "Screened"}]. dry_run: Bulk mode only - true (default) previews; false applies the update. Returns: Id mode: {"ok": true, "dataset", "updated", "rejected", "not_found", "results": [...]}. Bulk mode dry-run: {"ok": true, "requires_confirmation": true, "preview": {...}}. Bulk mode applied: {"ok": true, "dataset", "matched", "updated", "rejected", "results": [...]}. Example: update_rows(dataset="Candidates", values={"stage": "Rejected"}, conditions=[{"column": "score", "op": "lt", "value": 3}], dry_run=true) |
| delete_rowsA | Delete rows by explicit ids, or in bulk for every row matching a filter. Destructive: without confirm=true the tool only returns a preview listing the rows that would be deleted. Call it with confirm=false first, tell the user what will be lost, and only re-invoke with confirm=true after they agree. Args: dataset: Exact dataset name, e.g. "Candidates". row_ids: Explicit row ids to delete, e.g. ["4"]. Mutually exclusive with conditions. conditions: Filter selecting rows to delete, e.g. [{"column": "experience", "op": "lt", "value": 2}]. confirm: Must be true to actually delete (default false = preview only). Returns: {"ok": true, "dataset", "deleted": , "row_ids": [...], "not_found": [...]} after confirmation, {"ok": true, "requires_confirmation": true, "preview": {...}} without. Example: delete_rows(dataset="Candidates", conditions=[{"column": "stage", "op": "eq", "value": "Rejected"}]) |
| validate_rowsA | Validate rows against a dataset's schema without saving anything. Use this to pre-check data before committing it - e.g. when the user pastes a list of records and wants to know what would be rejected and why. Valid rows come back normalized (types coerced, defaults filled) so you can show the user exactly what would be stored. Args: dataset: Exact dataset name, e.g. "Candidates". rows: List of row objects to check (max 100 per call). Returns: {"ok": true, "dataset", "total": , "valid": , "invalid": , "results": [{"row": , "status": "valid", "normalized": {...}} | {"row": , "status": "invalid", "errors": ["..."]}]}. Example: validate_rows(dataset="Candidates", rows=[{"name": "Asha", "phone": "9876543210"}]) |
| search_rowsA | Search rows with exact filters, or typo-tolerant fuzzy matching, with sorting and pagination. Two search modes:
Results are always paginated: page with next_offset instead of raising the limit, and request only the columns you need via columns. Args: dataset: Exact dataset name, e.g. "Candidates". conditions: Exact-mode filters, e.g. [{"column": "stage", "op": "eq", "value": "Applied"}]. fuzzy: Set true for typo-tolerant matching (requires query). query: Text to fuzzy-match, e.g. "Rahual". fuzzy_columns: Optional text columns to fuzzy-match against (default: all text columns). fuzzy_threshold: Minimum similarity score 1-100 (default 80). sort_by: Column to sort by (exact mode). sort_order: "asc" (default) or "desc". limit: Page size 1-100 (default 20). offset: Rows to skip for pagination (default 0). columns: Column projection, e.g. ["name", "stage"]; id is always included. Returns: {"ok": true, "dataset", "rows": [{"id", ...columns, "_score"?}], "total": , "count": , "next_offset": }. Example: search_rows(dataset="Candidates", conditions=[ {"column": "applied_on", "op": "between", "value": ["2026-08-01", "2026-08-31"]}, {"column": "stage", "op": "ne", "value": "Rejected"} ], sort_by="applied_on", sort_order="desc", columns=["name", "stage"]) search_rows(dataset="Candidates", fuzzy=true, query="Rahual", fuzzy_columns=["name"]) |
| summarize_datasetA | Summarize a dataset with aggregates instead of raw rows. Use this when the user asks for totals or breakdowns ("how many candidates per stage?", "total inventory value?") - it returns row count, count/min/max/ avg/sum for every numeric column, and value breakdowns for every enum column, without ever dumping rows into the conversation. Args: dataset: Exact dataset name, e.g. "Inventory". Returns: {"ok": true, "dataset", "row_count": , "numeric": {"": {"count", "min", "max", "avg", "sum"} or {"count": 0}}, "enums": {"": {"": }}}. Example: summarize_dataset(dataset="Inventory") |
| import_rowsA | Import rows into a dataset from a CSV or JSON file, in two safe steps. Step 1 (confirm=false, default): returns a mapping preview - how each file column maps to a dataset column, unmatched file columns, missing required dataset columns, and a small sample. Share the mapping with the user and let them confirm or adjust the file. Step 2 (confirm=true): imports. Every row is validated against the dataset schema; valid rows are added and invalid rows are reported with plain-language reasons. CSV values are coerced automatically ("5" becomes the number 5, "true" becomes a boolean). Args: dataset: Exact dataset name, e.g. "Candidates". file_path: Path to the .csv or .json file on this machine. format: "auto" (default, infers from extension), or force "csv"/"json". confirm: Must be true to actually import (default false = preview only). create_if_missing: When the dataset does not exist, create it first with one string column per file header, then import (default false). Returns: Preview: {"ok": true, "requires_confirmation": true, "preview": {...}}. Commit: {"ok": true, "dataset", "added": , "rejected": , "rejected_rows": [{"row": , "errors": ["..."]}]}. Example: import_rows(dataset="Candidates", file_path="~/Downloads/applicants.csv") |
| export_rowsA | Export rows (optionally filtered and projected) to a CSV or JSON file. Use this when the user wants their data back in a spreadsheet-friendly form. Filters use the same conditions syntax as search_rows. The id column is always included. Refuses to overwrite an existing file unless overwrite=true. Args: dataset: Exact dataset name, e.g. "Candidates". file_path: Destination path for the .csv or .json file. format: "auto" (default, infers from extension), or force "csv"/"json". conditions: Optional filter, e.g. [{"column": "stage", "op": "eq", "value": "Applied"}]. columns: Optional column projection, e.g. ["name", "phone"]. overwrite: Allow replacing an existing file (default false). Returns: {"ok": true, "dataset", "file": "", "format", "rows_exported": }. Example: export_rows(dataset="Candidates", file_path="~/Documents/applied_august.csv", conditions=[{"column": "applied_on", "op": "between", "value": ["2026-08-01", "2026-08-31"]}]) |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kanishk393/mdm-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server