Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
"name": "interchange-plugin",
"interface": {
"displayName": "Apostra"
},
"plugins": [
{
"name": "apostra-developer",
"source": {
"source": "local",
"path": "./plugins/apostra-developer"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Development"
},
{
"name": "amc-listing",
"source": {
"source": "local",
"path": "./plugins/amc-listing"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "amc-merchandising",
"source": {
"source": "local",
"path": "./plugins/amc-merchandising"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "amc-distribution",
"source": {
"source": "local",
"path": "./plugins/amc-distribution"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Deployment"
},
{
"name": "amc-campaign-management",
"source": {
"source": "local",
"path": "./plugins/amc-campaign-management"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "buyer-account-setup",
"source": {
"source": "local",
"path": "./plugins/buyer-account-setup"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "buyer-campaign-management",
"source": {
"source": "local",
"path": "./plugins/buyer-campaign-management"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "buyer-creative-management",
"source": {
"source": "local",
"path": "./plugins/buyer-creative-management"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "buyer-reporting",
"source": {
"source": "local",
"path": "./plugins/buyer-reporting"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Monitoring"
},
{
"name": "sales-agent-testing",
"source": {
"source": "local",
"path": "./plugins/sales-agent-testing"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Testing"
},
{
"name": "amc-self-serve-buyer",
"source": {
"source": "local",
"path": "./plugins/amc-self-serve-buyer"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
}
]
}
23 changes: 23 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@
"email": "engineering@scope3.com"
},
"plugins": [
{
"name": "apostra-developer",
"description": "Plan, run, automate, and report on advertising across sellers, or build those jobs into an application.",
"author": {
"name": "Scope3 PBC",
"url": "https://interchange.io"
},
"source": "./plugins/apostra-developer",
"category": "development",
"keywords": [
"apostra",
"advertising",
"campaign automation",
"growth marketing",
"media buying",
"reporting",
"developer",
"mcp",
"agents"
],
"homepage": "https://docs.interchange.io/v3/overview",
"license": "Apache-2.0"
},
{
"name": "amc-listing",
"description": "Build and maintain an Agentic Media Company listing in Interchange.",
Expand Down
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,48 @@
# Interchange plugin marketplace
# Apostra developer marketplace

Install only the workflow packages relevant to your role. Packages select
instructions and starter workflows; they do not grant account permissions.
Interchange OAuth and server-side entitlements remain authoritative.
Connect a coding agent to Apostra, verify the account, and build an advertising
workflow. Start with `apostra-developer`; install the narrower operating
packages only when you need them. Packages do not grant account permissions.
Apostra OAuth and server-side entitlements remain authoritative.

## Install
## Install in Codex

```sh
codex plugin marketplace add scope3data/interchange-plugin
codex plugin add apostra-developer@interchange-plugin
```

The native plugin installs both the `build-with-apostra` skill and the Apostra
MCP connection. Complete OAuth when prompted, then ask Codex: "Verify my
Apostra account and help me build a seller discovery prototype."

## Install in Claude Code

```
/plugin marketplace add scope3data/interchange-plugin
/plugin install buyer-campaign-management@interchange-plugin
/plugin install apostra-developer@interchange-plugin
```

Complete OAuth when prompted. Never paste API keys or provider credentials
into a prompt.

## Install the skill in another compatible agent

```sh
npx skills add scope3data/interchange-plugin \
--skill build-with-apostra \
--yes
```

This route installs the instructions only. Connect the agent's MCP client to
`https://api.interchange.io/mcp/v3`, complete OAuth, and run the read-only
`get_status` check before building.

## Packages

| Package | Purpose | Current canonical skills |
|---|---|---|
| `apostra-developer` | Plan, run, automate, and report on advertising across sellers, or build those jobs into an application. | `build-with-apostra@1.0.0` |
| `amc-listing` | Build and maintain an Agentic Media Company listing in Interchange. | MCP access; workflow skill forthcoming |
| `amc-merchandising` | Merchandise an Agentic Media Company's inventory and products in Interchange. | MCP access; workflow skill forthcoming |
| `amc-distribution` | Prepare and distribute an Agentic Media Company through supported agent channels. | `publish-an-openai-app@1.0.0` |
Expand All @@ -37,8 +62,8 @@ Skill files are composed from the canonical, versioned Interchange skill
registry. When a registry current-version pointer or referenced asset changes,
the source workflow opens a reviewed sync PR for this repository.

Every durable change remains confirmation-gated by the underlying Interchange
tool contract. Full documentation lives at https://docs.interchange.io.
Every durable change remains confirmation-gated by the underlying Apostra
tool contract. Build guides live at https://docs.interchange.io/v3/overview.

## License

Expand Down
2 changes: 1 addition & 1 deletion SOURCE_DIGEST
Original file line number Diff line number Diff line change
@@ -1 +1 @@
689f2de18ba359a8c6faac22b53d6ad2fcb31320c66c135951733ae6b4a33d2a
2e4a53c3a0f1362322cb2dc398125123580d31198330264fa516f33a41cc5dfa
21 changes: 21 additions & 0 deletions examples/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Apostra Python starter

This Python 3.11+ starter connects to Apostra's v3 MCP endpoint with a scoped
access token and makes one read-only `get_status` call. Connection,
verification, and session teardown share a 15-second deadline. The starter
cancels SDK tasks and closes HTTP connections before returning. On timeout,
check network access and the MCP endpoint, then retry. For browser OAuth, use the
[direct MCP quickstart](https://docs.interchange.io/v3/quickstart).

```sh
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
APOSTRA_ACCESS_TOKEN='your-scoped-token' python main.py
python -m unittest test_main.py
```

Keep the token in an environment variable or secret manager. Do not commit it.
After verification works, follow the
[build-an-agent guide](https://docs.interchange.io/v3/build-an-agent) to add
tool discovery, durable checkpoints, confirmation gates, and retries.
70 changes: 70 additions & 0 deletions examples/python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""Verify an Apostra account through the v3 MCP endpoint."""

import asyncio
import json
import os
from typing import Any, Protocol

import anyio

IO_TIMEOUT_SECONDS = 15

APOSTRA_MCP_URL = "https://api.interchange.io/mcp/v3"


class ToolClient(Protocol):
async def call_tool(self, name: str, arguments: dict[str, Any]) -> Any: ...


async def verify_apostra_account(
client: ToolClient, timeout: float = IO_TIMEOUT_SECONDS
) -> Any:
"""Make exactly one read-only call and fail closed on a tool error."""
try:
result = await asyncio.wait_for(client.call_tool("get_status", {}), timeout)
except asyncio.TimeoutError as error:
raise RuntimeError(
"Apostra verification timed out. Check network access and retry."
) from error
if result.isError or result.structuredContent is None:
raise RuntimeError("Apostra account verification failed")
return result.structuredContent


async def connect_and_verify(token: str, endpoint: str = APOSTRA_MCP_URL) -> Any:
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

headers = {"Authorization": f"Bearer {token}"}
async with streamablehttp_client(endpoint, headers=headers) as streams:
read_stream, write_stream, _ = streams
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
return await verify_apostra_account(session)


async def run_verification(
token: str, timeout: float = IO_TIMEOUT_SECONDS,
endpoint: str = APOSTRA_MCP_URL
) -> Any:
# Level cancellation reaches every SDK task and every teardown await.
# asyncio.wait_for only cancels once, so SDK cleanup could outlive it.
try:
with anyio.fail_after(timeout):
return await connect_and_verify(token, endpoint)
except asyncio.TimeoutError as error:
raise RuntimeError(
"Apostra connection or verification timed out. "
"Check network access and the MCP endpoint, then retry."
) from error


async def main() -> None:
token = os.environ.get("APOSTRA_ACCESS_TOKEN")
if not token:
raise RuntimeError("Set APOSTRA_ACCESS_TOKEN before running")
print(json.dumps(await run_verification(token), indent=2))


if __name__ == "__main__":
asyncio.run(main())
2 changes: 2 additions & 0 deletions examples/python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mcp>=1.26,<2
anyio>=4.5,<5
Loading
Loading