External Agents
Connecting to external AI agents via OpenClaw, A2A protocol, and MCP -- connection lifecycle, delegation, and administration.
External Agents
The Sprinter Platform supports connections to external AI agents and services through three protocols: OpenClaw (OpenAI-compatible API), A2A (Agent-to-Agent protocol), and MCP (Model Context Protocol). Additional source-type connections (RSS, API, Authenticated Web) enable data ingestion from external services.
Connection types
| Type | Protocol | Test endpoint | Use case |
|---|---|---|---|
openclaw | OpenAI-compatible API | /v1/models | External LLM agents via OpenClaw gateway |
a2a | Agent-to-Agent | /.well-known/agent-card.json | Google A2A protocol agents |
mcp | Model Context Protocol | /tools/list (POST, JSON-RPC) | MCP tool servers |
rss | RSS/Atom feeds | Feed URL | Content ingestion from RSS feeds |
api | REST API | Base URL | JSON API data sources |
authenticated_web | HTTP with auth | Base URL | Authenticated website scraping |
The first three (openclaw, a2a, mcp) are agent gateway types -- they proxy to external agents that can receive delegated tasks. The remaining three are data source types used by the source sync system for content ingestion.
Database schema
Connections are stored in the agent_connections table:
| Column | Type | Purpose |
|---|---|---|
id | uuid | Primary key |
tenant_id | uuid | Tenant scope |
name | text | Display name |
connection_type | text | One of the six connection types |
base_url | text | Base URL for the external service |
encrypted_credentials | text | AES-encrypted credentials blob (never returned via API) |
config | jsonb | Additional configuration (custom headers, test path, user agent) |
status | text | active, inactive, or error |
last_health_check | timestamptz | Last successful health check |
last_error | text | Last error message |
created_by | uuid | User who created the connection |
Credentials are encrypted at rest using encryptCredentials() from lib/crypto/credentials.ts. The API-facing type (AgentConnection) redacts credentials to a boolean hasCredentials field via toPublicConnection().
Connection lifecycle
1. Create
Create a connection via Admin > Connections or the API:
POST /api/agent-connections
{
"name": "My OpenClaw Agent",
"connection_type": "openclaw",
"base_url": "https://agent.example.com",
"credentials": { "apiKey": "sk-..." },
"config": { "testPath": "/v1/models" }
}Credentials are encrypted before storage. The config object supports:
testPath-- custom endpoint for health checks (overrides the protocol default)userAgent-- custom User-Agent headerheaders-- additional HTTP headers as key-value pairsoauth-- optional provider metadata for generic OAuth 2 connectionsoauthScopes-- optional scope override for OAuth-backed connections
2. Test
Test connectivity and credentials:
POST /api/agent-connections/:id/testThe test endpoint sends a protocol-appropriate request:
- OpenClaw: GET to
/v1/models - A2A: GET to
/.well-known/agent-card.json - MCP: POST JSON-RPC
tools/listto the base URL - RSS/API/Web: GET to the base URL
On success, updates status to active and records last_health_check. On failure, updates status to error and stores the error message.
Requests have a 10-second timeout. Credentials (token, API key, cookie, or custom headers) are decrypted and applied to the request automatically.
OAuth connect / refresh
Some provider presets now support an OAuth authorization-code flow directly from the Connections UI. The same agent_connections row stores:
- encrypted client credentials and tokens in
encrypted_credentials - public connection state in
config.oauthStatus,config.oauthConnectedAt,config.oauthExpiresAt, andconfig.oauthScope
Routes:
GET /api/agent-connections/:id/oauth/start
GET /api/agent-connections/:id/oauth/callback
POST /api/agent-connections/:id/oauth/refreshThe current preset-backed OAuth connectors are Canva, Dropbox, Google Analytics, and LinkedIn. Other providers can still use the same flow by supplying config.oauth in advanced JSON.
3. Discover
For A2A connections, discover available agents:
POST /api/agent-connections/:id/discoverReturns a list of DiscoveredAgent objects with externalAgentId, name, description, and whether the agent has already been imported.
4. Update and delete
PATCH /api/agent-connections/:id
DELETE /api/agent-connections/:idUpdates can change the name, URL, credentials, config, or status. Deleting a connection removes it permanently.
Server actions
Connection CRUD is also available via server actions in features/agents/server/connection-actions.ts:
getConnections()-- list all connections for the current tenantgetConnectionById(id)-- fetch a single connection (API-safe, credentials redacted)getConnectionByIdInternal(id)-- fetch with encrypted credentials (server-only)createConnection(input)-- create with Zod-validated inputupdateConnection(id, input)-- partial updatedeleteConnection(id)-- removetestConnection(id)-- health check with status update
MCP connections in chat agents
When an admin creates an MCP connection and sets its status to active, that connection is automatically available to chat agents the next time a message is sent. No code change or agent reconfiguration is needed.
Chat agents receive two gateway tools — listMcpTools and callMcpTool — that are assembled at request time from the tenant's active MCP connections. This is the only way MCP servers surface to internal agents; there is no separate "enable MCP" toggle on an agent.
The flow from connection to agent use:
- Admin creates an MCP connection in Admin > Connections (connection type: MCP) and tests it.
- On the next chat request,
getMcpServerConfigs(tenantId)fetches active MCP connections (cached cross-request, invalidated after any mutation). createMcpGatewayTools(configs)produceslistMcpToolsandcallMcpToolwith the server names embedded in the description prefix.- The agent's ToolSet contains exactly 2 MCP-related tools regardless of how many MCP servers are connected.
- During the conversation the agent calls
listMcpToolsto discover available tools, thencallMcpToolto execute them.
Context cost is always 2 tool slots. MCP tool schemas are fetched lazily only when the agent calls listMcpTools, not at ToolSet assembly time. This keeps the prompt prefix stable and preserves Anthropic prompt caching.
Credential resolution. The gateway resolves all auth headers from the connection's encrypted credentials using resolveConnectionAuthHeaders(). Any credential type supported by the shared resolver (Bearer, cookie, basic, custom headers) works out of the box — no special MCP-specific auth configuration is needed.
Autonomous paths (heartbeat, extraction, workflows) are excluded by default. These paths pass an empty config list, so no MCP gateway tools are injected. This is intentional: autonomous runs execute without human oversight, and MCP tool calls reach external services. Opting in requires an explicit code change to pass mcpConfigs in those paths.
Agent delegation
Agents can delegate tasks to other agents (internal or external) via the delegation tool, which is automatically included in every agent's tool set.
The delegation factory at features/agents/lib/delegate.ts creates a delegateToAgent tool:
const delegateTool = createDelegateToAgentTool();
// Agents call: delegateToAgent({ agentSlug: "researcher", task: "Find market data for..." })Internal delegation: Resolves the target agent from the code registry, runs it inline within the same process.
External delegation: Looks up the target agent via agent_connections, routes the task through the connection-based provider (OpenClaw or A2A protocol). Supports configurable timeouts for external calls.
Credential types
The encrypted credentials blob supports several authentication patterns:
| Pattern | Fields | Header applied |
|---|---|---|
| OAuth 2 | { scheme: "oauth2", oauth2: { clientId, clientSecret, accessToken, refreshToken } } | Authorization: Bearer <accessToken> |
| Bearer token | { token: "..." } | Authorization: Bearer <token> |
| API key | { apiKey: "..." } | Authorization: Bearer <apiKey> |
| Cookie | { cookie: "..." } | Cookie: <cookie> |
| Basic auth | { basicAuth: { username, password } } | Authorization: Basic <base64> |
| Custom headers | { headers: { "X-Custom": "..." } } | Applied directly |
Multiple credential types can be combined in a single connection.
Zod validation schemas
All API inputs are validated with Zod schemas defined in features/agents/connection-types.ts:
CreateConnectionSchema-- validates name (1-255 chars), connection_type (enum), base_url (valid URL), optional credentials and configUpdateConnectionSchema-- all fields optional for partial updates
Administration
The Connections tab in Admin (/admin > Connections) provides:
- Table view of all connections with status indicators (green dot for active, gray for inactive, red for error)
- Badge indicating connection type (OpenClaw, A2A, MCP, RSS, API, Authenticated Web)
- Capability toggles so a single connection can be used for source monitoring, publishing, external agent runtime, or a combination of those roles
- Browser monitoring agent ID field for source-capable OpenClaw/A2A connections
- OAuth connect, reconnect, and token refresh actions for supported providers
- Test button for each connection with inline result display
- Add/edit dialog with credential input
- Last health check timestamp and error message display
- Delete with confirmation
Source connections
RSS, API, and Authenticated Web connections are used by the source sync system (features/source-sync/) to ingest external content into the entity graph. These connections provide:
- Authentication for paywalled or private content sources
- Custom headers and user agent configuration
- Domain and keyword filtering
- Deduplication with configurable time windows
Source entities reference connections via their content.connection_id field. The source sync function resolves the connection, decrypts credentials, and uses them when fetching content.
Browser-agent source monitoring
Some sites are too dynamic or hostile for plain HTTP scraping. In those cases a source can use the browser scrape strategy and point to a source-capable OpenClaw or A2A connection instead of an HTTP data-source connection.
Expected connection config:
config.capabilitiesincludessourceconfig.browserAgentId(orconfig.externalAgentId) names the external browser-capable agent to invoke
The Admin UI exposes this directly: select a gateway connection, enable the Source monitoring capability, and enter the browser agent's external ID. That makes existing gateway agents such as Chippy reusable for monitored-source jobs without creating a second browser-only connection model.
This keeps browser monitoring on the same connection primitive as the rest of the platform instead of introducing a second browser-specific credential model.
Connect your agents (quick start)
Three steps to connect any MCP-compatible agent to Amble:
- Create an API key in Admin > API Keys with scopes:
tools:execute,skills:read,views:read - Point your agent at
{AMBLE_URL}/api/mcp/serverwith the key as a Bearer token - Verify with a curl test:
curl -X POST https://app.sprinter.ai/api/mcp/server \
-H "Authorization: Bearer sk_..." \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2025-03-26" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}}}'A successful response returns {"jsonrpc":"2.0","id":1,"result":{...}} with server capabilities.
For production use at app.sprinter.ai, replace localhost:3000 in all examples below with your deployment URL.
Local interoperability endpoints
Amble exposes two complementary surfaces for external agent/app consumers:
1. Standard MCP server (preferred for Codex / Claude Code / OpenClaw)
POST /api/mcp/serverGET /api/mcp/serverDELETE /api/mcp/server
This is a real streamable HTTP MCP server backed by Amble tools. Point local coding agents here.
API-key scopes control what the MCP server exposes:
tools:execute— exposes tenant-accessible Amble toolsskills:read— exposes helper tools:amble_list_skillsamble_get_skill
views:read— exposes helper tools:amble_list_viewsamble_get_view
2. App/CLI-friendly REST + JSON-RPC primitives
POST /api/mcp/tools— JSON-RPCtools/list/tools/callGET /api/skills— list skills (skills:read)GET /api/skills/:id— fetch skill by id (skills:read)GET /api/skills/slug/:slug— fetch skill by slug (skills:read)GET /api/views— list views (views:read)GET /api/views/:id— fetch view by id (views:read)
These are useful for simple scripts, app integrations, and CLI workflows where a full MCP client is unnecessary.
Authentication
Authentication is API-key based:
Authorization: Bearer sk_...X-API-Key: sk_...
Recommended local-agent key scopes:
tools:executeskills:readviews:read
Add entities:read and entity-types:read if the consuming app also needs direct record/schema access.
Setup recipes
Set AMBLE_BASE_URL to your deployment (e.g. https://app.sprinter.ai for production, http://localhost:3000 for local dev).
Codex
export AMBLE_BASE_URL="https://app.sprinter.ai"
export AMBLE_API_KEY="sk_..."
codex mcp add amble --url "$AMBLE_BASE_URL/api/mcp/server" --bearer-token-env-var AMBLE_API_KEYClaude Code
export AMBLE_BASE_URL="https://app.sprinter.ai"
export AMBLE_API_KEY="sk_..."
claude mcp add --transport http amble "$AMBLE_BASE_URL/api/mcp/server" --header "Authorization: Bearer $AMBLE_API_KEY"OpenClaw ACP agents
Configure the ACP plugin's mcpServers to point at Amble's MCP server:
{
"plugins": {
"entries": [
{
"type": "acpx",
"enabled": true,
"config": {
"mcpServers": {
"amble": {
"type": "http",
"url": "https://app.sprinter.ai/api/mcp/server",
"headers": {
"Authorization": "Bearer sk_..."
}
}
}
}
}
]
}
}If you want secrets managed outside the raw config, use OpenClaw's secrets/env mechanisms and inject the bearer token there instead of hard-coding it.
CLI bootstrap
Use the Amble CLI to validate and bootstrap local setups:
pnpm cli doctor --base-url http://localhost:3000 --api-key sk_...
pnpm cli config codex --base-url http://localhost:3000 --api-key sk_...
pnpm cli config claude --base-url http://localhost:3000 --api-key sk_...
pnpm cli mcp list --base-url http://localhost:3000 --api-key sk_...
pnpm cli mcp call my-tool --payload '{"foo":"bar"}' --api-key sk_...
pnpm cli skills --base-url http://localhost:3000 --api-key sk_...
pnpm cli skills get my-skill --base-url http://localhost:3000 --api-key sk_...
pnpm cli views --base-url http://localhost:3000 --api-key sk_...Chippy rollout checklist
When rolling this out to Chippy later:
- Mint a dedicated API key for Chippy.
- Scope it to the minimum required capabilities.
- Point Chippy to
/api/mcp/server. - Validate with
pnpm cli doctoragainst the target environment. - Verify tool execution + skill fetch + view fetch before turning on autonomous runs.