Configuration¶
The server validates its configuration and Gmail access before starting either transport. Missing or invalid configuration, unreadable credentials, failed delegation, and failed Gmail requests stop startup with a nonzero exit code. Errors and logs go to stderr; stdout is reserved for MCP stdio.
CLI and environment variables¶
Run python -m justpen_integration_mcp --help for CLI help. From a development
checkout, prefix the command with uv run.
| CLI option | Environment variable | Default | Accepted values |
|---|---|---|---|
| — | JUSTPEN_CONTAINER_HOME |
~/.justpen |
Nonempty filesystem path; ~ expands and relative paths resolve from the working directory. |
--transport |
INTEGRATION_MCP_TRANSPORT |
stdio |
stdio or http. |
--host |
INTEGRATION_MCP_HOST |
127.0.0.1 |
IP address or hostname, without a URL scheme or port. |
--port |
INTEGRATION_MCP_PORT |
8932 |
Integer from 1 to 65535. |
--log-level |
INTEGRATION_MCP_LOG_LEVEL |
INFO |
DEBUG, INFO, WARNING, ERROR, CRITICAL, NOTSET; aliases WARN and FATAL are accepted. Case-insensitive. |
Precedence is CLI > environment > default, independently for each setting.
Validation applies to the effective values, including host and port in stdio
mode. An explicit CLI value replaces the corresponding environment value before
validation. Empty environment values are invalid. --help works without valid
configuration or credentials.
There is no separate integrations-file path setting: its location is always
<JUSTPEN_CONTAINER_HOME>/integrations.json.
Directories and integrations.json¶
Startup creates the home directory and its gmail child if they do not exist.
New directories request owner-only permissions, subject to platform behavior.
Existing permissions and file contents are left in place. Startup does not
generate integrations.json or a service-account key.
With the default home, the layout is:
~/.justpen/
├── integrations.json
└── gmail/
└── service-account.json
The minimal valid configuration is:
{
"email": {
"delegated_user": "[email protected]"
}
}
Its expanded form is:
{
"email": {
"type": "gmail",
"service_account_json_path": "gmail/service-account.json",
"delegated_user": "[email protected]"
}
}
| JSON field | Required | Default / validation |
|---|---|---|
email |
Yes | Object containing the Gmail integration. |
email.type |
No | gmail; other providers are rejected. |
email.service_account_json_path |
No | gmail/service-account.json, resolved beneath the configured home. Must refer to a readable, valid service-account key file. |
email.delegated_user |
Yes | Valid email address for the Google Workspace mailbox to impersonate. |
Unknown JSON fields are rejected, including misspellings. The file must contain
valid UTF-8 JSON. Relative credential paths resolve beneath the configured home;
absolute paths are used directly and explicit ~ paths expand to the user home.
Changing JUSTPEN_CONTAINER_HOME therefore relocates both default file paths.
Configuration is loaded once. Restart the server after configuration or
credential-file changes.
Gmail access validation¶
Enable the Gmail API and configure the service account for Google Workspace domain-wide delegation. An administrator must authorize this OAuth scope:
https://www.googleapis.com/auth/gmail.readonly
The delegated user must have an accessible Gmail mailbox. A service-account key by itself does not grant access to a personal Gmail inbox or to arbitrary Workspace mailboxes.
Startup creates one delegated Gmail client and calls
users.getProfile
with userId="me". This verifies token issuance, delegation, scope and actual
mailbox API access without fetching message content. Only after that succeeds
does the MCP transport start. Token refresh is automatic through Google Auth;
all tool calls reuse the client and the connection closes on shutdown.
Authentication failures, HTTP rejections and network failures have distinct error prefixes. Raw Google error bodies, tokens and private keys are not included in application error messages. Startup validation is a point-in-time check; revoked permissions or later network failures can still make tool calls fail.
Requests have a 10-second socket inactivity timeout. The startup operation has a 30-second budget, and each tool operation has a 60-second budget including queue time. Expired calls issue no further requests. An already running synchronous request cannot be forcibly interrupted: cleanup waits for it before closing the client, so these budgets are not hard process-exit deadlines. The client serializes Gmail operations because its HTTP transport is not thread-safe; this does not block the MCP event loop.
Stdio¶
python -m justpen_integration_mcp
Example MCP client configuration, using the Python environment where the server is installed:
{
"mcpServers": {
"justpen-integration": {
"command": "python",
"args": ["-m", "justpen_integration_mcp"],
"env": {
"JUSTPEN_CONTAINER_HOME": "/absolute/path/to/justpen-home"
}
}
}
}
Omit the env block to use ~/.justpen.
HTTP¶
python -m justpen_integration_mcp --transport http
Connect an MCP client using Streamable HTTP at http://127.0.0.1:8932/mcp.
The equivalent environment setting is INTEGRATION_MCP_TRANSPORT=http.
To choose another bind address and port:
python -m justpen_integration_mcp --transport http --host 127.0.0.1 --port 9000
HTTP serves the same tools and delegated mailbox as stdio. It has no built-in client authentication. The default bind address limits access to the local machine. If you expose it beyond that machine, put access control and TLS in front of it; callers can search the configured mailbox.