# GrantFlow Agent Tool Server

GrantFlow ships a dependency-free stdio tool server for agent runtimes that prefer tool discovery and tool calls over handwritten HTTP clients.

It exposes the same workflow as `/.well-known/agent-tools.json` with `grantflow_`-prefixed tool names:

- `grantflow_onboard_agent`
- `grantflow_create_session`
- `grantflow_introspect_agent`
- `grantflow_exchange_oauth_token`
- `grantflow_rotate_credential`
- `grantflow_revoke_credential`
- `grantflow_register_agent`
- `grantflow_run_preflight`
- `grantflow_start_generation`
- `grantflow_get_status`
- `grantflow_get_quality`
- `grantflow_get_events`
- `grantflow_run_sandbox_happy_path`

## Run Dependency-Free Stdio

Start the GrantFlow API separately, then launch the stdio server:

```bash
export GRANTFLOW_BASE_URL="http://127.0.0.1:8000"
export GRANTFLOW_API_KEY="optional-production-key"
python -m grantflow.mcp.server
```

The server accepts JSON lines shaped like MCP `tools/list` and `tools/call` messages.
Set `GRANTFLOW_BEARER_TOKEN` instead of `GRANTFLOW_API_KEY` when the agent has exchanged OAuth client credentials for an access token.

## Run Official SDK Transport

For production MCP deployments, install the optional MCP extra and use the official Python SDK transport:

```bash
pip install "grantflow[mcp]"
export GRANTFLOW_BASE_URL="http://127.0.0.1:8000"
export GRANTFLOW_API_KEY="optional-production-key"
GRANTFLOW_MCP_TRANSPORT=streamable-http python -m grantflow.mcp.fastmcp_server
```

The official SDK server uses `stateless_http=True` and `json_response=True`, matching the SDK guidance for scalable Streamable HTTP deployments.
It also accepts `GRANTFLOW_BEARER_TOKEN` for OAuth access tokens returned by `grantflow_exchange_oauth_token`.

## List Tools

```json
{"jsonrpc":"2.0","id":"tools","method":"tools/list"}
```

The response includes tool descriptions, JSON input schemas, and GrantFlow annotations such as HTTP method, path, auth requirement, and output hints.

## Call A Tool

```json
{"jsonrpc":"2.0","id":"register","method":"tools/call","params":{"name":"grantflow_register_agent","arguments":{"agent_name":"proposal-worker","agent_type":"workflow_agent","purpose":"Run sandbox generation"}}}
```

The result uses MCP-style content blocks:

```json
{"jsonrpc":"2.0","id":"register","result":{"content":[{"type":"json","json":{"status":"registered"}}],"isError":false}}
```

Errors also return JSON content with `isError=true`, preserving the machine-readable GrantFlow error shape when the API provides one.

## OAuth Token Exchange

When `/agents/onboarding` returns a self-serve OAuth client, exchange it through MCP instead of hand-writing HTTP:

```json
{"jsonrpc":"2.0","id":"token","method":"tools/call","params":{"name":"grantflow_exchange_oauth_token","arguments":{"client_id":"gf_client_agent_proposal_worker","client_secret":"gf_oauth_client_<returned-once>","scope":"generate:write status:read quality:read"}}}
```

Use the returned `access_token` as `Authorization: Bearer <token>` when configuring downstream HTTP callers. The stdio bridge and official SDK transport expose the same tool name.

Credential lifecycle tools:

```json
{"jsonrpc":"2.0","id":"rotate","method":"tools/call","params":{"name":"grantflow_rotate_credential","arguments":{"credential":"gf_agent_<current-token>","ttl_seconds":3600}}}
```

```json
{"jsonrpc":"2.0","id":"revoke","method":"tools/call","params":{"name":"grantflow_revoke_credential","arguments":{"credential":"gf_agent_<old-token>","reason":"credential rotation completed"}}}
```

Use these after failed handoff, suspected exposure, or scheduled credential refresh. Revocation is in-process for sandbox/controlled deployments.

## Sandbox Smoke Workflow

Agents can run the complete sandbox path with one call:

```json
{"jsonrpc":"2.0","id":"smoke","method":"tools/call","params":{"name":"grantflow_run_sandbox_happy_path","arguments":{"agent_name":"proposal-worker","timeout_seconds":20}}}
```

This registers a sandbox agent, uses the returned sample payloads, starts generation with a fresh `request_id`, waits for a terminal status, then returns status, quality, and events.

Use this as a startup self-test before giving an autonomous agent longer-running work.
