Skip to main content
Glama

Gulpy

One login for all your AI plugins.

Each AI agent has its own list of plugins. You connect the same tools again in each one. Gulpy is one place for your connections. You say "connect to Gulpy" to an agent, tap Allow one time, and the agent calls all your tools with plain HTTP and one key. Gulpy has no MCP server for agents.

"Plug", read from right to left, is "gulp". The mascot is a plug that eats tools.

The site

Your tools

Landing

My tools

The screenshots are from before 2026-10-03. The "Add Gulpy to an agent" panel changed since then.

The name is in one file: src/brand.ts. The folder and the key labels keep the first name, "connecty".

Run it

You need Bun 1.3 or later.

bun install
bun run dev

Address

What it is

http://localhost:4000

Gulpy: the site, your tools, the Allow page, the API for agents

http://localhost:4500

Orbit, an agent to try Gulpy with. It knows the Gulpy address only.

http://localhost:4600

Scout, a second agent

Gulpy has no fake data. The tools are the real connectors in the list.

Do these steps:

  1. Open Gulpy. Sign in with an email address. On this computer no mail goes out, so the page fills in the code.

  2. Select + on a tool, for example Notion or Linear. You sign in at the provider.

  3. Open Orbit. Select Connect with Gulpy. A Gulpy window opens. Tap Allow. Orbit takes its key (the device flow, as in /agents.md).

  4. Ask Orbit a question about your tools.

  5. Open Scout. Connect it. Add a new tool in Gulpy: Orbit and Scout get it.

  6. Open Gulpy. You see the agents and each call. Remove the access of one agent.

Orbit and Scout think with the claude command of this computer, with your Claude account. Each question uses a small part of your Claude plan. If the command is not on the computer, the agents show a list of tools that you can run.

Related MCP server: nice

Add Gulpy to a real agent

An agent on your computer: "Connect to Gulpy"

Say this to Claude Code, Codex, Cursor or any agent that can run commands:

Connect to Gulpy. Read https://app.gulpy.ai/agents.md and follow it.

The agent runs curl -fsSL https://app.gulpy.ai/connect.sh | sh. A browser window opens with a code. You sign in and tap Allow one time. The agent saves one key in ~/.config/gulpy/key and calls all your tools with plain HTTP:

curl https://app.gulpy.ai/v1/tools -H "Authorization: Bearer $(cat ~/.config/gulpy/key)"
curl -X POST https://app.gulpy.ai/v1/tools/email_search -H "Authorization: Bearer $(cat ~/.config/gulpy/key)" \
  -H "Content-Type: application/json" -d '{"query": "invoice"}'

The key reaches each tool, also the tools that you add later. It does not expire. Remove the agent on My tools to stop it. The sign-in is the device authorization grant (RFC 8628): POST /device/code, the page /device, POST /device/token. The one tap stays on purpose: anyone can ask for a code and send you the link.

An agent that can send web requests but not run commands

It follows case B of /agents.md: POST /device/code, sends you the link, you tap Allow, and it collects the key with POST /device/token.

An agent that can do neither (the ChatGPT, Claude and Grok chat apps) cannot use Gulpy. Gulpy has no MCP server. For an agent in the cloud, Gulpy needs a public https address: set GULPY_BASE_URL to it.

Real connectors

The list has 63 real connectors. On 2026-09-29 each MCP address answered with its sign-in metadata.

Group

Count

What you must do

Register automatically

25

Nothing. Select +. Notion, Linear, Atlassian, Stripe, Vercel, Supabase, Canva, Higgsfield and others.

Need an app that you register at the provider

7

GitHub, Slack, HubSpot, Asana, Box, Render, Figma. The list shows them as "Soon".

Use the API of the provider, with Gulpy tools (Beta)

2

Google (Gmail, Calendar, Drive) and Microsoft (Outlook, Calendar, OneDrive). One sign-in each. Register one Google app and one Microsoft app (table below).

Check the list against the real servers:

bun run scripts/check-catalog.ts              # reads public metadata only
bun run scripts/check-catalog.ts --register   # also registers Gulpy where the server permits it

Credentials for the connectors that need an app. Put them in the environment, or in the macOS Keychain for development.

Connector

Environment

Redirect address to register

GitHub, Slack, HubSpot, Asana, Box, Render, Figma

CONNECTOR_<NAME>_CLIENT_ID, CONNECTOR_<NAME>_CLIENT_SECRET

<base>/oauth/callback/mcp

Google

GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET

<base>/oauth/callback/google

Microsoft

MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET

<base>/oauth/callback/microsoft

