GitHub

Lightweight, dependency-free, in-memory GitHub REST v3 + GraphQL API fake for testing code that uses @octokit/rest, the gh CLI, or the raw GitHub REST/GraphQL API.

Default port: 4767

Quick start

Start the server:

import { GithubServer } from "./services/github/src/server.js";

const server = new GithubServer(4767);
await server.start();
// ... run your app/tests ...
await server.stop();

Point Octokit at it via baseUrl:

import { Octokit } from "@octokit/rest";

const octokit = new Octokit({
  auth: "ghp_parlel",
  baseUrl: "http://127.0.0.1:4767",
});

const { data } = await octokit.rest.users.getAuthenticated();
// data.login => "parlel-user"

Access via MCP / preview URL

Expose the running fake through the parlel pool and address it like the real API:

Any MCP server or agent that reads GITHUB_API_URL / GITHUB_TOKEN will transparently use the fake.

Implemented operations

All routes require an Authorization: Bearer <token> or Authorization: token <token> header (any non-empty token is accepted). State is in-memory and ephemeral.

REST v3

GraphQL

Service & inspection operations (parlel extensions)

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
GET /user✅ Supported
Repos create (POST /user/repos) / get / patch / list✅ Supported
POST /repos/:owner/:repo returns 404 (no create-by-path endpoint)✅ Supported (matches real API)
Issues create / get / list / patch (full shape incl. reactions, author_association, state_reason)✅ Supported
open_issues_count tracked on issue close / reopen✅ Supported
Pull requests create / get / list / patch✅ Supported
Contents get / put (base64, requires message + content; content._links + rich commit)✅ Supported
GraphQL viewer + repository✅ Supported (subset)
Bearer / token auth✅ Required (any non-empty token)
Repo/user *_url template fields (language, size, topics)◐ Partial — core fields present; some template URLs omitted
List pagination / state filter query params (per_page, page, state)◐ Accepted-not-enforced — accepted, full dataset returned
Full GraphQL schema (mutations, connections, pagination)⟳ Roadmap — Only viewer + repository basics
Webhooks / Actions / Checks / Releases⟳ Roadmap
Real OAuth / scope enforcement✓ By design — Any non-empty credential is accepted — no real secrets needed
Rate limiting (403/429)✓ By design — Never throttles — local tests run at full speed, zero cost

Error codes & shapes

Errors use the GitHub envelope:

{ "message": "Validation Failed", "documentation_url": "https://docs.github.com/rest", "errors": [ ... ] }
StatusWhen
400malformed JSON body ({ "message": "Problems parsing JSON" })
401missing/invalid authorization ({ "message": "Requires authentication" })
404unknown resource, or POST /repos/:owner/:repo (no such endpoint)
405method not allowed (issues/pulls/contents sub-routes)
422validation failed — missing name/title, duplicate repo, or PUT contents missing message/content. Carries an errors array of { resource, field, code } for repo/issue validation.

Manifest

See services/github/manifest.json:

<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

GITHUB_TOKEN=ghp_parlel
GITHUB_API_URL=http://parlel-bridge:4767
<!-- parlel:testenv:end -->