Announcing CIMD support for MCP Client registration
Learn more

Basecamp MCP vs Basecamp API for AI Agents

Vinayak Ravi
Head of Marketing

37signals now ships an official Basecamp MCP server inside the open-source Basecamp CLI and also maintains the full REST API. They are not two doors into the same room. One is a local process that borrows a single person's CLI login; the other is a REST surface where you own the OAuth app, the account selection, and every token. This guide compares what each path lets an agent do, why neither enforces least privilege at the Basecamp layer, and how to run a Basecamp agent across many customer accounts in production.

TL;DR

  • 37signals' official Basecamp MCP server ships inside the open-source Basecamp CLI as basecamp mcp, added in v0.10.0 on September 3, 2026. It runs locally over stdio, rides on the CLI's own sign-in, and exposes sixteen domain gateway tools such as basecamp_todos and basecamp_messages, each taking an action and params. A hosted endpoint at mcp.basecamp.com answers MCP requests with an OAuth challenge, but 37signals has not documented it.
  • The Basecamp API is OAuth 2.0 only, issued through 37signals Launchpad. Access tokens last 2 weeks (expires_in of 1209600 seconds), one grant covers every Basecamp account the user belongs to, and Basecamp-issued tokens carry a single documented scope value: full. There is no read-only grant to ask a user for.
  • Neither path enforces least privilege at the Basecamp layer. The CLI's --read-only and --domains flags narrow what the model sees, not what the token can do. On the API path, that narrowing is your job, at the tool layer.
  • MCP is the faster path for one person asking Claude or Cursor to triage their to-dos. The API is the right path for headless agents, webhook-driven workflows (Basecamp retries a webhook up to 10 times, then deactivates it), and anything that has to stay under the 50-requests-per-10-seconds-per-IP limit.
  • Scalekit's basecamp connector exposes 89 prebuilt tools (60 read, 28 write, 1 destructive) with per-user Launchpad OAuth stored in the token vault, so the MCP vs API decision doesn't change your auth infrastructure.

The decision your Basecamp agent forces first

Your agent needs to work inside your customers' Basecamp accounts: post a Monday status message, chase overdue to-dos, move a card from In progress to Done when a pull request merges. You notice 37signals now ships an official MCP server and also maintains the full REST API. They are not two doors into the same room. One is a local process that borrows a single person's CLI login; the other is a REST surface where you own the OAuth app, the account selection, and every token. Here's how to pick.

What Basecamp MCP and Basecamp API actually are

Basecamp MCP

The official Model Context Protocol (MCP) server is a subcommand of the Basecamp CLI, MIT licensed and maintained by 37signals. basecamp mcp serves MCP over stdin and stdout, so you register it as a local server: claude mcp add basecamp -- basecamp mcp. It authenticates with whatever account basecamp auth login stored. That login opens a browser, or uses an OAuth device flow when the issuer advertises one, and falls back to Launchpad's authorization code flow otherwise. Tokens land in the OS keyring, or in credentials.json in the config directory when no keyring is available, and refresh tokens rotate on each refresh.

The server exposes sixteen domain gateway tools: basecamp_projects, basecamp_todos, basecamp_cards, basecamp_messages, basecamp_campfires, basecamp_boosts, basecamp_schedules, basecamp_files, basecamp_people, basecamp_automation, basecamp_reports, basecamp_everything, basecamp_clientside, basecamp_forwards, basecamp_account, and basecamp_recordings. Each one takes an action and params, and a describe action returns the schema for each action on demand. --read-only serves only read actions, and --domains projects,todos narrows the tool list and fails closed on unknown names. The CLI is pre-1.0 and 37signals does not label the MCP server's maturity.

There is also mcp.basecamp.com, which responds to MCP requests with a sign-in challenge and publishes OAuth metadata. The CLI README notes that the basecamp plugin name is reserved for a hosted connector backed by Basecamp's own MCP server. As of late October 2026 that hosted server has no public documentation and no self-registration path for Claude or ChatGPT custom connectors. Community servers fill the gap, such as stefanoverna/basecamp-mcp with 47 tools, and each one asks you to register your own Launchpad OAuth app.

Basecamp API

The Basecamp API is a JSON REST API where every path sits under the account ID, as in https://3.basecampapi.com/999999999/projects.json. It covers projects, to-dos and to-do lists, card tables, message boards, comments, Campfires, documents and vaults, schedules, check-ins, client visibility, email forwards, reports, search, and webhooks. 37signals also publishes an OpenAPI spec and SDK for code generation.