security add-generic-password -a "$USER" -s gulpy-connector-github-client-id -w "<client id>" -U
security add-generic-password -a "$USER" -s gulpy-connector-github-client-secret -w "<client secret>" -U

How it works

   Agent (any)                                     Gulpy                      Connector (Notion)
        |                                             |                               |
        |  1. POST /device/code                       |                               |
        |-------------------------------------------->|                               |
        |  2. the user opens the link, taps Allow     |                               |
        |  3. POST /device/token  -> gulpy_... key    |                               |
        |<--------------------------------------------|                               |
        |  4. GET /v1/tools, POST /v1/tools/:name     |   the call, with the token    |
        |     Authorization: Bearer gulpy_...         |   of the user                 |
        |-------------------------------------------->|------------------------------>|
        |     { "result": ... } (plain JSON)          |                               |
        |<--------------------------------------------|<------------------------------|

Three objects carry the design:

  • A connection is one account at one connector. It belongs to the user. It holds the tokens, encrypted.

  • A grant gives one agent access to one connection. Allow gives each connection, with read and write. A new connection goes to each agent of the user (GULPY_AUTO_APPROVE).

  • A connector is an entry in the list. It is an MCP server that the provider operates, or a provider API for which Gulpy supplies the tools.

The agent never gets the token of a connector. Gulpy reads the grant on each call and then makes the call. Many providers offer their tools only as an MCP server. Gulpy talks to those servers itself, in src/upstream/. The agent sees only plain JSON.

An app can also open Gulpy in a window from its own page, as Plaid Link does. Register the app at http://localhost:4000/developers.

// 1. On your server
const { link_token } = await post("/v1/link/token/create", {
  client_id, secret, capabilities: ["email.read", "calendar.read"],
});
<!-- 2. On your page. Call Gulpy.open directly in the click handler. -->
<script src="http://localhost:4000/link.js"></script>
<script>
  button.onclick = () =>
    Gulpy.open({
      linkToken: () => fetch("/api/link-token", { method: "POST" }).then((r) => r.json()).then((d) => d.link_token),
      onSuccess: ({ publicToken }) => fetch("/api/exchange", { method: "POST", body: JSON.stringify({ publicToken }) }),
    });
</script>
// 3. On your server
const { access_token } = await post("/v1/link/public_token/exchange", { client_id, secret, public_token });
const mail = await fetch("http://localhost:4000/v1/email/messages?q=invoice", {
  headers: { authorization: `Bearer ${access_token}` },
});

All paths start with /v1. Errors have the shape { "error": { "code", "message" } }.

Method and path

Auth

What it does

POST /link/token/create

client ID + secret

Makes a link token. It works for 30 minutes.

POST /link/public_token/exchange

client ID + secret

Gives an access token for one user.

GET /connections

access token

Lists the accounts that the user shared.

DELETE /connections/:id

access token

The app gives up its access to one account.

GET /email/messages, GET /email/messages/:id, POST /email/messages

access token

Mail

GET /calendar/events, POST /calendar/events

access token

Calendar

GET /files?q=, GET /files/:id

access token

Files in Google Drive and OneDrive: search, and read the text. Beta.

