Skip to main content
Glama
README.md
# sds-mcp-server

An [MCP](https://modelcontextprotocol.io) server that lets Claude (or any MCP client) search for
Safety Data Sheets (SDS) by chemical or product name, using
[chemicalsafety.com](https://chemicalsafety.com)'s SDS search.

## Tools

### `search_sds_by_name`

Search for SDS records by chemical or product name.

| Argument | Type | Default | Description |
|---|---|---|---|
| `chemical_name` | string | — | Chemical or product name to search for, e.g. `"Acetone"` |
| `is_contains` | bool | `false` | Match names containing the text instead of requiring an exact match (useful for misspelled or partial names) |
| `limit` | int | `25` | Max results to return (common chemicals can return 100+ matches) |

Returns a list of records with `id`, `product_name`, `manufacturer`, `cas_number`,
`msds_number`, `revision_date`, `has_sds`, and `sds_url` (a direct link to the SDS
document, usually a PDF).

Synonym matching (`IncludeSynonyms`) is intentionally not exposed — it's the source
endpoint's slowest query mode and was the main cause of Claude Science's local-connector
calls stalling past its response-latency comfort zone, with no real benefit for named
chemicals. `is_contains` covers the useful "fuzzy match" case within normal response
times.

## Setup

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
```

## Using with Claude Code

Copy `.mcp.json.example` to `.mcp.json` and update the paths to point at this repo's
`.venv/bin/python3` and `server.py`:

```bash
cp .mcp.json.example .mcp.json
```

Then edit the paths inside, restart Claude Code in this directory, and approve the
project MCP server when prompted.

## Using with Claude Science

Claude Science connects to local MCP servers via a custom connector, which runs under a
macOS sandbox (`sandbox-exec`) with restricted process execution, filesystem access, and
network access. Getting this working needs both a sandbox exception (below) and the
connector itself.

### 1. Allow this repo through the sandbox

Claude Science reads optional settings from `~/.claude-science/config.toml` (create the
file if it doesn't exist — it's not created by default). Add this repo's path to
`[sandbox] user_read_paths` so the sandbox permits reading `server.py` and its
dependencies, and add `chemicalsafety.com` to `[sandbox.network] allowed_domains` so the
sandboxed process can actually reach the search endpoint:

```toml
[sandbox]
user_read_paths = [
    "/Users/you/sds-mcp-server",
]

[sandbox.network]
allowed_domains = [
    "chemicalsafety.com",
]
```

This file is only read at startup, so **restart Claude Science** after editing it. See
the [configuration file reference](https://claude.com/docs/claude-science/configuration-file-reference)
for the full set of `config.toml` keys.

### 2. Add the connector

1. Run the setup steps above so `.venv/` exists with dependencies installed in this repo.
2. In Claude Science, go to **Settings > Connectors > Add connector > Local command**.
3. Fill in:
   - **Name**: `sds-lookup`
   - **Command** (single field, the whole command line): the absolute path to this
     repo's venv Python interpreter, **including its version number**, followed by the
     absolute path to `server.py`, e.g.

     ```
     /Users/you/sds-mcp-server/.venv/bin/python3.14 /Users/you/sds-mcp-server/server.py
     ```

     Run `ls .venv/bin | grep python3\\.` to find your exact interpreter name (e.g.
     `python3.14`). Using the unversioned `python` or `python3` symlink instead fails
     with `sandbox-exec: execvp() of '.../.venv/bin/python' failed: Operation not
     permitted` — the sandbox's exec check doesn't resolve the extra symlink hop those
     names add, but the version-numbered binary resolves directly and is covered by the
     `user_read_paths` grant from step 1.
4. Click **Add**, then approve the `search_sds_by_name` tool when Claude first tries to
   use it (or set it to **Always allow** on the connector's page under **Tools**).

No `PYTHONPATH` or system-Python juggling needed — once the repo is in
`user_read_paths`, the sandbox can execute the venv's own interpreter directly, and it
already knows where its own `site-packages` are.

## Notes

The chemicalsafety.com search endpoint is undocumented and returns 403 unless the
request includes browser-like `User-Agent`, `Origin`, and `Referer` headers — this is
already handled in `sds_search.py`.

## Roadmap

Not yet implemented:
- Search by CAS number
- Filter by manufacturer
- Fetch and extract full SDS document content (most links are PDFs)

TDQS

A4.4/5.0

Scored across 1 tool

Disambiguation5/5

Only one tool exists, so there is no possibility of ambiguity or overlap. The tool's purpose is clearly defined as searching for SDS by chemical or product name.

Naming Consistency5/5

The single tool name 'search_sds_by_name' is consistent with a clear verb_noun pattern and clearly indicates its function. There are no other tools to conflict with.

Tool Count3/5

With only one tool, the server feels thin for a domain that could reasonably include fetching by ID or listing all SDS. However, for a focused search-only server, a single tool may be acceptable, so this is borderline.

Completeness3/5

The tool provides comprehensive search options (exact, partial, synonyms, limit) and returns useful metadata including a direct URL to the SDS. Gaps include lack of direct retrieval by ID or pagination beyond a simple limit, but the core search use case is well covered.

Maintenance

ActivitySlowing
ResponsivenessNo issues