Auth is OAuth 2.0 through Launchpad. You register an app at launchpad.37signals.com/integrations, send users to https://launchpad.37signals.com/authorization/new, and exchange the code at /authorization/token with grant_type=authorization_code. Basic auth is not supported. Every request must also carry a User-Agent header naming your app and a contact address, or Basecamp returns 400 Bad Request.

What your agent can actually do

Capability
Basecamp MCP (basecamp mcp)
Basecamp API
List and read projects
Yes
Yes
Create, update, complete to-dos
Yes
Yes
Card tables: create, move, step completion
Yes
Yes: Card table endpoints
Post messages and comments
Yes
Yes: Messages and Comments
Campfire chat lines
Yes
Yes
Search across the account
Yes
Yes: Search with time, project, and creator filters
Overdue and assignment reports
Yes
Yes: Reports and My assignments
Schedules and upcoming events
Yes
Yes
Webhooks on new to-dos, messages, comments
No: Not exposed; the server only answers when a chat calls it
Yes: Project-scoped webhooks across 18 recording types
Serve multiple users from one deployment
No: One CLI login per process
Yes: One Launchpad grant per user, stored by your backend
Restrict the token to read-only
Limited: Filters tools; the token is still full access
Limited: No read-only OAuth scope is documented
Delete projects or content
Limited: Depends on the action set exposed by each domain
Yes: Trash endpoints exist; the Scalekit connector ships no delete tool

Coverage is close to parity. The CLI wraps the same API that you would call directly, and its sixteen gateways reach most of it. The gap is not what the agent can do inside a chat. It is everything outside one: event triggers, other users, and a token you can scope down.

What the MCP path makes easier

The Basecamp data model is deep. A to-do lives in a to-do list, which lives in a to-do set, which you find in the project's dock array under the entry named todoset. Pagination is geared: 15 results on page 1, 30 on page 2, 50 on page 3, then 100 per page, and you must follow the Link header rather than build page URLs. A model that has to discover all of that from raw endpoint docs burns turns doing it.

The gateway design hides it. Sixteen tools in context instead of a hundred, with describe loading an action's schema only when the model needs it, keeps the decision space small. Composite helpers do work no single endpoint does: basecamp_recordings summarize builds a compact view from an event feed row.

Writing the schema is the hard part. Not the API call.

The tradeoff is ownership and scope. The schemas track the CLI's release cadence, which reached v0.13.2 on October 13, 2026, and pre-1.0 software is allowed to change its action names. And the server always acts as the person who ran basecamp auth login on that machine.

The auth path each one puts you on

Basecamp MCP: one person's login on one machine

The CLI server has no auth configuration of its own. It reuses the stored CLI login, so the MCP server is exactly as powerful as that user, across every Basecamp account their identity can reach. That suits a developer driving Claude Code against their own projects. It does not map to a multi-tenant product: there is no way to hand the local server a different user's credential per request, and the refresh token sits in a keyring or a JSON file on a laptop.

--read-only deserves precision. It removes write actions from the tool list. The token underneath is unchanged, so anything else on that machine that reads credentials.json holds full write access. Tool filtering limits the model. It does not limit the credential.

Basecamp API: your Launchpad app, one grant per user

On the direct path you register a Launchpad app and run the Authorization Code flow per user. Four details shape the design:

  • Token lifetime. Access tokens expire after 2 weeks. Refresh with grant_type=refresh_token against the same /authorization/token endpoint. Two weeks is long enough that a missing refresh path survives a pilot and fails in week three of production.
  • Account selection. One Launchpad identity can belong to several Basecamp accounts. The first call after consent is GET https://launchpad.37signals.com/authorization.json, which returns the accounts array; you pick the entry with "product": "bc3" and use its href as the base URL. A consultant who belongs to four client accounts gives your agent one token that reaches all four.
  • Scope. Basecamp-issued tokens include a scope field, and the only documented value is full. Basecamp's own authorization document adds a resource indicator per account (in the form urn:bc:account:99999999, RFC 8707) for requesting a token scoped to one account, which narrows which account a token reaches, not which actions it allows.
  • Agent identities. Basecamp now models AI agents as people with personable_type Agent. An agent that authenticates with its own client-credentials token acts as itself, sees only projects it was added to, and reaches a limited endpoint set: messages, comments, Campfire lines, boosts, subscriptions, event feed, and reads of to-dos and cards. Everything else returns 403 Forbidden. A token a user delegated to the agent acts as that user, with that user's access.

