Custom apps
Bring private MCP servers, callbacks and SDK functions into Arc0.
Use Custom apps to expose your internal tools through Arc0’s permissions and audit trail. They appear alongside built-in apps in the same tool catalog. Private tools stay scoped to their project; personal custom apps belong to their owner.
Choose where the tools run
| Type | Execution location | Authentication |
|---|---|---|
| Remote MCP | Your HTTPS MCP server | Explicit bearer token or no server credential |
| HTTP callback | Your HTTPS JSON endpoint | Endpoint-specific bearer token or no credential |
| SDK functions | Your application process | Arc0 authorizes preparation and completion |
Remote OAuth discovery is not supported by this integration. A bearer token must be intended for the endpoint you register. Do not reuse a GitHub or other provider token for an unrelated callback. Arc0 encrypts source credentials and never returns them in source details.
Register, review and publish
- Add an app name and choose its type. Enter the endpoint and optional token for remote tools; supply JSON tool definitions for callbacks and SDK functions.
- Review the imported input/output schemas and descriptions. Remote annotations are untrusted.
- Select the tools to publish and classify each as read, write or destructive. Tools you omit remain unpublished. Optional workflow guidance describes how an agent should use a tool; it does not grant permission.
- Publish the revision. Subsequent revisions do not silently change existing version pins.
- Select Use version for each tool you want to upgrade.
Changing schemas, endpoints or credentials creates a revision. Replacing an authenticated endpoint requires a replacement credential. Review and update the pins after rotating credentials; revoked credentials cannot be used merely because an older tool version is pinned.
A remote MCP pin identifies the imported schema and source configuration. It cannot guarantee that another operator never changes their server’s implementation.
SDK registration
A key with sources:manage can manage sources. Create it under API keys → Access → Manage
custom apps and tool definitions. Execution still requires an appropriately scoped execution key.
const { source, candidate } = await arc0.createActionSource({
name: "Internal search",
type: "remote_mcp",
endpoint: "https://tools.your-company.example/mcp",
bearerToken: process.env.INTERNAL_MCP_TOKEN,
});
const publication = await arc0.publishActionSource(source.id, {
candidateId: candidate.id,
tools: [{ name: "search", risk: "read" }],
});
// On a later revision, explicitly choose each new version after reviewing it.
await arc0.pinSourceTool(source.id, publication.tools[0].action, publication.tools[0].version);Python exposes create_action_source, sync_action_source, list_source_candidates,
publish_action_source, pin_source_tool and set_action_source_enabled.
A client configured with an end-user binding retains that binding on every request.
SDK-local functions
Register the schema through Custom apps, publish it, then register the implementation in your server process using the returned action ID and exact version:
arc0.registerLocalHandler(actionId, version, async (args, context) => {
// Use context.executionId as an idempotency key for your own side effects.
return internalSearch(String(args.query));
});
const receipt = await arc0.executeLocal({
action: actionId,
actionVersion: version,
arguments: { query: "order status" },
idempotencyKey: "your-stable-request-key",
});arc0.register_local_handler(action_id, version, lambda args, context: internal_search(args["query"]))
receipt = arc0.execute_local(
action=action_id, action_version=version, arguments={"query": "order status"},
idempotency_key="your-stable-request-key",
)Preparation checks current access and can return an approval requirement. The SDK invokes only
an exact action/version handler, then reports through an expiring completion claim. Results are
marked caller_reported: Arc0 did not independently observe the local operation.
The same client retains up to 128 completion reports until their claims expire, so retrying an uncertain completion does not rerun its handler. This in-memory protection does not survive a process restart. Make side-effecting handlers idempotent using the execution ID. Do not log or persist completion tokens in public locations. Remote MCP clients cannot execute these local function bodies.