Simple agent SDK

Your agent,
ready to ship.

Any model. Built-in tools, memory, and MCP. Serve locally or publish to the Agentinc marketplace — all from one package.

pip install "agentinc-sdk[openai,serve]"

Installation

Install the SDK with pip or uv. Core depends only on Pydantic — extras add provider clients and the A2A server.

shell
# Core (pydantic only) pip install agentinc-sdk # With OpenAI + A2A server pip install "agentinc-sdk[openai,serve]" # With Anthropic + A2A server pip install "agentinc-sdk[anthropic,serve]" # Everything pip install "agentinc-sdk[all]"
ExtraInstallsUse for
openaiopenai>=1.0OpenAI + any OpenAI-compatible endpoint (DeepSeek, Groq, Ollama…)
anthropicanthropic>=0.25Anthropic Claude models
geminigoogle-genai>=1.0Google Gemini models
memoryredis>=5.0Redis-backed session memory
mcpmcp>=1.0MCP server connections
servefastapi, uvicorn, sse-starletteA2A HTTP server
allall of the aboveFull install
Requires Python 3.12+. Provider libraries are lazy-imported — missing extras raise a clear ImportError with install instructions.

Agent Skill

Install the agentinc-sdk skill so your coding agent understands the Agent API and can help you build agents faster.

shell
npx skills add agentinc/sdk
Build agents
Ask your agent to create an Agent() with tools, MCP servers, or memory — it uses current SDK patterns.
Debug issues
Your coding agent knows the Agent constructor, provider config rules, tool schemas, and A2A formats.
Add tools
Your coding agent uses @tool correctly with proper type hints and JSON Schema generation.
Serve & deploy
Your coding agent knows create_app() vs serve(), A2A protocol, and how to test with curl.

Quickstart

Create an Agent, give it a model and a tool, then serve it over A2A.

quickstart.py
import os from agentinc.sdk import Agent from agentinc.sdk.serve import serve def get_weather(city: str) -> str: """Gets the current weather for a city.""" return f"72°F and sunny in {city}" agent = Agent( role="You are a helpful assistant.", model={"model": "gpt-4o-mini", "api_key": os.environ["OPENAI_API_KEY"]}, tools=[get_weather], ) serve(agent, name="my-agent", port=8000)
shell
# Start the server python quickstart.py # Call it curl -X POST http://localhost:8000 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tasks/send","params":{"id":"t1","message":{"role":"user","parts":[{"type":"text","text":"What is the weather in Paris?"}]}}}'

Core Concepts

The SDK defines the contract between your agent code and the Agentinc platform.

Agent
The main class. Wires the provider, tool dispatch loop, session memory, and MCP connections automatically.
AgentProtocol
Universal agent contract. Implement run() for framework integrations that manage their own LLM calls.
ToolProtocol
Expose functions as tools the agent can call. Use @tool or pass plain functions to tools=.
@tool Decorator
Turn any function into a ToolProtocol with auto-generated JSON schema from type hints and docstrings.
Plain functions passed to Agent(tools=[...]) are auto-wrapped — @tool is optional. Use it when you want an explicit name or description.

Agent

The main developer-facing class. Implements AgentProtocol — pass it directly to serve().

ClassAgent

Wires together a provider, tool dispatch loop, optional Redis memory, and optional MCP connections. The tool loop is built-in: the agent calls tools, feeds results back to the LLM, and repeats until a text response is produced.

