jobescape-concierge 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jobescape_concierge-0.1.0/.gitignore +25 -0
- jobescape_concierge-0.1.0/PKG-INFO +69 -0
- jobescape_concierge-0.1.0/README.md +57 -0
- jobescape_concierge-0.1.0/pyproject.toml +25 -0
- jobescape_concierge-0.1.0/src/concierge_mcp/__init__.py +1 -0
- jobescape_concierge-0.1.0/src/concierge_mcp/server.py +113 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Secrets & local state — never commit
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
*.json
|
|
6
|
+
!**/.vscode/*.json
|
|
7
|
+
chat_memory.db
|
|
8
|
+
*.db
|
|
9
|
+
*.csv
|
|
10
|
+
result.csv
|
|
11
|
+
*.egg-info/
|
|
12
|
+
# Build artifacts
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
# Python
|
|
16
|
+
__pycache__/
|
|
17
|
+
**/__pycache__/
|
|
18
|
+
*.pyc
|
|
19
|
+
.venv/
|
|
20
|
+
venv/
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
|
|
23
|
+
# Editor
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jobescape-concierge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Concierge text2sql MCP server — connects Claude (and other MCP clients) to the Concierge BigQuery assistant over stdio.
|
|
5
|
+
Author-email: JobEscape <team@jobescape.me>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: anyio>=4.0
|
|
9
|
+
Requires-Dist: httpx>=0.27
|
|
10
|
+
Requires-Dist: mcp>=1.28.1
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# jobescape-concierge
|
|
14
|
+
|
|
15
|
+
Concierge text2sql MCP server. Connects Claude (and any MCP-compatible client) to the Concierge BigQuery assistant over stdio — no repo clone, no database or cloud credentials required.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- [`uv`](https://docs.astral.sh/uv/) installed (for `uvx`)
|
|
20
|
+
- A Concierge API token (request one from the Concierge admin; tokens are tied to your `@nvs.team` email)
|
|
21
|
+
|
|
22
|
+
## Add to Claude Desktop / Claude Code
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
claude mcp add concierge \
|
|
26
|
+
-e CONCIERGE_API_TOKEN=t2s_... \
|
|
27
|
+
-- uvx jobescape-concierge
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or edit `claude_desktop_config.json` directly:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"concierge": {
|
|
36
|
+
"command": "uvx",
|
|
37
|
+
"args": ["jobescape-concierge"],
|
|
38
|
+
"env": {
|
|
39
|
+
"CONCIERGE_API_TOKEN": "t2s_..."
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Replace `t2s_...` with your actual token, then fully quit and reopen Claude Desktop.
|
|
47
|
+
|
|
48
|
+
## Local development
|
|
49
|
+
|
|
50
|
+
Point the server at a locally running Concierge instance:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
CONCIERGE_API_TOKEN=t2s_... CONCIERGE_MCP_URL=http://localhost:8080/mcp/ uvx jobescape-concierge
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Environment variables
|
|
57
|
+
|
|
58
|
+
| Variable | Required | Default | Description |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| `CONCIERGE_API_TOKEN` | Yes | — | Plaintext API token (`t2s_...` prefix). |
|
|
61
|
+
| `CONCIERGE_MCP_URL` | No | `https://concierge-yh7apzuicq-ue.a.run.app/mcp/` | Base URL for the Concierge MCP endpoint. Use a `localhost` URL for local dev. |
|
|
62
|
+
|
|
63
|
+
## How it works
|
|
64
|
+
|
|
65
|
+
On startup the server connects to the Concierge cloud MCP endpoint over HTTPS, validates your token, and fetches the available tool list. It then re-serves those tools over the MCP stdio protocol and forwards every tool call to the cloud. No SQL, schema, or credentials live in this package — all data access happens server-side.
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# jobescape-concierge
|
|
2
|
+
|
|
3
|
+
Concierge text2sql MCP server. Connects Claude (and any MCP-compatible client) to the Concierge BigQuery assistant over stdio — no repo clone, no database or cloud credentials required.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- [`uv`](https://docs.astral.sh/uv/) installed (for `uvx`)
|
|
8
|
+
- A Concierge API token (request one from the Concierge admin; tokens are tied to your `@nvs.team` email)
|
|
9
|
+
|
|
10
|
+
## Add to Claude Desktop / Claude Code
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
claude mcp add concierge \
|
|
14
|
+
-e CONCIERGE_API_TOKEN=t2s_... \
|
|
15
|
+
-- uvx jobescape-concierge
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or edit `claude_desktop_config.json` directly:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"concierge": {
|
|
24
|
+
"command": "uvx",
|
|
25
|
+
"args": ["jobescape-concierge"],
|
|
26
|
+
"env": {
|
|
27
|
+
"CONCIERGE_API_TOKEN": "t2s_..."
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Replace `t2s_...` with your actual token, then fully quit and reopen Claude Desktop.
|
|
35
|
+
|
|
36
|
+
## Local development
|
|
37
|
+
|
|
38
|
+
Point the server at a locally running Concierge instance:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
CONCIERGE_API_TOKEN=t2s_... CONCIERGE_MCP_URL=http://localhost:8080/mcp/ uvx jobescape-concierge
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Environment variables
|
|
45
|
+
|
|
46
|
+
| Variable | Required | Default | Description |
|
|
47
|
+
|---|---|---|---|
|
|
48
|
+
| `CONCIERGE_API_TOKEN` | Yes | — | Plaintext API token (`t2s_...` prefix). |
|
|
49
|
+
| `CONCIERGE_MCP_URL` | No | `https://concierge-yh7apzuicq-ue.a.run.app/mcp/` | Base URL for the Concierge MCP endpoint. Use a `localhost` URL for local dev. |
|
|
50
|
+
|
|
51
|
+
## How it works
|
|
52
|
+
|
|
53
|
+
On startup the server connects to the Concierge cloud MCP endpoint over HTTPS, validates your token, and fetches the available tool list. It then re-serves those tools over the MCP stdio protocol and forwards every tool call to the cloud. No SQL, schema, or credentials live in this package — all data access happens server-side.
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "jobescape-concierge"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Concierge text2sql MCP server — connects Claude (and other MCP clients) to the Concierge BigQuery assistant over stdio."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "JobEscape", email = "team@jobescape.me" },
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"mcp>=1.28.1",
|
|
17
|
+
"anyio>=4.0",
|
|
18
|
+
"httpx>=0.27",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
jobescape-concierge = "concierge_mcp.server:main"
|
|
23
|
+
|
|
24
|
+
[tool.hatch.build.targets.wheel]
|
|
25
|
+
packages = ["src/concierge_mcp"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Stdio MCP server — connects Claude (and other MCP clients) to the Concierge cloud.
|
|
2
|
+
|
|
3
|
+
Run as:
|
|
4
|
+
CONCIERGE_API_TOKEN=t2s_... uvx jobescape-concierge
|
|
5
|
+
|
|
6
|
+
This is a thin proxy. It holds no SQL, schema, or credentials: it opens an
|
|
7
|
+
authenticated connection to the already-deployed Concierge MCP server over HTTPS,
|
|
8
|
+
mirrors the tools that server exposes, and forwards every tool call to it over
|
|
9
|
+
stdio. All the real work (table selection, RAG, BigQuery, chat memory) happens
|
|
10
|
+
server-side in the cloud deployment.
|
|
11
|
+
|
|
12
|
+
Environment variables:
|
|
13
|
+
CONCIERGE_API_TOKEN Required. The plaintext API token (prefix t2s_...).
|
|
14
|
+
CONCIERGE_MCP_URL Optional. Base URL for the Concierge MCP endpoint.
|
|
15
|
+
Defaults to the production Cloud Run URL below.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
import anyio
|
|
23
|
+
import httpx
|
|
24
|
+
import mcp.server.stdio
|
|
25
|
+
import mcp.types as types
|
|
26
|
+
from mcp import ClientSession
|
|
27
|
+
from mcp.client.streamable_http import streamable_http_client
|
|
28
|
+
from mcp.server.lowlevel import Server
|
|
29
|
+
|
|
30
|
+
DEFAULT_URL = "https://concierge-yh7apzuicq-ue.a.run.app/mcp/"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def _async_main() -> None:
|
|
34
|
+
token = os.environ.get("CONCIERGE_API_TOKEN", "").strip()
|
|
35
|
+
if not token:
|
|
36
|
+
print(
|
|
37
|
+
"ERROR: CONCIERGE_API_TOKEN environment variable is not set.",
|
|
38
|
+
file=sys.stderr,
|
|
39
|
+
)
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
|
|
42
|
+
url = os.environ.get("CONCIERGE_MCP_URL", DEFAULT_URL)
|
|
43
|
+
|
|
44
|
+
# The cloud server requires a valid Bearer token on EVERY HTTP request. Set it
|
|
45
|
+
# as a default header on the httpx client so it is attached to all requests
|
|
46
|
+
# (tool-call POSTs, the SSE GET stream, and the session-terminate DELETE).
|
|
47
|
+
auth_headers = {"Authorization": f"Bearer {token}"}
|
|
48
|
+
http_timeout = httpx.Timeout(30.0, read=300.0)
|
|
49
|
+
|
|
50
|
+
# Open one long-lived connection to the cloud MCP server for the whole
|
|
51
|
+
# lifetime of this process, then re-serve its tools locally over stdio.
|
|
52
|
+
try:
|
|
53
|
+
async with httpx.AsyncClient(
|
|
54
|
+
headers=auth_headers, timeout=http_timeout, follow_redirects=True
|
|
55
|
+
) as http_client:
|
|
56
|
+
async with streamable_http_client(url, http_client=http_client) as (
|
|
57
|
+
read_stream,
|
|
58
|
+
write_stream,
|
|
59
|
+
_get_session_id,
|
|
60
|
+
):
|
|
61
|
+
async with ClientSession(read_stream, write_stream) as client:
|
|
62
|
+
init_result = await client.initialize()
|
|
63
|
+
remote_tools = (await client.list_tools()).tools
|
|
64
|
+
|
|
65
|
+
print(
|
|
66
|
+
f"jobescape-concierge: connected to {url} "
|
|
67
|
+
f"({len(remote_tools)} tools)",
|
|
68
|
+
file=sys.stderr,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Reuse the cloud server's own instructions so client guidance
|
|
72
|
+
# (chat_memory_id handling, etc.) updates without re-publishing.
|
|
73
|
+
instructions = getattr(init_result, "instructions", None)
|
|
74
|
+
server = Server("concierge", instructions=instructions)
|
|
75
|
+
|
|
76
|
+
@server.list_tools()
|
|
77
|
+
async def handle_list_tools() -> list[types.Tool]:
|
|
78
|
+
return [
|
|
79
|
+
types.Tool(
|
|
80
|
+
name=t.name,
|
|
81
|
+
description=t.description,
|
|
82
|
+
inputSchema=t.inputSchema,
|
|
83
|
+
)
|
|
84
|
+
for t in remote_tools
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
@server.call_tool()
|
|
88
|
+
async def handle_call_tool(
|
|
89
|
+
name: str, arguments: dict | None
|
|
90
|
+
) -> list[types.ContentBlock]:
|
|
91
|
+
result = await client.call_tool(name, arguments or {})
|
|
92
|
+
return list(result.content)
|
|
93
|
+
|
|
94
|
+
init_options = server.create_initialization_options()
|
|
95
|
+
async with mcp.server.stdio.stdio_server() as (r, w):
|
|
96
|
+
await server.run(r, w, init_options)
|
|
97
|
+
except SystemExit:
|
|
98
|
+
raise
|
|
99
|
+
except Exception as exc:
|
|
100
|
+
print(
|
|
101
|
+
f"ERROR: could not connect to Concierge at {url}: {exc}",
|
|
102
|
+
file=sys.stderr,
|
|
103
|
+
)
|
|
104
|
+
sys.exit(1)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main() -> None:
|
|
108
|
+
"""Console entry point — invoked by `jobescape-concierge` / `uvx jobescape-concierge`."""
|
|
109
|
+
anyio.run(_async_main)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
if __name__ == "__main__":
|
|
113
|
+
main()
|