What the user can't do, the agent can't do. With a full token, the reverse also holds: whatever the user can do, the agent can. Least privilege for a Basecamp agent is enforced at your tool layer or not at all.

Both paths still need per-user isolation

In a multi-tenant B2B agent, MCP gives you a credential per user and the direct API gives you a credential per user. In neither case does the path itself solve storage, rotation, or revocation; those are infrastructure problems regardless of which path you choose.

Basecamp adds its own wrinkle. A 404 does not always mean "not found." Basecamp returns 404 for deleted content, for content the user lost access to, and for inactive accounts, which it flags with a Reason: Account Inactive header. An agent that treats every 404 as a missing record will keep retrying against a customer who churned.

Recommended reading: OAuth vs API keys for AI agents

What you own in production

On the MCP path

37signals owns the tool schemas, the action dispatch, and the token refresh inside the CLI. You own the machine. The server runs only while a chat session is open on a computer that is awake, so nothing happens when a to-do is assigned at 2am. You own the CLI version, too: upgrading from one pre-1.0 release to the next can change an action your prompts depend on.

You also own the credential sprawl. Every teammate who installs the CLI and runs basecamp auth login creates another long-lived Basecamp grant on another laptop. When that person leaves, disabling their SSO account does not reach the refresh token in their keyring.

On the API path

You own schemas, pagination, retries, and the token lifecycle. Rate limits are dynamic and layered by method and window. The first one most integrations hit is 50 requests per 10 seconds per IP address; a 429 carries a Retry-After header in seconds. Because the limit is per IP, an agent fleet behind one NAT gateway shares a single budget across every customer. Retry 500, 502, 503, and 504 with exponential backoff, and do not retry 404s. Use ETag and If-None-Match on polls so unchanged resources return 304 Not Modified with no body.

Webhooks replace polling, with constraints. They are created per project, the payload URL must be HTTPS, and you choose from 18 recording types including Todo, Message, Comment, Kanban::Card, and Schedule::Entry. Basecamp retries a failed delivery up to 10 times with exponential backoff, does not follow 3xx redirects, and then deactivates the webhook. A deploy that breaks your receiver for a few hours silently ends the event stream. Payloads carry a generic recording summary, so a to-do event omits assignees and completed, and your agent makes a follow-up read. When an agent acted on a user's behalf, the payload includes a top-level performed_by person with personable_type Agent, which is useful for keeping your agent from reacting to its own writes.

Schema drift and versioning

The REST API has no version prefix in its URLs, and 37signals extends it in place. The reference now calls it the Basecamp 5 API, flat routes such as /todos/1069479521.json are canonical while project-scoped /buckets/ routes are legacy, and new personable_type values can appear without a version change. On the direct path you read the changelog and update your code. On the MCP path, 37signals absorbs those changes in the CLI, and you absorb the CLI's own changes in return.

When to use MCP, when to use the API

Use Basecamp MCP when

  • A project lead wants Claude Code or Cursor to answer "what's overdue across my projects and who owns it" against their own Basecamp login, with --read-only on.
  • A developer is scripting a one-off cleanup, such as moving last quarter's cards to Done, and wants the model to chain basecamp_cards actions without writing tool definitions.
  • You are prototyping a Basecamp assistant and want to learn which questions people actually ask before committing to a tool surface.
  • The work is single-user and interactive, and it is acceptable that nothing runs when the laptop is closed.

Use the Basecamp API when

  • The agent runs headless and event-driven: a Todo webhook fires on assignment, the agent reads the to-do, checks the assignee's calendar, and posts a comment with a realistic due date.
  • You serve many customers, each with their own Basecamp account, and must pick the right bc3 account per user from authorization.json.
  • The workflow is a deterministic pipeline, such as a Monday status message per project assembled from overdue to-dos and the week's schedule entries.
  • You need to budget against the 50-requests-per-10-seconds-per-IP limit, handle Retry-After, and detect inactive accounts from the Reason header.

The credential problem that exists on both paths

Both paths hand you a Launchpad OAuth grant per user. Neither hands you a vault. A multi-tenant agent with 80 customers and 6 Basecamp users each is 480 refresh tokens, each tied to one Launchpad identity that may span several Basecamp accounts, each with full access. Each one must be stored encrypted, refreshed before its 2-week access token lapses, kept out of logs and LLM context, and deleted when a user disconnects or a customer churns.

