使用说明
twisp-mcp
A local stdio bridge to Twisp's authenticated cloud MCP, with an optional direct GraphQL connection for local development. It can launch Codex with the bridge configured for that session and obtain renewable Twisp tokens from AWS credentials.
| Mode | graphql_execute |
Search, documentation, and other tools |
|---|---|---|
local (default) |
Direct to TWISP_ENDPOINT |
Cloud MCP |
cloud |
Cloud MCP | Cloud MCP |
flowchart LR
Launcher[twisp-mcp launcher] --> Agent[Codex]
Agent -->|stdio| Bridge[twisp-mcp bridge]
Bridge -->|AWS identity proof| Auth[Twisp token exchange]
Auth -->|short-lived JWT| Bridge
Bridge -->|JWT + tenant| Cloud[Hosted Twisp MCP]
Bridge -->|local mode GraphQL only| Local[Local Twisp]
Installation
The commands below use a macOS or Linux shell. Install these prerequisites:
- Go 1.25.5 or newer, with
goonPATH. - Codex CLI, with
codexonPATH, if you want to launch Codex. Startcodexonce to complete its sign-in. - AWS CLI v2 if you use the AWS SSO setup and login commands below. The bridge itself uses the AWS SDK and does not require the AWS CLI for other credential sources.
Install or update from main
Run this from any directory; no repository checkout or GitHub SSH key is needed:
GOBIN="$HOME/bin" GOWORK=off go install github.com/parsnips/twisp-mcp@main
~/bin/twisp-mcp --version
This builds the current main branch and installs ~/bin/twisp-mcp. Run the
same command whenever you want to update. GOWORK=off keeps installation
independent of any Go workspace configured by your current project.
You can use ~/bin/twisp-mcp directly in every command below. To also run it as
twisp-mcp, add this line to your shell startup file (~/.zshrc for zsh or
~/.bashrc for interactive bash), then open a new terminal:
export PATH="$HOME/bin:$PATH"
Build from a checkout
If you want to modify the source, install Git and Make as well, then run:
git clone https://github.com/parsnips/twisp-mcp.git
cd twisp-mcp
GOWORK=off make install
~/bin/twisp-mcp --version
This builds ./twisp-mcp and copies it to ~/bin/twisp-mcp. To update an
existing checkout on main:
git pull --ff-only origin main
GOWORK=off make install
Launch Codex against the cloud
You need an existing Twisp tenant/account, a deployed MCP endpoint, and an AWS
identity registered as a client in that tenant. The AWS profile and the Twisp
account are separate: choosing an AWS profile does not select a Twisp tenant.
A profile named dev-ro is read-only only if its Twisp client policies enforce
that access. This bridge does not grant additional permissions.
With Twisp's aws/env wrapper
Run from your Twisp core checkout:
./aws/env us-east-1 dev-ro \
~/bin/twisp-mcp --mode cloud --account '<tenant>' codex
The bridge infers dev from ZONE and us-east-1 from AWS_REGION, both set by
that wrapper. It uses the AWS session supplied by aws-vault and restores
Codex to your original working directory after Bazel enters its runfiles tree.
Relative credential-file paths are preserved. To avoid repeating
the account, set TWISP_MCP_ACCOUNT_ID before launching.
With a standard AWS profile
Configure a profile using your organization's normal AWS sign-in process. For an IAM Identity Center / SSO profile, the initial setup and login are:
aws configure sso --profile twisp-dev
aws sso login --profile twisp-dev
Then launch:
AWS_PROFILE=twisp-dev ~/bin/twisp-mcp \
--mode cloud --env dev --region us-east-1 --account '<tenant>' codex
Existing shared-credentials, assume-role, and credential_process profiles also
use AWS_PROFILE; they do not require the SSO commands above. No aws/env
wrapper is needed. Ambient environment credentials and AWS container/instance
role credentials work through the AWS SDK credential chain as well.
You can also use aws-vault directly:
aws-vault exec twisp-dev -- ~/bin/twisp-mcp \
--mode cloud --env dev --region us-east-1 --account '<tenant>' codex
Flags before codex configure the bridge. Everything after codex is passed
unchanged to Codex, including subcommands and prompts:
AWS_PROFILE=twisp-dev ~/bin/twisp-mcp \
--mode cloud --env dev --account '<tenant>' \
codex exec 'Use the Twisp tools to describe the schema.'
The default target is https://api.us-east-1.dev.twisp.com/mcp. Other environments
or regions work only when MCP is deployed there; selecting a target does not
deploy it. The core branch that introduced hosted MCP enables dev / us-east-1.
Verify cloud access
Replace <tenant> with your Twisp account ID or alias. From the directory where
you want to work, run a preflight without opening an interactive Codex session:
AWS_PROFILE=twisp-dev ~/bin/twisp-mcp \
--mode cloud --env dev --region us-east-1 --account '<tenant>' codex --version
With the Twisp wrapper, run this from the core checkout instead:
./aws/env us-east-1 dev-ro \
~/bin/twisp-mcp --mode cloud --account '<tenant>' codex --version
Success prints the Codex version after authenticating and listing the cloud
tools. Remove --version to start a session, then use /mcp to check that the
Twisp bridge is connected. If preflight fails, see
Troubleshooting preflight.
What the launcher does
The launcher verifies cloud credentials and lists tools before starting Codex.
It injects invocation-only MCP settings and replaces itself with Codex on Unix,
so terminal input, signals, and the exit code behave normally. Codex starts a
second twisp-mcp process for the stdio bridge. That process keeps its own token
in memory and refreshes it before expiry.
Use /mcp in Codex to find twisp_bridge_<session-id>. A unique name prevents
Codex's configuration merging from picking up stale settings from an older MCP
entry. Other configured MCP servers remain enabled; disable an older Twisp entry
in your own Codex configuration if you do not want duplicate Twisp tools.
The launcher does not write ~/.codex/config.toml. It passes credential variable
names in MCP configuration and inherits their values through the process
environment; JWTs and AWS credential values are not placed in command arguments
or token files. Use the launcher again when resuming a session so its bridge
configuration and AWS environment are supplied again.
Local GraphQL development
Local mode preserves the existing routing and credential separation. With your local Twisp running:
TWISP_ENDPOINT=http://localhost:8080/financial/v1/graphql \
TWISP_ACCOUNT_ID=000000000000 \
AWS_PROFILE=twisp-dev \
~/bin/twisp-mcp --mode local --env dev --account '<cloud-tenant>' codex
Here --account is the cloud tenant for documentation/search billing;
TWISP_ACCOUNT_ID is the direct GraphQL account. Local GraphQL never uses the
cloud token or passes its requests through hosted MCP.
The Codex launcher checks cloud access in either mode. For offline local GraphQL,
configure the stdio server directly in an MCP client rather than using the
launcher; plain twisp-mcp starts local mode without requiring cloud access.
Other MCP clients
No launcher is required. Configure your client to run the executable over stdio:
{
"mcpServers": {
"twisp": {
"command": "/absolute/path/to/twisp-mcp",
"args": ["--mode", "cloud", "--env", "dev", "--region", "us-east-1", "--account", "<tenant>", "serve"],
"env": { "AWS_PROFILE": "twisp-dev" }
}
}
}
Perform any interactive AWS login first. Allow at least 45 seconds for startup and 130 seconds for tool calls. The bridge uses the AWS configuration and cached login of the OS user running that MCP process. A GUI client may not inherit your shell environment; set its profile and bridge options explicitly.
Configuration
Usage: twisp-mcp [options] [serve | codex [codex arguments...]]. Options must
precede the command. No command means serve. --help lists flags;
--version prints the version. Logs go to stderr; stdio server stdout is MCP only.
| Variable | Purpose | Default / precedence |
|---|---|---|
TWISP_MCP_MODE |
Tool routing | --mode, then variable, then local |
TWISP_MCP_ENV |
Cloud deployment environment | --env, variable, ZONE, dev |
TWISP_MCP_REGION |
Cloud deployment region | --region, variable, AWS_REGION, AWS_DEFAULT_REGION, us-east-1 |
TWISP_MCP_URL |
Explicit cloud MCP URL | --url, variable, URL built from environment/region |
TWISP_MCP_ACCOUNT_ID |
Cloud tenant/account | --account, then variable; required for cloud requests |
TWISP_MCP_TOKEN_FILE |
File containing cloud OIDC token | Read on every request; takes precedence over other sources |
TWISP_MCP_BEARER_TOKEN |
Explicit cloud OIDC token | Used when no token file is configured |
AWS_PROFILE |
AWS credential profile | AWS SDK default credential chain |
TWISP_ENDPOINT |
Direct GraphQL endpoint in local mode | http://localhost:8080/financial/v1/graphql |
TWISP_ACCOUNT_ID |
Direct GraphQL account in local mode | 000000000000 |
TWISP_BEARER_TOKEN |
Direct GraphQL bearer token | None |
TWISP_API_KEY |
Direct GraphQL API key | Used when no direct bearer token is set |
Credentials and refresh
Without an explicit cloud token or file, the bridge signs a regional AWS STS
GetCallerIdentity request and exchanges it at
https://auth.<region>.<env>.twisp.com/token/iam. The proof is bound to that
Twisp issuer. The returned JWT is cached in memory and renewed on the next
request when it is within one minute of expiry. Concurrent requests share the
cached token. Commercial AWS regions are supported for this exchange.
AWS credential providers that can refresh credentials continue to do so through
the SDK. Fixed credentials injected into the environment by a wrapper cannot
renew themselves: when that AWS session expires, obtain a new session and
relaunch. Expired interactive SSO logins likewise need aws sso login again.
JWT refresh does not extend the underlying AWS login.
An explicit bearer token is static. An explicit token file is re-read on each request, so another process may atomically replace it with a renewed token. Empty, unreadable, or invalid explicit credentials never fall back to AWS. Do not check credentials into the repository.
The bridge mints AWS-derived tokens only for the exact environment/region MCP URL it selects. Custom URLs require an explicit token or token file. All cloud URLs require HTTPS except loopback HTTP for development. Neither GraphQL nor cloud requests follow redirects. Tool arguments cannot change endpoints or credential configuration.
Troubleshooting preflight
An HTTP 401 with a plain unauthorized response can come from the load balancer's
fixed default action, before the request reaches Twisp authentication. Check that
/mcp has a forwarding rule and that the MCP-enabled API service has been deployed.
A running AgentCore runtime alone is not sufficient. If the same identity and
account can query GraphQL but MCP gets this response, check deployment/routing
before changing credentials.
Other 401 responses suggest a rejected bearer token. A 403 indicates an access
rejection: check the account and the identity's Twisp client registration. Pass
literal account IDs as-is; use alias/<name> when selecting a tenant alias.
HTTP errors include their status and a troubleshooting hint without printing
response bodies or credentials.
Tool behavior
Cloud tool definitions, descriptions, schemas, annotations, results, errors, and
metadata are forwarded through the MCP SDK, including JSON and SSE responses.
Tools are discovered rather than hardcoded. In local mode, cloud
graphql_execute is excluded and blocked by the forwarding client; in cloud
mode, that same tool is forwarded with all other cloud tools. The bridge does
not advertise cloud prompts or resources.
The catalog refreshes on tools/list and picks up added, changed, or removed
tools. During an outage, the last successful catalog remains available and cloud
calls return tool errors. Local stdio startup can expose only local GraphQL when
the cloud is unavailable. Pure cloud startup fails if discovery fails.
Discovery has a five-second deadline after startup; initial cloud startup has a
30-second budget and tool calls have a two-minute deadline. The application does
not automatically replay failed tool calls, including mutations.
Search embeddings and write-unit billing stay in the cloud. In local mode, cloud docs and schema may describe a newer Twisp release than your local instance.
Development
make build
go test -race ./...
go vet ./...
Set GOWORK=off for these commands if your shell points at another Go workspace.
Builds and tests need no AWS credentials, live Twisp service, Bedrock access, or
docs corpus. Tests use local HTTP fixtures and a subprocess launcher fixture.
The MCP SDK is pinned to v1.0.0.
main.go,launcher*.go: options, cloud preflight, Codex invocation.internal/server: stdio MCP and mode-specific tool routing.internal/cloud: authenticated HTTP client, AWS exchange/refresh, token files.internal/graphql,internal/tools: direct GraphQL client and local tool.