source-context-mcp 0.1.dev3__tar.gz → 0.1.dev4__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.
Files changed (31) hide show
  1. source_context_mcp-0.1.dev4/PKG-INFO +209 -0
  2. source_context_mcp-0.1.dev4/README.md +193 -0
  3. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/pyproject.toml +1 -1
  4. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/pyproject.toml.orig +1 -1
  5. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/cli.py +8 -4
  6. source_context_mcp-0.1.dev4/src/source_context_mcp/core/metadata.py +16 -0
  7. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/core/settings.py +7 -2
  8. source_context_mcp-0.1.dev4/src/source_context_mcp/prompts/__init__.py +19 -0
  9. source_context_mcp-0.1.dev4/src/source_context_mcp/prompts/analyze_architecture.py +30 -0
  10. source_context_mcp-0.1.dev4/src/source_context_mcp/prompts/prepare_for_change.py +49 -0
  11. source_context_mcp-0.1.dev4/src/source_context_mcp/prompts/summarize_file.py +33 -0
  12. source_context_mcp-0.1.dev4/src/source_context_mcp/resources/__init__.py +11 -0
  13. source_context_mcp-0.1.dev4/src/source_context_mcp/server.py +92 -0
  14. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/tools/__init__.py +4 -1
  15. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/tools/base.py +25 -28
  16. source_context_mcp-0.1.dev4/src/source_context_mcp/tools/debug.py +27 -0
  17. source_context_mcp-0.1.dev4/src/source_context_mcp/tools/graph.py +76 -0
  18. source_context_mcp-0.1.dev4/src/source_context_mcp/tools/vector.py +42 -0
  19. source_context_mcp-0.1.dev3/PKG-INFO +0 -17
  20. source_context_mcp-0.1.dev3/README.md +0 -1
  21. source_context_mcp-0.1.dev3/src/source_context_mcp/server.py +0 -48
  22. source_context_mcp-0.1.dev3/src/source_context_mcp/tools/debug.py +0 -11
  23. source_context_mcp-0.1.dev3/src/source_context_mcp/tools/graph.py +0 -48
  24. source_context_mcp-0.1.dev3/src/source_context_mcp/tools/vector.py +0 -37
  25. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/__init__.py +0 -0
  26. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/__main__.py +0 -0
  27. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/core/__init__.py +0 -0
  28. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/core/api_client.py +0 -0
  29. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/core/context.py +0 -0
  30. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/core/dependencies.py +0 -0
  31. {source_context_mcp-0.1.dev3 → source_context_mcp-0.1.dev4}/src/source_context_mcp/py.typed +0 -0