The MCP path does not shrink that number. It moves the tokens onto laptops, one CLI login at a time, where you cannot rotate or revoke them centrally. The tempting shortcut on the API path is one admin's grant per customer. That collapses 480 tokens into 80 and turns every agent action into an action by that admin, with that admin's access to every project, including the HR and finance projects nobody else can see. Fewer secrets, larger blast radius per secret.

Scalekit's basecamp connector handles the Launchpad OAuth flow, stores each user's tokens in the token vault, and refreshes them, so the MCP vs API decision doesn't change your auth infrastructure. Your agent passes an identifier; the token never enters the agent runtime or the LLM context.

Recommended reading: why a token vault matters for AI agent workflows

How to connect a Basecamp agent with Scalekit

Scalekit's basecamp connector is an API-path connector with 89 tools: 60 read, 28 write, and 1 destructive (basecamp_todo_uncomplete). No tool deletes content. It authenticates with your own Basecamp OAuth app: each user signs in to Basecamp once, and Scalekit stores and refreshes their tokens as that user's connected account. basecamp_account_get confirms which Basecamp account a connection is using.

Prerequisites and the connection name

In the Scalekit dashboard, go to AgentKit > Connections, create a Basecamp connection, and copy its redirect URI. Register an app at launchpad.37signals.com/integrations, add that redirect URI, and paste the app's client ID and client secret into the Basecamp connection.

The connection name you choose is the connection_name your code passes, and the string must match the dashboard exactly. This is the most common integration error. Copy SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, and SCALEKIT_CLIENT_SECRET from Developers > API Credentials into .env.

pip install scalekit-sdk-python python-dotenv langchain-openai

Authorize each user once

get_or_create_connected_account returns the user's connected account. If it is not ACTIVE, get_authorization_link returns a Basecamp consent link. The user approves once on Launchpad; Scalekit exchanges the code and stores the tokens.

import os from dotenv import load_dotenv from scalekit import ScalekitClient load_dotenv() scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions CONNECTION_NAME = "basecamp" # must match the connection name in AgentKit > Connections identifier = "user_123" # your app's stable ID for this user account = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=identifier, ) if account.connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=identifier, ) print("Authorize Basecamp:", link.link) input("Press Enter after approving access in Basecamp...") account = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=identifier, ) if account.connected_account.status != "ACTIVE": raise RuntimeError(f"Basecamp is {account.connected_account.status}, not ACTIVE") whoami = actions.execute_tool( tool_name="basecamp_account_get", tool_input={}, connection_name=CONNECTION_NAME, identifier=identifier, ) print(whoami.execution_id, whoami.data)

Retrieve the Basecamp tools this user can call

This is not a catalog load. The agent asks for the tools this user's connected account is authorized to call, then narrows them to the six a status-report agent needs. The 28 write tools never reach the model, so it cannot complete, reassign, or reschedule a to-do while summarizing one. The Basecamp token is still full; the tool surface is where least privilege actually gets enforced.

tools = actions.langchain.get_tools( identifier=identifier, connection_names=[CONNECTION_NAME], tool_names=[ "basecamp_projects_list", "basecamp_project_get", "basecamp_todolists_list", "basecamp_todos_list", "basecamp_overdue_todos_get", "basecamp_comments_list", ], page_size=100, ) tool_map = {t.name: t for t in tools} print(sorted(tool_map))

Run the agent loop

The loop runs until the model stops requesting tools. Every tool call executes with this user's Basecamp credential, so the agent sees only the projects this user can see.

from langchain_core.messages import HumanMessage, SystemMessage, ToolMessage from langchain_openai import ChatOpenAI llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [ SystemMessage( "You report on Basecamp projects. To read a project's to-dos, call " "basecamp_project_get, take the todoset ID from the dock entry named " "todoset, then call basecamp_todolists_list and basecamp_todos_list." ), HumanMessage( "List every overdue to-do in the account, grouped by project and assignee. " "For each project with more than three overdue items, read the latest " "comments on the oldest one and say what it is blocked on." ), ] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: print(response.content) break for tc in response.tool_calls: tool = tool_map.get(tc["name"]) if tool: result = tool.invoke(tc["args"]) else: result = f"Unknown tool: {tc['name']}" messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))

Deterministic calls with execute_tool

