Skip to main content
Glama

legacy-mcps

A Model Context Protocol server that gives AI agents tools for managing files and data on two legacy platforms:

  • Internet Archive — search items, read item metadata, and upload files to items over the archive.org S3 gateway.

  • SourceForge — upload release files to a project's File Release System (FRS) tree and list what is published, over SSH/SFTP.

The server is credential-aware: read-only tools that need no authentication are always available, and write tools are registered only when the matching credentials are present in the environment.

Install

pip install -e .          # runtime dependencies only
pip install -e '.[dev]'   # plus pytest

Requires Python 3.10 or newer.

Related MCP server: lms-ssh-client-mcp

Run

legacy-mcps                       # stdio transport (default)
legacy-mcps --transport sse       # also: streamable-http
legacy-mcps --describe            # print which tools are enabled, then exit

--describe is the quickest way to check configuration. It prints the registration decision as JSON without opening a transport:

{
  "server": "legacy-mcps",
  "version": "0.1.0",
  "internet_archive": {
    "read_tools": ["ia_search_items", "ia_get_item_metadata"],
    "write_tools": ["ia_upload_file"],
    "enabled": true,
    "write_enabled": true,
    "note": null
  },
  "sourceforge": {
    "tools": ["sf_upload_release_file", "sf_list_release_files"],
    "enabled": true,
    "note": null
  }
}

Client configuration

An MCP client launches the server as a subprocess and talks to it over stdio. For example, in a mcpServers block:

{
  "mcpServers": {
    "legacy-mcps": {
      "command": "legacy-mcps",
      "env": {
        "IA_ACCESS_KEY": "...",
        "IA_SECRET_KEY": "...",
        "SF_USERNAME": "your-sourceforge-username",
        "SF_SSH_KEY_PATH": "/home/you/.ssh/sourceforge_rsa",
        "SF_PROJECT_NAME": "your-project"
      }
    }
  }
}

Configuration

Every credential is read from the environment at tool-registration time and at call time. Nothing is stored on disk.

Variable

Used by

Meaning

IA_ACCESS_KEY

Internet Archive

S3 access key from https://archive.org/account/s3.php

IA_SECRET_KEY

Internet Archive

S3 secret key from the same page

SF_USERNAME

SourceForge

Your SourceForge account name

SF_SSH_KEY_PATH

SourceForge

Path to the private key whose public half is registered with SourceForge

SF_PROJECT_NAME

SourceForge

The unix name of the project, e.g. my-project

SF_HOST

SourceForge

SSH host, defaults to frs.sourceforge.net

Which tools appear depends on what is set:

Credentials present

Tools registered

none

ia_search_items, ia_get_item_metadata

IA_ACCESS_KEY + IA_SECRET_KEY

the above, plus ia_upload_file

SF_USERNAME + SF_SSH_KEY_PATH + SF_PROJECT_NAME

sf_upload_release_file, sf_list_release_files

Tools

Internet Archive

Tool

Credentials

Description

ia_search_items

none

Search archive.org with a Lucene-style query, e.g. collection:nasa AND mediatype:image.

ia_get_item_metadata

none

Fetch an item's metadata and file listing by identifier.

ia_upload_file

IA_ACCESS_KEY, IA_SECRET_KEY

Upload a local file to an item, creating the item if it does not exist.