@@ -0,0 +1,209 @@
1
+ Metadata-Version: 2.3
2
+ Name: source-context-mcp
3
+ Version: 0.1.dev4
4
+ Summary: Local Model Context Protocol (MCP) server for Source Context code intelligence.
5
+ Author: Le Ngoc Tu, Dang Huu Hieu, Huynh Phat Tai
6
+ Author-email: Le Ngoc Tu <tuleaibk@gmail.com>, Dang Huu Hieu <danghuuhieu038@gmail.com>, Huynh Phat Tai <huynhphtai@gmail.com>
7
+ Requires-Dist: httpx>=0.28.1
8
+ Requires-Dist: mcp[cli]>=2.0.0
9
+ Requires-Dist: pydantic>=2.13.4
10
+ Requires-Dist: pydantic-settings>=2.14.2
11
+ Requires-Dist: tomli-w>=1.2.0
12
+ Requires-Dist: typer>=0.27.0
13
+ Requires-Python: >=3.12
14
+ Project-URL: Repository, https://github.com/TuLe142857/source-context
15
+ Description-Content-Type: text/markdown
16
+
17
+ # Table of Contents
18
+ - [Introduction](#intro)
19
+ - [Requirements](#requirements)
20
+ - [Setup API Server](#setup-api-server)
21
+ - [Setup MCP Server](#setup-mcp-server)
22
+ - [Available CLI Commands](#available-cli-commands)
23
+ - [Available MCP Capabilities](#available-mcp-capabilities)
24
+ - [Tools](#tools)
25
+ - [Resources](#resources)
26
+ - [Prompts](#prompts)
27
+
28
+ # Introduction <a name="intro"></a>
29
+ This MCP server runs on your local machine and communicates over the `stdio` (Standard Input/Output) transport - meaning
30
+ it talks to your coding agent through standard input/output streams rather than over the network.
31
+
32
+ The server is published to `PyPI`, so you can run it directly with the `uvx` command, without a
33
+ manual installation step.
34
+ - Package name: `source-context-mcp`
35
+ - For more details: https://pypi.org/project/source-context-mcp/
36
+
37
+ This MCP server does not analyze your source code by itself. It is a thin bridge:
38
+ - It receives tool calls from your coding agent.
39
+ - It forwards those calls, with your credentials, to a REST API server.
40
+ - That API server is the one actually indexing and analyzing your codebase, and it returns the results back through
41
+ the MCP server to your agent.
42
+
43
+ So before using this MCP server, you need that REST API server up and running (locally or publicly hosted).
44
+
45
+ ```mermaid
46
+ flowchart
47
+ Agents["Coding Agents (Claude, Antigravity, ...)"]
48
+ MCP["This MCP Server"]
49
+ API["REST API Server (locally or publicly hosted)"]
50
+
51
+ Agents --> MCP
52
+ MCP --> API
53
+ ```
54
+
55
+ # Requirements <a name="requirements"></a>
56
+ - uv: a Python package manager, used to run this MCP locally via the `uvx` command (similar in spirit to `npx` for
57
+ Node.js packages).
58
+ - Python version: 3.12+
59
+ - A running REST API server with authentication enabled — see [Setup MCP Server](#setup-mcp-server) below for setup.
60
+
61
+ # Setup API Server <a name="setup-api-server"></a>
62
+ See: https://github.com/TuLe142857/source-context
63
+
64
+ This server manages your team workspace (a workspace can contain many repositories), handles indexing, analyzes the
65
+ codebase, and exposes the REST API that this MCP server calls. You can host it on your local machine or make it public
66
+ on the internet.
67
+
68
+ # Setup MCP Server <a name="setup-mcp-server"></a>
69
+ ## Step 1: Get your Personal Access Token
70
+ Log in to your REST API server and generate a PAT (Personal Access Token) from your account settings. This token
71
+ authenticates the MCP server's requests to the API on your behalf - treat it like a password.
72
+
73
+ ## Step 2: Configure the MCP Server
74
+ You have two ways to set the configuration:
75
+
76
+ **Option A — CLI command:**
77
+ ```shell
78
+ uvx source-context-mcp config \
79
+ --token <your token> \
80
+ --server-url <server_url>
81
+ ```
82
+ Security note: this command may save your token in your shell's command history.
83
+ Prefer Option B below if that's a concern for you.
84
+
85
+ **Option B (recommended) — edit the config file directly:**
86
+ Edit `~/.source_context_mcp/config.toml` (Linux/macOS) or `C:\Users\{username}\.source_context_mcp\config.toml` (Windows):
87
+ ```toml
88
+ SERVER_URL = "http://localhost:8000/mcp/v1"
89
+ PAT = "your token"
90
+ ```
91
+
92
+ ## Step 3: Add MCP server to your coding agent
93
+ This package is published to PyPI, so it can be run via `uvx source-context-mcp run`. It uses `typer` to wrap the MCP
94
+ server as a CLI (Command-Line Interface), so besides `run` it also exposes utility commands like `config`, `show-config`,
95
+ and `config-dir` - see [Available CLI Commands](#available-cli-commands) below.
96
+
97
+ ### Antigravity (IDE & CLI)
98
+ Global scope - Edit `~/.gemini/config/mcp_config.json` (Linux/macOS) or
99
+ `C:\Users\{username}\.gemini\config\mcp_config.json` (Windows):
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "source-context-mcp": {
104
+ "command": "uvx",
105
+ "args": ["source-context-mcp", "run"]
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ Project scope - Edit `.agents/mcp_config.json`:
112
+ ```json
113
+ {
114
+ "mcpServers": {
115
+ "source-context-mcp": {
116
+ "command": "uvx",
117
+ "args": ["source-context-mcp", "run"]
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ ### Claude Code
124
+ Global scope:
125
+ ```shell
126
+ claude mcp add --scope user source-context-mcp -- uvx source-context-mcp run
127
+ ```
128
+
129
+ Project scope - The following command writes to `.mcp.json`, which is shared with your team when committed to git:
130
+ ```shell
131
+ claude mcp add --scope project source-context-mcp -- uvx source-context-mcp run
132
+ ```
133
+
134
+ Local scope - Not shared with your team:
135
+ ```shell
136
+ claude mcp add source-context-mcp -- uvx source-context-mcp run
137
+ ```
138
+
139
+ ### Other Agents
140
+ If you're using a different coding agent, check its documentation for how to add a local MCP server over the `stdio`
141
+ transport. Most agents accept a generic JSON block like this:
142
+
143
+ ```json
144
+ {
145
+ "mcpServers": {
146
+ "source-context-mcp": {
147
+ "command": "uvx",
148
+ "args": ["source-context-mcp", "run"]
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ # Available CLI Commands <a name="available-cli-commands"></a>
155
+ The package installs a `source-context-mcp` CLI (built with `typer`). Run `uvx source-context-mcp --help` at any time
156
+ to see this list from the tool itself.
157
+
158
+ | Command | Description | Options |
159
+ |---------------|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
160
+ | `run` | Run the MCP server over the `stdio` transport. | `--server-url <url>`, `--token <token>`, `--workspace-id <id>` - override the saved config for this run only |
161
+ | `config` | Save configuration (server URL, token, default workspace ID) to the config file. | `--server-url <url>`, `--token <token>`, `--workspace-id <id>` |
162
+ | `show-config` | Print the current configuration. Secret values (e.g. the token) are masked as `*`. | |
163
+ | `config-dir` | Print the path to the configuration directory. | |
164
+
165
+ Global option (on the base `source-context-mcp` command):
166
+ - `--version` / `-v` - print the installed package version and exit.
167
+
168
+ # Available MCP Capabilities <a name="available-mcp-capabilities"></a>
169
+
170
+ ## Tools <a name="tools"></a>
171
+ Tools are like functions that this MCP server exposes to your coding agent. This server provides the following tools:
172
+
173
+ ### General
174
+ - `list_workspaces()` - List all workspaces accessible to the current user.
175
+ - `get_path_settings(path)` - Get the default workspace and repository settings configured for a local path.
176
+ - `default_workspace()` - Get the server-configured default workspace ID, used when the current path has no path-specific default.
177
+ - `list_repositories(workspace_id)` - List all repositories in a workspace.
178
+ - `list_branches(workspace_id, repository_id)` - List all branches in a repository.
179
+ - `list_projects(workspace_id, repository_id, branch_name)` - List all projects on a branch.
180
+
181
+ ### Graph (code structure & relationships)
182
+ - `list_files_in_project(project_id)` - List all files in a project.
183
+ - `get_file_structure(file_id)` - Get a file's structure: classes and methods.
184
+ - `get_file_content(file_id)` - Read a file's full content.
185
+ - `get_node_info(node_id)` - Get node metadata: id, name, file_id, position in file.
186
+ - `get_node_content(node_id)` - Get a node's source content.
187
+ - `find_node_usages(node_id)` - Find all nodes that call or reference the specified node.
188
+ - `find_node_callees(node_id)` - Find all nodes that the specified node calls or references.
189
+ - `find_node_by_name(name, node_type)` - *Not implemented yet.*
190
+
191
+ ### Vector (semantic search)
192
+ - `search_in_workspace(query, workspace_id, top_k)` - Semantic search across all repositories and branches in a workspace.
193
+ - `search_in_repo_and_branch(repository_id, branch_name, query, top_k)` - Semantic search scoped to a specific repository and branch.
194
+
195
+ > Note: development builds (versions containing `dev`) also register an internal `debug` tool for inspecting the
196
+ > server's configuration. It is not available in stable releases.
197
+
198
+ ## Resources <a name="resources"></a>
199
+ Not implemented yet.
200
+
201
+ ## Prompts <a name="prompts"></a>
202
+ Prompts are reusable, pre-written instructions your coding agent can pull in as a starting point for a task. This
203
+ server provides the following prompts:
204
+
205
+ - `analyze_architecture(project)` - Analyze the software architecture of the given project: locate it, inspect its
206
+ file/project structure, and trace dependencies to produce a structured architecture summary.
207
+ - `prepare_for_change()` - Intended for use before refactoring, to look up usages of a function, class, or other
208
+ object and assess the blast radius of a change. *(work in progress)*
209
+ - `summarize_file()` - Summarize a file. *(work in progress)*
@@ -0,0 +1,193 @@
1
+ # Table of Contents
2
+ - [Introduction](#intro)
3
+ - [Requirements](#requirements)
4
+ - [Setup API Server](#setup-api-server)
5
+ - [Setup MCP Server](#setup-mcp-server)
6
+ - [Available CLI Commands](#available-cli-commands)
7
+ - [Available MCP Capabilities](#available-mcp-capabilities)
8
+ - [Tools](#tools)
9
+ - [Resources](#resources)
10
+ - [Prompts](#prompts)
11
+
12
+ # Introduction <a name="intro"></a>
13
+ This MCP server runs on your local machine and communicates over the `stdio` (Standard Input/Output) transport - meaning
14
+ it talks to your coding agent through standard input/output streams rather than over the network.
15
+
16
+ The server is published to `PyPI`, so you can run it directly with the `uvx` command, without a
17
+ manual installation step.
18
+ - Package name: `source-context-mcp`
19
+ - For more details: https://pypi.org/project/source-context-mcp/
20
+
21
+ This MCP server does not analyze your source code by itself. It is a thin bridge:
22
+ - It receives tool calls from your coding agent.
23
+ - It forwards those calls, with your credentials, to a REST API server.
24
+ - That API server is the one actually indexing and analyzing your codebase, and it returns the results back through
25
+ the MCP server to your agent.
26
+
27
+ So before using this MCP server, you need that REST API server up and running (locally or publicly hosted).
28
+
29
+ ```mermaid
30
+ flowchart
31
+ Agents["Coding Agents (Claude, Antigravity, ...)"]
32
+ MCP["This MCP Server"]
33
+ API["REST API Server (locally or publicly hosted)"]
34
+
35
+ Agents --> MCP
36
+ MCP --> API
37
+ ```
38
+
39
+ # Requirements <a name="requirements"></a>
40
+ - uv: a Python package manager, used to run this MCP locally via the `uvx` command (similar in spirit to `npx` for
41
+ Node.js packages).
42
+ - Python version: 3.12+
43
+ - A running REST API server with authentication enabled — see [Setup MCP Server](#setup-mcp-server) below for setup.
44
+
45
+ # Setup API Server <a name="setup-api-server"></a>
46
+ See: https://github.com/TuLe142857/source-context
47
+
48
+ This server manages your team workspace (a workspace can contain many repositories), handles indexing, analyzes the
49
+ codebase, and exposes the REST API that this MCP server calls. You can host it on your local machine or make it public
50
+ on the internet.
51
+
52
+ # Setup MCP Server <a name="setup-mcp-server"></a>
53
+ ## Step 1: Get your Personal Access Token
54
+ Log in to your REST API server and generate a PAT (Personal Access Token) from your account settings. This token
55
+ authenticates the MCP server's requests to the API on your behalf - treat it like a password.
56
+
57
+ ## Step 2: Configure the MCP Server
58
+ You have two ways to set the configuration:
59
+
60
+ **Option A — CLI command:**
61
+ ```shell
62
+ uvx source-context-mcp config \
63
+ --token <your token> \
64
+ --server-url <server_url>
65
+ ```
66
+ Security note: this command may save your token in your shell's command history.
67
+ Prefer Option B below if that's a concern for you.
68
+
69
+ **Option B (recommended) — edit the config file directly:**
70
+ Edit `~/.source_context_mcp/config.toml` (Linux/macOS) or `C:\Users\{username}\.source_context_mcp\config.toml` (Windows):
71
+ ```toml
72
+ SERVER_URL = "http://localhost:8000/mcp/v1"
73
+ PAT = "your token"
74
+ ```
75
+
76
+ ## Step 3: Add MCP server to your coding agent
77
+ This package is published to PyPI, so it can be run via `uvx source-context-mcp run`. It uses `typer` to wrap the MCP
78
+ server as a CLI (Command-Line Interface), so besides `run` it also exposes utility commands like `config`, `show-config`,
79
+ and `config-dir` - see [Available CLI Commands](#available-cli-commands) below.
80
+
81
+ ### Antigravity (IDE & CLI)
82
+ Global scope - Edit `~/.gemini/config/mcp_config.json` (Linux/macOS) or
83
+ `C:\Users\{username}\.gemini\config\mcp_config.json` (Windows):
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "source-context-mcp": {
88
+ "command": "uvx",
89
+ "args": ["source-context-mcp", "run"]
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ Project scope - Edit `.agents/mcp_config.json`:
96
+ ```json
97
+ {
98
+ "mcpServers": {
99
+ "source-context-mcp": {
100
+ "command": "uvx",
101
+ "args": ["source-context-mcp", "run"]
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### Claude Code
108
+ Global scope:
109
+ ```shell
110
+ claude mcp add --scope user source-context-mcp -- uvx source-context-mcp run
111
+ ```
112
+
113
+ Project scope - The following command writes to `.mcp.json`, which is shared with your team when committed to git:
114
+ ```shell
115
+ claude mcp add --scope project source-context-mcp -- uvx source-context-mcp run
116
+ ```
117
+
118
+ Local scope - Not shared with your team:
119
+ ```shell
120
+ claude mcp add source-context-mcp -- uvx source-context-mcp run
121
+ ```
122
+
123
+ ### Other Agents
124
+ If you're using a different coding agent, check its documentation for how to add a local MCP server over the `stdio`
125
+ transport. Most agents accept a generic JSON block like this:
126
+
127
+ ```json
128
+ {
129
+ "mcpServers": {
130
+ "source-context-mcp": {
131
+ "command": "uvx",
132
+ "args": ["source-context-mcp", "run"]
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ # Available CLI Commands <a name="available-cli-commands"></a>
139
+ The package installs a `source-context-mcp` CLI (built with `typer`). Run `uvx source-context-mcp --help` at any time
140
+ to see this list from the tool itself.
141
+
142
+ | Command | Description | Options |
143
+ |---------------|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
144
+ | `run` | Run the MCP server over the `stdio` transport. | `--server-url <url>`, `--token <token>`, `--workspace-id <id>` - override the saved config for this run only |
145
+ | `config` | Save configuration (server URL, token, default workspace ID) to the config file. | `--server-url <url>`, `--token <token>`, `--workspace-id <id>` |
146
+ | `show-config` | Print the current configuration. Secret values (e.g. the token) are masked as `*`. | |
147
+ | `config-dir` | Print the path to the configuration directory. | |
148
+
149
+ Global option (on the base `source-context-mcp` command):
150
+ - `--version` / `-v` - print the installed package version and exit.
151
+
152
+ # Available MCP Capabilities <a name="available-mcp-capabilities"></a>
153
+
154
+ ## Tools <a name="tools"></a>
155
+ Tools are like functions that this MCP server exposes to your coding agent. This server provides the following tools:
156
+
157
+ ### General
158
+ - `list_workspaces()` - List all workspaces accessible to the current user.
159
+ - `get_path_settings(path)` - Get the default workspace and repository settings configured for a local path.
160
+ - `default_workspace()` - Get the server-configured default workspace ID, used when the current path has no path-specific default.
161
+ - `list_repositories(workspace_id)` - List all repositories in a workspace.
162
+ - `list_branches(workspace_id, repository_id)` - List all branches in a repository.
163
+ - `list_projects(workspace_id, repository_id, branch_name)` - List all projects on a branch.
164
+
165
+ ### Graph (code structure & relationships)
166
+ - `list_files_in_project(project_id)` - List all files in a project.
167
+ - `get_file_structure(file_id)` - Get a file's structure: classes and methods.
168
+ - `get_file_content(file_id)` - Read a file's full content.
169
+ - `get_node_info(node_id)` - Get node metadata: id, name, file_id, position in file.
170
+ - `get_node_content(node_id)` - Get a node's source content.
171
+ - `find_node_usages(node_id)` - Find all nodes that call or reference the specified node.
172
+ - `find_node_callees(node_id)` - Find all nodes that the specified node calls or references.
173
+ - `find_node_by_name(name, node_type)` - *Not implemented yet.*
174
+
175
+ ### Vector (semantic search)
176
+ - `search_in_workspace(query, workspace_id, top_k)` - Semantic search across all repositories and branches in a workspace.
177
+ - `search_in_repo_and_branch(repository_id, branch_name, query, top_k)` - Semantic search scoped to a specific repository and branch.
178
+
179
+ > Note: development builds (versions containing `dev`) also register an internal `debug` tool for inspecting the
180
+ > server's configuration. It is not available in stable releases.
181
+
182
+ ## Resources <a name="resources"></a>
183
+ Not implemented yet.
184
+
185
+ ## Prompts <a name="prompts"></a>
186
+ Prompts are reusable, pre-written instructions your coding agent can pull in as a starting point for a task. This
187
+ server provides the following prompts:
188
+
189
+ - `analyze_architecture(project)` - Analyze the software architecture of the given project: locate it, inspect its
190
+ file/project structure, and trace dependencies to produce a structured architecture summary.
191
+ - `prepare_for_change()` - Intended for use before refactoring, to look up usages of a function, class, or other
192
+ object and assess the blast radius of a change. *(work in progress)*
193
+ - `summarize_file()` - Summarize a file. *(work in progress)*
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "source-context-mcp"
3
- version = "0.1.dev3"
3
+ version = "0.1.dev4"
4
4
  description = "Local Model Context Protocol (MCP) server for Source Context code intelligence."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "source-context-mcp"
3
- version = "0.1.dev3"
3
+ version = "0.1.dev4"
4
4
  description = "Local Model Context Protocol (MCP) server for Source Context code intelligence."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -1,8 +1,7 @@
1
- import importlib.metadata
2
-
3
1
  import typer
4
2
 
5
- from .core.settings import CONFIG_FILE, get_settings, get_settings_with_overrides, write_settings
3
+ from .core.metadata import get_package_version
4
+ from .core.settings import CONFIG_DIR, CONFIG_FILE, get_settings, get_settings_with_overrides, write_settings
6
5
  from .server import create_server
7
6
 
8
7
  cli = typer.Typer()
@@ -51,9 +50,14 @@ def show_config():
51
50
  typer.echo(settings_json)
52
51
 
53
52
 
53
+ @cli.command(name="config-dir", help="Show the MCP server's configuration directory")
54
+ def show_config_dir():
55
+ typer.echo(CONFIG_DIR)
56
+
57
+
54
58
  @cli.callback(invoke_without_command=True)
55
59
  def version_check(
56
60
  version: bool = typer.Option(False, "--version", "-v", help="Show version"),
57
61
  ):
58
62
  if version:
59
- typer.echo(importlib.metadata.version("source-context-mcp"))
63
+ typer.echo(get_package_version())
@@ -0,0 +1,16 @@
1
+ import importlib.metadata
2
+ from functools import lru_cache
3
+
4
+ _PACKAGE_NAME = "source-context-mcp"
5
+
6
+
7
+ @lru_cache
8
+ def get_package_version() -> str:
9
+ """
10
+ Get package version.
11
+ Read from ``pyproject.toml`` file.
12
+
13
+ Returns:
14
+ This package version.
15
+ """
16
+ return importlib.metadata.version("source-context-mcp")
@@ -14,8 +14,8 @@ class Settings(BaseSettings):
14
14
  toml_file=str(CONFIG_FILE),
15
15
  )
16
16
 
17
- SERVER_URL: str = "default"
18
- """Server URL. Include prefix. Example: http://localhost:8000/mcp/v1"""
17
+ SERVER_URL: str = "http://localhost:8000/mcp/v1"
18
+ """Server URL. Include prefix. Default: http://localhost:8000/mcp/v1"""
19
19
 
20
20
  PAT: SecretStr = SecretStr("Default")
21
21
  """Personal access token"""
@@ -24,7 +24,10 @@ class Settings(BaseSettings):
24
24
  """Default Workspace ID"""
25
25
 
26
26
  PATH_WORKSPACE: dict[str, int] = {}
27
+ """Map [path, default_workspace_id]]"""
28
+
27
29
  PATH_REPO: dict[str, int] = {}
30
+ """Map [path, default_repo_id]]"""
28
31
 
29
32
  @classmethod
30
33
  def settings_customise_sources(
@@ -85,6 +88,8 @@ def write_settings(settings: Settings):
85
88
  "SERVER_URL": settings.SERVER_URL,
86
89
  "PAT": settings.PAT.get_secret_value(),
87
90
  "DEFAULT_WORKSPACE_ID": settings.DEFAULT_WORKSPACE_ID,
91
+ "PATH_WORKSPACE": settings.PATH_WORKSPACE,
92
+ "PATH_REPO": settings.PATH_REPO,
88
93
  }
89
94
 
90
95
  with CONFIG_FILE.open("wb") as f:
@@ -0,0 +1,19 @@
1
+ from mcp.server import MCPServer
2
+
3
+ from .analyze_architecture import register_prompts as register_analyze_architecture
4
+ from .prepare_for_change import register_prompts as register_prepare_for_change
5
+ from .summarize_file import register_prompts as register_summarize_file
6
+
7
+
8
+ def register_prompts(mcp: MCPServer) -> None:
9
+ """
10
+ Register prompts for MCP server
11
+ Args:
12
+ mcp: MCPServer instance
13
+ """
14
+ register_analyze_architecture(mcp)
15
+ register_prepare_for_change(mcp)
16
+ register_summarize_file(mcp)
17
+
18
+
19
+ __all__ = ["register_prompts"]
@@ -0,0 +1,30 @@
1
+ from typing import Annotated
2
+
3
+ from mcp.server import MCPServer
4
+ from pydantic import Field
5
+
6
+
7
+ def register_prompts(mcp: MCPServer):
8
+ @mcp.prompt(
9
+ description="Analyze the software architecture of the given project",
10
+ )
11
+ def analyze_architecture(project: Annotated[str, Field(description="Project name")]):
12
+ return f"""
13
+ Analyze the software architecture of the project: '{project}'.
14
+
15
+ Step 1:Identify the Project:
16
+ - If the exact project location or repository is unclear, use tools such as `list_projects`, `list_repositories`, \
17
+ or `list_branches` to locate and confirm the target project.
18
+
19
+ Step 2: Analyze Project Structure (Token-Efficient Approach):
20
+ - Start by calling `get_file_structure` (or `list_files`) to inspect the directory layout.
21
+ - *Best Practice*: Always prefer `get_file_structure` first, as it returns only the structure without full source \
22
+ code, conserving API tokens.
23
+ - Only call `get_file_content` for specific files when you need detailed implementation insights.
24
+
25
+ Step 3: Deepen Architecture Analysis(If needed):
26
+ - Depending on the architecture aspects you are investigating, use additional tools such as `find_node_usages`, \
27
+ `find_node_callees`, or any other relevant analysis tools to trace dependencies and data flow.
28
+
29
+ Provide a clear, structured summary of the architectural patterns, key components, and relationships found in the \
30
+ project."""
@@ -0,0 +1,49 @@
1
+ from typing import Annotated
2
+
3
+ from mcp.server import MCPServer
4
+ from pydantic import Field
5
+
6
+
7
+ def register_prompts(mcp: MCPServer):
8
+ @mcp.prompt(
9
+ description="Use when refactor code. Look for object(function, class, ...) usage to detect refactor effect"
10
+ )
11
+ def prepare_for_change(
12
+ target: Annotated[
13
+ str, Field(description="Name of the function, class, method, or variable you are about to change.")
14
+ ],
15
+ project: Annotated[str, Field(description="Project name where the target is located, if known.")] = "",
16
+ change_description: Annotated[
17
+ str, Field(description="Optional description of the change you intend to make.")
18
+ ] = "",
19
+ ):
20
+ change_note = f"\nIntended change: {change_description}\n" if change_description else ""
21
+ project_note = f" in project '{project}'" if project else ""
22
+
23
+ return f"""
24
+ Prepare for a change to '{target}'{project_note}.{change_note}
25
+
26
+ Step 1: Locate the Target:
27
+ - If the exact project, file, or node is unclear, use `list_projects`, `list_repositories`, `list_branches`, or \
28
+ semantic search (`search_in_workspace` / `search_in_repo_and_branch`) to find it.
29
+ - Once the project is known, prefer `list_files_in_project` and `get_file_structure` to locate the node without \
30
+ reading full file contents.
31
+ - Use `get_node_info` to confirm you have the right node before proceeding.
32
+
33
+ Step 2: Understand the Current Implementation:
34
+ - Call `get_node_content` on the target node to review its current signature and behavior.
35
+
36
+ Step 3: Assess the Blast Radius:
37
+ - Call `find_node_usages` on the target node to list every node that calls or references it. This is the primary \
38
+ signal for how risky the change is - the more usages, the wider the blast radius.
39
+ - For each usage that could be affected (e.g. call sites depending on a changed signature, return type, or \
40
+ behavior), inspect it with `get_node_content` or `get_file_content` to understand exactly how the target is used.
41
+
42
+ Step 4: Check Internal Dependencies (if the change affects internal logic):
43
+ - Call `find_node_callees` on the target node to see what it depends on, so you don't break assumptions the \
44
+ target relies on.
45
+
46
+ Step 5: Summarize:
47
+ - List every affected file/node found in Step 3.
48
+ - Flag usages that are likely to break or need updating given the intended change.
49
+ - Recommend what should be tested or reviewed before making the change."""
@@ -0,0 +1,33 @@
1
+ from typing import Annotated
2
+
3
+ from mcp.server import MCPServer
4
+ from pydantic import Field
5
+
6
+
7
+ def register_prompts(mcp: MCPServer):
8
+ @mcp.prompt(description="Summarize file")
9
+ def summarize_file(
10
+ file: Annotated[str, Field(description="File path or file name to summarize.")],
11
+ project: Annotated[
12
+ str, Field(description="Project name the file belongs to, to help locate it if the path is ambiguous.")
13
+ ] = "",
14
+ ):
15
+ project_note = f" in project '{project}'" if project else ""
16
+
17
+ return f"""
18
+ Summarize the file '{file}'{project_note}.
19
+
20
+ Step 1: Locate the File:
21
+ - If the exact project or file ID is unclear, use `list_projects` to find the project, then `list_files_in_project` \
22
+ to find the matching file.
23
+
24
+ Step 2: Inspect Structure (Token-Efficient Approach):
25
+ - Start with `get_file_structure` to see the file's classes, methods, and functions without reading the full \
26
+ source.
27
+ - Only call `get_file_content` if you need the actual implementation details to write an accurate summary.
28
+
29
+ Step 3: Summarize:
30
+ - State the file's purpose and its role within the project.
31
+ - List its main classes/functions and what each one does, at a high level.
32
+ - Note any notable dependencies or relationships to other parts of the codebase (use `find_node_usages` or \
33
+ `find_node_callees` on specific nodes only if that context is needed)."""
@@ -0,0 +1,11 @@
1
+ from mcp.server import MCPServer
2
+
3
+
4
+ def register_resources(mcp: MCPServer):
5
+ """
6
+ Currently not implemented
7
+ """
8
+ pass
9
+
10
+
11
+ __all__ = ["register_resources"]
@@ -0,0 +1,92 @@
1
+ from collections.abc import AsyncIterator
2
+ from contextlib import asynccontextmanager
3
+
4
+ from mcp.server import MCPServer
5
+
6
+ from source_context_mcp.core import ApiClient, AppContext, get_settings_with_overrides
7
+ from source_context_mcp.core.metadata import get_package_version
8
+ from source_context_mcp.prompts import register_prompts
9
+ from source_context_mcp.resources import register_resources
10
+ from source_context_mcp.tools import register_tools
11
+
12
+ SERVER_DESCRIPTION = """
13
+ SourceContextMCP is an MCP server that gives AI coding assistants structured, queryable access to indexed source code \
14
+ across workspaces, repositories, branches, and projects. It exposes tools to browse project/file structure, read file \
15
+ and code-node content, traverse call/reference graphs between code nodes, and run semantic (vector) search over a \
16
+ codebase — letting an agent explore and understand large, multi-repository codebases without needing direct local file \
17
+ access."
18
+ """
19
+
20
+ SERVER_INSTRUCTIONS = """
21
+ SourceContextMCP gives read-only access to a pre-indexed source of truth for one or more codebases, organized as: \
22
+ workspace -> repository -> branch -> project -> file -> node (class/method/function/variable/...).
23
+
24
+ Most tools require one or more IDs (workspace_id, repository_id, project_id, file_id, node_id). These are opaque and \
25
+ server-assigned - never guess them. Always obtain them from the matching listing tool or reuse an ID from a previous \
26
+ call.
27
+
28
+ Resolve scope before calling graph or search tools. Try get_path_settings(path) first if the user is working inside a \
29
+ local checkout; fall back to default_workspace() if no path-specific config exists. Otherwise narrow down with \
30
+ list_workspaces -> list_repositories -> list_branches -> list_projects.
31
+
32
+ Once you have a project_id, use list_files_in_project for file_ids, then get_file_structure before get_file_content \
33
+ when you only need an overview or a node_id - avoid reading full file contents unless necessary.
34
+
35
+ For call-graph relationships on a node_id: use find_node_usages before renaming or changing a signature to assess \
36
+ blast radius, and find_node_callees to understand what a symbol depends on. Prefer graph traversal over semantic \
37
+ search when you need precise, complete relationships - semantic search is approximate and may miss or over-return \
38
+ results.
39
+
40
+ Use search_in_workspace or search_in_repo_and_branch (prefer the latter when repository/branch is already known - more \
41
+ precise) when you don't know exact file/node names. Treat semantic search as an entry point, then switch to graph \
42
+ tools for precise structured details.
43
+ """
44
+
45
+
46
+ def make_life_span(
47
+ base_url_override: str | None = None, pat_override: str | None = None, workspace_id_override: int | None = None
48
+ ):
49
+ @asynccontextmanager
50
+ async def server_lifespan(app: MCPServer) -> AsyncIterator[AppContext]:
51
+ settings = get_settings_with_overrides(
52
+ server_url_override=base_url_override,
53
+ pat_override=pat_override,
54
+ default_workspace_id_override=workspace_id_override,
55
+ )
56
+
57
+ yield AppContext(
58
+ api_client=ApiClient(base_url=settings.SERVER_URL, token=settings.PAT.get_secret_value()), settings=settings
59
+ )
60
+
61
+ return server_lifespan
62
+
63
+
64
+ def create_server(
65
+ base_url_override: str | None = None, pat_override: str | None = None, workspace_id_override: int | None = None
66
+ ) -> MCPServer:
67
+ """
68
+ Create an MCPServer instance.
69
+
70
+ Args:
71
+ base_url_override: override default server URL
72
+ pat_override: override default Personal Access Token
73
+ workspace_id_override: override default workspace ID
74
+ """
75
+
76
+ life_span = make_life_span(
77
+ base_url_override=base_url_override, pat_override=pat_override, workspace_id_override=workspace_id_override
78
+ )
79
+
80
+ server = MCPServer(
81
+ name="source-context-mcp",
82
+ lifespan=life_span,
83
+ version=get_package_version(),
84
+ description=SERVER_DESCRIPTION,
85
+ instructions=SERVER_INSTRUCTIONS,
86
+ )
87
+
88
+ register_tools(server)
89
+ register_resources(server)
90
+ register_prompts(server)
91
+
92
+ return server
@@ -8,7 +8,7 @@ from .vector import register_tools as register_vector_tools
8
8
 
9
9
  def register_tools(mcp: MCPServer) -> None:
10
10
  """
11
- Registry tools for MCPServer.
11
+ Register tools for MCPServer.
12
12
  Args:
13
13
  mcp: instance of MCPServer
14
14
  """
@@ -17,3 +17,6 @@ def register_tools(mcp: MCPServer) -> None:
17
17
  register_base_tools(mcp)
18
18
  register_graph_tools(mcp)
19
19
  register_vector_tools(mcp)
20
+
21
+
22
+ __all__ = ["register_tools"]
@@ -1,34 +1,24 @@
1
- from typing import Any
1
+ from typing import Annotated, Any
2
2
 
3
3
  from mcp.server import MCPServer
4
4
  from mcp.server.mcpserver import Context
5
+ from pydantic import Field
5
6
 
6
7
  from source_context_mcp.core import ApiClientDep, AppContext
7
8
 
8
9
 
9
10
  def register_tools(mcp: MCPServer) -> None:
10
- """
11
- Register bases tools:
12
- - list user's available workspaces
13
- - list repos in workspace
14
- - list branches in repo
15
- - list projects in branch
16
11
 
17
- Args:
18
- mcp: MCPServer instance
19
- """
20
-
21
- @mcp.tool(description="List all available workspaces that current user can access")
12
+ @mcp.tool(description="List all workspaces accessible to the current user.")
22
13
  async def list_workspaces(client: ApiClientDep) -> Any:
23
14
  res = await client.get("/general/workspaces", response_model=list)
24
15
  return res.result()
25
16
 
26
- @mcp.tool(
27
- description=(
28
- "Get the default settings for specified directory.Include default workspace id adn default repository id."
29
- )
30
- )
31
- async def get_path_settings(ctx: Context[AppContext], path: str) -> dict[str, Any]:
17
+ @mcp.tool(description="Get default workspace and repository settings configured for a local path.")
18
+ async def get_path_settings(
19
+ ctx: Context[AppContext],
20
+ path: Annotated[str, Field(description="Local directory path to look up default settings for.")],
21
+ ) -> dict[str, Any]:
32
22
  app_context: AppContext = ctx.request_context.lifespan_context
33
23
  settings = app_context.settings
34
24
  return {
@@ -38,25 +28,27 @@ def register_tools(mcp: MCPServer) -> None:
38
28
  }
39
29
 
40
30
  @mcp.tool(
41
- description=(
42
- "Get default workspace. "
43
- "This is the default workspace use settings in case current path has no default config"
44
- )
31
+ description="Get the server-configured default workspace ID, used when the current path has no path-specific "
32
+ "default."
45
33
  )
46
34
  async def default_workspace(ctx: Context[AppContext]) -> Any:
47
35
  app_context: AppContext = ctx.request_context.lifespan_context
48
36
  return app_context.settings.DEFAULT_WORKSPACE_ID
49
37
 
50
- @mcp.tool(description="List all available repositories in workspace")
38
+ @mcp.tool(description="List all repositories in a workspace.")
51
39
  async def list_repositories(
52
40
  client: ApiClientDep,
53
- workspace_id: int,
41
+ workspace_id: Annotated[int, Field(description="Workspace ID.", ge=1)],
54
42
  ) -> Any:
55
43
  res = await client.post("/general/repositories", {"workspace_id": workspace_id})
56
44
  return res.result()
57
45
 
58
- @mcp.tool(description="List all available branches in specified repository.")
59
- async def list_branches(client: ApiClientDep, workspace_id: int, repository_id: int) -> Any:
46
+ @mcp.tool(description="List all branches in a repository.")
47
+ async def list_branches(
48
+ client: ApiClientDep,
49
+ workspace_id: Annotated[int, Field(description="Workspace ID.", ge=1)],
50
+ repository_id: Annotated[int, Field(description="Repository ID.", ge=1)],
51
+ ) -> Any:
60
52
  req_body = {
61
53
  "workspace_id": workspace_id,
62
54
  "repository_id": repository_id,
@@ -64,8 +56,13 @@ def register_tools(mcp: MCPServer) -> None:
64
56
  res = await client.post("/general/branches", req_body)
65
57
  return res.result()
66
58
 
67
- @mcp.tool(description="List all available projects in specific branch.")
68
- async def list_projects(client: ApiClientDep, workspace_id: int, repository_id: int, branch_name: str) -> Any:
59
+ @mcp.tool(description="List all projects on a branch.")
60
+ async def list_projects(
61
+ client: ApiClientDep,
62
+ workspace_id: Annotated[int, Field(description="Workspace ID.", ge=1)],
63
+ repository_id: Annotated[int, Field(description="Repository ID.", ge=1)],
64
+ branch_name: Annotated[str, Field(description="Branch name.")],
65
+ ) -> Any:
69
66
  req_body = {
70
67
  "workspace_id": workspace_id,
71
68
  "repo_id": repository_id,
@@ -0,0 +1,27 @@
1
+ from mcp.server import MCPServer
2
+ from mcp.server.mcpserver import Context
3
+
4
+ from source_context_mcp.core import AppContext, Settings
5
+ from source_context_mcp.core.metadata import get_package_version
6
+
7
+
8
+ def register_tools(mcp: MCPServer):
9
+ """
10
+ Register development-only MCP tools.
11
+
12
+ These tools are registered only when the package version is a
13
+ development release (e.g. ``0.1.0.dev1``). They are excluded from
14
+ alpha, beta, release candidate, and stable builds.
15
+
16
+ Args:
17
+ mcp: The MCP server instance to register tools with.
18
+ """
19
+
20
+ version = get_package_version()
21
+ if "dev" not in version:
22
+ return
23
+
24
+ @mcp.tool(description="Show current server configuration. For development use only.")
25
+ def debug(ctx: Context[AppContext]) -> Settings:
26
+ app_context: AppContext = ctx.request_context.lifespan_context
27
+ return app_context.settings
@@ -0,0 +1,76 @@
1
+ from typing import Annotated, Any, Literal
2
+
3
+ from mcp.server import MCPServer
4
+ from pydantic import Field
5
+
6
+ from source_context_mcp.core import ApiClientDep
7
+
8
+
9
+ def register_tools(mcp: MCPServer) -> None:
10
+
11
+ @mcp.tool(description="List all files in a project.")
12
+ async def list_files_in_project(
13
+ client: ApiClientDep,
14
+ project_id: Annotated[str, Field(description="Project ID.")],
15
+ ) -> Any:
16
+ res = await client.get(f"/graph/projects/{project_id}/files")
17
+ return res.result()
18
+
19
+ @mcp.tool(description="Get file structure: classes and methods.")
20
+ async def get_file_structure(
21
+ client: ApiClientDep,
22
+ file_id: Annotated[str, Field(description="File ID.")],
23
+ ) -> Any:
24
+ res = await client.get(f"/graph/files/{file_id}/structure")
25
+ return res.result()
26
+
27
+ @mcp.tool(description="Read file content.")
28
+ async def get_file_content(
29
+ client: ApiClientDep,
30
+ file_id: Annotated[str, Field(description="File ID.")],
31
+ ) -> Any:
32
+ res = await client.get(f"/graph/files/{file_id}/content")
33
+ return res.result()
34
+
35
+ @mcp.tool(description="Get node metadata: id, name, file_id, position in file.")
36
+ async def get_node_info(
37
+ client: ApiClientDep,
38
+ node_id: Annotated[str, Field(description="Node ID.")],
39
+ ) -> Any:
40
+ res = await client.get(f"/graph/nodes/{node_id}")
41
+ return res.result()
42
+
43
+ @mcp.tool(description="Get node source content.")
44
+ async def get_node_content(
45
+ client: ApiClientDep,
46
+ node_id: Annotated[str, Field(description="Node ID.")],
47
+ ) -> Any:
48
+ res = await client.get(f"/graph/nodes/{node_id}/content")
49
+ return res.result()
50
+
51
+ # @mcp.tool(description="This tool not implemented yet.")
52
+ # async def find_node_by_name(
53
+ # client: ApiClientDep,
54
+ # name: Annotated[str, Field(description="The name of the node")],
55
+ # node_type: Annotated[
56
+ # Literal["type-definition", "", None],
57
+ # Field(default=None, description="The type of the node. Default is all types"),
58
+ # ],
59
+ # ) -> Any:
60
+ # return []
61
+
62
+ @mcp.tool(description="Find all nodes that call or reference the specified node.")
63
+ async def find_node_usages(
64
+ client: ApiClientDep,
65
+ node_id: Annotated[str, Field(description="Node ID.")],
66
+ ) -> Any:
67
+ res = await client.get(f"/graph/nodes/{node_id}/usages")
68
+ return res.result()
69
+
70
+ @mcp.tool(description="Find all nodes that the specified node calls or references.")
71
+ async def find_node_callees(
72
+ client: ApiClientDep,
73
+ node_id: Annotated[str, Field(description="Node ID.")],
74
+ ) -> Any:
75
+ res = await client.get(f"/graph/nodes/{node_id}/callees")
76
+ return res.result()
@@ -0,0 +1,42 @@
1
+ from typing import Annotated, Any
2
+
3
+ from mcp.server import MCPServer
4
+ from pydantic import Field
5
+
6
+ from source_context_mcp.core import ApiClientDep
7
+
8
+
9
+ def register_tools(mcp: MCPServer) -> None:
10
+
11
+ @mcp.tool(description="Semantic search across all repositories and branches in a workspace.")
12
+ async def search_in_workspace(
13
+ client: ApiClientDep,
14
+ query: Annotated[str, Field(description="Query to search in workspace.")],
15
+ workspace_id: Annotated[int, Field(ge=1, description="Workspace ID.")],
16
+ top_k: Annotated[int, Field(default=5, ge=1, le=50, description="Number of top results to return.")],
17
+ ) -> Any:
18
+ req_body = {
19
+ "query": query,
20
+ "top_k": top_k,
21
+ }
22
+
23
+ res = await client.post(f"/vector/search/{workspace_id}", req_body)
24
+
25
+ return res.result()
26
+
27
+ @mcp.tool(description="Semantic search scoped to a specific repository and branch.")
28
+ async def search_in_repo_and_branch(
29
+ client: ApiClientDep,
30
+ repository_id: Annotated[int, Field(ge=1, description="Repository ID.")],
31
+ branch_name: Annotated[str, Field(description="Branch name.")],
32
+ query: Annotated[str, Field(description="Query to search in branch scope.")],
33
+ top_k: Annotated[int, Field(default=5, ge=1, le=50, description="Number of top results to return.")],
34
+ ) -> Any:
35
+ req_body = {
36
+ "query": query,
37
+ "top_k": top_k,
38
+ }
39
+
40
+ res = await client.post(f"/vector/search/{repository_id}/{branch_name}", req_body)
41
+
42
+ return res.result()
@@ -1,17 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: source-context-mcp
3
- Version: 0.1.dev3
4
- Summary: Local Model Context Protocol (MCP) server for Source Context code intelligence.
5
- Author: Le Ngoc Tu, Dang Huu Hieu, Huynh Phat Tai
6
- Author-email: Le Ngoc Tu <tuleaibk@gmail.com>, Dang Huu Hieu <danghuuhieu038@gmail.com>, Huynh Phat Tai <huynhphtai@gmail.com>
7
- Requires-Dist: httpx>=0.28.1
8
- Requires-Dist: mcp[cli]>=2.0.0
9
- Requires-Dist: pydantic>=2.13.4
10
- Requires-Dist: pydantic-settings>=2.14.2
11
- Requires-Dist: tomli-w>=1.2.0
12
- Requires-Dist: typer>=0.27.0
13
- Requires-Python: >=3.12
14
- Project-URL: Repository, https://github.com/TuLe142857/source-context
15
- Description-Content-Type: text/markdown
16
-
17
- # Readme for MCP Server
@@ -1 +0,0 @@
1
- # Readme for MCP Server
@@ -1,48 +0,0 @@
1
- from collections.abc import AsyncIterator
2
- from contextlib import asynccontextmanager
3
-
4
- from mcp.server import MCPServer
5
-
6
- from source_context_mcp.core import ApiClient, AppContext, get_settings_with_overrides
7
- from source_context_mcp.tools import register_tools
8
-
9
-
10
- def make_life_span(
11
- base_url_override: str | None = None, pat_override: str | None = None, workspace_id_override: int | None = None
12
- ):
13
- @asynccontextmanager
14
- async def server_lifespan(app: MCPServer) -> AsyncIterator[AppContext]:
15
- settings = get_settings_with_overrides(
16
- server_url_override=base_url_override,
17
- pat_override=pat_override,
18
- default_workspace_id_override=workspace_id_override,
19
- )
20
-
21
- yield AppContext(
22
- api_client=ApiClient(base_url=settings.SERVER_URL, token=settings.PAT.get_secret_value()), settings=settings
23
- )
24
-
25
- return server_lifespan
26
-
27
-
28
- def create_server(
29
- base_url_override: str | None = None, pat_override: str | None = None, workspace_id_override: int | None = None
30
- ) -> MCPServer:
31
- """
32
- Create an MCPServer instance.
33
- Returns:
34
- MCPServer instance.
35
- """
36
-
37
- life_span = make_life_span(
38
- base_url_override=base_url_override, pat_override=pat_override, workspace_id_override=workspace_id_override
39
- )
40
-
41
- server = MCPServer(
42
- name="SourceContextMCP",
43
- lifespan=life_span,
44
- )
45
-
46
- register_tools(server)
47
-
48
- return server
@@ -1,11 +0,0 @@
1
- from mcp.server import MCPServer
2
- from mcp.server.mcpserver import Context
3
-
4
- from source_context_mcp.core import AppContext, Settings
5
-
6
-
7
- def register_tools(mcp: MCPServer):
8
- @mcp.tool(description="This tool for development env only. Show all current config. Read source code to see more")
9
- def debug(ctx: Context[AppContext]) -> Settings:
10
- app_context: AppContext = ctx.request_context.lifespan_context
11
- return app_context.settings
@@ -1,48 +0,0 @@
1
- from typing import Any
2
-
3
- from mcp.server import MCPServer
4
-
5
- from source_context_mcp.core import ApiClientDep
6
-
7
-
8
- def register_tools(mcp: MCPServer) -> None:
9
- """
10
- Registers all the graph tools.
11
- Args:
12
- mcp: MCPServer instance
13
- """
14
-
15
- @mcp.tool(description="List all files in specified project.")
16
- async def list_files_in_project(client: ApiClientDep, project_id: str) -> Any:
17
- res = await client.get(f"/graph/projects/{project_id}/files")
18
- return res.result()
19
-
20
- @mcp.tool(description="Inspect file structure(classes and methods")
21
- async def get_file_structure(client: ApiClientDep, file_id: str) -> Any:
22
- res = await client.get(f"/graph/files/{file_id}/structure")
23
- return res.result()
24
-
25
- @mcp.tool(description="Read file content.")
26
- async def get_file_content(client: ApiClientDep, file_id: str) -> Any:
27
- res = await client.get(f"/graph/files/{file_id}/content")
28
- return res.result()
29
-
30
- @mcp.tool(description="Get node information: id, name, file_id, position in file")
31
- async def get_node_info(client: ApiClientDep, node_id: str) -> Any:
32
- res = await client.get(f"/graph/nodes/{node_id}")
33
- return res.result()
34
-
35
- @mcp.tool(description="Get node information.")
36
- async def get_node_content(client: ApiClientDep, node_id: str) -> Any:
37
- res = await client.get(f"/graph/nodes/{node_id}/content")
38
- return res.result()
39
-
40
- @mcp.tool(description="Find all nodes that call/reference to the specified node.")
41
- async def find_node_usages(client: ApiClientDep, node_id: str) -> Any:
42
- res = await client.get(f"/graph/nodes/{node_id}/usages")
43
- return res.result()
44
-
45
- @mcp.tool(description="Find all nodes(or its children) that the specified node is calling or reference to.")
46
- async def find_node_callees(client: ApiClientDep, node_id: str) -> Any:
47
- res = await client.get(f"/graph/nodes/{node_id}/callees")
48
- return res.result()
@@ -1,37 +0,0 @@
1
- from typing import Any
2
-
3
- from mcp.server import MCPServer
4
-
5
- from source_context_mcp.core import ApiClientDep
6
-
7
-
8
- def register_tools(mcp: MCPServer) -> None:
9
- """
10
- Registers all the vector tools.
11
- Args:
12
- mcp: MCP server instance
13
- """
14
-
15
- @mcp.tool(description="Sematic search.")
16
- async def search_in_workspace(client: ApiClientDep, query: str, workspace_id: int, top_k: int = 5) -> Any:
17
- req_body = {
18
- "query": query,
19
- "top_k": top_k,
20
- }
21
-
22
- res = await client.post(f"/vector/search/{workspace_id}", req_body)
23
-
24
- return res.result()
25
-
26
- @mcp.tool(description="Sematic search.")
27
- async def search_in_repo_and_branch(
28
- client: ApiClientDep, repository_id: int, branch_name: str, query: str, top_k: int = 5
29
- ) -> Any:
30
- req_body = {
31
- "query": query,
32
- "top_k": top_k,
33
- }
34
-
35
- res = await client.post(f"/vector/search/{repository_id}/{branch_name}", req_body)
36
-
37
- return res.result()