Skip to content

Latest commit

 

History

History
594 lines (514 loc) · 16.2 KB

File metadata and controls

594 lines (514 loc) · 16.2 KB

Contributing to MCP Apps SDK

We welcome contributions to the MCP Apps SDK! This document outlines the process for contributing to the project.

Getting Started

  1. Fork the repository
  2. Clone your fork: git clone https://github.com/YOUR-USERNAME/ext-apps.git
  3. Install dependencies: npm install
  4. Build the project: npm run build
  5. Run tests: npm test

Development Process

  1. Create a new branch for your changes
  2. Make your changes
  3. Run npm run prettier to ensure code style compliance
  4. Run npm test to verify all tests pass
  5. Submit a pull request

Pull Request Guidelines

  • Follow the existing code style
  • Include tests for new functionality
  • Update documentation as needed
  • Keep changes focused and atomic
  • Provide a clear description of changes
  • Keep "Allow edits by maintainers" checked when opening your PR — this lets maintainers rebase your branch and lets the /update-snapshots workflow push updated screenshots to it

Running Examples

Start the development environment with hot reloading:

npm run examples:dev

Or build and run examples:

npm run examples:start

With MCP Clients

To use these examples with MCP clients that support the stdio transport (such as Claude Desktop or VS Code), add this MCP server configuration to your client's settings:

MCP client configuration for all examples (using stdio)
{
  "mcpServers": {
    "basic-react": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-react",
        "--stdio"
      ]
    },
    "basic-vanillajs": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-vanillajs",
        "--stdio"
      ]
    },
    "basic-vue": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-vue",
        "--stdio"
      ]
    },
    "basic-svelte": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-svelte",
        "--stdio"
      ]
    },
    "basic-preact": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-preact",
        "--stdio"
      ]
    },
    "basic-solid": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-basic-solid",
        "--stdio"
      ]
    },
    "budget-allocator": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-budget-allocator",
        "--stdio"
      ]
    },
    "cohort-heatmap": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-cohort-heatmap",
        "--stdio"
      ]
    },
    "customer-segmentation": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-customer-segmentation",
        "--stdio"
      ]
    },
    "map": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-map",
        "--stdio"
      ]
    },
    "pdf": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-pdf",
        "--stdio"
      ]
    },
    "scenario-modeler": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-scenario-modeler",
        "--stdio"
      ]
    },
    "shadertoy": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-shadertoy",
        "--stdio"
      ]
    },
    "sheet-music": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-sheet-music",
        "--stdio"
      ]
    },
    "system-monitor": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-system-monitor",
        "--stdio"
      ]
    },
    "threejs": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-threejs",
        "--stdio"
      ]
    },
    "transcript": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-transcript",
        "--stdio"
      ]
    },
    "video-resource": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-video-resource",
        "--stdio"
      ]
    },
    "wiki-explorer": {
      "command": "npx",
      "args": [
        "-y",
        "--silent",
        "--registry=https://registry.npmjs.org/",
        "@modelcontextprotocol/server-wiki-explorer",
        "--stdio"
      ]
    },
    "qr": {
      "command": "uv",
      "args": [
        "run",
        "/path/to/ext-apps/examples/qr-server/server.py",
        "--stdio"
      ]
    },
    "say": {
      "command": "uv",
      "args": [
        "run",
        "--default-index",
        "https://pypi.org/simple",
        "https://raw.githubusercontent.com/modelcontextprotocol/ext-apps/refs/heads/main/examples/say-server/server.py",
        "--stdio"
      ]
    }
  }
}

Note

The qr server requires cloning the repository first. See qr-server README for details.

Local Development

To test local modifications with MCP clients, first clone and install the repository:

git clone https://github.com/modelcontextprotocol/ext-apps.git
cd ext-apps
npm install

Then configure your MCP client to build and run the local server. Replace ~/src/ext-apps with your actual clone path.

Most example servers have a start:stdio script that builds and launches in stdio mode:

MCP client configuration for local development (all examples)
{
  "mcpServers": {
    "basic-react": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/basic-server-react && npm --silent run start:stdio"
      ]
    },
    "basic-vanillajs": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/basic-server-vanillajs && npm --silent run start:stdio"
      ]
    },
    "basic-vue": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/basic-server-vue && npm --silent run start:stdio"
      ]
    },
    "basic-svelte": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/basic-server-svelte && npm --silent run start:stdio"
      ]
    },
    "basic-preact": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/basic-server-preact && npm --silent run start:stdio"
      ]
    },
    "basic-solid": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/basic-server-solid && npm --silent run start:stdio"
      ]
    },
    "budget-allocator": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/budget-allocator-server && npm --silent run start:stdio"
      ]
    },
    "cohort-heatmap": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/cohort-heatmap-server && npm --silent run start:stdio"
      ]
    },
    "customer-segmentation": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/customer-segmentation-server && npm --silent run start:stdio"
      ]
    },
    "map": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/map-server && npm --silent run start:stdio"
      ]
    },
    "pdf": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/pdf-server && npm --silent run start:stdio"
      ]
    },
    "scenario-modeler": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/scenario-modeler-server && npm --silent run start:stdio"
      ]
    },
    "shadertoy": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/shadertoy-server && npm --silent run start:stdio"
      ]
    },
    "sheet-music": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/sheet-music-server && npm --silent run start:stdio"
      ]
    },
    "system-monitor": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/system-monitor-server && npm --silent run start:stdio"
      ]
    },
    "threejs": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/threejs-server && npm --silent run start:stdio"
      ]
    },
    "transcript": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/transcript-server && npm --silent run start:stdio"
      ]
    },
    "video-resource": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/video-resource-server && npm --silent run start:stdio"
      ]
    },
    "wiki-explorer": {
      "command": "bash",
      "args": [
        "-c",
        "cd ~/src/ext-apps/examples/wiki-explorer-server && npm --silent run start:stdio"
      ]
    },
    "qr": {
      "command": "bash",
      "args": [
        "-c",
        "uv run ~/src/ext-apps/examples/qr-server/server.py --stdio"
      ]
    },
    "say": {
      "command": "bash",
      "args": [
        "-c",
        "uv run --index https://pypi.org/simple ~/src/ext-apps/examples/say-server/server.py --stdio"
      ]
    }
  }
}

