diff --git a/.github/workflows/publish-mcp.yaml b/.github/workflows/publish-mcp.yaml new file mode 100644 index 0000000..4279908 --- /dev/null +++ b/.github/workflows/publish-mcp.yaml @@ -0,0 +1,89 @@ +name: Publish to MCP Registry + +on: + push: + tags: ['v*'] + workflow_dispatch: + +permissions: + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + env: + MCP_PUBLISHER_VERSION: v1.8.1 + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Prepare registry version + run: | + VERSION=$(node -p "require('./package.json').version") + if [[ "$GITHUB_REF" == refs/tags/* && "${GITHUB_REF#refs/tags/v}" != "$VERSION" ]]; then + echo "Tag must match package.json version $VERSION" + exit 1 + fi + jq --arg version "$VERSION" '.version = $version | .packages[].version = $version' server.json > server.tmp + mv server.tmp server.json + + - name: Install dependencies + run: npm ci + + - name: Lint and build + run: | + npm run lint + npm run typecheck + npm run build + + - name: Publish npm package if needed + run: | + npm view @linkedapi/mcp versions --json > "$RUNNER_TEMP/npm-versions.json" + if ! node -e 'const versions = require(process.argv[1]); process.exit(versions.includes(require("./package.json").version) ? 0 : 1)' "$RUNNER_TEMP/npm-versions.json"; then + npm publish --access public + fi + VERSION=$(node -p "require('./package.json').version") + MCP_NAME=$(node -p "require('./package.json').mcpName") + for ATTEMPT in {1..30}; do + if [[ "$(npm view "@linkedapi/mcp@$VERSION" mcpName 2>/dev/null)" == "$MCP_NAME" ]]; then + exit 0 + fi + echo "Waiting for @linkedapi/mcp@$VERSION metadata to become available ($ATTEMPT/30)" + sleep 10 + done + echo 'Published npm metadata did not become available within five minutes' + exit 1 + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Install cosign + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 + + - name: Download and verify mcp-publisher + run: | + BASE_URL="https://github.com/modelcontextprotocol/registry/releases/download/$MCP_PUBLISHER_VERSION" + ARCHIVE=mcp-publisher_linux_amd64.tar.gz + curl --fail --location --silent --show-error --output "$RUNNER_TEMP/$ARCHIVE" "$BASE_URL/$ARCHIVE" + curl --fail --location --silent --show-error --output "$RUNNER_TEMP/$ARCHIVE.sigstore.json" "$BASE_URL/$ARCHIVE.sigstore.json" + cosign verify-blob \ + --bundle "$RUNNER_TEMP/$ARCHIVE.sigstore.json" \ + --certificate-identity "https://github.com/modelcontextprotocol/registry/.github/workflows/release.yml@refs/tags/$MCP_PUBLISHER_VERSION" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + "$RUNNER_TEMP/$ARCHIVE" + tar xzf "$RUNNER_TEMP/$ARCHIVE" -C "$RUNNER_TEMP" mcp-publisher + + - name: Authenticate to MCP Registry + run: '"$RUNNER_TEMP/mcp-publisher" login github-oidc' + + - name: Publish server to MCP Registry + run: '"$RUNNER_TEMP/mcp-publisher" publish' diff --git a/package-lock.json b/package-lock.json index f405f16..7c6f02b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@linkedapi/mcp", - "version": "2.3.20", + "version": "2.3.21", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@linkedapi/mcp", - "version": "2.3.20", + "version": "2.3.21", "license": "MIT", "dependencies": { "@linkedapi/node": "^2.3.20", diff --git a/package.json b/package.json index fcf59cd..fa175b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@linkedapi/mcp", - "version": "2.3.20", + "version": "2.3.21", "description": "MCP server that lets AI assistants control LinkedIn accounts and retrieve real-time data.", "main": "dist/index.js", "bin": { @@ -55,5 +55,6 @@ "tsx": "^4.7.1", "typescript": "^5.8.3", "typescript-eslint": "^8.38.0" - } + }, + "mcpName": "io.github.Linked-API/linkedapi-mcp" } diff --git a/server.json b/server.json new file mode 100644 index 0000000..8cbb269 --- /dev/null +++ b/server.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", + "name": "io.github.Linked-API/linkedapi-mcp", + "title": "Linked API", + "description": "Manage LinkedIn messages, connections, posts, and profile data through Linked API.", + "websiteUrl": "https://linkedapi.io", + "repository": { + "url": "https://github.com/Linked-API/linkedapi-mcp", + "source": "github" + }, + "version": "2.3.21", + "packages": [ + { + "registryType": "npm", + "identifier": "@linkedapi/mcp", + "version": "2.3.21", + "transport": { + "type": "stdio" + }, + "environmentVariables": [ + { + "name": "LINKED_API_TOKEN", + "description": "Linked API access token from https://app.linkedapi.io.", + "isRequired": true, + "isSecret": true + }, + { + "name": "IDENTIFICATION_TOKEN", + "description": "Identification token for the LinkedIn account from https://app.linkedapi.io.", + "isRequired": true, + "isSecret": true + } + ] + } + ], + "remotes": [ + { + "type": "streamable-http", + "url": "https://mcp.linkedapi.io/mcp", + "headers": [ + { + "name": "linked-api-token", + "description": "Linked API access token from https://app.linkedapi.io.", + "isRequired": true, + "isSecret": true + }, + { + "name": "identification-token", + "description": "Identification token for the LinkedIn account from https://app.linkedapi.io.", + "isRequired": true, + "isSecret": true + } + ] + } + ] +}