ia_upload_file takes identifier, file_path, an optional remote_name, optional metadata (which becomes x-archive-meta-* headers — title, mediatype and collection are the fields the site uses to build the item's details page), queue_derive and keep_old_version.

Uploads go to the custom S3 endpoint https://s3.us.archive.org. The x-archive-* headers are injected into the request before SigV4 signing, so they are covered by the signature the gateway verifies.

SourceForge

Tool

Credentials

Description

sf_upload_release_file

SF_USERNAME, SF_SSH_KEY_PATH, SF_PROJECT_NAME

Upload a local file into a release directory such as releases/1.2.0, creating the directory if needed.

sf_list_release_files

same

List files and directories in a release directory. An empty remote_dir lists the project release root.

Uploads land in /home/frs/project/<project>/<remote_dir>/ on frs.sourceforge.net. Each file is written to a temporary name and then renamed into place, so a partial transfer is never visible and the mirror sees a single completed write. overwrite=False (the default) refuses to replace an existing file; with overwrite=True the swap uses the posix-rename@openssh.com extension so the published file is replaced atomically.

Unknown SSH host keys are rejected by default, so a network attacker cannot impersonate SourceForge. On first use, add the host key to your known_hosts (for example with ssh -o StrictHostKeyChecking=accept-new <user>@frs.sourceforge.net) or construct the client with allow_unknown_host_key=True.

Response shape

Tools never raise and never tear down the MCP session. Every call returns a JSON object:

{ "ok": true, "remote_path": "/home/frs/project/my-project/releases/1.2.0/app.tar.gz", "size_bytes": 4096, "download_url": "https://sourceforge.net/projects/my-project/files/releases/1.2.0/app.tar.gz/download" }
{ "ok": false, "error": "missing_credentials", "message": "Missing required environment variable(s): SF_USERNAME, SF_PROJECT_NAME.", "retryable": false }

error is one of a small stable set: missing_credentials, invalid_input, file_not_found, remote_rejected, not_found, rate_limited, timeout, connection_error, ambiguous_write, unexpected_error. retryable is true for rate_limited, timeout and connection_error, so an agent can retry without guessing.

ambiguous_write is the exception worth knowing about. A timeout or a dropped connection during an upload does not reveal whether the bytes arrived, so the file may already be published. The result carries retryable: false and asks the caller to reconcile the remote state (for example with sf_list_release_files or ia_get_item_metadata) before retrying.

Project layout

src/legacy_mcps/
├── errors.py                  # error codes, error payloads, credential helpers
├── server.py                  # unified entrypoint; credential-aware registration
├── internet_archive/
│   ├── api.py                 # public metadata + search HTTP endpoints
│   ├── client.py              # S3 client: SigV4 signing, x-archive-* headers, upload
│   └── tools.py               # MCP tool wrappers
└── sourceforge/
    ├── client.py              # SFTP client: upload, list, path validation
    └── tools.py               # MCP tool wrappers

Tests

pip install -e '.[dev]'
pytest

The suite is deliberately built on real protocol code rather than mocks:

  • Internet Archive tests drive a real boto3 client against a loopback HTTP server standing in for the S3 gateway, then re-derive the SigV4 signature from the recorded request. That checks the property the real gateway enforces — that the injected x-archive-meta-* headers are part of the signed header set.

  • SourceForge tests run against an in-process SSH/SFTP server (paramiko) rooted in a temporary directory, so the stage-then-rename write path, directory creation, overwrite handling and error mapping are all exercised end to end.

  • Server tests drive the FastMCP server through the SDK's in-memory transport, including a full list_tools / call_tool round trip.

License

MIT — see LICENSE.

Available Tools

2 tools
ia_get_item_metadataB

Fetch an archive.org item's metadata and file listing by identifier. No credentials required.

NameRequiredDescriptionDefault
file_limitNo
identifierYes
include_filesNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It usefully discloses that no credentials are required and implies a read-only fetch, but says nothing about behavior on an unknown identifier, rate limiting, or the effect of the file_limit cap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short, front-loaded sentences with no filler; the qualification that no credentials are needed earns its place by preempting an authentication question.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained. However, for a tool with three parameters and a default truncation limit on file listing, the description leaves the caller without guidance on include_files or the 100-file cap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across three parameters, and the description only explains identifier implicitly through 'by identifier'. The include_files and file_limit parameters—including the default cap of 100 files—are never addressed, so the description does not compensate for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Fetch) and resource (archive.org item metadata and file listing) with the key input (identifier). It implicitly contrasts with the sibling ia_search_items, but never names it, so the differentiation is left to inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when this tool applies (you already have an identifier) versus a search tool, but it never states usage conditions or exclusions explicitly, and does not mention what to do when you only have a query rather than an identifier.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ia_search_itemsB

Search archive.org items. Example query: 'collection:nasa AND mediatype:image'. No credentials required.

NameRequiredDescriptionDefault
pageNo
rowsNo
sortNo
queryYes
fieldsNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden; it does disclose that no credentials are required, which is genuinely useful. It says nothing about pagination defaults, result caps, rate limits, or sort behavior, which an agent must guess from the bare schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the purpose, then a concrete query example, then the auth note. Nothing is padded or redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be explained, but with 0% schema description coverage the description should compensate for the four undocumented parameters and does not. For a 5-parameter search tool, this is notably incomplete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 5 parameters, and the description only clarifies the required query via a Solr-style example ('collection:nasa AND mediatype:image'). The page, rows, sort, and fields parameters receive no explanation anywhere.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Search archive.org items'), which is clearly distinct from the sibling ia_get_item_metadata. However, it never explicitly names the sibling or the boundary between searching and fetching metadata.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this versus ia_get_item_metadata, nor any conditions, exclusions, or prerequisites beyond the credential note. The example query demonstrates syntax but not tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.1.0
    • First observedia_get_item_metadata
    • First observedia_search_items

TDQS

B3.3/5.0

Scored across 2 tools

Disambiguation5/5

The two tools are clearly distinct: one performs discovery queries, the other retrieves metadata for a known identifier. There is no overlap in purpose or expected arguments.

Naming Consistency4/5

Both names use the ia_ prefix and snake_case verb_noun structure (search_items, get_item_metadata), which is predictable. Minor inconsistency in noun phrasing (plural 'items' vs. singular 'item_metadata') keeps it from perfect.

Tool Count3/5

Two tools is thin even for a focused read-only archive.org integration; the natural next steps (download/fetch content, browse collections) are absent. Each tool does earn its place, but the surface feels minimal.

Completeness3/5

Search plus metadata retrieval covers the basic discovery flow, but there is no way to fetch item content/files, list collections, or paginate/refine results beyond the raw query. Agents needing actual archive content hit a dead end.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables AI agents to connect to and control a Virtual Private Server via SSH. It provides a comprehensive suite of tools for remote file system operations, session management, and shell command execution.
    10
    5 npm
    2
    ISC
  • A
    license
    B
    quality
    D
    maintenance
    Enables AI agents to perform FTP/FTPS/SFTP file operations including upload, download, sync, and directory management with multi-server support.
    36
    35 npm
    7
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides a browsable, mutable SFTP filesystem for AI agents, supporting file operations like listing, uploading, downloading, moving, and deleting.
    MIT