ANY /proxy/:connection_id/:service/*

access token

A raw request to the provider API. Off by default.

Error code

Status

Meaning

not_granted

403

The user did not give this.

connection_needs_reauth

409

The provider cancelled the token. The user must reconnect.

connection_required

400

The user shared two or more accounts. Send connection_id.

invalid_token

401

The user removed the access, or the token is wrong.

Settings

Variable

Default

Meaning

GULPY_BASE_URL

http://localhost:4000

The public address of Gulpy

GULPY_MASTER_KEY

made and kept in the Keychain (development)

32 bytes, base64. Encrypts the tokens. Necessary in production.

GULPY_DB

.data/gulpy.db

The SQLite file

RESEND_API_KEY, MAIL_FROM

not set

Sends sign-in codes by email. Necessary in production.

GULPY_RAW_PROXY

none

Provider ids for which /v1/proxy is on. Keep Google and Microsoft out.

STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET

not set

Paid plans through Stripe. See Paid plans. Without them, each person is on Free.

GULPY_AUTO_APPROVE

on

off: a new connection does not go to the agents that the user has already.

GULPY_BACKUP_DIR

not set

Gulpy writes a copy of the database to this folder each day and keeps 14 copies.

In development on macOS, each secret can also sit in the Keychain: gulpy-stripe-secret-key, gulpy-stripe-webhook-secret, and the same pattern for the provider credentials.

Paid plans

Gulpy sells the plans Personal, Family and Business through Stripe. The products, the prices and the payment links live in Stripe; the stripe script of the marketing site makes them. Gulpy needs only the secret key and the signing secret of one webhook endpoint at <GULPY_BASE_URL>/stripe/webhook, with the events checkout.session.completed, customer.subscription.created, customer.subscription.updated and customer.subscription.deleted.

Address

What it does

GET /billing/checkout?plan=personal&interval=yearly

Sends the signed-in person to the Stripe checkout of the plan. The link carries the user id, so the payment lands on this account. The pricing page of the site links here.

POST /stripe/webhook

Stripe reports each payment and each change of a subscription. Gulpy checks the signature and writes the plan of the person into the subscriptions table.

GET /?checkout=<session id>

Where Stripe sends the person after payment. Gulpy reads the session and shows the plan at once.

POST /billing/portal

Opens the Stripe customer portal: cancel, change the plan or the number of users, change the card, see invoices.

What a plan changes: a person on Free keeps 7 days of calls in the activity list; a paid plan keeps LEGAL.callLogDays. The dashboard shows the plan under Your account, and the export has it. With no Stripe settings, all of this is off and Gulpy shows no plan.

Security model

Threat

Control

The database is stolen

Tokens and client registrations are encrypted with AES-256-GCM. Each value is bound to its row. Secrets of apps, access tokens, refresh tokens and session IDs are stored as hashes only.

A fault gives the row of one user to a different user

Each user has a vault key of their own. It comes from the master key and the id of the user. The token of one user does not open with the key of a different user.

Someone sends the user a connect link

The user must tap Allow. Gulpy then emails the user ("Not you? Remove it"). A link works one time, for 10 minutes.

An agent gets a provider token

The agent never gets the token of a connector. Gulpy reads the grant on each call.

A key leaks

A key reaches all the tools of the user. Gulpy stores only its hash. The user removes the agent to stop it. Each call is on the dashboard.

A page on a different site submits a form

Gulpy checks Sec-Fetch-Site, and each form has a secret field. Cookies are SameSite=Lax and HttpOnly.

An attacker signs the victim in to the attacker's account

A sign-in code works only in the browser that asked for it. A provider callback works only in the session that started it.

A hidden frame gets a click on Allow

Pages forbid frames (frame-ancestors 'none').

Two apps compare their users

Each Link app sees a different user ID for the same person.

The user wants to know what happened

The dashboard shows each call. It records the tool and the result, not the content.

Known gaps:

  • Tool descriptions come from the connector and go to the AI model. A bad connector can put instructions in them. Gulpy limits the length. It does not inspect the text.

  • A key has no scopes and does not expire. Anyone with the key has all the tools.

  • No rate limits. One server process only: the refresh lock is in memory.

  • The copies of the database are on the disk of the server. A copy in a different place is not made.

Logos

Each connector and each agent shows the logo of its company. The images are in src/assets/logos/. manifest.json in that folder has the source address of each one.

~/.local/py/bin/python scripts/fetch-logos.py          # gets all logos again
~/.local/py/bin/python scripts/fetch-logos.py slack    # gets one

An agent gives its own name, so the name is not proof.

Project layout

src/
  catalog.ts        the list of connectors
  logos.ts          the logo images, and the rule for the logo of an agent
  device.ts         "connect to Gulpy": the device flow that gives an agent its key
  agents.ts         gives a new connection to the agents of the user
  tools.ts          the tools that agents call: GET /v1/tools, POST /v1/tools/:name
  guide.ts          /agents.md and /connect.sh
  upstream/         Gulpy as a client of an upstream MCP server
  service.ts        tools, mail, calendar and proxy operations
  vault.ts          token encryption and refresh, with one key for each user
  backup.ts         the daily copy of the database
  store.ts          all SQL (SQLite), with migrations
  link.ts           Link: tokens, account choices, approval
  oauth.ts          sign-in at a provider that has its own API
  providers/        google.ts, microsoft.ts
  routes/           pages.tsx, info.tsx (support, security, privacy, terms), connect.ts (device flow, guide), api.ts, billing.ts (the Stripe webhook)
  billing.ts        paid plans: the Stripe checkout, the webhook events, the customer portal
  views/            the pages
examples/
  agent/            Orbit and Scout. They think with the `claude` command.
scripts/            dev.ts, check-catalog.ts, fetch-logos.py, make-social.py (the picture for link previews),
                    deploy-vm.sh (puts Gulpy on a server)
deploy/             compose.yml: the app and the Cloudflare tunnel on a server
Dockerfile          Gulpy for a host
test/               end-to-end tests. They use no network.
  fixtures/         a mail provider and MCP connectors for the tests only

Releases

test.gulpy.ai

app.gulpy.ai

How

Merge a pull request to main

Publish a GitHub release with a tag v* (for example v2026.10.03) on a commit of main

Checks first

CI (typecheck, tests, Docker image starts)

CI, then a reviewer approves the production environment

Data

Its own database and Stripe TEST keys

The real database and Stripe LIVE keys

Pull requests run CI only. To send any branch to test, or to roll back production to an older tag: Actions > Deploy > Run workflow. deploy/release.sh sends the image built by CI to the server and starts it. If the new copy does not answer, it starts the previous one again. The secrets of the app stay on the server. GitHub holds only a deploy SSH key.

Tests

bun test
bun run typecheck

Status

Verified:

  • The full flow: 136 automated tests, and runs in a real browser (Chromium) with the pop-up window. The tests use a mail provider and connectors that exist for the tests only.

  • A real AI agent: Claude answered questions with tools that came through Gulpy.

  • The agent side: the device flow, keys, GET /v1/tools and POST /v1/tools/:name, in the tests and live with Orbit on 2026-10-03.

  • The registration of Gulpy at 24 real connectors. Their sign-in pages show the name "Gulpy".

  • Gulpy in production mode with the real address setting (https://gulpy.ai).

  • On 2026-09-29, Gulpy on a server (https://cloud.gulpy.ai, Google Cloud, Docker, Cloudflare tunnel): the container build from Dockerfile, sign-in with a code that Resend sent to a real mailbox, the dashboard, the registration of an agent, and the registration of Gulpy at Linear and Notion, which sent the browser to their sign-in pages.

Not verified:

  • The sign-in of a user at a real connector, and a tool call with a real account. This needs your accounts. Select + on a tool to try it.

  • The Google and Microsoft adapters did not run against the real services. They show Beta.

  • Google Drive and OneDrive give text for Google Docs, Sheets (first sheet), Slides and text files only. Word, Excel, PowerPoint and PDF files give a link and no text.

  • Mail to a real person. The ResendMailer sent one message to the test mailbox of Resend (HTTP 200).

Not built yet:

  • The Google and Microsoft apps. Without GOOGLE_* and MICROSOFT_*, their 2 cards show "Soon".

  • The 7 tools that show "Soon": GitHub, Slack, HubSpot, Asana, Box, Render, Figma. Each needs an app at the provider.

  • Skills and plugin packs. Gulpy has connectors only.

  • Connectors that use an API key and no OAuth, for example Exa and Firecrawl.

  • Passkeys for sign-in to Gulpy.

  • A search across the 830 connectors of the Claude directory.

Run your own Gulpy

Gulpy is one process with one SQLite file. You can run it on your own server and keep all your connections there.

On a server that has Docker, one command does all the steps. It makes the master key, makes a Cloudflare tunnel for the public https address, sends the code, and starts Gulpy:

GULPY_VM=<ssh host> GULPY_HOST=<name in your domain> scripts/deploy-vm.sh

Run it again to send new code. The data stays. The secrets are on the server in /etc/gulpy, which only root can read. A copy of the master key stays in the macOS Keychain as gulpy-vm-master-key.

By hand:

  1. Copy .env.example to .env.

  2. Set GULPY_BASE_URL to your public https address.

  3. Set GULPY_MASTER_KEY to 32 random bytes (openssl rand -base64 32). Keep a copy in a safe place. Without it, the stored tokens cannot be read.

  4. Set RESEND_API_KEY and MAIL_FROM, so that the sign-in codes go out by email.

  5. Start it with bun run start, or build the Dockerfile.

  6. Optional: sell plans. See Paid plans. Without it, everybody is on Free.

Security

Report a security problem in private. Do not open a public issue. See SECURITY.md.

License

GNU Affero General Public License v3.0. You can use, change and run Gulpy for free. If you run a changed copy as a service for other people, you must publish your changes under the same license.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    A
    maintenance
    Self-hosted MCP gateway that connects Claude, ChatGPT, and other AI agents to 20+ enterprise tools (GitLab, Jira, Notion, Google Workspace, Slack, Grafana, …) with OAuth, audit logs, and zero data leaving your infrastructure
    1
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides a secure MCP gateway for AI agents to access APIs without exposing raw credentials, with scoped access, audit logging, and OAuth support.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to discover and invoke 2,000+ models and APIs—including web search, social media, scraping, image/video generation, and audio—through a single local MCP bridge using OAuth, with no per-API keys.
    149 npm
    188
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides an OAuth-protected, scoped, and audited MCP server that lets AI assistants safely query business data through a fixed set of tools without direct database access.
    1
    MIT