Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 64 additions & 6 deletions modelcontextprotocol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ The Atlan [Model Context Protocol](https://modelcontextprotocol.io/introduction)

## Available Tools

| Tool | Description |
| ------------------------- | ----------------------------------------------------------------- |
| `search_assets` | Search for assets based on conditions |
| `get_assets_by_dsl` | Retrieve assets using a DSL query |
| `traverse_lineage` | Retrieve lineage for an asset |
| `update_assets` | Update asset attributes (user description and certificate status) |
| Tool | Description |
| ------------------------- | --------------------------------------------------------------------------- |
| `search_assets` | Search for assets based on conditions |
| `get_assets_by_dsl` | Retrieve assets using a DSL query |
| `traverse_lineage` | Retrieve lineage for an asset |
| `update_assets` | Update asset attributes (user description and certificate status) |
| `create_unstructured_asset` | Create a File asset (PDF, Excel, etc.) and optionally set custom metadata |
| `read_custom_metadata` | Retrieve one or more custom metadata sets for any asset |

## Running the MCP server
- There are 2 different ways to run the Atlan MCP server locally
Expand Down Expand Up @@ -209,6 +211,62 @@ Want to develop locally? Check out our [Local Build](./docs/LOCAL_BUILD.md) Guid
- You can also directly create a [GitHub issue](https://github.com/atlanhq/agent-toolkit/issues) and we will answer it for you

## Troubleshooting
## Working with unstructured assets

The new `create_unstructured_asset` tool lets your MCP client register documents like PDFs or Excel workbooks as Atlan `File` assets.

Minimum inputs:

```json
{
"name": "Quarterly Financials",
"connection_qualified_name": "default/s3",
"file_type": "excel"
}
```

Optional fields:

- `file_path`: Provide a local path or object storage URI so teammates can locate the document.
- `description`: Human friendly summary.
- `custom_metadata`: Map of custom metadata set names to attribute/value pairs. Example:

```json
{
"custom_metadata": {
"Document Details": {
"Owner": "[email protected]",
"Quarter": "Q1 FY26"
}
}
}
```

The response contains the Atlan GUID and qualified name so you can link follow-up actions (add terms, tag, etc.).

## Reading custom metadata

Use the `read_custom_metadata` tool to pull template values for any asset:

```json
{
"guid": "12345678-90ab-cdef-1234-567890abcdef",
"custom_metadata_sets": [
"Document Details",
"Data Sensitivity"
],
"include_unset": true
}
```

Parameters:

- Supply either `guid` **or** `qualified_name`.
- `asset_type` defaults to `Asset`, but you can pass a concrete type like `"File"` or `"Table"` for stricter validation.
- When `custom_metadata_sets` is omitted, all custom metadata on the asset is returned.
- `include_unset` fills in attributes defined on the template but currently blank so you can see everything that is expected.

These additions make it easy for MCP clients to create unstructured documents and inspect their governance metadata without leaving your IDE or chat workflow.
1. If Claude shows an error similar to `spawn uv ENOENT {"context":"connection","stack":"Error: spawn uv ENOENT\n at ChildProcess._handle.onexit`, it is most likely [this](https://github.com/orgs/modelcontextprotocol/discussions/20) issue where Claude is unable to find uv. To fix it:
- Make sure uv is installed and available in your PATH
- Run `which uv` to verify the installation path
Expand Down
86 changes: 86 additions & 0 deletions modelcontextprotocol/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
get_assets_by_dsl,
traverse_lineage,
update_assets,
create_unstructured_asset,
read_custom_metadata,
UpdatableAttribute,
CertificateStatus,
UpdatableAsset,
Expand Down Expand Up @@ -390,6 +392,90 @@ def update_assets_tool(
return {"updated_count": 0, "errors": [str(e)]}


@mcp.tool()
def create_unstructured_asset_tool(
name,
connection_qualified_name,
file_type,
file_path=None,
description=None,
custom_metadata=None,
):
"""
Create a File asset for an unstructured document such as a PDF or Excel workbook.

Args:
name (str): Display name for the file asset (for example, "Customer Playbook.pdf").
connection_qualified_name (str): Qualified name of the connection that should own the asset.
file_type (str): Supported values include "pdf", "excel", "xls", "xlsx", "xlsm".
file_path (str, optional): Optional file system path or object storage URI for reference.
description (str, optional): Optional human-readable description.
custom_metadata (dict, optional): Mapping of custom metadata set names to attribute/value pairs.

Returns:
Dict[str, Any]: Information about the created asset including the assigned GUID.

Example:
create_unstructured_asset_tool(
name="Quarterly Financials",
connection_qualified_name="default/s3",
file_type="excel",
file_path="s3://corp-data/finance/q1.xlsx",
custom_metadata={
"Document Details": {"Owner": "[email protected]", "Quarter": "Q1"}
}
)
"""

return create_unstructured_asset(
name=name,
connection_qualified_name=connection_qualified_name,
file_type=file_type,
file_path=file_path,
description=description,
custom_metadata=custom_metadata,
)


@mcp.tool()
def read_custom_metadata_tool(
guid=None,
qualified_name=None,
asset_type="Asset",
custom_metadata_sets=None,
include_unset=False,
):
"""
Retrieve custom metadata values for an asset.

Args:
guid (str, optional): GUID of the asset.
qualified_name (str, optional): Qualified name of the asset (required if GUID is not provided).
asset_type (str): Atlan asset type name (e.g., "File", "Table"). Defaults to "Asset".
custom_metadata_sets (Union[str, List[str]], optional): Specific custom metadata set names to read.
When omitted, all custom metadata sets on the asset are returned.
include_unset (bool): Include attributes that exist on the template but do not yet have values.

Returns:
Dict[str, Any]: Asset identifiers and the requested custom metadata.

Example:
read_custom_metadata_tool(
guid="12345678-90ab-cdef-1234-567890abcdef",
custom_metadata_sets=["Document Details", "Data Sensitivity"],
include_unset=True,
)
"""

return read_custom_metadata(
guid=guid,
qualified_name=qualified_name,
asset_type=asset_type,
custom_metadata_sets=custom_metadata_sets,
include_unset=include_unset,
)


def main():
mcp.run()

Expand Down
8 changes: 7 additions & 1 deletion modelcontextprotocol/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
from .search import search_assets
from .dsl import get_assets_by_dsl
from .lineage import traverse_lineage
from .assets import update_assets
from .assets import (
create_unstructured_asset,
read_custom_metadata,
update_assets,
)
from .models import CertificateStatus, UpdatableAttribute, UpdatableAsset

__all__ = [
"search_assets",
"get_assets_by_dsl",
"traverse_lineage",
"update_assets",
"create_unstructured_asset",
"read_custom_metadata",
"CertificateStatus",
"UpdatableAttribute",
"UpdatableAsset",
Expand Down
Loading