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.
@@ -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()