For pipelines, skip the model. execute_tool runs one tool with a fixed input and returns data plus an execution_id you can log. This job, triggered when a release ships, files a follow-up to-do in a known list and assigns it with a due date.

from datetime import date, timedelta todolist_id = int(os.environ["BASECAMP_RELEASE_TODOLIST_ID"]) qa_lead_id = int(os.environ["BASECAMP_QA_LEAD_PERSON_ID"]) created = actions.execute_tool( tool_name="basecamp_todo_create", tool_input={ "todolist_id": todolist_id, "content": "Verify v2.4.0 release notes against shipped changes", "description": "<div>Opened automatically when <strong>v2.4.0</strong> was tagged.</div>", "assignee_ids": [qa_lead_id], "due_on": (date.today() + timedelta(days=2)).isoformat(), "notify": True, }, connection_name=CONNECTION_NAME, identifier=identifier, ) print(created.execution_id, created.data)

Comments work on any commentable recording: a to-do, message, document, card, or schedule entry. Pass the recording's ID as recording_id. Content is Basecamp rich text, so use HTML tags such as div, strong, and a.

todo_id = int(os.environ["BASECAMP_TODO_ID"]) comment = actions.execute_tool( tool_name="basecamp_comment_create", tool_input={ "recording_id": todo_id, "content": "<div>Release pipeline finished. Staging build is ready for review.</div>", }, connection_name=CONNECTION_NAME, identifier=identifier, ) print(comment.execution_id, comment.data)

For a weekly planning digest, basecamp_upcoming_schedule_get returns schedule entries and dated to-dos and cards across every project in a date window.

today = date.today() upcoming = actions.execute_tool( tool_name="basecamp_upcoming_schedule_get", tool_input={ "window_starts_on": today.isoformat(), "window_ends_on": (today + timedelta(days=6)).isoformat(), }, connection_name=CONNECTION_NAME, identifier=identifier, ) print(upcoming.execution_id, upcoming.data)

The connector does not manage Basecamp webhooks. For event-driven agents, register a project webhook against Basecamp directly, and use the payload's recording.id as the input to basecamp_todo_get or basecamp_comments_list under the same connected account.

Multi-tool, multi-tenant Basecamp agents on a virtual MCP server

At 89 tools and roughly 200 tokens each, the full basecamp connector costs around 17,800 tokens of definitions before the agent does any work. Scoping a status agent to six tools cuts that by more than 90%. Overreach is the second risk: an agent that holds basecamp_project_update, basecamp_card_move, and basecamp_todo_update alongside its read tools can reschedule or re-stage a customer's work on a misread instruction. A Scalekit virtual MCP server declares exactly which tools an agent role can see, and session tokens keep each run bound to one user's connected accounts. Docs: set up a virtual MCP server.

Create the server once per agent role

from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping vmcp = actions.mcp.create_config( name="basecamp-overdue-digest", description="Reads overdue Basecamp to-dos and posts a weekly digest to Slack", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="basecamp", tools=[ "basecamp_overdue_todos_get", "basecamp_todo_get", "basecamp_comments_list", ], ), McpConfigConnectionToolMapping( connection_name="slack", tools=["slack_send_message"], ), ], ) print(vmcp.config.id, vmcp.config.mcp_server_url)

Mint a session token per user, per run

One server definition serves every user. Before each run, check that the user's accounts are active and mint a short-lived session token scoped to them. Any MCP client that speaks Streamable HTTP can connect; this example uses langchain-mcp-adapters (pip install langchain-mcp-adapters) and passes the token as a Bearer header.

import asyncio from datetime import timedelta from langchain_mcp_adapters.client import MultiServerMCPClient config_id = vmcp.config.id mcp_server_url = vmcp.config.mcp_server_url user_id = "user_123" accounts = actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier=user_id, include_auth_link=True, ) not_ready = [ a for a in accounts.connected_accounts if str(a.connected_account_status).upper() != "ACTIVE" ] for a in not_ready: print(f"{a.connection_name} is {a.connected_account_status}: {a.authentication_link}") if not_ready: raise RuntimeError("Connect the accounts above before starting this run") session_token = actions.mcp.create_session_token( mcp_config_id=config_id, identifier=user_id, expiry=timedelta(minutes=30), ).token async def load_tools(): client = MultiServerMCPClient( { "scalekit": { "transport": "streamable_http", "url": mcp_server_url, "headers": {"Authorization": f"Bearer {session_token}"}, } } ) return await client.get_tools() mcp_tools = asyncio.run(load_tools()) print([t.name for t in mcp_tools])

