Gateco

ai.gatecoPublished by gateco.aiv1.13.0Updated Oct 24, 2026

Permission-aware retrieval for AI systems: policy-enforced access to organizational knowledge.

Overview

AI-generated overview

Gateco MCP server gives an assistant policy-enforced, permission-aware retrieval over organizational knowledge, so only content a given principal may see…

What you can do
  • Run permission-aware retrieval over connectors using vector, keyword, hybrid or grep search modes
  • Ask grounded questions and get synthesized answers with policy-filtered citations
  • List connectors with readiness levels, list principals and groups, and resolve a principal by email or provider subject
  • Dry-run an access simulation to check what a principal would be allowed to see
When to use it
Use it when an assistant must answer questions from company documents while respecting per-user access policies, and you want retrieval gated by Gateco without writing custom code. It fits teams already using Gateco connectors and identity data.
Requirements
Local Python package installed with uvx or pip (gateco[mcp]) and started as a local process. A Gateco account and a GATECO_API_KEY with the retrieve scope; the access-check tool instead needs a stored user session from gateco login. GATECO_BASE_URL is optional and defaults to the hosted API. Network access to the Gateco API.
Before you install
The API key is a secret sent as a credential on every request; keep it out of shared configs. The access-check tool is not callable with an API key and relies on a stored login session file, which should not be copied between machines. Queries and principal identifiers are sent to the Gateco API, and answers are synthesized from retrieved content, so results depend on correctly configured policies.

Installation

In SourceWeft

  1. Open Gateco in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

Gateco Python SDK

Official Python client for the Gateco API — permission-aware retrieval for AI systems.

[PyPI version] [Python 3.10+] [GitHub]


The problem it solves

Without Gateco, when an employee asks your AI assistant "What is the CEO's salary?", the RAG pipeline returns the salary from a leaked HR document.

With Gateco:

python
from gateco_sdk import GatecoClient
client = GatecoClient("https://api.gateco.ai")client.login("[email protected]", "...")
result = client.retrievals.execute(    query="What is the CEO's salary?",    principal_id="user_james_wu",    connector_id="connector_hr_docs",    search_mode="hybrid",)
# result.allowed_chunks → [] (denied — James Wu lacks HR classification access)# result.denied_count   → 1# result.decision       → "DENIED"# Your AI model never sees the salary data

Gateco sits between your AI agent and your vector store. Every retrieval is evaluated against your access policies before any content reaches the model.


Installation

bash
pip install gateco

For MCP server support (Claude Desktop, Cursor, etc.):

bash
pip install gateco[mcp]

Authentication

Gateco API keys use the format gck_<env>_<random> (e.g. gck_live_abc123...).

Generate keys via the dashboard or via client.api_keys.create(name="my-service").

python
from gateco_sdk import AsyncGatecoClient, GatecoClient
# Async client with API keyclient = AsyncGatecoClient("https://api.gateco.ai", api_key="gck_live_abc123...")
# Sync client with API keyclient = GatecoClient("https://api.gateco.ai", api_key="gck_live_abc123...")
# Or use email/password login (issues a short-lived JWT)client = GatecoClient("https://api.gateco.ai")client.login("[email protected]", "password")

The API key is sent as the X-API-Key header on every request. Set it via the GATECO_API_KEY environment variable when using the CLI or MCP server. The key takes precedence over a stored login.

No credential at all? Since 1.13.0 a client constructed with no api_key, no GATECO_API_KEY and no access_token reads the session that gateco login stored in ~/.gateco/credentials.json (and its base_url), and writes refreshed tokens back. One login on a machine serves the CLI, the MCP server and your own scripts; do not copy the file between machines, because refresh rotates and the two copies would revoke each other.

Which routes accept an API key

A key carries explicit scopes, chosen when it is created (Settings > API Keys, every plan). Everything not listed here needs a user session (gateco login or client.login(...)); a key sent there gets 401 AUTH_JWT_REQUIRED, and a key without the needed scope gets 403 API_KEY_SCOPE_MISSING.

