A close-up portrait of a man with a salt-and-pepper beard wearing a white collared shirt against a textured beige background.
A close-up portrait of a man with a salt-and-pepper beard wearing a white collared shirt against a textured beige background.

API keys, the SDK, and MCP from one spec

Jesse James Richard
|
Mar 1, 2026
|
6 min read
#APIs & MCP
#Access Control
#Signature

Everything a customer can do by clicking in the console, they can do from a script. That is not a bonus feature bolted onto Giant Context. It was a core objective of the system day one. To do MCP I needed an API, and to do an API I needed auth. Once that was done, the entire platform was available programmatically.

A developer goes from an empty terminal to a working, permission-checked API call, and there is barely any trick to it.

The key

Access starts with a key, created in settings, and there are two kinds because there are two questions a key can answer.

A personal API key acts as you. It carries your exact permissions, no more, and it is for automating your own work. If you are a viewer in an organization, your personal key is a viewer there too.

A service key belongs to the organization itself, with its own scoped permissions granted like any other member's. It is for automation that outlives any one person, the nightly sync that should keep running after the developer who wrote it changes jobs. It is the organization's own hands, not a borrowed pair.

Same permission model underneath both. A key is a principal, exactly like a human is a principal, and it holds a role. The only difference is whether the principal is a person or the org.

The create service account dialog, with fields for name, description, an organization role, and per-project access.
Creating a service account. It takes a role and project access, exactly like a member does.

Using the SDK

The key is a bearer token, so a hand-built request works. The key's real job is powering the SDK:

The SDK, from key to call

import { createGiantContext } from "@giantcontext/sdk";
const gc = createGiantContext({ apiKey: "gct_..." });
const orgs = await gc.organizations.getOrganizations();const project = await gc.projects.getProject({  id: "org-id",  projectId: "project-id",});

Every SDK has autocomplete. What is different here is that gc.email, gc.crm, gc.kb, one property per domain, are not a wrapper I hand-wrote around the API and now maintain by hand. Nobody wrote them. They fall out of the API's own description.

Where the SDK comes from

I did not write that SDK. It is generated.

The API describes itself in an OpenAPI specification, and generators turn that description into the SDK, in both TypeScript and Python, every time the API changes. Each operation carries flags in its description that decide who it is for. One flag marks an operation as part of the SDK. Another marks it as part of the MCP tool surface, the set of tools an AI agent is allowed to call.

That second flag is why any of this exists. The API was not built so developers could script the platform. It was built so an AI agent could operate it, and an agent needs a described, permission-checked API to act through. Building that API for the agent produced, from the identical specification read through a different filter, an SDK for humans. One description becomes three things. The console's typed client, the developer's SDK, and the toolbox an agent uses on a customer's behalf. The SDK was almost a side effect of teaching the platform to describe itself well enough for a machine to use it.

So programmatic access is first-class here for a structural reason, not a virtuous one. A hand-maintained API rots the week feature work gets busy. An API that materializes from the same schema the console uses cannot fall behind the console, because it is the console's source read one filter over.

The call crosses the same gates

The developer runs their script. The SDK attaches the key and sends the request, and from the server's point of view nothing about this request is special.

It hits the same authentication the console's requests hit. The key resolves to its principal, a person or the org. The request crosses the same permission gates, checked against the same tables, and a call the key's role is not allowed to make fails exactly as a forbidden click fails. The same audit trail records it, stamped with which key did it.

1

API key

a caller presents a key

2

Authentication

resolves to a principal

3

Same gates

the same permission checks run

4

Allowed or denied

decided, and written to the audit trail

1

API key

a caller presents a key

2

Authentication

resolves to a principal

3

Same gates

the same permission checks run

4

Allowed or denied

decided, and written to the audit trail

There is no second, weaker permission system for machines. Most breaches through an API are not clever. They are a company that built a real permission model for its UI and a hopeful one for its API. Here there is one model.

Wiring this up yourself

If you are giving customers programmatic access, three decisions carry most of the value.

Make keys principals in your existing permission model, not a parallel one. A key holds a role. Personal keys act as their user, organization keys act as the org. Reuse the RBAC you already built for humans, because a second permission system is a second thing to get wrong.

Generate the SDK from your API description, do not hand-write it. A hand-written SDK is perpetually one release behind your API. A generated one ships with the endpoint that spawned it. If your API already describes itself, the SDK is nearly free.

And make the key the whole setup. Plop in a key, get a typed client, call the backend. Every step you add between a developer's key and their first successful call is a step where you lose the developer. The best API onboarding is three lines, and two of them are the import.

The same app, four times

#Architecture
#Signature

This week I got the Giant Context console running as a native desktop app, then stopped without shipping it. API-first design means every surface is a...

Jesse James Richard

|

Feb 28, 2026
Read previous

Building something like this

I'm Jesse. I build platforms end to end, and I'm open to work. If this is the kind of engineering you need, get in touch.

Contact Jesse
Home
About
Contact
Sitemap
Privacy Policy
Terms of Service
Cookie Policy

Some posts on this site may be updated on occasion.

API keys, the SDK, and MCP from one spec | Jesse James Richard