Getting StartedPython SDK

Python SDK API reference

Reference for the MarcoPolo Python SDK resources, methods, models, and errors.

Preview release

This reference covers marcopolo-sdk 0.3.0 (Python 3.11+).

New to the SDK? Start with the developer guide.

Conventions

  • All methods are async; both clients are async context managers and should be closed (or used with async with).
  • Request models reject unknown fields; response models tolerate additive fields while validating all published ones strictly, so old SDKs keep working as the API grows.
  • Empty or blank string arguments raise ValueError locally, before any request leaves the client.
  • Timestamps are timezone-aware datetime objects; enums are typed Literals.

Client and authentication

Marcopolo(...)

Marcopolo(
    access_token: str,                        # an API token from Developer Tools, or a namespace user token
    base_url: str = "https://mcp.marcopolo.dev",
    timeout: float = 60.0,
    max_retries: int = 2,                     # transport-level connection retries
    client_name: str | None = None,           # User-Agent override
    client_version: str | None = None,
)

Resources covered here: client.connections, client.connection_types, client.connection_setup, client.operations, client.catalog, client.workspace, and client.toolkit (see Agent toolkit).

Plain-HTTP base URLs are rejected unless loopback, because the bearer credential rides every request. The client sends X-Marcopolo-SDK-Version on every call; see compatibility.

MarcopoloNamespace(...)

For platforms with a namespace provisioned by Marcopolo; most callers authenticate with an API token and don't need it. See MarcoPolo Namespace with Per-User Workspaces.

MarcopoloNamespace(
    api_key: str,                             # namespace key, "mpk_..."
    base_url: str = "https://mcp.marcopolo.dev",
    timeout: float = 30.0,
)

The namespace key is attached only to the token-exchange request, never stored on client headers, and the exchange is never retried automatically.

Namespace user tokens

Only for platforms with a provisioned namespace. See MarcoPolo Namespace with Per-User Workspaces.

MarcopoloNamespace.issue_user_token(email)

write

Returns UserToken. Provisions the user on first issue. The tenant is derived from the email domain server-side. Consumer email domains are refused with ValidationError.

UserToken

FieldTypeNotes
access_tokenstrBearer credential for Marcopolo(access_token=...). Scrubbed from repr().
token_typestr"Bearer"
expires_inintSeconds; fixed at 300. Re-exchange the key rather than refreshing.
email, namespace, tenantstrEchoed so the caller can confirm where the token landed without decoding it.

Connection types

client.connection_types.list(...)

read

connection_types.list(search=None, category=None, auth_method=None) returns list[ConnectionType]. Filters combine. auth_method is one of manual | oauth | service_account | builtin.

client.connection_types.get(connection_type)

read

Returns ConnectionType; 404 for unknown types.

ConnectionType

FieldTypeNotes
connection_typestrStable identifier, e.g. "pg", "hubspot".
display_name, description, categorystr / str? / str?
auth_methodslistWhich creation paths the type supports.
capabilitieslistSetup-time features (test, schema, ssh_tunnel, file handling, …). Runnable operations come from workspace connections.
setup_methodslistThe type's ways of connecting, in recommended order. See SetupMethod below.
setup_schemadictDeprecated in favor of setup_methods: the flat JSON schema for the non-interactive path.
icon_pathstrPublic logo path, e.g. /app/static/db-logos/pg.png — join onto the service base URL; served unauthenticated, with default.png available as a fallback.
ui_featuresmodelPresentation hints, including requires_oauth.
deprecatedbool

SetupMethod and SetupField

Each SetupMethod carries method (stable id), kind (fields: collect the listed inputs and call create; hosted_oauth: start a hosted setup session), category, display_name, description, and fields.

Each SetupField carries name (dotted for nested groups, e.g. ssh_tunnel.ssh_pkey), type, required, secret, label, description, default, plus everything a form renderer needs:

FieldNotes
choicesSetupFieldChoice value/label pairs for enum inputs.
item_type, min_itemsElement type and minimum length for array fields.
fileA SetupFileSpec (extensions, max_size_mb, allow_create_empty, info_text) for file-backed inputs.
group_labelDisplay heading shared by a dotted group.
advancedRender collapsed by default.