ScopeRoutes
retrievePOST /api/retrievals/execute, POST /api/retrievals/filter, POST /api/answers/execute, GET /api/principals, GET /api/principals/:id, POST /api/principals/resolve, GET /api/groups (since 2026-10-02), GET /api/connectors (id, name, type, status)
ingestPOST /api/v1/ingest, /batch, /file, /files, DELETE /api/v1/resources/:id, /api/v1/ingest/jobs*
relationshipsPOST, GET, DELETE /api/relationships
principalsPOST, PATCH, DELETE /api/principals (local directory)
any keyGET /api/users/me (reports the key's name and scopes)

Session only: policies, connector create/update/delete and their search and ingestion configs, identity providers, API-key management, audit, retrieval history, billing, the access simulator, classification suggestions.


Quick Start

Async (recommended for production services)

python
import asynciofrom gateco_sdk import AsyncGatecoClient
async def main():    async with AsyncGatecoClient(        "https://api.gateco.ai",        api_key="gck_live_abc123...",    ) as client:
        # Policy-gated retrieval — the core Gateco primitive        result = await client.retrievals.execute(            query="What is the CEO's salary?",            principal_id="user_james_wu",            connector_id="connector_hr_docs",            search_mode="hybrid",            alpha=0.7,   # 70% vector weight, 30% keyword            top_k=5,        )
        # Allowed chunks are safe to pass to your LLM        for chunk in result.allowed_chunks:            print(f"[ALLOWED] {chunk.resource_id} score={chunk.score}")
        # Denied chunks are redacted — only metadata is surfaced        print(f"Denied: {result.denied_count} chunk(s)")
asyncio.run(main())

Synchronous (scripts and notebooks)

python
from gateco_sdk import GatecoClient
with GatecoClient("https://api.gateco.ai", api_key="gck_live_abc123...") as client:    result = client.retrievals.execute(        query="What is the CEO's salary?",        principal_id="user_james_wu",        connector_id="connector_hr_docs",        search_mode="hybrid",    )    print(result.decision)  # "DENIED"

Available Namespaces

Every namespace, and every method on it, is available on both AsyncGatecoClient (async) and GatecoClient (sync); tests/test_sync_parity.py fails the build if the two drift.

NamespaceDescription
client.answersGrounded answer synthesis with policy-filtered citations (Team+)
client.api_keysCreate, list, delete, and rotate API keys
client.auditAudit log listing and CSV export
client.authLogin, signup, token refresh, logout
client.billingPlans, usage meters, invoices, subscription, Stripe checkout and portal
client.connectorsConnector CRUD, connection testing, search/ingestion config, coverage, classification suggestions
client.dashboardAggregated dashboard statistics with optional sparklines
client.data_catalogGated resource listing and metadata updates
client.groupsRead-only groups directory with live member counts
client.identity_providersIdentity provider CRUD and sync (Okta, Azure Entra ID, AWS IAM, GCP)
client.ingestSingle-document, batch, and file ingestion (Tier 1 connectors)
client.onboardingOnboarding status (6 computed steps) and checklist dismissal
client.pipelinesPipeline CRUD and run management
client.policiesPolicy CRUD, lifecycle (activate/archive), and templates
client.principalsPrincipal listing, detail, and resolution by email or provider subject
client.relationshipsREBAC direct-relation CRUD — create, list, delete 1-hop tuples (Team+)
client.retroactiveRetroactive vector registration for existing connectors
client.retrievalsPermission-gated retrieval execution, policy filter, and history
client.simulatorDry-run, live-preview, and batch-preview access simulation (Growth+)
client.sourcesContent-source connections (Drive, SharePoint, Confluence, Notion): create, test, ACL coverage
client.usersCurrent user profile — get_me(), update_me(name)

Retrieval Search Modes

python
# Vector search (default) — semantic similarityresult = await client.retrievals.execute(    query="quarterly earnings", principal_id="...", connector_id="...",)
# Keyword search — ranked full-text search (BM25)result = await client.retrievals.execute(    query="quarterly earnings", principal_id="...", connector_id="...",    search_mode="keyword",)
# Hybrid search — vector + keyword fused (RRF)result = await client.retrievals.execute(    query="quarterly earnings", principal_id="...", connector_id="...",    search_mode="hybrid",    alpha=0.5,   # 1.0 = all-vector, 0.0 = all-keyword)
# Grep — exact pattern matchingresult = await client.retrievals.execute(    query="ERR-4021", principal_id="...", connector_id="...",    search_mode="grep",    pattern_type="regex",    case_sensitive=False,)

API Key Management

python
# Create a key — the plaintext is returned exactly oncekey_info = await client.api_keys.create(name="prod-worker")print(key_info["key"])    # gck_live_abc123...  (store this securely)print(key_info["prefix"]) # gck_live_abc
# List keys (plaintext never returned after creation)keys = await client.api_keys.list()
# Rotate a key — old key is invalidated immediatelynew_key = await client.api_keys.rotate(key_id="key-uuid-here")
# Delete a keyawait client.api_keys.delete(key_id="key-uuid-here")

Relationship-Based Access Control (REBAC)

python
# Create a direct relation: Alice owns resource Rrel = await client.relationships.create(    subject_principal_id="principal-uuid",    relation_name="owner_of",    object_resource_id="resource-uuid",)print(rel["id"])
# List relations for a principalrels = await client.relationships.list(    subject_id="principal-uuid",    relation="owner_of",)
# Delete a relation (invalidates policy cache immediately)await client.relationships.delete(relationship_id=rel["id"])

Use relation.<name> as a policy condition field to gate access on the existence of a tuple:

python
# Policy rule: allow access when principal has owner_of relation on the resourcerule = {"field": "relation.owner_of", "operator": "eq", "value": True}

Onboarding Status

python
# Check which onboarding steps are completestatus = await client.onboarding.status()for step in status["steps"]:    print(f"{step['name']:30s}  {step['status']}")
# Dismiss the checklist once the org is fully configuredawait client.onboarding.dismiss()

Principal Resolution

python
# Resolve a principal by email (read-only — never creates)principal = await client.principals.resolve(email="[email protected]")
# Resolve by raw IDP-side user IDprincipal = await client.principals.resolve(provider_subject="okta-user-123")
# Scoped to a specific identity providerprincipal = await client.principals.resolve(    email="[email protected]",    identity_provider_id="idp-uuid-here",)

Grounded Answer Synthesis (Team+)

python
answer = await client.answers.execute(    query="Summarise the Q4 revenue results.",    principal_id="user_alice",    connector_id="connector_finance_docs",    search_mode="hybrid",)
print(answer.answer_text)      # LLM-generated answer from allowed chunks onlyprint(answer.outcome)          # "answered" | "no_access" | "insufficient_context"for citation in answer.citations:    print(f"  [{citation.score:.2f}] {citation.resource_id}")

Policy Creation

python
# Create an RBAC policypolicy = await client.policies.create(    name="Engineering read-only",    description="Allow engineering group to read internal resources",    type="rbac",    effect="allow",    rules=[{        "description": "Engineering group members",        "effect": "allow",        "conditions": [{"field": "principal.groups", "operator": "contains", "value": "engineering"}],        "priority": 1,    }],    resource_selectors=[{"field": "resource.classification", "op": "lte", "value": "internal"}],)

Policy validation rules:

  • Condition fields must use resource., principal., or relation. prefix. Bare field names (e.g., "classification") are rejected with 422 — they silently resolve against the principal rather than the resource.
  • Policies with empty resource_selectors require apply_to_all_resources=True in the request body to opt into matching all resources explicitly.

Retrieval Diagnostics

python
result = await client.retrievals.execute(    query="quarterly earnings",    principal_id="user_alice",    connector_id="connector_finance_docs",    search_mode="hybrid",)
# All retrieval responses include diagnosticsprint(result.diagnostics.outcome_detail)    # Human-readable explanationprint(result.diagnostics.candidates_fetched)  # How many candidates were checkedprint(result.diagnostics.candidates_denied)   # How many were denied by policyprint(result.diagnostics.refill_rounds)       # How many refill rounds ran (0 = first pass sufficient)

Connector Preflight Check

python
# Check if a connector is production-ready before using it in retrievalspreflight = client.connectors.preflight(connector_id="...")print(preflight.ready_for_production)  # boolprint(preflight.recommendation)        # What to fix nextfor check in preflight.checks:    print(f"{check.name}: {'PASS' if check.passed else 'FAIL'} (blocking={check.blocking})")

Dashboard Activation Metrics

python
# Aggregated dashboard statisticsstats = await client.dashboard.stats()print(stats["total_retrievals"])print(stats["allowed_retrievals"])
# Activation funnel metricsactivation = client.dashboard.get_activation_stats()print(activation.total_retrievals_30d)print(activation.allowed_retrievals_30d)print(activation.no_access_retrievals_30d)  # Retrievals where 0 results were authorizedprint(activation.p95_latency_ms)            # End-to-end p95 latency

Pagination

List endpoints return a Page object. Use list_all() for automatic async pagination:

python
async for connector in client.connectors.list_all():    print(connector.name)

Rate Limits

Three endpoints enforce per-org-per-minute limits:

EndpointLimit
POST /api/retrievals/execute60/min
POST /api/answers/execute20/min
POST /api/simulator/preview10/min

Exceeded limits raise RateLimitError. The SDK retries automatically with exponential backoff (configurable via max_retries). Limits are org-scoped and reset on process restart (in-memory implementation).


Error Handling

python
from gateco_sdk.errors import NotFoundError, RateLimitError, AuthenticationError
try:    conn = await client.connectors.get("nonexistent-id")except NotFoundError:    print("Connector not found")except RateLimitError as e:    print(f"Rate limited — retry after {e.retry_after}s")except AuthenticationError:    print("Invalid or expired credentials")

CLI

The gateco command is installed with the SDK and uses the same credentials.

bash
# Log in once; you are prompted for the password (or pipe it on stdin).# Passing --password on the command line works but lands in shell history.gateco login --email [email protected]
gateco whoami                       # base URL, credential in use, key scopes
# Connectors: inspect and configure (user session only)gateco connectors listgateco connectors get <connector_id>gateco connectors get-search-config <connector_id>gateco connectors set-search-config <connector_id> --json '{"table_name": "docs", "vector_column": "embedding", "content_column": "text"}'gateco connectors get-ingestion-config <connector_id>gateco connectors set-ingestion-config <connector_id> --file ingestion.json
# Ingest: .txt/.md are sent as text; PDF, Word, PowerPoint, Excel and CSV are uploadedgateco ingest report.txt --connector-id <id> --classification confidential --sensitivity highgateco ingest "Q3 board deck.pdf" --connector-id <id> --classification confidential --sensitivity high --domain financegateco ingest-batch ./documents --connector-id <id> --glob "*.md"
# Retrieve as a principal (API key with the retrieve scope, or a session)gateco retrieve --connector-id <id> --principal-id <id> --query "revenue report" --search-mode hybrid

--classification accepts public, internal, confidential, restricted; --sensitivity accepts low, medium, high, critical (gateco ingest --help lists them).


MCP Server (Model Context Protocol)

The optional MCP server lets AI agents (Claude Desktop, Cursor, etc.) perform permission-aware retrieval without any custom code.

bash
pip install gateco[mcp]
# Start the servergateco mcp serve
# Or use the direct entry point (for MCP host configs)gateco-mcp

Claude Desktop Configuration

json
{  "mcpServers": {    "gateco": {      "command": "gateco-mcp",      "env": {        "GATECO_API_KEY": "gck_live_abc123...",        "GATECO_BASE_URL": "https://api.gateco.ai"      }    }  }}

Available MCP Tools

ToolDescription
gateco_retrievePermission-aware retrieval (vector/keyword/hybrid/grep)
gateco_askGrounded answer synthesis with search modes (Team+)
gateco_check_accessDry-run access simulation (Growth+). User session only (gateco login); not callable with an API key
gateco_list_connectorsList connectors with readiness levels
gateco_list_principalsList identity principals
gateco_list_groupsList groups (IdP-synced and local directory) with live member counts. Works with a retrieve-scoped key against a backend from 2026-10-02 on; older backends answer that a user session is needed
gateco_resolve_principalResolve a principal by email or provider subject

All tools return markdown-formatted text. Denied content is never exposed — only denial reasons and counts are shown.


Development

bash
pip install -e ".[dev]"pytest -v
# Run MCP server testspytest tests/test_mcp/ -v
# With coveragepytest --cov=src/gateco_sdk

Links

Source: README.md at commit d188b83

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

3
  1. v1.13.0LatestOct 4, 2026
  2. v1.12.1Sep 27, 2026
  3. v1.11.1Sep 16, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts