From 819154ac315c5cbcb6c718cf76ecb0945c9183f7 Mon Sep 17 00:00:00 2001 From: Mohammod Al Amin Ashik Date: Wed, 11 Feb 2026 13:14:34 +0000 Subject: [PATCH 1/4] Add 1Password MCP server definition Community 1Password MCP server for accessing secrets from vaults. List vaults, retrieve items, and search credentials. Uses @takescake/1password-mcp. https://claude.ai/code/session_013AxurW8hPAfnUNvik354Xx --- servers/community.1password.json | 64 ++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 servers/community.1password.json diff --git a/servers/community.1password.json b/servers/community.1password.json new file mode 100644 index 0000000..4495eef --- /dev/null +++ b/servers/community.1password.json @@ -0,0 +1,64 @@ +{ + "$schema": "../schemas/server-definition.schema.json", + "id": "community.1password", + "name": "1Password", + "alias": "1password", + "description": "Access secrets from 1Password vaults. List vaults, retrieve items, and search for credentials using a service account token.", + "icon": "https://avatars.githubusercontent.com/u/38230737?v=4", + "schema_version": "2.1", + "categories": ["security"], + "tags": ["1password", "secrets", "passwords", "credentials", "vaults", "security"], + + "transport": { + "type": "stdio", + "command": "npx", + "args": ["-y", "@takescake/1password-mcp"], + "env": { + "OP_SERVICE_ACCOUNT_TOKEN": "${input:OP_SERVICE_ACCOUNT_TOKEN}" + }, + "metadata": { + "inputs": [ + { + "id": "OP_SERVICE_ACCOUNT_TOKEN", + "label": "1Password Service Account Token", + "description": "Service account token for accessing 1Password vaults. Scoped to specific vaults.", + "type": "password", + "required": true, + "secret": true, + "placeholder": "ops_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "obtain": { + "url": "https://my.1password.com/developer-tools/infrastructure-secrets/serviceaccount", + "instructions": "1. Go to 1Password.com > Developer Tools > Service Accounts\n2. Click 'Create a Service Account'\n3. Name it and select which vaults it can access\n4. Copy the token (starts with ops_)", + "button_label": "Create Service Account" + } + } + ] + } + }, + + "auth": { + "type": "api_key", + "instructions": "Create a 1Password Service Account at https://my.1password.com/developer-tools/infrastructure-secrets/serviceaccount" + }, + + "contributor": { + "name": "TakesCake", + "github": "CakeRepository", + "url": "https://github.com/CakeRepository" + }, + + "links": { + "repository": "https://github.com/CakeRepository/1Password-MCP", + "homepage": "https://1password.com", + "documentation": "https://github.com/CakeRepository/1Password-MCP#readme" + }, + + "platforms": ["all"], + + "capabilities": { + "tools": true, + "resources": false, + "prompts": false, + "read_only_mode": true + } +} From f569fcc5d1dbc3a25a5082e7736a772080cfa8b5 Mon Sep 17 00:00:00 2001 From: Mohammod Al Amin Ashik Date: Thu, 19 Feb 2026 19:08:05 +0800 Subject: [PATCH 2/4] fix: update server definition (input type 'password' -> 'text' for OP_SERVICE_ACCOUNT_TOKEN) --- fix_branches.py | 222 +++++++++++++++++++++++++++++++ servers/community.1password.json | 30 +++-- 2 files changed, 241 insertions(+), 11 deletions(-) create mode 100644 fix_branches.py diff --git a/fix_branches.py b/fix_branches.py new file mode 100644 index 0000000..d93d54f --- /dev/null +++ b/fix_branches.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python3 +""" +Process all claude/add-* branches: +1. Rebase onto main +2. Fix common issues in server definition JSON files +3. Commit changes +4. Push to new fix/* branch +""" +import subprocess +import json +import sys +import os +import re + +REPO_DIR = r"d:\mcpmux\mcp-servers" + +# Known icon fixes: MCP org icon -> actual project icon +ICON_FIXES = { + "community.filesystem": "https://avatars.githubusercontent.com/u/182288589?v=4", # keep MCP - it IS the MCP org project + "community.puppeteer": "https://avatars.githubusercontent.com/u/182288589?v=4", + "community.sqlite": "https://avatars.githubusercontent.com/u/182288589?v=4", + "community.fetch": "https://avatars.githubusercontent.com/u/182288589?v=4", + "community.memory": "https://avatars.githubusercontent.com/u/182288589?v=4", + "community.sequential-thinking": "https://avatars.githubusercontent.com/u/182288589?v=4", + "community.postgresql": "https://www.postgresql.org/media/img/about/press/elephant.png", + "community.gitlab": "https://avatars.githubusercontent.com/u/1086321?v=4", + "community.google-maps": "https://avatars.githubusercontent.com/u/1342004?v=4", +} + +# Known repo URL fixes +REPO_FIXES = { + "com.hubspot-mcp": "https://github.com/HubSpot/mcp-server", + "com.resend-mcp": "https://github.com/resend/resend-mcp", + "com.pagerduty-mcp": "https://github.com/PagerDuty/pagerduty-mcp-server", +} + +# Known doc URL fixes +DOC_FIXES = { + "community.postgresql": "https://github.com/modelcontextprotocol/servers/tree/main/src/postgres#readme", +} + +# Servers with known wrong packages +PACKAGE_FIXES = { + "com.pagerduty-mcp": {"args": ["pagerduty-mcp"]}, +} + +# Stytch: repo URL is org page, should be removed or pointed to specific repo +STYTCH_REPO = "https://github.com/stytchauth/stytch-mcp" + +VALID_INPUT_TYPES = ["text", "number", "boolean", "url", "select", "file_path", "directory_path"] + +def run(cmd, cwd=REPO_DIR, check=True): + result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, shell=True) + if check and result.returncode != 0: + return None, result.stderr.strip() + return result.stdout.strip(), result.stderr.strip() + +def fix_definition(filepath, server_id): + """Fix common issues in a server definition JSON file. Returns list of fixes applied.""" + with open(filepath, 'r', encoding='utf-8') as f: + data = json.load(f) + + fixes = [] + + # Fix invalid input types + transport = data.get('transport', {}) + metadata = transport.get('metadata', {}) + inputs = metadata.get('inputs', []) + + for inp in inputs: + if inp.get('type') not in VALID_INPUT_TYPES: + old_type = inp.get('type') + inp['type'] = 'text' + fixes.append(f"input type '{old_type}' -> 'text' for {inp['id']}") + + # Fix MCP org icon for non-MCP-org projects + icon = data.get('icon', '') + if server_id in ICON_FIXES: + new_icon = ICON_FIXES[server_id] + if icon != new_icon: + data['icon'] = new_icon + fixes.append(f"icon updated") + + # Fix known repo URLs + if server_id in REPO_FIXES: + links = data.get('links', {}) + if links.get('repository') != REPO_FIXES[server_id]: + links['repository'] = REPO_FIXES[server_id] + data['links'] = links + fixes.append(f"repo URL fixed") + + # Fix known doc URLs + if server_id in DOC_FIXES: + links = data.get('links', {}) + if links.get('documentation') != DOC_FIXES[server_id]: + links['documentation'] = DOC_FIXES[server_id] + data['links'] = links + fixes.append(f"doc URL fixed") + + # Fix stytch repo + if server_id == "com.stytch-mcp": + links = data.get('links', {}) + links['repository'] = STYTCH_REPO + data['links'] = links + fixes.append("repo URL: org page -> specific repo") + + # Fix pagerduty package + if server_id in PACKAGE_FIXES: + transport['args'] = PACKAGE_FIXES[server_id]['args'] + fixes.append("fixed package name") + + if fixes: + with open(filepath, 'w', encoding='utf-8') as f: + json.dump(data, f, indent=2, ensure_ascii=False) + f.write('\n') + + return fixes + +def get_remote_branches(): + out, _ = run('git for-each-ref --format="%(refname:short)" "refs/remotes/origin/claude/add-*"') + if not out: + return [] + return [b.strip().replace('origin/', '') for b in out.strip().split('\n') if b.strip()] + +def process_branch(branch_name): + """Process a single branch: rebase, fix, commit, push.""" + short_name = branch_name.replace('claude/add-', '').replace('-mcp-nYwV7', '').replace('-nYwV7', '') + fix_branch = f"fix/{short_name}" + + # Create fix branch from the remote branch, rebased on main + run(f'git branch -D {fix_branch}', check=False) + out, err = run(f'git checkout -b {fix_branch} origin/{branch_name}') + if out is None: + return {"branch": branch_name, "status": "ERROR", "error": f"checkout failed: {err}"} + + # Rebase onto main + out, err = run('git rebase main') + if out is None: + run('git rebase --abort', check=False) + run('git checkout main', check=False) + run(f'git branch -D {fix_branch}', check=False) + return {"branch": branch_name, "status": "REBASE_CONFLICT", "error": err} + + # Find the server definition files that differ from main + out, _ = run('git diff main --name-only -- servers/') + if not out: + run('git checkout main', check=False) + run(f'git branch -D {fix_branch}', check=False) + return {"branch": branch_name, "status": "NO_CHANGES", "error": "No server files differ from main"} + + diff_files = [f for f in out.strip().split('\n') if f.strip()] + + all_fixes = [] + for f in diff_files: + filepath = os.path.join(REPO_DIR, f) + if os.path.exists(filepath) and f.endswith('.json'): + try: + with open(filepath, 'r', encoding='utf-8') as fh: + data = json.load(fh) + server_id = data.get('id', '') + fixes = fix_definition(filepath, server_id) + if fixes: + all_fixes.extend([(f, fix) for fix in fixes]) + except Exception as e: + all_fixes.append((f, f"PARSE_ERROR: {e}")) + + # Commit fixes if any + if all_fixes: + run('git add -A') + fix_desc = "; ".join([fix for _, fix in all_fixes[:5]]) + commit_msg = f"fix: update server definition ({fix_desc})" + run(f'git commit -m "{commit_msg}"') + + # Push + out, err = run(f'git push -u origin {fix_branch} --force') + if out is None and "error" in str(err).lower(): + result = {"branch": branch_name, "fix_branch": fix_branch, "status": "PUSH_ERROR", "error": err, "fixes": all_fixes} + else: + result = {"branch": branch_name, "fix_branch": fix_branch, "status": "PUSHED", "fixes": all_fixes, "files": diff_files} + + # Back to main + run('git checkout main') + + return result + +def create_pr(fix_branch, server_name, files): + """Create a PR for a fix branch.""" + file_list = ", ".join([os.path.basename(f) for f in files]) + title = f"feat: add {server_name} MCP server definition" + body = f"Add {server_name} MCP server definition.\\n\\nFiles: {file_list}" + + out, err = run(f'gh pr create --base main --head {fix_branch} --title "{title}" --body "{body}"') + if out and "http" in out: + return out.strip() + return f"PR_ERROR: {err}" + +if __name__ == "__main__": + os.chdir(REPO_DIR) + + # Ensure we're on main + run('git checkout main') + + branches = get_remote_branches() + print(f"Found {len(branches)} branches to process") + + results = [] + for i, branch in enumerate(branches): + print(f"\n[{i+1}/{len(branches)}] Processing {branch}...") + result = process_branch(branch) + results.append(result) + print(f" Status: {result['status']}") + if result.get('fixes'): + for f, fix in result['fixes']: + print(f" Fix: {fix}") + + # Summary + print("\n\n=== SUMMARY ===") + for r in results: + status = r['status'] + branch = r['branch'] + fixes = len(r.get('fixes', [])) + print(f" {status:20s} {branch} ({fixes} fixes)") diff --git a/servers/community.1password.json b/servers/community.1password.json index 4495eef..6b87534 100644 --- a/servers/community.1password.json +++ b/servers/community.1password.json @@ -6,13 +6,24 @@ "description": "Access secrets from 1Password vaults. List vaults, retrieve items, and search for credentials using a service account token.", "icon": "https://avatars.githubusercontent.com/u/38230737?v=4", "schema_version": "2.1", - "categories": ["security"], - "tags": ["1password", "secrets", "passwords", "credentials", "vaults", "security"], - + "categories": [ + "security" + ], + "tags": [ + "1password", + "secrets", + "passwords", + "credentials", + "vaults", + "security" + ], "transport": { "type": "stdio", "command": "npx", - "args": ["-y", "@takescake/1password-mcp"], + "args": [ + "-y", + "@takescake/1password-mcp" + ], "env": { "OP_SERVICE_ACCOUNT_TOKEN": "${input:OP_SERVICE_ACCOUNT_TOKEN}" }, @@ -22,7 +33,7 @@ "id": "OP_SERVICE_ACCOUNT_TOKEN", "label": "1Password Service Account Token", "description": "Service account token for accessing 1Password vaults. Scoped to specific vaults.", - "type": "password", + "type": "text", "required": true, "secret": true, "placeholder": "ops_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", @@ -35,26 +46,23 @@ ] } }, - "auth": { "type": "api_key", "instructions": "Create a 1Password Service Account at https://my.1password.com/developer-tools/infrastructure-secrets/serviceaccount" }, - "contributor": { "name": "TakesCake", "github": "CakeRepository", "url": "https://github.com/CakeRepository" }, - "links": { "repository": "https://github.com/CakeRepository/1Password-MCP", "homepage": "https://1password.com", "documentation": "https://github.com/CakeRepository/1Password-MCP#readme" }, - - "platforms": ["all"], - + "platforms": [ + "all" + ], "capabilities": { "tools": true, "resources": false, From 2045a64e03a79c515090ad23c521380dad2dab4d Mon Sep 17 00:00:00 2001 From: Mohammod Al Amin Ashik Date: Thu, 19 Feb 2026 22:43:42 +0800 Subject: [PATCH 3/4] fix: rename server files with transport suffix - community.1password.json -> community.1password-npx.json (id: community.1password-npx) Signed-off-by: Mohammod Al Amin Ashik --- inventory.py | 81 ++++++++ rename_files.py | 185 ++++++++++++++++++ ...word.json => community.1password-npx.json} | 4 +- 3 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 inventory.py create mode 100644 rename_files.py rename servers/{community.1password.json => community.1password-npx.json} (97%) diff --git a/inventory.py b/inventory.py new file mode 100644 index 0000000..21e3d4c --- /dev/null +++ b/inventory.py @@ -0,0 +1,81 @@ +"""Inventory all NEW server definitions across fix branches with transport details.""" +import json, subprocess, re + +main_files = set(subprocess.check_output( + ['git', 'ls-tree', '-r', '--name-only', 'main', '--', 'servers/'], + text=True +).strip().split('\n')) + +branches = subprocess.check_output(['git', 'branch', '--list', 'fix/*'], text=True).strip().split('\n') +branches = [b.strip().lstrip('* ') for b in branches if b.strip()] + +servers = [] + +for branch in sorted(branches): + try: + files = subprocess.check_output( + ['git', 'ls-tree', '-r', '--name-only', branch, '--', 'servers/'], + text=True + ).strip().split('\n') + except: + continue + + new_files = [f for f in files if f not in main_files and f.endswith('.json')] + + for f in new_files: + try: + content = subprocess.check_output(['git', 'show', f'{branch}:{f}'], text=True) + defn = json.loads(content) + except: + continue + + transport = defn.get('transport', {}) + t_type = transport.get('type', '?') + command = transport.get('command', '') + url = transport.get('url', '') + repo = defn.get('links', {}).get('repository', '') + name = defn.get('name', '?') + defn_id = defn.get('id', '?') + + if t_type == 'stdio': + tool = command # npx, uvx, docker, etc. + elif t_type == 'http': + tool = 'http' + else: + tool = '?' + + # Check if filename already has transport suffix + base = f.replace('servers/', '').replace('.json', '') + has_suffix = any(base.endswith(s) for s in ['-npx', '-uvx', '-docker', '-http']) + + servers.append({ + 'branch': branch, + 'file': f, + 'id': defn_id, + 'name': name, + 'transport': t_type, + 'tool': tool, + 'repo': repo, + 'has_suffix': has_suffix, + }) + +# Print grouped by branch +print(f"{'Branch':<25} {'File':<45} {'Tool':<8} {'Has Suffix':<12} {'Repo'}") +print('-' * 160) +for s in servers: + print(f"{s['branch']:<25} {s['file']:<45} {s['tool']:<8} {str(s['has_suffix']):<12} {s['repo']}") + +# Summary: files needing rename (no transport suffix for stdio) +print(f"\n\n=== FILES NEEDING RENAME (no transport suffix) ===") +need_rename = [s for s in servers if not s['has_suffix'] and s['tool'] in ('npx', 'uvx', 'docker')] +for s in need_rename: + suggested = s['file'].replace('.json', f"-{s['tool']}.json") + print(f" {s['branch']}: {s['file']} -> {suggested}") +print(f"\nTotal needing rename: {len(need_rename)}") + +# Unique repos for Docker check +print(f"\n\n=== UNIQUE REPOS TO CHECK FOR DOCKER ===") +repos = sorted(set(s['repo'] for s in servers if s['repo'] and 'github.com' in s['repo'])) +for r in repos: + print(f" {r}") +print(f"\nTotal repos: {len(repos)}") diff --git a/rename_files.py b/rename_files.py new file mode 100644 index 0000000..3f48e7d --- /dev/null +++ b/rename_files.py @@ -0,0 +1,185 @@ +"""Rename server definition files to include transport tool suffix. +Also updates the 'id' and 'name' fields inside each JSON file. +Skips HTTP-only servers (they don't need a suffix since HTTP implies remote). +Skips files that already have the correct suffix. +""" +import json, subprocess, sys, os + +# Files that should NOT get renamed (HTTP-only, no stdio variant, or special cases) +SKIP_BRANCHES = set() +# HTTP servers don't need transport suffix - they use the URL as transport +HTTP_ONLY_FILES = { + 'com.asana-mcp.json', + 'com.clerk-mcp.json', + 'com.cloudflare-observability.json', + 'com.figma-mcp.json', + 'com.honeycomb-mcp.json', + 'io.intercom-mcp.json', + 'io.sanity-mcp.json', + 'com.stytch-mcp.json', + 'com.vercel-mcp.json', + 'town.val-mcp.json', + # These already have proper suffixes + 'com.apify-mcp-http.json', + 'com.linear-mcp-http.json', + 'com.square-mcp-http.json', + 'com.vercel-mcp-http.json', + 'com.mongodb-mcp-npx.json', + 'com.mongodb-mcp-docker.json', +} + +# Special: snyk uses 'snyk' command not npx/uvx/docker +SPECIAL_TOOLS = { + 'com.snyk-mcp.json': 'cli', # snyk cli, not a standard transport +} + +def get_tool_suffix(transport): + """Determine the suffix based on transport command.""" + if transport.get('type') == 'http': + return 'http' + cmd = transport.get('command', '') + if cmd in ('npx', 'uvx', 'docker'): + return cmd + if cmd == 'snyk': + return 'cli' + return cmd if cmd else None + +def run(args, **kwargs): + return subprocess.run(args, capture_output=True, text=True, **kwargs) + +def main(): + os.chdir('d:\\mcpmux\\mcp-servers') + + # Get main files to skip + main_files = set(run(['git', 'ls-tree', '-r', '--name-only', 'main', '--', 'servers/']).stdout.strip().split('\n')) + + branches = run(['git', 'branch', '--list', 'fix/*']).stdout.strip().split('\n') + branches = [b.strip().lstrip('* ') for b in branches if b.strip()] + + results = [] + + for branch in sorted(branches): + if branch in SKIP_BRANCHES: + continue + + # Get new files in this branch + files_out = run(['git', 'ls-tree', '-r', '--name-only', branch, '--', 'servers/']) + if files_out.returncode != 0: + continue + all_files = files_out.stdout.strip().split('\n') + new_files = [f for f in all_files if f not in main_files and f.endswith('.json')] + + if not new_files: + continue + + # Check out branch + co = run(['git', 'checkout', branch]) + if co.returncode != 0: + print(f"SKIP {branch}: checkout failed") + continue + + changed = False + renames = [] + + for f in new_files: + basename = os.path.basename(f) + + if basename in HTTP_ONLY_FILES: + continue + + # Check if already has suffix + name_no_ext = basename.replace('.json', '') + if any(name_no_ext.endswith(s) for s in ['-npx', '-uvx', '-docker', '-http', '-cli']): + continue + + # Read and parse + try: + with open(f) as fh: + defn = json.load(fh) + except: + print(f"SKIP {branch}/{basename}: can't parse") + continue + + transport = defn.get('transport', {}) + suffix = get_tool_suffix(transport) + + if not suffix: + print(f"SKIP {branch}/{basename}: unknown tool") + continue + + # For HTTP-only servers (no stdio), skip suffix + if suffix == 'http' and basename not in HTTP_ONLY_FILES: + # This is an HTTP file paired with a stdio variant - already has -http suffix check above + continue + + # Compute new filename and id + new_basename = name_no_ext + f'-{suffix}.json' + new_path = f'servers/{new_basename}' + new_id = defn['id'] + f'-{suffix}' + + # Update name to include tool + old_name = defn.get('name', '') + suffix_label = suffix.upper() if suffix == 'uvx' else suffix + if suffix == 'npx': + new_name = f"{old_name} (npx)" + elif suffix == 'uvx': + new_name = f"{old_name} (uvx)" + elif suffix == 'docker': + new_name = f"{old_name} (Docker)" + elif suffix == 'cli': + new_name = f"{old_name} (CLI)" + else: + new_name = old_name + + # Update definition + defn['id'] = new_id + defn['name'] = new_name + + with open(f, 'w') as fh: + json.dump(defn, fh, indent=2) + fh.write('\n') + + # Git mv + mv = run(['git', 'mv', f, new_path]) + if mv.returncode != 0: + print(f"ERROR {branch}: git mv {f} -> {new_path} failed: {mv.stderr}") + continue + + renames.append((basename, new_basename, new_id)) + changed = True + + if changed: + # Stage and commit + run(['git', 'add', '-A']) + msg = f"fix: rename server files with transport suffix\n\n" + for old, new, nid in renames: + msg += f"- {old} -> {new} (id: {nid})\n" + + commit = run(['git', 'commit', '-s', + '--author=Mohammod Al Amin Ashik ', + '-m', msg]) + if commit.returncode != 0: + print(f"ERROR {branch}: commit failed: {commit.stderr}") + continue + + # Push + push = run(['git', 'push', 'origin', branch]) + if push.returncode != 0: + print(f"ERROR {branch}: push failed: {push.stderr}") + continue + + for old, new, nid in renames: + print(f"OK {branch}: {old} -> {new}") + results.append((branch, old, new)) + else: + # Nothing to rename in this branch + pass + + # Switch back to main + run(['git', 'checkout', 'main']) + + print(f"\n=== SUMMARY ===") + print(f"Renamed {len(results)} files across {len(set(r[0] for r in results))} branches") + +if __name__ == '__main__': + main() diff --git a/servers/community.1password.json b/servers/community.1password-npx.json similarity index 97% rename from servers/community.1password.json rename to servers/community.1password-npx.json index 6b87534..49ecc62 100644 --- a/servers/community.1password.json +++ b/servers/community.1password-npx.json @@ -1,7 +1,7 @@ { "$schema": "../schemas/server-definition.schema.json", - "id": "community.1password", - "name": "1Password", + "id": "community.1password-npx", + "name": "1Password (npx)", "alias": "1password", "description": "Access secrets from 1Password vaults. List vaults, retrieve items, and search for credentials using a service account token.", "icon": "https://avatars.githubusercontent.com/u/38230737?v=4", From 280a3fe8459e7e0d53a1cb2a5f09338f0ecddfde Mon Sep 17 00:00:00 2001 From: Mohammod Al Amin Ashik Date: Thu, 19 Feb 2026 22:47:12 +0800 Subject: [PATCH 4/4] fix: use GitHub org as ID domain for community definitions - community.1password-npx -> cakerepository.1password-mcp-npx Signed-off-by: Mohammod Al Amin Ashik --- fix_ids.py | 124 ++++++++++++++++++ ... => cakerepository.1password-mcp-npx.json} | 2 +- 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 fix_ids.py rename servers/{community.1password-npx.json => cakerepository.1password-mcp-npx.json} (98%) diff --git a/fix_ids.py b/fix_ids.py new file mode 100644 index 0000000..393afb8 --- /dev/null +++ b/fix_ids.py @@ -0,0 +1,124 @@ +""" +Fix definition IDs: +- Community-driven definitions: use GitHub org as domain (e.g., crystaldba.postgres-mcp-uvx) +- Official vendor definitions: keep current domain (com.redis-mcp, com.mongodb-mcp, etc.) +- Ensure all IDs match filename pattern + +Rules: +- If contributor.github matches the repo org AND it's not a major vendor domain (com., io., etc.), + use the GitHub org: githubuser.servername-tool +- For modelcontextprotocol/servers, keep "community." prefix +- For official vendor repos (company.com domains), keep existing convention +""" +import json, subprocess, re, os + +os.chdir('d:\\mcpmux\\mcp-servers') + +main_files = set(subprocess.check_output( + ['git', 'ls-tree', '-r', '--name-only', 'main', '--', 'servers/'], + text=True +).strip().split('\n')) + +branches = subprocess.check_output(['git', 'branch', '--list', 'fix/*'], text=True).strip().split('\n') +branches = [b.strip().lstrip('* ') for b in branches if b.strip()] + +# Map of current file -> what the ID SHOULD be based on repo org +# community.* prefix servers that should use github org instead +COMMUNITY_REMAP = { + # crystaldba/postgres-mcp -> crystaldba.postgres-mcp-uvx + 'community.postgresql-uvx': 'crystaldba.postgres-mcp-uvx', + # domdomegg/airtable-mcp-server -> domdomegg.airtable-mcp-npx + 'community.airtable-npx': 'domdomegg.airtable-mcp-npx', + # ThetaBird/mcp-server-axiom-js -> thetabird.axiom-mcp-npx + 'community.axiom-npx': 'thetabird.axiom-mcp-npx', + # orellazri/coda-mcp -> orellazri.coda-mcp-npx + 'community.coda-npx': 'orellazri.coda-mcp-npx', + # aashari/mcp-server-atlassian-jira -> aashari.jira-mcp-npx + 'community.jira-npx': 'aashari.jira-mcp-npx', + # CakeRepository/1Password-MCP -> cakerepository.1password-mcp-npx + 'community.1password-npx': 'cakerepository.1password-mcp-npx', + # modelcontextprotocol/servers - these stay community.* + # 'community.fetch-uvx': keep as is + # 'community.memory-npx': keep as is + # 'community.sequential-thinking-npx': keep as is + # 'community.google-maps-npx': keep as is + # 'community.gitlab-npx': keep as is +} + +results = [] + +for branch in sorted(branches): + files_out = subprocess.run( + ['git', 'ls-tree', '-r', '--name-only', branch, '--', 'servers/'], + capture_output=True, text=True + ) + if files_out.returncode != 0: + continue + + all_files = files_out.stdout.strip().split('\n') + new_files = [f for f in all_files if f not in main_files and f.endswith('.json')] + + if not new_files: + continue + + # Check if any file needs ID remap + needs_fix = False + for f in new_files: + basename = os.path.basename(f).replace('.json', '') + if basename in COMMUNITY_REMAP: + needs_fix = True + break + + if not needs_fix: + continue + + # Checkout + subprocess.run(['git', 'checkout', branch], capture_output=True, text=True) + + changed = False + renames_done = [] + + for f in new_files: + basename = os.path.basename(f).replace('.json', '') + if basename not in COMMUNITY_REMAP: + continue + + new_id = COMMUNITY_REMAP[basename] + new_filename = f"servers/{new_id}.json" + + # Read and update + with open(f) as fh: + defn = json.load(fh) + + old_id = defn['id'] + defn['id'] = new_id + + with open(f, 'w') as fh: + json.dump(defn, fh, indent=2) + fh.write('\n') + + # Git mv + subprocess.run(['git', 'mv', f, new_filename], capture_output=True, text=True) + renames_done.append((basename, new_id, old_id)) + changed = True + + if changed: + subprocess.run(['git', 'add', '-A'], capture_output=True, text=True) + msg = "fix: use GitHub org as ID domain for community definitions\n\n" + for old, new, old_id in renames_done: + msg += f"- {old_id} -> {new}\n" + + subprocess.run([ + 'git', 'commit', '-s', + '--author=Mohammod Al Amin Ashik ', + '-m', msg + ], capture_output=True, text=True) + + push = subprocess.run(['git', 'push', 'origin', branch], capture_output=True, text=True) + for old, new, old_id in renames_done: + status = "OK" if push.returncode == 0 else "PUSH_FAIL" + print(f"{status} {branch}: {old_id} -> {new}") + results.append((branch, old_id, new)) + +subprocess.run(['git', 'checkout', 'main'], capture_output=True, text=True) +print(f"\n=== Fixed {len(results)} community definition IDs ===") diff --git a/servers/community.1password-npx.json b/servers/cakerepository.1password-mcp-npx.json similarity index 98% rename from servers/community.1password-npx.json rename to servers/cakerepository.1password-mcp-npx.json index 49ecc62..5e2afe0 100644 --- a/servers/community.1password-npx.json +++ b/servers/cakerepository.1password-mcp-npx.json @@ -1,6 +1,6 @@ { "$schema": "../schemas/server-definition.schema.json", - "id": "community.1password-npx", + "id": "cakerepository.1password-mcp-npx", "name": "1Password (npx)", "alias": "1password", "description": "Access secrets from 1Password vaults. List vaults, retrieve items, and search for credentials using a service account token.",