python
Agent( role: str, # system prompt / persona model: ModelConfig, # provider + credentials dict tools: list[Callable] = [], # plain functions — auto-wrapped mcps: list[MCPConfig] = [], # MCP server connections memory: MemoryConfig | None = None, # Redis-backed session memory context: str | None = None, # extra context appended to system prompt data: DataConfig | None = None, # RAG config (reserved) )

ModelConfig

Provider credentials as a plain dict. Provider auto-detected from model name prefix. When base_url is set, the OpenAI-compatible provider is used regardless of model name.

python
# OpenAI {"model": "gpt-4o-mini", "api_key": "sk-..."} # Anthropic {"model": "claude-sonnet-4-6", "api_key": "sk-ant-..."} # Google Gemini {"model": "gemini-1.5-pro", "api_key": "..."} # Any OpenAI-compatible endpoint (DeepSeek, Groq, Ollama, …) {"model": "deepseek-chat", "api_key": "sk-...", "base_url": "https://api.deepseek.com"}
Model prefixAuto-detected providerRequired extra
gpt-*, o1-*, o3-*OpenAI[openai]
claude-*Anthropic[anthropic]
gemini-*Google Gemini[gemini]
any + base_urlOpenAI-compatible[openai]

MemoryConfig

Redis-backed session memory. History is loaded at the start of each run() and saved at the end. Requires pip install 'agentinc-sdk[memory]'.

python
{ "type": "redis", "connection": "redis://localhost:6379/0", "user": "optional", "password": "optional", }

Session ID from input.metadata["session_id"]. Falls back to a per-request UUID when absent. History stored with a 24-hour TTL.

shell — passing session_id
curl -X POST http://localhost:8000 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tasks/send","params":{"id":"t1","metadata":{"session_id":"user-123"},"message":{"role":"user","parts":[{"type":"text","text":"My name is Alice"}]}}}'

MCPConfig

Connect to MCP servers. Tool schemas are fetched on the first run() call and merged with local tools. Requires pip install 'agentinc-sdk[mcp]'.

python
# stdio — spawns a subprocess { "type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], } # SSE — connects to a running HTTP server { "type": "sse", "url": "http://localhost:3001/sse", }

AgentProtocol

The universal agent contract. Use this for framework integrations that manage their own LLM calls. Agent already implements it.

ProtocolAgentProtocol

Any object with a matching run method satisfies the protocol. No inheritance needed.

protocol.py
@runtime_checkable class AgentProtocol(Protocol): def run(self, input: AgentInput) -> AsyncIterator[AgentOutput]: ...

Direct implementation

my_agent.py
from agentinc.sdk import AgentInput, AgentOutput, AgentProtocol from agentinc.sdk.serve import serve class MyAgent: async def run(self, input: AgentInput): yield AgentOutput(content=f"Hello! You said: {input.message}", done=True) assert isinstance(MyAgent(), AgentProtocol) # passes serve(MyAgent(), name="my-agent", port=8000)

ToolProtocol

The contract for tools the agent can invoke.

ProtocolToolProtocol

Any object with schema() and call() satisfies this protocol.

protocol.py
@runtime_checkable class ToolProtocol(Protocol): def schema(self) -> ToolSchema: ... async def call(self, tool_call: ToolCall) -> str: ...

Schemas

Pydantic models forming the data contract between agents, tools, and the platform.

ModelAgentInput

Input to every agent invocation.

FieldTypeDefaultDescription
messagestrrequiredThe user's message
historylist[Message][]Conversation history
tool_schemaslist[ToolSchema][]Caller-supplied tool schemas
metadatadict[str, Any]{}session_id key used by Redis memory
ModelAgentOutput

A single chunk yielded by an agent's run().

FieldTypeDefaultDescription
contentstr | NoneNoneText content of this chunk
tool_callslist[ToolCall][]Tool calls the agent wants to make
doneboolFalseWhether this is the final chunk
metadatadict[str, Any]{}Arbitrary output metadata

@tool Decorator

Turn any function into a ToolProtocol with one line. Schema auto-generated from type hints and docstring.

Decorator@tool

Returns a ToolWrapper. Works with sync and async functions.

python
from agentinc.sdk import tool # Bare — schema from type hints + docstring @tool async def search(query: str, limit: int = 10) -> str: """Searches the web for a query.""" return f"Results for {query}" # With explicit name / description @tool(name="add", description="Adds two numbers") def add_numbers(a: float, b: float) -> str: return str(a + b)

Type mappings

PythonJSON Schema
str{"type": "string"}
int{"type": "integer"}
float{"type": "number"}
bool{"type": "boolean"}
list[str]{"type": "array", "items": {"type": "string"}}
dict{"type": "object"}

ToolWrapper

The object returned by @tool. Satisfies ToolProtocol — call directly or via a ToolCall.

ClassToolWrapper

Wraps any sync or async callable with a JSON schema and ToolProtocol interface.

python
from agentinc.sdk import tool, ToolCall @tool def greet(name: str) -> str: """Says hello.""" return f"Hello, {name}!" # Via ToolCall (how the platform dispatches) result = await greet.call(ToolCall(id="1", name="greet", arguments={"name": "World"})) # Direct call result = await greet(name="World")

RawAdapter ⚠ Deprecated

Kept for backward compatibility. Emits DeprecationWarning on instantiation. Will be removed in v0.3.

DeprecatedRawAdapter(fn)

Wraps any callable as AgentProtocol.run(). Migrate to Agent() or implement AgentProtocol directly.

Migrate to Agent(role=..., model=..., tools=[...]). For framework integrations, implement AgentProtocol directly.

A2A Server

Serve any AgentProtocol as an A2A-compliant HTTP endpoint. Requires [serve] extra.

MethodPathDescription
GET/.well-known/agent.jsonAgent card
POST/JSON-RPC 2.0 (tasks/send, tasks/sendSubscribe)

create_app()

Functioncreate_app(agent, *, name, description) → FastAPI

Returns a FastAPI app for custom ASGI deployments.

python
from agentinc.sdk import Agent from agentinc.sdk.serve import create_app app = create_app( Agent(role="You are helpful.", model={"model": "gpt-4o-mini", "api_key": "sk-..."}), name="my-agent", ) # uvicorn myfile:app --port 8000

serve()

Functionserve(agent, *, name, description, host, port)

Blocking one-liner. Calls uvicorn internally. Best for scripts and local dev.

ParameterTypeDefaultDescription
agentAgentProtocolrequiredThe agent to serve
namestr"agent"Agent name
descriptionstr""Agent description
hoststr"0.0.0.0"Bind address
portint8000Bind port

Example: OpenAI Agent

Minimal Agent with a tool using an OpenAI model.

openai_agent.py
import os from agentinc.sdk import Agent from agentinc.sdk.serve import serve def get_weather(city: str) -> str: """Gets the current weather for a city.""" return f"72°F and sunny in {city}" agent = Agent( role="You are a helpful assistant.", model={"model": "gpt-4o-mini", "api_key": os.environ["OPENAI_API_KEY"]}, tools=[get_weather], ) serve(agent, name="openai-agent", port=8000)

Example: Anthropic Agent

Claude-powered agent — provider auto-detected from the claude- prefix.

anthropic_agent.py
import os from agentinc.sdk import Agent from agentinc.sdk.serve import serve def lookup(topic: str) -> str: """Looks up a fact in the knowledge base.""" return f"Here's what we know about {topic}: it's fascinating." agent = Agent( role="You are a helpful assistant.", model={"model": "claude-sonnet-4-6", "api_key": os.environ["ANTHROPIC_API_KEY"]}, tools=[lookup], ) serve(agent, name="anthropic-agent", port=8002)

Example: Session Memory

Persistent multi-turn conversations backed by Redis.

memory_agent.py
import os from agentinc.sdk import Agent from agentinc.sdk.serve import serve agent = Agent( role="You are a friendly assistant with a long memory.", model={"model": "gpt-4o-mini", "api_key": os.environ["OPENAI_API_KEY"]}, memory={ "type": "redis", "connection": os.environ.get("REDIS_URL", "redis://localhost:6379/0"), "password": os.environ.get("REDIS_PASSWORD"), }, ) serve(agent, name="memory-agent", port=8000)
shell — two-turn session test
# Turn 1 curl -X POST http://localhost:8000 \ -d '{"jsonrpc":"2.0","id":1,"method":"tasks/send","params":{"id":"t1","metadata":{"session_id":"demo"},"message":{"role":"user","parts":[{"type":"text","text":"My name is Alice"}]}}}' # Turn 2 — agent recalls the name curl -X POST http://localhost:8000 \ -d '{"jsonrpc":"2.0","id":2,"method":"tasks/send","params":{"id":"t2","metadata":{"session_id":"demo"},"message":{"role":"user","parts":[{"type":"text","text":"What is my name?"}]}}}'

Example: MCP Server

Connect to an MCP server. Tool schemas are fetched on first call and merged with local tools.

mcp_agent.py
import os from agentinc.sdk import Agent from agentinc.sdk.serve import serve def read_file(path: str) -> str: """Reads a local file.""" with open(path) as f: return f.read() agent = Agent( role="You are a helpful file assistant.", model={"model": "gpt-4o-mini", "api_key": os.environ["OPENAI_API_KEY"]}, tools=[read_file], # local tools mcps=[{ # MCP tools — discovered on first run() "type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], }], ) serve(agent, name="mcp-agent", port=8000)

Example: LangChain Agent

LangChain manages its own LLM calls — implement AgentProtocol directly.

langchain_agent.py
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage from langchain_core.tools import tool as lc_tool from langchain_openai import ChatOpenAI from agentinc.sdk import AgentInput, AgentOutput from agentinc.sdk.serve import serve @lc_tool def calculator(expression: str) -> str: """Evaluates a math expression.""" return str(eval(expression)) llm = ChatOpenAI(model="gpt-4o-mini").bind_tools([calculator]) class LangChainAgent: async def run(self, input: AgentInput): messages = [SystemMessage(content="You are a helpful assistant.")] for msg in input.history: messages.append( HumanMessage(content=msg.content) if msg.role == "user" else AIMessage(content=msg.content or "") ) messages.append(HumanMessage(content=input.message)) response = await llm.ainvoke(messages) if response.tool_calls: yield AgentOutput( tool_calls=[{"id": tc["id"], "name": tc["name"], "arguments": tc["args"]} for tc in response.tool_calls], done=False, ) else: yield AgentOutput(content=response.content, done=True) serve(LangChainAgent(), name="langchain-agent", port=8003)

Example: CrewAI Agent

CrewAI manages its own orchestration — implement AgentProtocol directly and wrap the blocking call.

crewai_agent.py
import asyncio from crewai import Agent as CrewAgent, Crew, Task from agentinc.sdk import AgentInput, AgentOutput from agentinc.sdk.serve import serve researcher = CrewAgent( role="Senior Research Analyst", goal="Provide thorough research on any topic", backstory="You are an experienced research analyst.", verbose=False, ) class CrewAIAgent: async def run(self, input: AgentInput): task = Task(description=input.message, expected_output="Clear analysis", agent=researcher) crew = Crew(agents=[researcher], tasks=[task], verbose=False) # kickoff() is synchronous — wrap to avoid blocking the event loop result = await asyncio.to_thread(crew.kickoff) yield AgentOutput(content=str(result), done=True) serve(CrewAIAgent(), name="crewai-agent", port=8004)

Ship to the Marketplace

Once your agent works locally, publish it to the Agentinc marketplace so tenants can discover and deploy it into their own isolated namespaces.

1. Build & test locally
Run serve() and verify your agent responds correctly over A2A before publishing.
2. Add an agent manifest
Create agent.json in your project with name, description, version, and entry point.
3. Publish via CLI
Run agentinc publish to bundle and upload your agent to the marketplace registry.
4. Tenants deploy it
Tenants find your agent in the marketplace and deploy it into their namespace with one click.

agent.json manifest

agent.json
{ "name": "my-agent", "version": "1.0.0", "description": "A helpful assistant with tool support", "entrypoint": "agent.py", "runtime": "python3.12", "capabilities": { "streaming": true, "tools": true, "memory": false } }

Publish

shell
# Login to the Agentinc registry agentinc login # Publish from your project directory agentinc publish # Publish a specific version agentinc publish --version 1.2.0 # List your published agents agentinc agents list

Entry point structure

Your entrypoint file must expose a top-level variable named agent that satisfies AgentProtocol.

agent.py
# agent.py — this file is what the platform imports import os from agentinc.sdk import Agent def get_weather(city: str) -> str: """Gets the current weather for a city.""" return f"72°F and sunny in {city}" # The platform reads this variable — name must be "agent" agent = Agent( role="You are a helpful weather assistant.", model={"model": "gpt-4o-mini", "api_key": os.environ["OPENAI_API_KEY"]}, tools=[get_weather], ) # Optional: run locally for testing if __name__ == "__main__": from agentinc.sdk.serve import serve serve(agent, name="weather-agent", port=8000)
API keys are never bundled. The platform injects them at runtime from the tenant's secret store. Reference them via os.environ as shown above.

All Exports

Everything exported from agentinc.sdk.

python
from agentinc.sdk import ( # Core Agent, # Main class — declare and run agents AgentProtocol, # Protocol — implement run() for custom integrations ToolProtocol, # Protocol — implement schema() + call() AgentFactory, # Type alias — callable returning AgentProtocol # Schemas AgentInput, # Model — agent invocation input AgentOutput, # Model — single output chunk Message, # Model — conversation history entry ToolCall, # Model — tool invocation request ToolSchema, # Model — tool JSON schema # Config TypedDicts ModelConfig, # Provider + credentials MemoryConfig, # Redis memory config MCPConfig, # MCP server connection config DataConfig, # RAG config (reserved) # Tools ToolWrapper, # Class — wraps callable as ToolProtocol tool, # Decorator — function → ToolWrapper # Deprecated RawAdapter, # DEPRECATED — use Agent() instead ) # A2A serve module (requires [serve] extra) from agentinc.sdk.serve import create_app, serve