Getting started
Quickstart: calling MCP
This guide shows you how to mint an MCP passport and call a service tool in 5 minutes. We cover installing the SDK, minting the passport, and calling a tool. For AI agents: /docs/all.en.md.
At a glance#
| Fact | Value |
|---|---|
| Effort | ~5 minutes |
| Type | Agent-side SDK call |
| Delivery | Agent runtime → MCP service |
How it works#
- The agent keeps its Agent Token in the environment.
- The agent mints an
aud=mcppassport for the service domain. - The service verifies the passport locally and runs the tool.
What you need#
Create an agent in the LIME portal and copy its Agent Token — it is shown once, at creation.
Step 1. Install the SDK#
Install the official agent integration package: it handles the token exchange and caches the passport per domain.
pip install "lime-agents-sdk>=3.0.1"Result: python -c "import lime_agents" exits without error.
Step 2. Store the Agent Token#
Authenticate the agent with its Agent Token. Keep it in a .env file and never send it to the client side.
# .env — Agent Token lives here, not in the code
LIME_AGENT_TOKEN="<AGENT_TOKEN>"python -c "import os; print(os.environ['LIME_AGENT_TOKEN'][:4] + '…')"Result: the command prints the token prefix, confirming LIME_AGENT_TOKEN is set in the agent environment.
Step 3. Mint the MCP passport#
The passport proves to the service which agent is calling it. Pass the service host as target: the SDK extracts the host from a bare hostname or a full URL and silently strips any scheme, path, or port.
import asyncio
from lime_agents import LimeAgent
agent = LimeAgent(agent_token="<AGENT_TOKEN>") # replace with your Agent Token
async def main() -> None:
passport = await agent.get_mcp_access_token("<SERVICE_DOMAIN>")
print(passport.access_token)
await agent.aclose()
if __name__ == "__main__":
asyncio.run(main())The SDK maps each method to one concrete shape:
| Method | Accepts | Returns |
|---|---|---|
get_mcp_access_token(target, *, force_refresh=False) | a bare host or full URL, for example demo.lime.pics | McpAccessToken (.access_token, .token_type, .expires_in, .issued_at) |
list_tools(url) | a full URL with scheme and /mcp, for example https://demo.lime.pics/mcp | list[Tool] |
call_tool(url, name, arguments) | the same full URL, plus a tool name and JSON arguments | CallToolResult |
Result: passport.access_token is a JWT with aud=mcp and sub=<AGENT_ID>, issued for 300 seconds.
Step 4. Call a tool#
Send the passport in the Authorization: Bearer header, list the tools, then call one. The service decides which tools are allowed; LIME only confirms identity.
import asyncio
from lime_agents import LimeAgent
agent = LimeAgent(agent_token="<AGENT_TOKEN>") # replace with your Agent Token
async def main() -> None:
print(await agent.list_tools("https://demo.lime.pics/mcp"))
print(await agent.call_tool("https://demo.lime.pics/mcp", "who_am_i", {}))
await agent.aclose()
if __name__ == "__main__":
asyncio.run(main())Result: list_tools prints the tool names, call_tool returns the tool's result, and the service log records the same agent_id.
Example response (JSON)#
The mint call returns the passport and its lifetime in seconds.
{
"access_token": "<PASSPORT>",
"token_type": "Bearer",
"expires_in": 300
}Verify it worked#
| Check | Expected | Negative |
|---|---|---|
Decode passport.access_token | the aud claim is mcp | a wrong X-Agent-Token returns invalid_client (401) |
list_tools with the passport | the service returns at least one tool | a call without Authorization: Bearer returns 401 from the service |
Mint again after the TTL (300 s) | a fresh passport is issued | an empty target, an IP literal, or a reserved host (localhost) raises ValueError in the SDK — locally, before any HTTP request |
| Send the passport to a LIME API | rejected — LIME accepts only X-Agent-Token | a passport sent where X-Agent-Token is expected returns 401 |
Codes and errors#
The mint answers RFC 6749 without an envelope for a bad credential or body. The full public catalogue is in the value reference.
| Code | HTTP | Cause | Action |
|---|---|---|---|
invalid_client | 401 | The mint has no or a wrong X-Agent-Token (RFC 6749) | Re-copy the token into LIME_AGENT_TOKEN |
invalid_request | 400 | The raw HTTP body domain is empty, an IP literal, or a reserved host (localhost, *.internal) (RFC 6749) | Pass the public host, for example demo.lime.pics. On the SDK path a bad target raises ValueError before the call |