The agent sees four tools. The endpoint is static; the identity is per-user. Compare that with the CLI server: same MCP transport, but reachable over HTTP from any agent runtime, backed by a vaulted credential per user instead of one laptop's login, and with no server for you to deploy or host.

Observability: every Basecamp action tied to a user

Every execute_tool call returns an execution_id, and every execution is attributed to a connected account, which maps to one of your users and one customer. When a customer asks which agent run moved a card to Done or posted a comment on their client-visible message board, the answer is a lookup, not an investigation. Reads matter as much as writes: Basecamp projects hold contracts, client correspondence, and HR discussions, and your execution log is the record of which user's agent read which project, and when.

Basecamp's own records help on the receiving end. Webhook payloads and events include performed_by when an agent acted on someone's behalf, so a customer's admin can see the action was agent-driven. A shared credential breaks the chain on your side: if every run uses one admin's grant, Basecamp attributes every action to that admin, and you can only prove that the shared token did it. Shared credentials are a single-user solution. They do not survive a second user.

Recommended reading: audit trails for agent auth

Which one to build against

If your agent is one person's assistant inside Claude Code or Cursor, triaging their own to-dos and drafting messages on demand, the official basecamp mcp server is the shortest path, and --read-only is a sensible default. If your agent reacts to webhooks, runs on a schedule, or acts for more than one customer, build against the Basecamp API: you get per-user grants, account selection you control, and a rate-limit budget you can plan for. 37signals may document its hosted MCP endpoint next, and the transport question will shift again. The need to store, refresh, and revoke one full-scope Launchpad grant per user, per customer, will not, and that's what needs production-grade infrastructure.

FAQs

Does Basecamp have an official MCP server?

Yes, inside the open-source Basecamp CLI as basecamp mcp, added in v0.10.0 on September 3, 2026. It runs locally over stdio, authenticates with whatever account basecamp auth login stored, and exposes sixteen domain gateway tools such as basecamp_todos and basecamp_messages, each taking an action and params. A hosted endpoint at mcp.basecamp.com answers with an OAuth challenge, but 37signals has not documented it.

How does Basecamp API authentication work?

OAuth 2.0 only, issued through 37signals Launchpad. You register an app, send users to the authorization page, and exchange the code for an access token that lasts 2 weeks, with a refresh token. One grant covers every Basecamp account the user belongs to, so the first call after consent reads authorization.json and picks the right bc3 account. Every request must also carry a User-Agent header naming your app and a contact address.

Can a Basecamp token be restricted to read-only?

No. Basecamp-issued tokens carry a single documented scope, full. The CLI's --read-only flag removes write actions from the tool list but leaves the token unchanged, so anything else on that machine that reads the stored credentials holds full write access. Least privilege for a Basecamp agent is enforced at your tool layer or not at all.

What are the Basecamp API rate limits and webhook rules?

The first limit most integrations hit is 50 requests per 10 seconds per IP address, with a Retry-After header on 429. Webhooks are created per project with an HTTPS payload URL across 18 recording types. Basecamp retries a failed delivery up to 10 times with exponential backoff and then deactivates the webhook, so a receiver that is down for a few hours silently ends the event stream.

When should an agent use the Basecamp API instead of MCP?

When it reacts to webhooks, runs on a schedule, or acts for more than one customer. The CLI server runs only while a chat session is open on a computer that is awake, acts as the person who logged in, and cannot take a different user's credential per request, so it fits one person's interactive assistant and nothing multi-tenant.

How does Scalekit connect an AI agent to Basecamp?

The basecamp connector exposes 89 tools over the Basecamp API with your own Launchpad OAuth app. Each user signs in once, Scalekit stores and refreshes the tokens in the token vault, basecamp_account_get confirms which account a connection uses, a virtual MCP server narrows the tools per agent role, and every execution returns an execution_id attributed to that user. Webhooks are registered against Basecamp directly.

Build your Basecamp agent with Scalekit

Browse the Scalekit Basecamp connector and the Basecamp connector docs with the full tool list. See Scalekit pricing, or talk to us.

No items found.
Agent
Auth Quickstart
On this page
Share this article
Scalekit
Hosted per-user MCP

Acquire enterprise customers with
‍zero upfront cost.

Every feature unlocked. No hidden fees.