github/parse_url
Extract and validate owner, repository name, and path details from any GitHub URL for accurate repository parsing and integration workflows.
Instructions
Parses a GitHub URL to extract owner, repository name, and additional path information with validation
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | GitHub URL to parse (e.g., 'https://github.com/microsoft/vscode' or 'https://github.com/facebook/react/tree/main/packages') |
Implementation Reference
- src/server.ts:150-191 (handler)The main handler function that executes the tool logic: parses the GitHub URL, validates repository status, constructs result object, and returns formatted JSON string based on validation outcome.
export const parseGitHubUrlTool = async (args: { url: string }) => { const parsed = parseGitHubUrl(args.url); const validation = await validateRepository(parsed.owner, parsed.repo); const result = { owner: parsed.owner, repo: parsed.repo, status: validation.status, url: `https://github.com/${parsed.owner}/${parsed.repo}`, ...(parsed.path && { additionalPath: parsed.path }), }; switch (validation.status) { case "error": { const errorInfo = validation.error ? ` (${validation.error})` : ""; return JSON.stringify({ ...result, accessible: false, error: `Unable to verify repository${errorInfo}`, }); } case "not_found": return JSON.stringify({ ...result, accessible: false, warning: "Repository does not exist", }); case "private": return JSON.stringify({ ...result, accessible: false, note: "Repository exists but is private", }); case "public": return JSON.stringify({ ...result, accessible: true, }); default: return JSON.stringify(result); } }; - src/server.ts:229-236 (schema)Zod schema defining the input parameters for the tool: a single 'url' string that must be a valid URL with description.
parameters: z.object({ url: z .string() .url("Must be a valid URL") .describe( "GitHub URL to parse (e.g., 'https://github.com/microsoft/vscode' or 'https://github.com/facebook/react/tree/main/packages')", ), }), - src/server.ts:219-237 (registration)Registers the 'github/parse_url' tool with FastMCP server, specifying name, description, annotations, input schema, and handler function.
server.addTool({ annotations: { openWorldHint: false, // No external system interaction beyond validation readOnlyHint: true, // Does not modify any data title: "Parse GitHub URL", }, description: "Parses a GitHub URL to extract owner, repository name, and additional path information with validation", execute: parseGitHubUrlTool, name: "github/parse_url", parameters: z.object({ url: z .string() .url("Must be a valid URL") .describe( "GitHub URL to parse (e.g., 'https://github.com/microsoft/vscode' or 'https://github.com/facebook/react/tree/main/packages')", ), }), }); - src/server.ts:81-115 (helper)Helper function that performs the core URL parsing: extracts owner, repo, and optional additional path from the GitHub URL pathname, with validation for format and domain.
const parseGitHubUrl = ( urlString: string, ): { owner: string; path?: string; repo: string } => { let url: URL; try { url = new URL(urlString); } catch { throw new Error("Invalid URL format"); } if (url.hostname !== "github.com") { throw new Error("URL must be from github.com domain"); } const pathParts = url.pathname.slice(1).split("/").filter(Boolean); if (pathParts.length < 2) { throw new Error( "URL must contain both owner and repository name (e.g., https://github.com/owner/repo)", ); } const [owner, repo, ...remainingPath] = pathParts; if (!owner || !repo) { throw new Error("Invalid owner or repository name in URL"); } return { owner, path: remainingPath.length > 0 ? remainingPath.join("/") : undefined, repo, }; }; - src/server.ts:13-76 (helper)Helper function that validates repository existence and accessibility using HEAD requests to GitHub, distinguishing between not found, private, public, and errors with timeout handling.
const validateRepository = async ( owner: string, repo: string, ): Promise<{ error?: string; exists: boolean; isPrivate?: boolean; status: "error" | "not_found" | "private" | "public"; }> => { try { const response = await fetch(`https://github.com/${owner}/${repo}`, { method: "HEAD", // Add timeout to prevent hanging signal: AbortSignal.timeout(5000), }); if (response.status === 200) { return { exists: true, isPrivate: false, status: "public", }; } else if (response.status === 404) { // 404 can mean either the repo doesn't exist or it's private // Try to access the owner's profile to distinguish const ownerResponse = await fetch(`https://github.com/${owner}`, { method: "HEAD", signal: AbortSignal.timeout(5000), }); if (ownerResponse.status === 200) { // Owner exists, so the repo is likely private return { exists: true, isPrivate: true, status: "private", }; } else { // Owner doesn't exist, so repo doesn't exist return { exists: false, status: "not_found", }; } } else { // Other status codes (403, 500, etc.) return { error: `HTTP ${response.status}`, exists: false, status: "error", }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; return { error: errorMessage.includes("timeout") ? "Request timeout" : "Network error", exists: false, status: "error", }; } };