Supported connection types

79 connection types ship in this preview. This table is generated from the authoritative registry; discover the live set (and each type's setup methods) at runtime through connection_types.list().

TypeProviderCategoryAuth
clickupClickUpanalyticsoauth
freshdeskFreshdeskanalyticsmanual
grafana_lokiGrafana Lokianalyticsmanual
grafana_mimirGrafana Mimiranalyticsmanual
grafana_tempoGrafana Tempoanalyticsmanual
graphiteGraphiteanalyticsmanual
hubspotHubSpotanalyticsoauth
lightfieldLightfieldanalyticsmanual
mixpanelMixpanelanalyticsmanual
netsuiteNetSuiteanalyticsmanual
quickbooksQuickBooksanalyticsoauth
salesforceSalesforceanalyticsoauth
sentrySentryanalyticsmanual
slackSlackanalyticsmanual + oauth
treasuredataTreasureDataanalyticsmanual
workosWorkOSanalyticsmanual
yandex_appmetrikaYandex AppMetricaanalyticsmanual
yandex_metrikaYandex Metricaanalyticsmanual
cloudwatchAmazon CloudWatchcloudmanual
cloudwatch_insightsAmazon CloudWatch Logs Insightscloudmanual
aws_esAmazon Elasticsearch Servicecloudmanual
athenaAthenacloudmanual
s3AWS S3cloudmanual
abfsAzure Blob Storagecloudmanual
abfssAzure Blob Storage Securecloudmanual
azure_cosmosdbAzure Cosmos DB (SQL API)cloudmanual
bigqueryBigQuerycloudmanual
elasticsearch2ElasticSearchcloudmanual
fabsparkFabric Sparkcloudmanual
elasticsearch2_ImmersaSQLElasticSearchImmersaSQLElasticSearchcloudmanual
deltaMicrosoft Fabric OneLakecloudmanual
elasticsearch2_OpenDistroSQLElasticSearchOpenDistroSQLElasticSearchcloudmanual
sftpSFTPcloudmanual
elasticsearch2_XPackSQLElasticSearchXPackSQLElasticSearchcloudmanual
amazon_documentdbAmazon DocumentDBdatabasemanual
drillApache Drilldatabasemanual
arangodbArangoDBdatabasemanual
axibasetsdAxibase Time Series Databasedatabasemanual
CassandraCassandradatabasemanual
clickhouseClickHousedatabasemanual
cockroachCockroachDBdatabasemanual
dataprimeCoralogixdatabasemanual
couchbaseCouchbasedatabasemanual
dgraphDgraphdatabasemanual
druidDruiddatabasemanual
exasolExasoldatabasemanual
githubGitHubdatabaseoauth
hiveHivedatabasemanual
hive_httpHive (HTTP)databasemanual
impalaImpaladatabasemanual
influxdbInfluxDBdatabasemanual
kylinKylindatabasemanual
memsqlMemSQLdatabasemanual
mssqlMicrosoft SQL Serverdatabasemanual
mongodbMongoDBdatabasemanual
mysqlMySQLdatabasemanual
rds_mysqlMySQL (Amazon RDS)databasemanual
phoenixPhoenixdatabasemanual
pinotPinotdatabasemanual
pgPostgreSQLdatabasemanual
prestoPrestodatabasemanual
promqlPrometheusdatabasemanual
redshiftRedshiftdatabasemanual
redshift_iamRedshift (with IAM User/Role)databasemanual
remote_redashRemoteRedashdatabasemanual
rocksetRocksetdatabasemanual
insecure_scriptScriptdatabasemanual
scyllaScyllaDBdatabasemanual
snowflakeSnowflakedatabasemanual
sqliteSqlitedatabasemanual
trinoTrinodatabasemanual
verticaVerticadatabasemanual
google_driveGoogle Drivedocumentoauth + service_account
jiraJiradocumentmanual
jsonJSONdocumentmanual
local_fileLocal Filedocumentmanual
onedriveOneDrivedocumentoauth
sharepointSharePointdocumentoauth
uptycsUptycssecuritymanual

Connections

client.connections.list()

read

Returns list[Connection] — everything visible to the principal.

client.connections.get(connection)

read

Returns Connection. Invisible and missing are both 404.

client.connections.get_configuration(connection)

read

Returns ConnectionConfiguration: provider settings with secret values masked.

client.connections.create(...)

write

connections.create(connection_type=, display_name=, setup_method=, fields=) returns Connection.

Non-interactive creation: declare a method from the type's setup_methods and pass its inputs as one fields mapping — the server stores values by the method definition and rejects unknown fields, missing required fields, badly shaped values (wrong type, arrays below min_items), wrong-method submissions, and hosted-OAuth methods with errors naming the problem. Use hosted connection setup for OAuth methods, or authorize them in the web app. 409 when the derived name already exists.

FileUpload

FileUpload.from_path(path)
FileUpload.from_bytes(filename, content)
FileUpload.create_empty()        # only where the field's file spec sets allow_create_empty

The value for a file-backed setup field (one whose SetupField.file spec is set). Serialized as {"filename", "content_base64"} or {"create_empty": true}; the server validates the extension and decoded size against the published spec. A server-side path is never accepted.

client.connections.update(...)

write

connections.update(connection, display_name=None, configuration_patch=None) returns Connection. Patches metadata and non-secret configuration; at least one field required.

client.connections.test(connection)

Returns ConnectionTest. Runs the provider check through the runtime. A failed check is a returned outcome, not an exception.

client.connections.delete(connection)

delete

204 on success; requires management permission.

Connection

FieldTypeNotes
namestrStable machine identifier used in every other call.
display_namestrHuman name. Validated after trimming: 3–64 chars, at least one letter or number.
connection_type, connection_type_display_name, categorystr / str / str?
auth_methodliteralmanual | oauth | service_account | builtin
owner, is_owner, can_managestr? / bool / bool
share_modeliteralprivate | company | users
access_reasonliteralWhy the principal can see it: owner | shared_with_company | shared_with_you | admin | unowned
is_personal, is_demo_connectionbool

ConnectionTest

connection_name, connection_type, status (succeeded | failed), message, checked_at, latency_ms, and optional authorization_status (valid | reauthorization_required | check_failed) — the signal to send a user back through OAuth setup.

Connection sharing

client.connections.share(connection, scope, users=None)

write

Returns ConnectionSharing. ShareScope.COMPANY, or ShareScope.USERS with a user list.

client.connections.unshare(connection, scope, users=None)

write

Returns ConnectionSharing. Symmetric with share.

client.connections.get_sharing(connection)

read

Returns ConnectionSharing: shared_with_company, shared_with_users, optional warning.

Share targets must be members of the tenant. Sharing requires management permission on the connection.

Connection setup (hosted OAuth)

These SDK methods use the REST endpoints POST /api/v1/connection-setup-sessions and GET /api/v1/connection-setup-sessions/{setup_session_id}. They start and observe a browser authorization flow for the current user. They are separate from MarcoPolo's MCP tool surface.

client.connection_setup.start(...)

write

connection_setup.start(connection_type=, display_name=, return_url=None, client_session_id=None, requested_scopes=None) returns ConnectionSetupStart.

Without return_url, the provider returns the user to MarcoPolo's completion page. With a dedicated MarcoPolo namespace, return_url can point to your application on an origin registered for that namespace; Google Drive does not support this return path.

Retrying with the same client_session_id reuses an in-flight session instead of creating a duplicate.

Errors: ValidationError for an unknown or non-OAuth type or an unusable return_url; PermissionDeniedError when the caller may not create connections or the return origin is not registered; ServiceUnavailableError (503) when the provider is not configured on the deployment.

client.connection_setup.get(setup_session_id)

read

Returns ConnectionSetupSession. Missing, expired, and another user's sessions all read as 404.

ConnectionSetupSession

FieldTypeNotes
setup_session_idstrUnguessable, user-scoped.
statusliteralpending → exactly one of ready | failed. Terminal states never change.
connection_type, connection_name, display_namestrconnection_name is the name the connection is addressable by once ready.
return_urlstr?Where the user's browser returns in your application, when one was given.
created_at, expires_atdatetimeSessions expire 15 minutes after their last change.
failuremodel?code and message, set only on failed.

ConnectionSetupStart extends the session with authorization_url, which you open for the user. Provider tokens never appear in these models. See the SDK walkthrough.

Operations

client.operations.query(...)

write
operations.query(
    connection_name, *,
    source,
    parameters=None, input_reference=None,
    inline=False, inline_limit=500,
)

Returns Operation. source names exactly one kind:

sourceRuns
{"kind": "query_text", "text": "..."}Query text supplied with the request.
{"kind": "saved_query", "path": "..."}A query file in the user's workspace, by workspace-relative path. Absolute paths and parent traversal are rejected.
{"kind": "provider_operation", "definition": {...}}A provider action expressed as configuration rather than query text.

parameters template-substitutes into the query; input_reference chains a prior result reference in as input; a provider operation's definition is passed to the connector verbatim, in the shape its query guide documents. Synchronous: dispatched, executed, and returned terminal in one call; the execution ceiling is 300 seconds, beyond which UpstreamTimeoutError (504) is raised and nothing has completed. Raise the client timeout above the ceiling for long queries.

client.operations.records(operation_id, limit=500, offset=0)

read

Returns OperationRecords: a bounded page from a materialized result; limit accepts 1–5000. Continue with next_offset while it is not None. ResourceGoneError (410) when the relation has been dropped — distinct from 404.

offset = 0
while offset is not None:
    page = await client.operations.records(operation_id, limit=500, offset=offset)
    consume(page.rows)
    offset = page.next_offset

Operation

FieldTypeNotes
idstrIdentifies the run; pass to records().
kindliteral"query"
connection_name, started_at, duration_msstr / datetime / int
statusliteralsucceeded | failed. A query that ran and failed is a completed operation, not an HTTP error.
failuremodel?Category and message when status="failed".
resultResult?Present on success.

Result

FieldTypeNotes
inline_outcomeliteralnot_requested | included | unavailable — a degraded inline read is reported, not returned as an empty success.
referencemodel?name (addressable as a relation in queries against the reserved DUCKDB connection), row_count, and fields — each with name and type. References live in the caller's workspace result store and are not durable storage; a dropped reference reads as 410.
recordsmodel?Inline rows when requested: rows, fields, truncation metadata. inline_limit accepts 1–5000.

Catalog

client.catalog.inspect(connection, database=None, table=None)

read

Reads the requested depth in one call: databases with only connection, tables with database, and columns with both database and table. Returns the matching list model below. table without database raises ValueError.

client.catalog.databases(connection)

read

Returns CatalogDatabaseList: top-level containers. ValidationError when the connector publishes no catalog.

client.catalog.tables(connection, database=)

read

Returns CatalogTableList.

client.catalog.columns(connection, database=, table=)

read

Returns CatalogColumnList: column names, source types, descriptions, attributes.

client.catalog.query_guide(connection)

read

Returns QueryGuide: connection_name and markdown — connector-authored prose describing the provider's query syntax and provider_operation shapes. 404 when the connector publishes none.

Catalog reads authorize through the same rule as running an operation, so a connection you can describe is a connection you can query.

Workspace

client.workspace.connections()

read

Returns WorkspaceConnectionListResponse: connections, count, customer, and next_actions. Each entry in connections pairs a Connection with the operations it can actually run (capabilities, e.g. query, test, describe) plus workspace_path and an optional note. Slower than connections.list() because it consults the execution workspace.

client.workspace.shell(command, *, timeout=30)

write

Returns WorkspaceShellResult. Runs a command in the user's persistent workspace and waits up to timeout seconds (1–300). A command that outlives timeout keeps running and returns status="running"; poll it with workspace.shell(f"execution status {result.execution_id}"), whose stdout is the polled execution's record as JSON (status, failure, and an outcome with exit_code, stdout_tail, stderr_tail). A workspace permits one background command at a time. A command that ran and failed returns status="failed"; only a command that never ran raises.

WorkspaceShellResult

FieldTypeNotes
execution_idstrStable id used by execution status.
statusliteralrunning | succeeded | failed
exit_codeint?None while running.
stdout, stderrstrBounded output tails.
failuremodel?kind (timed_out | lost | command_failed) and message.
next_actionslist[str]Polling or inspection guidance when needed.

Agent toolkit

client.toolkit.tools()

read

Returns list[ToolDefinition]: name, description, input_schema, and result_schema (JSON Schema) for each agent tool. The catalog is bundled with the SDK release, so this makes no network request. Argument and result schemas are derived from the public API contract.

client.toolkit.execute(name, arguments=None)

Invokes the SDK resource method bound to name and returns its ordinary typed result or raises its ordinary error. An unknown name raises ValueError. Common data workflow tools include:

ToolCalls
connections_listworkspace.connections()
workspace_shellworkspace.shell(command, timeout=)
connection_catalogcatalog.inspect(connection, database=, table=)
query_guidecatalog.query_guide(connection)
operation_recordsoperations.records(operation_id, limit=, offset=)

marcopolo.toolkit.langchain.langchain_tools(toolkit)

Returns list[StructuredTool]: asynchronous LangChain tools, usable directly by LangGraph's ToolNode and create_react_agent. Requires the langchain extra (pip install "marcopolo-sdk[langchain]", langchain-core>=0.3.79,<2).

  • Arguments are validated against each tool's published input schema before the call.
  • Results are returned as JSON message content, with the same data as the ToolMessage artifact.
  • Failed executions and recoverable request errors become error ToolMessages the model can act on; a running shell execution keeps its execution_id and next_actions.
  • AuthenticationError, SDKVersionUnsupportedError, TransportError, and ResponseValidationError raise to application code.

Error contract

All exceptions derive from MarcopoloError and carry message, code, status_code, retryable, correlation_id, details, and retry_after. The correlation id ties a failure to Marcopolo's server-side traces — include it in support requests.

ExceptionStatusMeaning
AuthenticationError401Missing, invalid, expired, or revoked credential. Create a new API token; for namespace user tokens, re-exchange the namespace key.
PermissionDeniedError403Authenticated but not allowed — policy, ownership, or an unregistered OAuth return origin.
NotFoundError404Missing or not visible to this principal; the two are indistinguishable by design.
ValidationError400 / 422Input the contract rejects.
ConflictError409State conflict, e.g. a connection name that already exists.
ResourceGoneError410Existed and was dropped — e.g. an expired result relation.
SDKVersionUnsupportedError426Package below the service's compatibility floor; upgrade.
ServiceUnavailableError503The workspace or another required service is temporarily unavailable.
UpstreamTimeoutError504The execution ceiling was reached; nothing completed.
APIErrorotherAny other server response, including 429 and unclassified 5xx responses, with retryable derived from status and method safety.
TransportError—The request never produced an HTTP response.
ResponseValidationError—The response did not match the published contract; carries the correlation id for reporting.

Compatibility and transport

  • The client sends its immutable package version in X-Marcopolo-SDK-Version; the service rejects versions below its floor with 426 and always echoes X-Marcopolo-Min-SDK-Version.
  • Generated request models reject unknown fields; generated response models ignore unknown additive fields while validating all published fields strictly.
  • max_retries applies to transport-level connection failures. Application-level retries are the caller's decision, guided by error.retryable.
  • Non-loopback base URLs must be HTTPS.
  • Requests may be rate limited; a 429 surfaces as APIError with retryable=True and any server-provided retry_after.
  • Preview terms: current package version 0.3.0, Python 3.11+. Breaking wire changes before general availability are gated by the version floor rather than silently changing behavior. API tokens are created in Developer Tools; namespace keys, OAuth return-origin registration, and provider enablement are provisioned by your Marcopolo account team, which is also the support channel — include correlation_id values when reporting issues.
  • Models are regenerated from the service's committed OpenAPI contract on every build, keeping SDK types aligned with the wire.

On this page