diff --git a/.github/workflows/comment-trigger.yml b/.github/workflows/comment-trigger.yml new file mode 100644 index 0000000..2865dab --- /dev/null +++ b/.github/workflows/comment-trigger.yml @@ -0,0 +1,90 @@ +name: Comment Trigger + +on: + issue_comment: + types: [created] + +permissions: + contents: read + pull-requests: write + actions: write + +jobs: + trigger-checks: + name: Trigger Checks from Comment + if: | + github.event.issue.pull_request && + (github.event.comment.body == '/test all' || + github.event.comment.body == '/test-all' || + github.event.comment.body == '/run-all-checks') && + (github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'MEMBER' || + github.event.comment.author_association == 'COLLABORATOR') + runs-on: ubuntu-latest + steps: + - name: Get PR branch + uses: actions/github-script@v7 + id: get-pr + with: + script: | + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + return pr.data.head.ref; + + - name: Add reaction to comment + uses: actions/github-script@v7 + with: + script: | + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: 'rocket' + }); + + - name: Trigger Python CI + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'python.yml', + ref: '${{ fromJSON(steps.get-pr.outputs.result) }}' + }); + + - name: Trigger Go CI + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'go.yml', + ref: '${{ fromJSON(steps.get-pr.outputs.result) }}' + }); + + - name: Trigger TypeScript CI + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'typescript.yml', + ref: '${{ fromJSON(steps.get-pr.outputs.result) }}' + }); + + - name: Comment on PR + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '🚀 All CI checks triggered! Check the Actions tab for progress.' + }); \ No newline at end of file diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..87636b9 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,80 @@ +name: Go CI +on: + push: + branches: [main] + paths: + - 'go/**' + - '.github/workflows/go.yml' + pull_request: + paths: + - 'go/**' + - '.github/workflows/go.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + go-lint: + name: "Linting" + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Set up Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: "^1.25" + - name: Check formatting + run: | + cd go/sdk + unformatted=$(gofmt -l .) + if [ -n "$unformatted" ]; then + echo "The following files are not properly formatted:" + echo "$unformatted" + exit 1 + fi + echo "All Go files are properly formatted" + - name: Run Go vet + run: | + cd go/sdk + go vet ./... + - name: Run staticcheck + uses: dominikh/staticcheck-action@288b4e28bae83c59f35f73651aeb5cab746a06fc # v1.4.0 + with: + install-go: false + version: "v0.6.1" + working-directory: go/sdk + + go-test: + name: "Unit Tests" + runs-on: ubuntu-latest + strategy: + matrix: + go: ["1.23", "1.24", "1.25"] + steps: + - name: Check out code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Set up Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: ${{ matrix.go }} + - name: Test + run: | + cd go/sdk + go test -v ./... + + go-race-test: + name: "Race Detection" + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Set up Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: "1.24" + - name: Test with -race + run: | + cd go/sdk + go test -v -race ./... \ No newline at end of file diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..a1fb6bd --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,67 @@ +name: Python CI +on: + push: + branches: [main] + paths: + - 'python/**' + - '.github/workflows/python.yml' + pull_request: + paths: + - 'python/**' + - '.github/workflows/python.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + python-lint: + name: "Linting" + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install dependencies + run: | + cd python/sdk + pip install -e . + pip install ruff mypy + - name: Run Ruff formatter check + run: | + cd python/sdk + ruff format --check . + - name: Run Ruff linter + run: | + cd python/sdk + ruff check . + - name: Run mypy + run: | + cd python/sdk + mypy src/mcp_ext_variants --ignore-missing-imports + + python-test: + name: "Unit Tests" + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12"] + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + cd python/sdk + pip install -e . + pip install pytest pytest-cov + - name: Run tests + run: | + cd python/sdk + pytest -v --cov=src/mcp_ext_variants \ No newline at end of file diff --git a/.github/workflows/status-check.yml b/.github/workflows/status-check.yml new file mode 100644 index 0000000..63d22f4 --- /dev/null +++ b/.github/workflows/status-check.yml @@ -0,0 +1,138 @@ +name: Status Check + +# This workflow enforces that all relevant CI checks pass based on which files changed. +# It's the only required status check in branch protection settings. + +on: + pull_request: + types: [opened, synchronize, reopened] + workflow_run: + workflows: ["Python CI", "Go CI", "TypeScript CI"] + types: [completed] + +permissions: + contents: read + statuses: write + checks: write + pull-requests: read + +jobs: + verify-required-checks: + name: Verify Required Checks + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' || github.event.workflow_run.conclusion != 'cancelled' + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Get PR number + id: pr + run: | + if [ "${{ github.event_name }}" == "workflow_run" ]; then + PR_NUMBER=$(gh pr list --head "${{ github.event.workflow_run.head_branch }}" --json number --jq '.[0].number') + echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT + else + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get changed files + id: changed-files + uses: dorny/paths-filter@v3 + with: + filters: | + python: + - 'python/**' + - '.github/workflows/python.yml' + go: + - 'go/**' + - '.github/workflows/go.yml' + typescript: + - 'typescript/**' + - '.github/workflows/typescript.yml' + + - name: Check required statuses + uses: actions/github-script@v7 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const ref = context.payload.pull_request?.head.sha || context.payload.workflow_run?.head_sha; + + // Define required checks per language + const requiredChecks = { + python: [ + 'Python CI / Linting', + 'Python CI / Unit Tests (3.10)', + 'Python CI / Unit Tests (3.11)', + 'Python CI / Unit Tests (3.12)' + ], + go: [ + 'Go CI / Linting', + 'Go CI / Unit Tests (1.23)', + 'Go CI / Unit Tests (1.24)', + 'Go CI / Unit Tests (1.25)', + 'Go CI / Race Detection' + ], + typescript: [ + 'TypeScript CI / Linting', + 'TypeScript CI / Unit Tests (20)', + 'TypeScript CI / Unit Tests (22)' + ] + }; + + // Get changed files from previous step + const changedFiles = { + python: ${{ steps.changed-files.outputs.python }} === 'true', + go: ${{ steps.changed-files.outputs.go }} === 'true', + typescript: ${{ steps.changed-files.outputs.typescript }} === 'true' + }; + + // Collect all required checks based on changes + let allRequiredChecks = []; + for (const [lang, changed] of Object.entries(changedFiles)) { + if (changed) { + allRequiredChecks = allRequiredChecks.concat(requiredChecks[lang]); + } + } + + if (allRequiredChecks.length === 0) { + console.log('No language files changed, no checks required'); + return; + } + + // Get all check runs for this commit + const { data: checkRuns } = await github.rest.checks.listForRef({ + owner, + repo, + ref + }); + + // Verify all required checks have passed + const checkStatuses = {}; + for (const check of checkRuns.check_runs) { + checkStatuses[check.name] = check.conclusion; + } + + let allPassed = true; + let failureMessage = ''; + + for (const requiredCheck of allRequiredChecks) { + const status = checkStatuses[requiredCheck]; + if (!status) { + allPassed = false; + failureMessage += `❌ ${requiredCheck}: Not started\\n`; + } else if (status !== 'success') { + allPassed = false; + failureMessage += `❌ ${requiredCheck}: ${status}\\n`; + } else { + failureMessage += `✅ ${requiredCheck}: ${status}\\n`; + } + } + + if (!allPassed) { + core.setFailed(`Required checks have not passed:\\n${failureMessage}`); + } else { + console.log(`All required checks passed:\\n${failureMessage}`); + } \ No newline at end of file diff --git a/.github/workflows/typescript.yml b/.github/workflows/typescript.yml new file mode 100644 index 0000000..fba0aa6 --- /dev/null +++ b/.github/workflows/typescript.yml @@ -0,0 +1,61 @@ +name: TypeScript CI +on: + push: + branches: [main] + paths: + - 'typescript/**' + - '.github/workflows/typescript.yml' + pull_request: + paths: + - 'typescript/**' + - '.github/workflows/typescript.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + typescript-lint: + name: "Linting" + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v6 + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: "20" + - name: Install dependencies + run: | + cd typescript/sdk + npm install + - name: Run TypeScript compiler check + run: | + cd typescript/sdk + npm run build + - name: Run ESLint + run: | + cd typescript/sdk + npm run lint + + typescript-test: + name: "Unit Tests" + runs-on: ubuntu-latest + strategy: + matrix: + node-version: ["20", "22"] + steps: + - name: Check out code + uses: actions/checkout@v6 + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node-version }} + - name: Install dependencies + run: | + cd typescript/sdk + npm install + - name: Run tests + run: | + cd typescript/sdk + npm test \ No newline at end of file diff --git a/.gitignore b/.gitignore index aaadf73..17c097c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# # Binaries for programs and plugins *.exe *.exe~ @@ -30,3 +27,44 @@ go.work.sum # Editor/IDE # .idea/ # .vscode/ + +# Node.js / TypeScript +node_modules/ +dist/ +*.tsbuildinfo +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +.venv/ +venv/ +ENV/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +htmlcov/ +.coverage +.coverage.* +coverage.xml +*.cover \ No newline at end of file diff --git a/README.md b/README.md index c44bd0c..0afa166 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,73 @@ > #### **Status:** Experimental. This work is for prototyping and feedback only, and is not an accepted or official MCP extension. This repository provides a multi-language reference implementation of the variants proposal for the Model Context Protocol (MCP), as described in [SEP-2053](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2053). + +## Implementations + +| Language | Directory | Package | Status | +|----------|-----------|---------|--------| +| Go | `go/sdk/` | `github.com/modelcontextprotocol/experimental-ext-variants/go/sdk` | Planned | +| Python | `python/sdk/` | `mcp-ext-variants` | Planned | +| TypeScript | `typescript/sdk/` | `@ext-modelcontextprotocol/variants` | Planned | + + +## CI/CD + +This monorepo uses **path-based CI workflows** to efficiently test only what changes: + +### How It Works + +1. **Language-specific workflows** (`python.yml`, `go.yml`, `typescript.yml`) + - Only trigger when their language directory or workflow file changes + - Run all tests, linting, and checks for that language + +2. **Status check workflow** (`status-check.yml`) + - Runs on every PR to verify required checks passed + - Determines what needs to pass based on which files changed + - This is the only required check in branch protection + +### Examples + +- Change `python/sdk/file.py` → Only Python CI runs → PR requires Python checks to pass +- Change both Go and TypeScript files → Both CIs run → PR requires both to pass +- Change only `README.md` → No language CIs run → PR can merge immediately + +### Forcing All Checks + +To run all language checks regardless of changed files: +- **In a PR**: Comment `/test all` (only works for repo owners/members/collaborators) +- **Manually**: Use GitHub Actions UI or CLI to trigger individual workflows + +### Adding New Required Checks + +1. **Add your check** to the appropriate language workflow (e.g., `python.yml`): + ```yaml + python-security-scan: + name: "Security Scan" + runs-on: ubuntu-latest + steps: + - name: Run security checks + run: # your commands here + ``` + +2. **Update the status check** in `.github/workflows/status-check.yml`: + ```javascript + const requiredChecks = { + python: [ + 'Python CI / Linting', + 'Python CI / Unit Tests (3.10)', + // ... existing checks ... + 'Python CI / Security Scan' // ← Add your new check + ], + ``` + +3. **Submit PR** - Your new check is now required for all relevant changes! + +## License + +Apache License 2.0 - See LICENSE file for details + +## Resources + +- [Variants Proposal Specification (SEP-2053)](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2053) - Full specification and design details +- [Model Context Protocol](https://modelcontextprotocol.io/specification) diff --git a/conformance/.gitkeep b/conformance/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/go/sdk/README.md b/go/sdk/README.md new file mode 100644 index 0000000..56d7d0c --- /dev/null +++ b/go/sdk/README.md @@ -0,0 +1,3 @@ +# MCP Variants - Go Implementation + +This will contain the Go implementation of the MCP Variants based on [SEP-2053](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2053). \ No newline at end of file diff --git a/go/sdk/examples/.gitkeep b/go/sdk/examples/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/go/sdk/go.mod b/go/sdk/go.mod new file mode 100644 index 0000000..917c7e8 --- /dev/null +++ b/go/sdk/go.mod @@ -0,0 +1,3 @@ +module github.com/modelcontextprotocol/experimental-ext-variants/go/sdk + +go 1.23.0 \ No newline at end of file diff --git a/go/sdk/internal/.gitkeep b/go/sdk/internal/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/go/sdk/variants/variant.go b/go/sdk/variants/variant.go new file mode 100644 index 0000000..c7d3f83 --- /dev/null +++ b/go/sdk/variants/variant.go @@ -0,0 +1,6 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +// Package variants implements MCP Variants for experimental extensions. +package variants diff --git a/go/sdk/variants/variant_test.go b/go/sdk/variants/variant_test.go new file mode 100644 index 0000000..4962133 --- /dev/null +++ b/go/sdk/variants/variant_test.go @@ -0,0 +1,14 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +package variants + +import "testing" + +func TestPlaceholder(t *testing.T) { + // Placeholder test to ensure go test runs successfully + if false { + t.Error("This should not happen") + } +} diff --git a/python/sdk/README.md b/python/sdk/README.md new file mode 100644 index 0000000..5840587 --- /dev/null +++ b/python/sdk/README.md @@ -0,0 +1,31 @@ +# MCP Variants Python SDK + +Python implementation of the Model Context Protocol (MCP) variants framework. + +## Installation + +```bash +pip install mcp-ext-variants +``` + +## Usage + +```python +from mcp_ext_variants import Variant + +# Example usage will be added as the implementation progresses +``` + +## Development + +```bash +# Install in development mode +pip install -e . + +# Run tests (when available) +pytest +``` + +## License + +Apache License 2.0 - See LICENSE file in the root directory for details. \ No newline at end of file diff --git a/python/sdk/pyproject.toml b/python/sdk/pyproject.toml new file mode 100644 index 0000000..86aa188 --- /dev/null +++ b/python/sdk/pyproject.toml @@ -0,0 +1,71 @@ +[project] +name = "mcp-ext-variants" +version = "0.1.0" +description = "Python SDK for Model Context Protocol variants" +authors = [{name = "The MCP Variants Authors"}] +readme = "README.md" +license = {text = "Apache-2.0"} +requires-python = ">=3.10" +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dependencies = [ + "mcp>=1.0.0", +] + +[project.urls] +"Homepage" = "https://github.com/modelcontextprotocol/experimental-ext-variants" +"Bug Reports" = "https://github.com/modelcontextprotocol/experimental-ext-variants/issues" +"Source" = "https://github.com/modelcontextprotocol/experimental-ext-variants" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src/mcp_ext_variants"] + +[tool.ruff] +line-length = 120 +target-version = "py310" + +[tool.ruff.lint] +select = [ + "E", # pycodestyle + "F", # pyflakes + "I", # isort + "UP", # pyupgrade + "C4", # flake8-comprehensions + "PERF", # Perflint +] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] # Allow unused imports in __init__.py + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" + +[tool.mypy] +python_version = "3.10" +warn_return_any = true +warn_unused_configs = true +disallow_untyped_defs = true +ignore_missing_imports = true + +[tool.pyright] +typeCheckingMode = "basic" +include = ["src/mcp_ext_variants", "tests"] +venvPath = "." +venv = ".venv" + +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = ["test_*.py", "*_test.py"] +addopts = "--strict-markers --verbose" \ No newline at end of file diff --git a/python/sdk/src/mcp_ext_variants/__init__.py b/python/sdk/src/mcp_ext_variants/__init__.py new file mode 100644 index 0000000..87c3dc4 --- /dev/null +++ b/python/sdk/src/mcp_ext_variants/__init__.py @@ -0,0 +1,11 @@ +# Copyright 2025 The MCP Variants Authors. All rights reserved. +# Use of this source code is governed by a Apache-2.0 +# license that can be found in the LICENSE file. + +""" +MCP Variants Python SDK + +Implements experimental MCP Variants for extended functionality. +""" + +__all__: list[str] = [] # Export list will be populated as the SDK develops diff --git a/python/sdk/src/mcp_ext_variants/py.typed b/python/sdk/src/mcp_ext_variants/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/python/sdk/src/mcp_ext_variants/variant.py b/python/sdk/src/mcp_ext_variants/variant.py new file mode 100644 index 0000000..df4f03d --- /dev/null +++ b/python/sdk/src/mcp_ext_variants/variant.py @@ -0,0 +1,9 @@ +# Copyright 2025 The MCP Variants Authors. All rights reserved. +# Use of this source code is governed by a Apache-2.0 +# license that can be found in the LICENSE file. + +""" +Package variants implements experimental MCP Variants for extended functionality. +""" + +__all__ = [] # Export list will be populated as the SDK develops diff --git a/python/sdk/tests/__init__.py b/python/sdk/tests/__init__.py new file mode 100644 index 0000000..c7d5111 --- /dev/null +++ b/python/sdk/tests/__init__.py @@ -0,0 +1 @@ +# Tests for mcp-ext-variants diff --git a/python/sdk/tests/test_variants.py b/python/sdk/tests/test_variants.py new file mode 100644 index 0000000..0f41f0e --- /dev/null +++ b/python/sdk/tests/test_variants.py @@ -0,0 +1,10 @@ +# Copyright 2025 The MCP Variants Authors. All rights reserved. +# Use of this source code is governed by a Apache-2.0 +# license that can be found in the LICENSE file. + +"""Tests for MCP variants.""" + + +def test_placeholder(): + """Placeholder test to ensure pytest runs successfully.""" + assert True diff --git a/typescript/sdk/.eslintrc.json b/typescript/sdk/.eslintrc.json new file mode 100644 index 0000000..db42afc --- /dev/null +++ b/typescript/sdk/.eslintrc.json @@ -0,0 +1,24 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module", + "project": "./tsconfig.json" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking" + ], + "env": { + "node": true, + "es2022": true + }, + "rules": { + "@typescript-eslint/explicit-module-boundary-types": "error", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }] + } +} \ No newline at end of file diff --git a/typescript/sdk/.nvmrc b/typescript/sdk/.nvmrc new file mode 100644 index 0000000..2edeafb --- /dev/null +++ b/typescript/sdk/.nvmrc @@ -0,0 +1 @@ +20 \ No newline at end of file diff --git a/typescript/sdk/README.md b/typescript/sdk/README.md new file mode 100644 index 0000000..8277baa --- /dev/null +++ b/typescript/sdk/README.md @@ -0,0 +1,3 @@ +# MCP Variants - TypeScript Implementation + +This will contain the TypeScript implementation of the MCP Variants based on [SEP-2053](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2053). \ No newline at end of file diff --git a/typescript/sdk/package.json b/typescript/sdk/package.json new file mode 100644 index 0000000..ea62aa8 --- /dev/null +++ b/typescript/sdk/package.json @@ -0,0 +1,56 @@ +{ + "name": "@ext-modelcontextprotocol/variants", + "version": "0.1.0", + "description": "TypeScript SDK for Model Context Protocol variants", + "type": "module", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "engines": { + "node": ">=20" + }, + "scripts": { + "build": "tsc", + "test": "vitest run", + "test:watch": "vitest", + "lint": "eslint src --ext .ts", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "mcp", + "model-context-protocol", + "variants" + ], + "author": "The MCP Variants Authors", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/modelcontextprotocol/experimental-ext-variants.git", + "directory": "typescript/sdk" + }, + "bugs": { + "url": "https://github.com/modelcontextprotocol/experimental-ext-variants/issues" + }, + "homepage": "https://github.com/modelcontextprotocol/experimental-ext-variants", + "files": [ + "dist", + "src", + "README.md" + ], + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.0.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.0.0", + "typescript": "^5.0.0", + "vitest": "^2.0.0" + } +} \ No newline at end of file diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts new file mode 100644 index 0000000..eab7d8a --- /dev/null +++ b/typescript/sdk/src/index.ts @@ -0,0 +1,11 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +/** + * MCP Variants TypeScript SDK + * + * Implements experimental MCP Variants for extended functionality. + */ + +export * from './variants.js'; \ No newline at end of file diff --git a/typescript/sdk/src/variants.test.ts b/typescript/sdk/src/variants.test.ts new file mode 100644 index 0000000..4fdd95c --- /dev/null +++ b/typescript/sdk/src/variants.test.ts @@ -0,0 +1,11 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +import { describe, it, expect } from 'vitest'; + +describe('Variants', () => { + it('should be defined', () => { + expect(true).toBe(true); + }); +}); \ No newline at end of file diff --git a/typescript/sdk/src/variants.ts b/typescript/sdk/src/variants.ts new file mode 100644 index 0000000..2a38b2b --- /dev/null +++ b/typescript/sdk/src/variants.ts @@ -0,0 +1,11 @@ +// Copyright 2025 The MCP Variants Authors. All rights reserved. +// Use of this source code is governed by a Apache-2.0 +// license that can be found in the LICENSE file. + +/** + * Core variant functionality for MCP + * + * Experimental variant implementations for extended MCP functionality. + */ + +// Placeholder for variant implementation \ No newline at end of file diff --git a/typescript/sdk/tsconfig.json b/typescript/sdk/tsconfig.json new file mode 100644 index 0000000..95b0198 --- /dev/null +++ b/typescript/sdk/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "NodeNext", + "lib": ["esnext"], + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "isolatedModules": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "NodeNext", + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} \ No newline at end of file diff --git a/typescript/sdk/vitest.config.js b/typescript/sdk/vitest.config.js new file mode 100644 index 0000000..bfa5448 --- /dev/null +++ b/typescript/sdk/vitest.config.js @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/**/*.test.ts', 'test/**/*.test.ts'], + exclude: ['**/node_modules/**', '**/dist/**'] + } +}); \ No newline at end of file