generate-server-card
$
npx mdskill add agentic-community/mcp-gateway-registry/generate-server-cardExtract MCP server metadata from code or GitHub URLs
- Converts complex multi-file server projects into registry-ready JSON
- Scans Python files, configs, and OpenAPI specs for tool definitions
- Identifies server name, transport, auth, and tools via code analysis
- Outputs standardized mcp-gateway-registry format for gateway registration
SKILL.md
.github/skills/generate-server-cardView on GitHub ↗
---
name: generate-server-card
description: Generate an MCP server card JSON (mcp-gateway-registry format) by analyzing server source code in a folder or GitHub URL. Studies code to detect server name, tools, transport, auth, and generates a registry-compatible config.
argument-hint: "[folder-path-or-github-url]"
disable-model-invocation: true
---
# Generate MCP Server Card
Generate an MCP server card JSON file in the mcp-gateway-registry format by analyzing the source code at `$ARGUMENTS`.
This format is used by https://github.com/agentic-community/mcp-gateway-registry for registering MCP servers in the gateway registry.
## Steps
### 1. Carefully study the source code
Do NOT just skim the top-level files. MCP servers can be complex, multi-file projects. You MUST thoroughly explore the entire folder structure before generating the card.
If `$ARGUMENTS` is a local folder path, use Glob to find ALL Python files, YAML/JSON configs, and README files in the folder and its subfolders. Read every relevant file.
If `$ARGUMENTS` is a GitHub URL, use `WebFetch` to read the raw file contents. Follow imports to discover additional files.
**Where to look** (MCP servers are not always a single file):
- **Entrypoints**: `main.py`, `app.py`, `server.py`, `__main__.py`, `mcp_server.py`
- **Tool definitions**: look for `@mcp.tool()`, `@server.tool()`, `@tool`, tool handler functions, tool registrations
- **OpenAPI specs**: `.json` or `.yaml` files in `openapi-specs/`, `specs/`, `api/` folders - these define the tools when an API is exposed as MCP
- **Config files**: `pyproject.toml`, `requirements.txt`, `.bedrock_agentcore.yaml`, `deploy_*.py`, `docker-compose.yml`
- **Deployment scripts**: these reveal the gateway URL, auth scheme, transport type
- **Gateway configs**: `.deployment_info.json`, `.roo.json` - these have the actual MCP endpoint URL
- **Sub-folders**: check ALL subdirectories for additional tools, resources, or shared utilities
- **Resource definitions**: MCP servers can expose resources and prompts in addition to tools
From the code, detect:
- **Server name**: from constants, config files, class names, gateway name
- **Description**: from docstrings, README, module-level comments, OpenAPI spec info
- **Tools**: from `@tool` decorators, tool registrations, OpenAPI operationIds, function definitions
- **Tool schemas**: parameter types, required fields, descriptions from function signatures or OpenAPI specs
- **Supported transports**: `streamable-http`, `sse`, `stdio` - from server framework config
- **Auth scheme**: `none`, bearer JWT, API key, OAuth2, Cognito - from deployment scripts or middleware
- **MCP endpoint URL**: from deployment info, gateway URL, or config files
- **Proxy pass URL**: the backend URL the gateway proxies to (may differ from the MCP endpoint)
- **Version**: from constants, pyproject.toml, or default to `1.0.0`
- **Provider info**: organization name and URL if detectable
- **License**: from pyproject.toml or LICENSE file
- **Status**: `active`, `beta`, etc.
### 2. Generate the server card JSON
Create a JSON file following the mcp-gateway-registry server config format.
#### Required fields
```json
{
"server_name": "string - Human-readable server name",
"description": "string - What the server does",
"path": "string - URL path prefix on the gateway, must start with /",
"proxy_pass_url": "string - Backend URL to proxy to",
"tags": ["string - Relevant tags for discovery"],
"supported_transports": ["streamable-http"]
}
```
#### Recommended optional fields (include when detected)
```json
{
"auth_scheme": "string - none, bearer, api_key, oauth2",
"mcp_endpoint": "string - Custom MCP endpoint URL if different from proxy_pass_url",
"version": "string - Server version e.g. 1.0.0",
"status": "string - active, beta, deprecated",
"visibility": "string - public or private",
"provider_organization": "string - Organization name",
"provider_url": "string - Organization URL",
"num_tools": 0,
"license": "string - License identifier e.g. MIT, Apache-2.0",
"metadata": {
"category": "string - e.g. documentation, geolocation, utility",
"official": false,
"mcp_compatible": "1.0"
},
"tool_list": []
}
```
### 3. Do NOT populate tool_list
- Always set `"tool_list": []` (empty array)
- Do NOT add individual tool entries to tool_list - leave it empty
- Still count the tools and set `num_tools` to the correct count (for informational purposes)
- The tool details are intentionally omitted from the server card
### 4. Set the path
- The `path` must start with `/`
- Use the gateway name or a short descriptive slug, e.g. `/geo-mcp`, `/cloudflare-docs`
- Check `.deployment_info.json` for the gateway name if available
### 5. Set the proxy_pass_url and mcp_endpoint
- Check for `.deployment_info.json`, `.roo.json`, or `.bedrock_agentcore.yaml` for the actual deployed URL
- `proxy_pass_url`: the backend URL the gateway proxies to
- `mcp_endpoint`: the full MCP endpoint URL that clients connect to (if different from proxy_pass_url)
- If no deployment info found, use placeholder: `https://<GATEWAY_URL>/mcp`
### 6. Detect transport type
- `streamable-http`: most common for remote MCP servers, HTTP-based
- `sse`: Server-Sent Events based transport
- `stdio`: local process communication (not for remote servers)
- Default to `["streamable-http"]` for gateway-deployed servers
### 7. Detect auth scheme
- Cognito JWT / bearer token: `"bearer"` or describe as `"custom_jwt"`
- API key: `"api_key"`
- No auth: `"none"`
- Check deployment scripts for `authorizerType`, `customJWTAuthorizer`, bearer token usage
### 8. Save the output
- Name the file `{server_name}_server_card.json` using the detected server name in snake_case
- Save it in the server's folder (same folder as the source code)
- Pretty-print with 2-space indentation
### 9. Validate the generated JSON
After writing the file, validate it by running this Python script via Bash:
```bash
python3 -c "
import json
import sys
file_path = '<OUTPUT_FILE_PATH>'
# Step 1: JSON format check
try:
with open(file_path) as f:
card = json.load(f)
print('PASS: Valid JSON format')
except json.JSONDecodeError as e:
print(f'FAIL: Invalid JSON - {e}')
sys.exit(1)
# Step 2: Required fields
errors = []
REQUIRED = ['server_name', 'description', 'path', 'proxy_pass_url', 'tags', 'supported_transports']
for field in REQUIRED:
if field not in card:
errors.append(f'Missing required field: {field}')
elif field in ('server_name', 'description', 'path', 'proxy_pass_url') and not isinstance(card[field], str):
errors.append(f'{field} must be a string')
elif field in ('tags', 'supported_transports') and not isinstance(card[field], list):
errors.append(f'{field} must be an array')
# Step 3: Path must start with /
if 'path' in card and isinstance(card['path'], str) and not card['path'].startswith('/'):
errors.append('path must start with /')
# Step 4: proxy_pass_url must be a valid URL
if 'proxy_pass_url' in card and isinstance(card['proxy_pass_url'], str):
if not card['proxy_pass_url'].startswith(('http://', 'https://')):
errors.append('proxy_pass_url must start with http:// or https://')
# Step 5: tags must be non-empty
if not card.get('tags'):
errors.append('tags must have at least one entry')
# Step 6: supported_transports must be non-empty
if not card.get('supported_transports'):
errors.append('supported_transports must have at least one entry')
valid_transports = ['streamable-http', 'sse', 'stdio']
for t in card.get('supported_transports', []):
if t not in valid_transports:
errors.append(f'Unknown transport: {t}, must be one of {valid_transports}')
# Step 7: Validate tool_list is an empty array
if 'tool_list' in card:
if not isinstance(card['tool_list'], list):
errors.append('tool_list must be an array')
elif len(card['tool_list']) > 0:
errors.append('tool_list must be empty ([]) - do not populate individual tool entries')
# Step 8: num_tools must be present and a non-negative integer
if 'num_tools' in card:
if not isinstance(card['num_tools'], int) or card['num_tools'] < 0:
errors.append('num_tools must be a non-negative integer')
# Step 9: Report results
if errors:
print(f'FAIL: {len(errors)} validation error(s):')
for e in errors:
print(f' - {e}')
sys.exit(1)
else:
tool_count = len(card.get('tool_list', []))
transport_count = len(card.get('supported_transports', []))
print(f'PASS: All required fields present ({tool_count} tool(s), {transport_count} transport(s))')
"
```
Replace `<OUTPUT_FILE_PATH>` with the actual path of the generated JSON file.
If validation fails, fix the errors in the JSON and re-run validation until all checks pass. Do NOT report success to the user until validation passes.
### 10. Report results
After validation passes, output results in EXACTLY this format:
```
Validation passed. Here's a summary of the generated server card:
Output file: <filename>.json
Detected from code:
- Server name: <ServerName> (from <how it was detected>)
- Tools: <count> - <tool_name> (<brief description>), ...
- Transport: <streamable-http|sse|stdio> (<why>)
- Auth: <none|bearer|api_key|oauth2> (<details>)
- MCP endpoint: <URL or placeholder>
- Proxy pass URL: <URL or placeholder>
- Status: <active|beta>
- Provider: <org name> or <not detected>
```
If validation fails, show the errors first, fix them, re-validate, and only show the summary above after all checks pass.
## Reference: Minimal server card
```json
{
"server_name": "Minimal MCP Server",
"description": "A minimal server configuration with only required fields",
"path": "/minimal-server",
"proxy_pass_url": "http://minimal-server:9001/",
"supported_transports": ["streamable-http"],
"tags": ["mcp", "minimal", "example"]
}
```
## Reference: Full server card with tools
```json
{
"server_name": "Geolocation MCP Server",
"description": "IP geolocation lookup via ipwho.is, deployed on Amazon Bedrock AgentCore Gateway with Cognito JWT auth",
"path": "/geo-mcp",
"proxy_pass_url": "https://geo-mcp-abc123.gateway.bedrock-agentcore.us-east-1.amazonaws.com/mcp",
"supported_transports": ["streamable-http"],
"auth_scheme": "bearer",
"tags": ["geolocation", "ip-lookup", "aws", "bedrock-agentcore"],
"num_tools": 1,
"version": "1.0.0",
"status": "active",
"visibility": "public",
"provider_organization": "AWS",
"provider_url": "https://aws.amazon.com",
"license": "MIT",
"metadata": {
"category": "geolocation",
"official": false,
"mcp_compatible": "1.0"
},
"tool_list": []
}
```
More from agentic-community/mcp-gateway-registry
- agentcore-registerGiven an MCP server URL, probe the server via curl to discover its metadata and tools, then generate a markdown file with copy-pasteable content for each field in the Amazon Bedrock AgentCore "Create record" form.
- create-milestoneCreate a GitHub milestone for an upcoming release. Suggests the next version based on the latest release, gathers all merged PRs and closed issues since that release, presents a draft with two tables (Issues and PRs) for user approval, then creates the milestone and assigns all approved items.
- generate-agent-cardGenerate an A2A agent card JSON by analyzing agent source code in a folder or GitHub URL. Studies the code to detect agent name, skills, tools, auth, protocol, and generates a spec-compliant agent card.
- macos-setupComplete macOS setup and teardown for MCP Gateway & Registry (AI-registry). Clones the repository, installs all services, configures Keycloak auth, registers the Cloudflare docs server, and verifies the full stack. Also supports complete teardown. Can be run directly from its GitHub URL without the repository already cloned. Uses an interactive or default-values mode chosen at startup.
- new-feature-designDesign and document new features with GitHub issue, low-level design (LLD), expert review, and testing plan. Creates structured documentation in .scratchpad/ with issue spec, technical design with diagrams and pseudo-code, multi-persona expert review, and a testing plan covering functional (curl and registry_management.py), backwards-compatibility, UX, ECS/terraform, and E2E API tests. Supports starting from a user description OR an existing GitHub issue URL. Folder naming: issue-{number}/ for existing issues, {feature-name}/ for new features.
- release-notesCreate release notes for a new version tag. Gathers all commits, PRs, issues fixed, and breaking changes since a previous release. Creates the release notes markdown file, tags the repo, and pushes. Asks the user to confirm the base version to diff against.
- usage-reportGenerate a usage report for MCP Gateway Registry by SSHing into the telemetry bastion host, exporting telemetry data from DocumentDB, and producing a formatted markdown report with deployment insights.