This configuration rebuilds each server on launch, ensuring your local changes are picked up.

Testing

Unit Tests

Run unit tests with Bun:

npm test

E2E Tests

E2E tests use Playwright to verify all example servers work correctly with screenshot comparisons.

# Run all E2E tests
npm run test:e2e

# Run a specific server's tests
npm run test:e2e -- --grep "Budget Allocator"

# Run tests in interactive UI mode
npm run test:e2e:ui

Updating Golden Screenshots

When UI changes are intentional, update the golden screenshots:

# Update all screenshots
npm run test:e2e:update

# Update screenshots for a specific server
npm run test:e2e:update -- --grep "Three.js"

Note: Golden screenshots are platform-agnostic. Tests use canvas masking and tolerance thresholds to handle minor cross-platform rendering differences.

Updating Snapshots in CI

If E2E tests fail in CI due to screenshot mismatches, you can update snapshots directly from your PR:

  1. Comment /update-snapshots on the PR
  2. The workflow will update snapshots and push to your branch
  3. A comment will confirm when complete

Alternatively, use the workflow dispatch to manually trigger updates for any branch.

Code of Conduct

This project follows our Code of Conduct. Please review it before contributing.

Reporting Issues

  • Use the GitHub issue tracker
  • Search existing issues before creating a new one
  • Provide clear reproduction steps

Security Issues

Please review our Security Policy for reporting security vulnerabilities.


For Maintainers

Repository Setup

This repository uses npm trusted publishing with OIDC - no secrets required.

Before publishing releases, ensure the following are configured:

  1. Trusted publisher on npm: Configure the package to trust this GitHub repository

  2. Release environment (optional): Create a protected environment for additional safeguards

    • Go to Settings > Environments > New environment
    • Name it Release
    • Add required reviewers or other protection rules as needed
  3. RELEASE_TOKEN secret: The release workflow creates GitHub Releases that must trigger the npm-publish workflow. Events from the default GITHUB_TOKEN don't cascade to other workflows, so a separate token is needed.

    • Create a fine-grained PAT scoped to this repository with Contents: write permission
    • Go to Settings > Secrets and variables > Actions > New repository secret
    • Name: RELEASE_TOKEN, value: the PAT

Publishing a Release

Releases are automated via the Release workflow.

Steps to publish:

  1. Trigger the Release workflow:

    • Go to Actions → Release → "Run workflow"
    • Select the bump type (patch, minor, major, or prerelease)
    • Click "Run workflow"
  2. Review the release PR:

    • The workflow bumps the version across all packages and opens a PR labeled release
    • Add release notes to RELEASES.md in the PR
    • Approve and merge the PR
    • Note: re-running the workflow for the same version fails if the branch already exists. Delete the release/vX.Y.Z branch first if you need to redo the bump.
  3. Done — merging the PR automatically tags the commit and creates the GitHub Release (with auto-generated notes), which triggers the npm-publish workflow. Approve the deployment once when prompted.

Manual alternative

You can also bump versions locally:

npm run bump -- patch   # or: minor | major | prerelease --preid=beta

Then commit, push, and create a GitHub Release manually — the npm-publish workflow triggers on release creation.

npm Tags

The workflow automatically determines the npm dist-tag:

Version Pattern npm Tag Install Command
X.Y.Z (from main) latest npm install @modelcontextprotocol/ext-apps
X.Y.Z-beta.N beta npm install @modelcontextprotocol/ext-apps@beta
X.Y.Z (from release branch) release-X.Y npm install @modelcontextprotocol/ext-apps@release-X.Y

Maintenance Releases

To release a patch for an older version:

  1. Create a release branch from the tag: git checkout -b release-0.1 v0.1.0
  2. Cherry-pick or apply fixes
  3. Bump the patch version
  4. Create a GitHub Release targeting the release branch
  5. The package will be published with tag release-0.1

Testing Pre-releases

Every commit and PR automatically publishes a preview package via pkg-pr-new. Check the PR comments or workflow logs for the install command.


License

By contributing, you agree that your contributions will be licensed under the MIT License.