Skip to main content
Glama
fundownloader-link-mcp

fundownloader-link-mcp

by boddapQ
README.md
# fundownloader-link-mcp

A local, **read-only** [Model Context Protocol](https://modelcontextprotocol.io) server that validates and canonicalizes Spotify track/playlist, Instagram post/reel, and Twitter/X status URLs.

It parses links. It does not fetch metadata, check whether content exists, or download media.

[![test](https://github.com/boddapQ/fundownloader-link-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/boddapQ/fundownloader-link-mcp/actions/workflows/ci.yml)

## Why this exists

Agents paste media links constantly, and the same track arrives in a dozen forms:

```
https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC
https://open.spotify.com/intl-de/track/4uLU6hMCjMI75M1A2tKUQC?si=abc123
https://open.spotify.com/embed/track/4uLU6hMCjMI75M1A2tKUQC
spotify:track:4uLU6hMCjMI75M1A2tKUQC
```

Without normalization, an agent stores the same track five times, or retypes a URL and gets it wrong. This server turns any supported form into one canonical URL, deterministically, before the model reasons about it.

## Requirements

- Node.js **22.12+**
- Any MCP client (Claude Desktop, Cursor, VS Code, Cline, Windsurf, etc.)

## Install

From source:

```bash
git clone https://github.com/boddapQ/fundownloader-link-mcp.git
cd fundownloader-link-mcp
npm install --ignore-scripts
```

Then add it to your MCP client configuration:

```json
{
  "mcpServers": {
    "fundownloader-links": {
      "command": "node",
      "args": ["/absolute/path/to/fundownloader-link-mcp/server.mjs"]
    }
  }
}
```

Once published to npm (tracked in [#1](https://github.com/boddapQ/fundownloader-link-mcp/issues/1)):

```json
{
  "mcpServers": {
    "fundownloader-links": {
      "command": "npx",
      "args": ["-y", "fundownloader-link-mcp"]
    }
  }
}
```

## Tool

### `normalize_media_link`

| Argument | Type | Required | Default | Notes |
|---|---|---|---|---|
| `url` | string | yes | — | Max 512 characters |
| `platform` | `spotify` \| `instagram` \| `twitter` | no | `spotify` | — |

Returns JSON as text:

```json
{
  "type": "track",
  "id": "4uLU6hMCjMI75M1A2tKUQC",
  "url": "https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC",
  "platform": "spotify",
  "website": "https://fundownloader.online",
  "availabilityChecked": false
}
```

Invalid input returns `isError: true` with a `{ "error": "..." }` payload.

## Supported URL formats

| Platform | Accepted | Canonical output |
|---|---|---|
| Spotify | `open.spotify.com/track/{id}`, `/playlist/{id}`, `/intl-xx/...`, `/embed/...`, `spotify:track:{id}` | `https://open.spotify.com/{type}/{id}` |
| Instagram | `instagram.com/p/{id}`, `/reel/{id}`, `/reels/{id}`, `/tv/{id}`, `/{user}/reel/{id}` | `https://www.instagram.com/{type}/{id}/` |
| Twitter/X | `twitter.com/{user}/status/{id}`, `x.com/...`, `mobile.*`, `i/web/status/{id}`, optional `/video/1` or `/photo/1` | `https://twitter.com/{user}/status/{id}` |

### Deliberately rejected

- **`spotify.link` short links** — resolving them requires a network call, which this server does not make. You get an explicit error instead of a wrong canonical URL.
- **Albums and artist pages** — not track- or playlist-level.
- **Private/authenticated URLs** — credentials in the URL, non-default ports, and non-HTTPS schemes are rejected.
- **Unsupported platforms** — `tiktok`, `youtube`, etc. return an error rather than a guess.

## HTTP API

The same logic powers a free, keyless, CORS-enabled endpoint:

```bash
curl --get 'https://fundownloader.online/api/v1/link' \
  --data-urlencode 'url=https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC'
```

Docs: <https://fundownloader.online/developers>

## Use as a library

The parser has no MCP dependency and works standalone:

```js
import { downloadReference } from 'fundownloader-link-mcp/validation';

downloadReference('https://open.spotify.com/intl-de/track/4uLU6hMCjMI75M1A2tKUQC?si=abc');
// { type: 'track', id: '4uLU6...', url: 'https://open.spotify.com/track/4uLU6...' }
```

## Development

```bash
npm install --ignore-scripts
npm test
```

Tests use the built-in `node:test` runner and cover locale prefixes, URI form, short links, tracking parameters, Instagram path variants, and X/Twitter host normalization.

## Privacy and security

- No network requests after the tool call — parsing is local and synchronous.
- No API key, account, cookies, or telemetry.
- No media is fetched, stored, or redistributed.
- Read-only: the tool cannot write files, execute commands, or call other services.
- Canonicalization does not grant any rights to the linked content.

## License

MIT. See [LICENSE](LICENSE).

Not affiliated with Spotify, Instagram, X, or YouTube.

TDQS

A4/5.0

Scored across 1 tool

Disambiguation5/5

Only one tool exists, so there is nothing to confuse it with. Its purpose (validate and canonicalize media URLs) is stated precisely, including explicit boundaries about what it does not do.

Naming Consistency5/5

The single name normalize_media_link follows a clear verb_noun snake_case convention. No inconsistency is possible with one tool, and the name matches its function.

Tool Count2/5

A single tool is too thin a surface for a server named around downloading media. There is only one operation, so any multi-step workflow requires other servers.

Completeness2/5

The domain implied by the server name (downloading media) has only link normalization, with no download, metadata fetch, or availability check, which the description explicitly rules out. Significant gaps remain that will send agents elsewhere.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues